利用 autoconf 和 automake 生成 Makefile 文件
一、相关概念的介绍
什么是 Makefile?怎么书写 Makefile?竟然有工具可以自动生成 Makefile?怎么生成啊?开始的时候,我有这么多疑问,所以,必须得先把基本的概念搞个清楚。
1、Makefile
makefile用来定义整个工程的编译规则。一个工程中的源文件计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
2、Autoconf
Autoconf是一个用于生成可以自动地配置软件源代码包以适应多种Unix类系统的 shell脚本的工具。由Autoconf生成的配置脚本在运行的时候与Autoconf是无关的, 就是说配置脚本的用户并不需要拥有Autoconf。
对于每个使用了Autoconf的软件包,Autoconf从一个列举了该软件包需要的,或者可以使用的系统特征的列表的模板文件中生成配置脚本。在shell代码识别并响应了一个被列出的系统特征之后,Autoconf允许多个可能使用(或者需要)该特征的软件包共享该特征。 如果后来因为某些原因需要调整shell代码,就只要在一个地方进行修改; 所有的配置脚本都将被自动地重新生成以使用更新了的代码。
3、Automake
Automake是一个从文件 Makefile.am 自动生成 Makefile.in 的工具。每个 Makefile.am 基本上是一系列 make 的宏定义 (make规则也会偶尔出现)。生成的 Makefile.in 服从 GNU Makefile 标准。GNU Makefile 标准文档长、复杂,而且会发生改变。Automake 的目的就是解除个人GNU维护者维护 Makefile 的负担 (并且让Automake的维护者来承担这个负担)。典型的 Automake 输入文件是一系列简单的宏定义。处理所有这样的文件以创建 Makefile.in。在一个项目(project)的每个目录中通常包含一个 Makefile.am 。Automake 在几个方面对一个项目做了限制,例如它假定项目使用 Autoconf 并且对 configure.in 的内容施加了某些限制。
Automake支持三种目录层次: “flat”、“shallow”和“deep”。一个flat(平)包指的是所有文件都在一个目录中的包。为这类包提供的 Makefile.am 缺少宏 SUBDIRS。这类包的一个例子是 termutils。一个deep(深)包指的是所有的源代码都被储存在子目录中的包;顶层 目录主要包含配置信息。GNU cpio 是这类包的一个很好的例子,GNU tar也是。deep包的顶层 Makefile.am 将包括 宏SUBDIRS,但没有其它定义需要创建的对象的宏。一个shallow(浅)包指的是主要的源代码储存在顶层目录中,而 各个部分(典型的是库)则储存在子目录中的包。Automake本身就是这类包(GNU make也是如此,它现在已经不使用automake)。
二、安装必须的工具
Unbuntu 下安装方式
sudo apt-get -y install gcc autoconf automake libtool
三、Flat目录结构:
1、目录结构:
helloworld
├── mymain.c
├── mytest.c
└── mytest.h
顶级目录helloworld,该目录下存在三个文件。mytest.h头文件声明了sayhello()方法;mytest.c中实现了sayhello()方法;mymain.c中的main调用了sayhello()方法。
mytest.h 文件内容:
#ifndef MYTEST_H_
#define MYTEST_H_ void sayHello(); #endif
mytest.c 文件内容:
#include <stdio.h>
#include "mytest.h" void sayHello()
{
printf("Hello World!\n");
}
mymain.c 文件内容:
#include "mytest.h" int main()
{
sayHello();
return 0;
}
2、执行步骤:
2.1. 执行 autoscan
,在helloworld目录下执行autoscan命令,其中生成一个 configure.scan 的文件。
2.2. 将 configure.scan 文件更名为 configure.in
文件
2.3. 打开 configure.in 文件,修改文件内容
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script. #AC_PREREQ([2.68])
AC_INIT([hello], [1.0], [php-note.com@163.com])
AC_CONFIG_SRCDIR([mymain.c])
#AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE(hello, 1.0) # Checks for programs.
AC_PROG_CC # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT(Makefile)
2.4. 然后分别执行以下两个命令:
aclocal
autoconf
2.5. 在helloworld文件夹下创建一个名为 Makefile.am
的文件,并输入一下内容:
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=hello
hello_SOURCES=mymain.c mytest.c mytest.h
2.6. 执行命令“automake --add-missing
”,automake 会根据 Makefile.am 文件产生一些文件,其中包含最重要的 Makefile.in
2.7. 执行“./configure
”命令生成 Makefile 文件
2.8. 执行“make
”命令来编译 mymain.c 程序,从而生成可执行程序 hello。生成可执行程序hello后,执行“./hello
”,输出“Hello World!”。
四、Shallow目录结构
1、目录结构
helloworld
├── head
│ ├── mytest.c
│ └── mytest.h
└── mymain.c
顶级目录 helloworld,该目录下存在一个主文件 mymain.c 和一个目录 head。head目录中,mytest.h 头文件声明了 sayHello()方法;mytest.c 中实现了 sayHello()方法;mymain.c 中的 main 调用了 sayhello()方法。
head/mytest.h 文件内容:
#ifndef MYTEST_H_
#define MYTEST_H_ void sayHello(); #endif
head/mytest.c 文件内容:
#include <stdio.h>
#include "mytest.h" void sayHello()
{
printf("Hello World !\n");
}
mymain.c 文件内容:
#include "head/mytest.h" int main()
{
sayHello();
return 0;
}
2、执行步骤:
2.1. 在顶层目录下运行 autoscan
产生 configure.scan 文件
2.2. 将 configure.scan 文件更名为 configure.in
文件
2.3. 打开 configure.in 文件,修改文件内容
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script. AC_PREREQ([2.68])
AC_INIT([hello], [1.0], [php-note.com@163.com])
AC_CONFIG_SRCDIR([mymain.c])
#AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE(hello, 1.0) # Checks for programs.
AC_PROG_CC # 使用静态库编译,需要此宏定义
AC_PROG_RANLIB # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT(Makefile head/Makefile)
2.4. 然后分别执行以下两个命令:
aclocal
autoconf
2.5 在 head 文件夹下创建 Makefile.am
文件,内容如下:
AUTOMAKE_OPTIONS=foreign
noinst_LIBRARIES=libmytest.a
libmytest_a_SOURCES=mytest.h mytest.c
2.6. 在 helloworld 文件夹下创建 Makefile.am
文件,内容如下:
AUTOMAKE_OPTIONS=foreign
SUBDIRS=head
bin_PROGRAMS=hello
hello_SOURCES=mymain.c
hello_LDADD=head/libmytest.a
2.7. 执行命令“automake --dd-missing
”,automake 会根据 Makefile.am 文件产生一些文件,其中包含最重要的 Makefile.in
2.8. 执行“./configure
”命令生成 Makefile 文件
2.9. 执行“make
”命令来编译 mymain.c 程序,从而生成可执行程序hello。生成可执行程序 hello 后,执行“./hello
”,输入“Hello World!”。
五、Deep目录结构
1、目录结构
helloworld
├── head
│ ├── mytest.c
│ └── mytest.h
└── src
└── mymain.c
顶级目录 helloworld,该目录下存在两个目录 src 和 head。head 目录中,mytest.h 头文件声明了 sayHello() 方法;mytest.c 中实现了 sayHello()方法;src目 录中的 mymain.c 中的 main 调用了 sayHello()方法。
head/mytest.c 文件内容:
#ifndef MYTEST_H_
#define MYTEST_H_ void sayHello(); #endif
head/mytest.c 文件内容:
#include <stdio.h>
#include "mytest.h" void sayHello()
{
printf("Hello World!\n");
}
src/mymain.c 文件内容:
#include <stdio.h>
#include "../head/mytest.h" int main()
{
printf("Hello World! \n");
return 0;
}
顶级目录 helloworld,该目录下存在两个目录 src 和 head 。head 目录中,mytest.h 头文件声明了 sayhello()方法;mytest.c 中实现了 sayhello()方法;src 目录中的 mymain.c 中的 main 调用了 sayhello()方法。
2. 执行步骤
2.1. 在顶层目录下运行 autoscan
产生 configure.scan 文件
2.2. 将 configure.scan 文件更名为 configure.in
文件
2.3. 打开 configure.in 文件,修改文件内容
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script. AC_PREREQ([2.68])
AC_INIT([hello], [1.0], [php-note.com@163.com])
AC_CONFIG_SRCDIR([src/mymain.c])
#AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE(hello, 1.0) # Checks for programs.
AC_PROG_CC # 使用静态库编译,需要此宏定义
AC_PROG_RANLIB # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT(Makefile head/Makefile src/Makefile)
2.4. 然后分别执行以下两个命令:
aclocal
autoconf
2.5. 在 head 文件夹下创建 Makefile.am
文件,内容如下:
AUTOMAKE_OPTIONS=foreign
noinst_LIBRARIES=libmytest.a
libmytest_a_SOURCES=mytest.h mytest.c
2.6. 在 src 文件夹下创建 Makefile.am
文件,内容如下:
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=hello
hello_SOURCES=mymain.c
hello_LDADD=../head/libmytest.a
2.7. 在 helloworld 文件夹下创建 Makefile.am
文件,内容如下:
AUTOMAKE_OPTIONS=foreign
SUBDIRS=head src
2.8. 执行命令“automake --add-missing
”,automake 会根据 Makefile.am 文件产生一些文件,其中包含最重要的 Makefile.in
2.9. 执行“make
”命令来编译 mymain.c 程序,从而生成可执行程序 hello。生成可执行程序 hello后,执行“./src/hello”,输出“Hello World!”。
六、总结
归纳一下以上所有例子的流程:
(1)在存放源代码的顶层目录下执行 autoscan
命令生成 configure.scan 文件;
(2)将 configure.scan 文件改名为 configure.in
,并对其默认配置进行修改;
(3)执行 aclocal
、autoconf
两个命令,分别生成 aclocal.m4、configure 文件;
(4)在每个目录下创建一个名为 Makefile.am
的文件,并输入相应的内容;
(5)执行 automake --add-missing
,它根据 Makefile.am 文件,生成 Makefile.in;
(6)执行 ./configure
脚本文件,它根据 Makefile.in 文件,生成最终的 Makefile 文件;
(7)生成 Makefile 之后,执行 make
编译工程并且生成可执行程序。
六、能力进阶
以上的的程序还只是处于初级阶段,并且生成的是 静态库 。我们可以发现,用 autoconf 和 automake 生成 Makefile 的关键在于 configure.in
和 Makefile.am
的文件的书写。所以,要想使自己的功力更上一层,需要熟悉 autoconf 和 automake 这两个工具的使用,其中有很多重要的宏需要我们了解。这里时具体的参考手册:
autoconf手册
英文版:http://www.gnu.org/software/autoconf/manual/autoconf.html
中文版:http://www.linuxforum.net/books/autoconf.html
automake手册
中文版:http://www.linuxforum.net/books/automake.html
七、configure.in文件解析
autoconf 是用来产生“configure”文件的工具。“configure”是一个Shell脚本,它可以自动设定一些编译参数使程序能够在不同平台上进行编译。autoconf 读取 configure.in 文件然后产生“configure”这个Shell脚本。
configure.in 文件的内容是一系列 GNU m4 的宏,这些宏经 autoconf 处理后会变成检查系统特性的Shell脚本。configure.in文件中宏的顺序并没有特别的规定,但是每一个configure.in 文件必须以宏 AC_INIT 开头,以宏 AC_OUTPUT 结束。一般可先用 autoscan 这个工具扫描原始文件以产生一个 configure.scan 文件,再对 configure.scan 作些修改,从而生成 configure.in 文件。
configure.in 文件中一些宏的含义如下:
#或dnl |
#或dnl后面的内容作为注释不会被处理,它们是注释的起始标志 |
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) |
|
AM_INIT_AUTOMAKE(PACKAGE,VERSION) |
这个是后面运行automake命令所必需的宏,PACKAGE指明要产生软件的名称,VERSION 是其版本号 |
AC_PROG_CC |
检查系统可用的C编译器,若源代码是用C语言编写的就需要这个宏 |
AC_OUTPUT(FILE) |
设置configure命令所要产生的文件。我们最终期望产生Makefile 这个文件,因此一般将其设置为AC_OUTPUT(Makefile) |
在运行 automake 命令时,还需要一些其他的宏,这些额外的宏由 aclocal 产生。执行 aclocal 会产生 aclocal.m4 文件,如果没有特别的要求,无需修改它。用 aclocal 产生的宏将会提示 automake 如何动作。
另一个重要的文件是 Makefile.am。automake 根据 configure.in 中的宏并在perl的帮助下把 Makefile.am 转成 Makefile.in 文件。Makefile.am 文件定义所要产生的目标。
八、makefile.am
对于可执行文件 和 静态库类型,如果只想编译,不想安装到系统中,可以用 noinst_PROGRAMS 代替 bin_PROGRAMS,noinst_LIBRARIES 代替 lib_LIBRARIES。
automake设置了默认的安装路径:
1) 标准安装路径
默认安装路径为:$(prefix) = /usr/local,可以通过./configure --prefix=<new_path>的方法来覆盖。
其它的预定义目录还包括:bindir = $(prefix)/bin, libdir = $(prefix)/lib, datadir = $(prefix)/share, sysconfdir = $(prefix)/etc等等。
2) 定义一个新的安装路径
比如test, 可定义builddir = $(prefix)/build, 然后test_LIBRARIES =mytest.h mytest.c,则mytest.h mytest.c 会作为静态库安装到$(prefix)/build目录下。
九、如何使用产生的Makefile文件
执行 configure 脚本文件所产生的 Makefile 文件有几个预定的选项可供使用:
make all:产生设定的目标,即生成所有的可执行文件。使用make也可以达到此目的。
make clean:删除之前编译时生成的可执行文件及目标文件(形如*.o的中间文件)。
make distclean:除了删除可执行文件和目标文件以外,把 configure 所产生的 Makefile 文件也清除掉。通常在发布软件前执行该命令。
make install:将使用 make all 或 make 命令产生的可执行文件以软件的形式安装到系统中。若使用 bin_PROGRAMS 宏,程序将会被安装到 /usr/local/bin 下,否则安装到预定义的目录下。
make dist:将程序和相关的文档包装为一个压缩文档以供发布。执行完该命令,在当前目录下会产生一个名为 PACKAGE-VERSION.tar.gz 的文件。PACKAGE 和 VERSION 这两个参数是来自 configure.in文件中的AM_INIT_AUTOMAKE(PACKAGE,VERSION)。如在上个例子中执行 make dist 命令,会产生名为“hello-1.0.tar.gz
”的文件。
make distcheck:与make dist类似,但是加入了检查包装以后的压缩文件是否正常。
十、动态库编译
需要在 Makefile.am 中指定:
lib_LTLIBRARIES=libhello.al
libhello_al_SOURCES=mytest.h mytest.c
在根目录下的 configure.in 中加 AC_PROG_LIBTOOL
若出现:“required file `./ltmain.sh' not found”错误,是因为 libtool 的配置问题。
解决方法:
$ libtoolize --automake --debug --copy –force
参考:
http://www.cnblogs.com/ericdream/archive/2011/12/09/2282359.html
http://www.cnblogs.com/resound/archive/2011/04/19/2021681.html
http://www.jellythink.com/archives/1056
http://www.ibm.com/developerworks/cn/linux/l-makefile
http://www.laruence.com/2009/11/18/1154.html
利用 autoconf 和 automake 生成 Makefile 文件的更多相关文章
- 例解 autoconf 和 automake 生成 Makefile 文件
本文介绍了在 linux 系统中,通过 Gnu autoconf 和 automake 生成 Makefile 的方法.主要探讨了生成 Makefile 的来龙去脉及其机理,接着详细介绍了配置 Con ...
- 使用autoconf和automake生成Makefile文件(转)
Makefile好难写 曾经也总结了一篇关于Makefile的文章<make和makefile的简单学习>.但是,总结完以后,发现写Makefile真的是一件非常痛苦的事情,的确非常痛苦. ...
- 运用Autoconf和Automake生成Makefile的学习之路
作为Linux下的程序开发人员,大家一定都遇到过Makefile,用make命令来编译自己写的程序确实是很方便.一般情况下,大家都是手工写一个简单Makefile,如果要想写出一个符合自由软件惯例的M ...
- 使用autoconf和automake生成Makefile
使用环境: 我的是Ubuntu 16.04,需要用到autoconf和automake,没有的话自行安装. 以helloworld为例: 1.首先新建一个文件夹然后进去没的说:然后自然得先写出那个著名 ...
- linux下使用automake工具自动生成makefile文件
linux环境下,当项目工程很大的时候,编译的过程很复杂,所以需要使用make工具,自动进行编译安装,但是手写makefile文件比较复杂,所幸在GNU的计划中,设计出了一种叫做Autoconf/Au ...
- 使用automake等命令自动生成Makefile文件 (转载)
使用automake等命令自动生成Makefile文件 Linux下编程时,为了方便编译,往往使用Makefile文件自动完成编译,但是Makefile文件本身的书写十分复杂,规则很多.好在Lin ...
- 利用qmake生成Makefile文件
在linux下写程序,免不了要写Makefile文件,用automake,总感觉比较麻烦,linux人喜欢做麻烦的事,以显得风格迥异. 其实用qmake生成Makefile文件相当简单. 1 装好qm ...
- 生成Makefile文件全过程
[1]生成Makefile文件全过程 整体流程如下图: 注意:以下文件根目录为testmake(任意位置新建即可) (1)测试程序 1.1 建立两个目录:mkdir include source 1. ...
- 自动生成Makefile文件
主要的工具有autoscan, aclocal, autoheader, autoconfig,automake 1 .创建c源文件hello.c #include <stdio.h> i ...
随机推荐
- postman使用之四:切换环境和设置读取变量
postman提供了environment管理功能,想要在多个环境中测试,比如在测试环境.灰度环境.生产环境等,只需要用同样的接口,切换下环境即可,非常方便.具体步骤: 切换环境 1.点击界面右上角的 ...
- 俄罗斯方块(Java实现)
程序效果: 代码: //Box.java 1 package tetris; public class Box { private final int M = 30, N = 12; private ...
- 第23章 java线程通信——生产者/消费者模型案例
第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...
- 微信扫描打开APP下载链接提示代码优化
上一次我发了一篇文章叫“微信打开网址添加在浏览器中打开提示”,里面我发出来了三个代码,分别是纯JS.js+html.jQuery+HTML代码.今天来一个简化版带可以关闭的按钮操作.使用的是纯JS+H ...
- 为什么 Java 8 中不再需要 StringBuilder 拼接字符串
为什么 Java 8 中不再需要 StringBuilder 拼接字符串 来源:codeceo 发布时间:2016-12-27 阅读次数:427 0 在Java开发者中,字符串的拼接占用资源高往往 ...
- 《Java程序设计与数据结构教程(第二版)》学习指导
<Java程序设计与数据结构教程(第二版)>学习指导 欢迎关注"rocedu"微信公众号(手机上长按二维码) 做中教,做中学,实践中共同进步! 原文地址:http:// ...
- logback 配置详解
一:根节点<configuration>包含的属性: scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true. scanPeriod: 设置监测配置文 ...
- sqlserver 游标
DECLARE ChangeInvCodeCursor CURSOR FOR SELECT A.name AS tablecolumn,C.name AS tablename FROM sys.col ...
- php 读取csv 乱码
在php手册里面有这样一个例子,为什么读出的是乱码<?php$row = 1;$handle = fopen("test.csv","r");while ...
- Spring AOP动态切换数据源
现在稍微复杂一点的项目,一个数据库也可能搞不定,可能还涉及分布式事务什么的,不过由于现在我只是做一个接口集成的项目,所以分布式就先不用了,用Spring AOP来达到切换数据源,查询不同的数据库就可以 ...