我们知道在Linux
下编译一个比较大型的项目,我们可以通过Makefile
的方式来完成。但是,Makefile
拥有复杂的语法结构,甚至让人难以领会,当我们项目非常大的时候,维护Makefile
会成为一件非常头疼的事。Autotools
工具就是专门用来生成Makefile
的,这个工具让让我们很大程度上降低了开发的难道。
Autotools
并不是一个工具,而是一系列工具:
autoscan
aclocal
autoconf
autoheader
automake
这一系列工具看着复杂,但我们只要记住:最终目标是生成Makefile。
一般情况下系统会默认安装这一系列工具,若未安装,在CentOS
中可以使用下面命令安装:
sudo yum install automake
有关Autotools
的详细完整的介绍,详见官网:https://www.lrde.epita.fr/~adl/autotools.html
一般过程是configure
,make
,make install
三部曲。这种方式成为一种习惯,被广泛使用。
在上图中,开发者在分发源码包时,除了源代码中的头文件(.h)和程序源文件(.c),还有许多支持软件构建的文件和工具。最重要的就是Makefile.in
和config.h
。
configure
脚本执行时,将为每一个.in文件处理成对应的非.in文件,即生成:Makefile
,src/Makefile
,config.h
。大部分情况下,只有Makefile
和config.h
。Makefile
用于被make
程序识别并构建软件,而config.h
中定义的宏,有助于软件通过预编译来改变自身代码,来适应目标平台某些特殊性。
有些软件在configure
阶段,还可以生成其他文件,这完全取决于软件本身。
开发者除了编写软件本身的代码外,还需要负责生成构建软件所需要的文件和工具。因此对于开发者而言,要么自己编写构建用的脚本,要么选择部分依赖工具。Autotools
就是这样的工具。Autotools
包括了autoconf
和automake
等命令。
autoreconf
命令为了生成configure
脚本和Makefile.in
等文件,开发者需要创建并维护一个configure.ac
文件,以及一些列的Makefile.am
。autoreconf
程序能够自动按照合理的顺序调用autoconf
、automake
、aclocal
程序
configure.ac
文件configure.ac
用于生成configure
脚本,autoconf
工具用来完成这一步。下面是一个简单的configure.ac
例子:
AC_PREREQ
AC_PREREQ([2.63])
AC_INIT([st], [1.0], [zhoupingtkbjb@163.com])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_HEADERS([src/config.h])
AM_INIT_AUTOMAKE([foreign])
# Checks for programs.
AC_PROG_CC
AC_PROG_LIBTOOL
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile
src/Makefile
src/a/Makefile
src/b/Makefile])
AC_OUTPUT
其中以AC_
开头的类似函数调用一样的代码,实际上时被称为“宏”的调用。这里的宏,与C语言中的宏概念类似,会被替换展开。configure.ac
文件的一般布局是:
AC_INIT
测试程序
测试函数库
测试头文件
测试类型定义
测试结构
测试编译器特性
测试库函数
测试系统调用
AC_OUTPUT
m4
是一个经典的宏工具。autoconf
正是构建在m4
之上,可以理解为autoconf
预先定义了大量的、用户检查系统可移植性的宏,这些宏在展开就是大量的shell脚本。所以编写configure.ac
就需要对这些宏掌握熟练,并且合理调用。
autoscan
和configure.scan
通过调用autoscan
命令,得到一个初始化的configure.scan
文件。然后重命名为configure.ac
后,在此基础上编辑configure.ac
。
autoscan
会扫描源码,并生成一些通用的宏调用,输入的声明,以及输出的声明。尽管autoscan
十分方便,但是没人能够在构建之前,就把源码完全写好。因此,autoscan
通常用于初始化configure.ac
,即生成configure.ac
的雏形文件configure.scan
。
autoheader
和configure.h
autoheader
命令扫描configure.ac
文件,并确定如何生成config.h.in
。每当configure.ac
变化时,都可以通过执行autoheader
更新config.h.in
。
在configure.ac
通过AC_CONFIG_HEADERS([config.h])
告诉autoheader
应当生成config.h.in
的路径。config.h
包含了大量的宏定义,其中包括软件包的名字等信息,程序可以直接使用这些宏。更重要的是,程序可以根据其中的对目标平台的可移植相关的宏,通过条件编译,动态的调整编译行为。
automake
和Makefile.am
手工编写Makefile
是一件相当繁琐的事情,并且随着项目的复杂程序变大,编写难度越来越大。automake
工具应运而生。可以编辑Makefile.am
文件,并依靠automake
来生成Makefile.in
。
aclocal
configure.ac
实际是依靠宏展开来得到configure
。因此,能否成功生成,取决于宏定义是否能够找打。
autoconf
会从自身安装路径下寻找事先定义好的宏。然而对于像automake
、libtool
、gettex
等第三方扩展宏,autoconf
便无从知晓。
因此,aclocal
将在configure.ac
同一个目录下生成aclocal.m4
,在扫描configure.ac
过程中,将第三方扩展和开发者自己编写的宏定义复制进去。
如此一来,autoconf
遇到不认识的宏时,就会从aclocal.m4
中查找。
上述命令与不同文件之间的关系如下图所示:
autoscan
命令,扫描工作目录并生成configure.scan
文件;configure.scan
为configure.ac
文件,并修改配置内容;aclocal
命令,扫描configure.ac
文件并生成aclocal.m4
文件;autoconf
命令,将configure.ac
文件中的宏展开,生成configure
脚本;autoheader
命令,生成config.h.in
文件;Makefile.am
文件,修改配置内容;automake --add-missing
命令,生成Makefile.in
文件;./configure
命令,生成Makefile
文件;make
命令,生成需要的库或可执行程序;make install/uninstall
进行安装和卸载;make dist
对软件进行打包工作。若是开发过程中,修改了部分文件(configure.ac
、各目录的Makefile.am
等),可以使用简化的autoreconf
命令,它将自动按照合理的顺序调用aclocal
、autoconf
、automake
命令。
configure.ac
标签说明标签 | 说明 |
---|---|
AC_PREREQ |
声明autoconf 要求的版本号 |
AC_INIT |
定义软件名称、版本号、联系方式 |
AM_INIT_AUTOMAKE |
必须要的,参数为软件名称和版本号 |
AC_CONFIG_SRCDIR |
用来侦测所指定的源文件是否存在,来确定源码目录的有效性 |
AC_CONFIG_HEADERS |
用于生成config.h 文件,以便autoheader 命令使用 |
AC_PROG_CC |
指定编译器,默认为CC |
AC_CHECK_HEADERS |
autoscan 侦测到的头文件 |
AC_CONFIG_FILES |
生成相应的Makefile 文件,不同文件夹下的Makefile 通过空格分隔 |
AC_OUTPUT |
指定configure 所要产生的文件,如果是makefile ,configure 会把它检查出来的结果带入makefile.in 文件产生合适的makefile |
规则 | 说明 |
---|---|
bin_PROGRAMS |
指定生成可执行文件的名称,如果可执行文件为多个,则可以通过空格方式分割;当运行make install 命令时,会被默认安装到/usr/local/bin 目录下。 |
noinst_PROGRAMS |
指定生成可执行文件的名称,如果可执行文件为多个,则可以通过空格方式分割;当运行make install 命令时,不会被安装。 |
hello_SOURCES |
编译可执行文件hello 所依赖的*.c 源文件,多个文件之间用空格分割。 |
hello_LDADD |
编译可执行文件hello 所依赖的*.so 和*.a 的库文件。 |
hello_CPPFLAGS |
编译可执行文件hello所需要的编译选项。 |
hello_LDFLAGS |
链接可执行文件时所需要的链接选项。 |
库文件类型,一般会将C源码放在不同的文件夹中,并且每个文件夹中都会有各自的Makefile.am
文件,并且会被编译成动态库*.so
或者静态库*.a
格式的库文件。
如果使用静态库,只需要在configure.ac
中加入AC_PROG_RANLIB
定义;如果生成动态库,则使用AC_PROG_LIBTOOL
。
规则 | 说明 |
---|---|
lib_LIBRARIES |
指定生成静态库或动态库文件的名称,当运行make install 命令时,会被默认安装到/usr/local/lib 目录下。 |
noinst_LIBRARIES |
指定生成静态库或动态库文件的名称,当运行make install 命令时,不会被安装。 |
libsrc_a_SOURCES |
编译libsrc.a/so 库所依赖的*.c 源文件,多个文件之间用空格分隔。 |
libsrc_a_LDADD |
加载libsrc.a/so 库时所依赖的库文件。 |
libsrc_a_CPPFLAGS |
编译libsrc.a/so 库所需要的编译选项。 |
libsrc_a_LDFLAGS |
链接libsrc.a/so 库文件时所需要的链接选项。 |
我们一般需要导入一些*.h
的头文件,如果在Makefile.am
中没有标识需要导入的头文件,那么在make dist
打包的时候会出现头文件不被打包的问题。因此,建议都加上头文件标识。
include_HEADERS = xxx.h xxx.h xxx.h
在make install
时,头文件默认会被安装到linux
系统的/usr/local/include
目录。
data_DATA = data1, data2
变量 | 含义 |
---|---|
INCLUDES |
编译所需要的头文件 |
LDADD |
链接时需要的库文件 |
LDFLAGS |
连接时所需要的链接选项 |
SUBDIRS |
处理本目录之前,先递归处理的子目录 |
EXTRA_DIST |
源程序和一些默认的文件将自动打包入.tar.gz 包,其他文件需要进入.tar.gz 包可以使用这个变量指定,比如配置文件、数据文件等等 |
AM_V_AR |
用于指定把目标文件打包成静态库时使用的ar命令 |
RANLIB |
用于指定为静态库创建索引的ranlib 命令 |
在Makefile.am
中尽量使用相对路径,系统预定义了两个基本路径:
$(top_srcdir)
:工程最顶层目录,用于引用源程序;$(top_builddir)
:定义了生成目标文件最上层目录,用于引用.o等编译的中间文件。默认情况下,执行make install
命令会将文件安装到/usr/local/bin
、/usr/local/include
、/usr/local/lib
目录下面。我们可以通过./configure --prefix=
指定安装路径。
我们也可以修改下面变量,指定安装的路径:
bindir = $(prefix)/bin
libdir = $(prefix)/bin
datadir = $(prefix)/share
sysconfdir = $(prefix)/etc
includedir = $(prefix)/include
如果你的C源文件放在同一个目录下面,那么使用Autotools
的时候会相对简单很多。比较著名的开源软件Memcache
也是放在同一目录下的。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "sum.h"
#include "get.h"
int main(void)
{
int x = 10;
int y = 20;
int z = sum(x, y);
puts("This is main");
printf("Z:%d\n", z);
x = 20;
z = get(x, y);
printf("Z:%d\n", z);
return 0;
}
/* sum.h */
extern int sum(int x, int y);
/* sum.c */
#include <stdio.h>
#include <stdlib.h>
#include "val.h"
int sum(int x, int y)
{
val(x);
printf("This is sum method!\n");
return (x + y);
}
/* val.h */
extern int val(int x);
/* val.c */
#include <stdio.h>
int val(int x)
{
printf("This is val method, X:%d\n", x);
return x;
}
/* get.h */
extern int get(int x, int y);
/* get.c */
#include <stdio.h>
int get(int x, int y)
{
printf("This is get method\n");
return (x*y);
}
目录文件结构如下:
$ ls
get.c get.h main.c sum.c sum.h val.c val.h
autoscan
命令第一步,我们使用autoscan
命令扫描工作目录,并生成configure.scan
文件,并将其重新命名为configure.ac
。
$ autoscan
$ ls
autoscan.log configure.scan get.c get.h main.c sum.c sum.h val.c val.h
$ mv configure.scan configure.ac
$ cat configure.ac
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([sum.h])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([stdlib.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT
接着我们编辑configure.ac
文件,将其修改为:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([hello], [1.0], [konishi5202@163.com])
AM_INIT_AUTOMAKE(hello, 1.0)
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([stdlib.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
aclocal
命令第二步,执行aclocal
命令,扫描configure.ac
文件生成aclocal.m4
文件,该文件主要处理本地的宏定义,它根据已经安装的宏、用户定义宏和acinclude.m4
文件中的宏,将configure.ac
文件需要的宏集中定义到文件aclocal.m4
中。
$ ls
autoscan.log configure.ac get.c get.h main.c sum.c sum.h val.c val.h
$ aclocal
$ ls
aclocal.m4 autom4te.cache autoscan.log configure.ac get.c get.h main.c sum.c sum.h val.c val.h
autoconf
命令第三步,执行autoconf
命令,将configure.ac
文件中的宏展开,生成configure
脚本,这个过程需要用到第二步生成的aclocal.m4
中定义的宏。
$ ls
aclocal.m4 autom4te.cache autoscan.log configure.ac get.c get.h main.c sum.c sum.h val.c val.h
$ autoconf
$ ls
aclocal.m4 autom4te.cache autoscan.log configure configure.ac get.c get.h main.c sum.c sum.h val.c val.h
autoheader
命令第四步,执行autoheader
命令,生成config.h.in
文件。该命令通常会从acconfig.h
文件中复制用户附加的符号定义。本例中没有附加的符号定义,所以不需要创建acconfig.h
文件。
$ ls
aclocal.m4 autom4te.cache autoscan.log configure configure.ac get.c get.h main.c sum.c sum.h val.c val.h
$ autoheader
$ ls
aclocal.m4 autom4te.cache autoscan.log config.h.in configure configure.ac get.c get.h main.c sum.c sum.h val.c val.h
Makefile.am
文件第五步,创建Makefile.am
文件,aotumake
工具会根据configure.in
中的参量把Makefile.am
转换成Makefile.in
文件,最终通过Makefile.in
生成Makefile
文件。所以Makefile.am文件非常重要,它定义了一些生成Makefile的规则。
$ vim Makefile.am
$ cat Makefile.am
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = hello
hello_SOURCES = main.c val.h val.c get.h get.c sum.h sum.c
automake
命令第六步,执行automake --add-missing
命令,生成Makefile.in
文件。选型‘--add-missing
’可以让automake
自动添加一些必须的脚本文件,如果发现一些文件不存在,可以通过手工touch创建:
$ automake --add-missing
configure.ac:6: warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated. For more info, see:
configure.ac:6: http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation
configure.ac:6: installing './install-sh'
configure.ac:6: installing './missing'
Makefile.am: installing './INSTALL'
Makefile.am: error: required file './NEWS' not found
Makefile.am: error: required file './README' not found
Makefile.am: error: required file './AUTHORS' not found
Makefile.am: error: required file './ChangeLog' not found
Makefile.am: installing './COPYING' using GNU General Public License v3 file
Makefile.am: Consider adding the COPYING file to the version control system
Makefile.am: for your code, to avoid questions about which license your project uses
Makefile.am: installing './depcomp'
$ touch NEWS README AUTHORS ChangeLog
$ automake --add-missing
configure.ac:6: warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated. For more info, see:
configure.ac:6: http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation
$ ls
aclocal.m4 autom4te.cache ChangeLog configure COPYING get.c INSTALL main.c Makefile.in NEWS sum.c val.c
AUTHORS autoscan.log config.h.in configure.ac depcomp get.h install-sh Makefile.am missing README sum.h val.h
接下来,就是大家非常熟悉的三部曲了:configure
、make
、make install
。
configure
主要把Makefile.in
变成最终的Makefile文件,同时configure
会把一些配置参数配置到Makefile文件里面。
configure
命令执行结果,生成Makefile
文件:
$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for stdlib.h... (cached) yes
checking for unistd.h... (cached) yes
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: executing depfiles commands
make
命令执行结果,生成hello
可执行程序:
$ make
make all-am
make[1]: Entering directory `/work/study/Module/autotools/test_c2'
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
mv -f .deps/main.Tpo .deps/main.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT val.o -MD -MP -MF .deps/val.Tpo -c -o val.o val.c
mv -f .deps/val.Tpo .deps/val.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT get.o -MD -MP -MF .deps/get.Tpo -c -o get.o get.c
mv -f .deps/get.Tpo .deps/get.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT sum.o -MD -MP -MF .deps/sum.Tpo -c -o sum.o sum.c
mv -f .deps/sum.Tpo .deps/sum.Po
gcc -g -O2 -o hello main.o val.o get.o sum.o
make[1]: Leaving directory `/work/study/Module/autotools/test_c2'
执行可执行程序hello:
$ ./hello
This is val method, X:10
This is sum method!
This is main
Z:30
This is get method
Z:400
执行make dist
命令可以对软件进行打包:
$ make dist
make dist-gzip am__post_remove_distdir='@:'
make[1]: Entering directory `/work/study/Module/autotools/test_c2'
if test -d "hello-1.0"; then find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "hello-1.0" || { sleep 5 && rm -rf "hello-1.0"; }; else :; fi
test -d "hello-1.0" || mkdir "hello-1.0"
test -n "" \
|| find "hello-1.0" -type d ! -perm -755 \
-exec chmod u+rwx,go+rx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec /bin/sh /work/study/Module/autotools/test_c2/install-sh -c -m a+r {} {} \; \
|| chmod -R a+r "hello-1.0"
tardir=hello-1.0 && ${TAR-tar} chof - "$tardir" | GZIP=--best gzip -c >hello-1.0.tar.gz
make[1]: Leaving directory `/work/study/Module/autotools/test_c2'
if test -d "hello-1.0"; then find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "hello-1.0" || { sleep 5 && rm -rf "hello-1.0"; }; else :; fi
$ ls
aclocal.m4 ChangeLog config.status depcomp hello main.c Makefile.in stamp-h1 val.c
AUTHORS config.h configure get.c hello-1.0.tar.gz main.o missing sum.c val.h
autom4te.cache config.h.in configure.ac get.h INSTALL Makefile NEWS sum.h val.o
autoscan.log config.log COPYING get.o install-sh Makefile.am README sum.o
注意上面的hello-1.0.tar.gz
文件即是打包发布的文件。使用发布文件的方法如下:
hello-1.0.tar.gz
压缩包;tar -zxvf hello-1.0.tar.gz
命令解压;./configure
命令生成Makefile
文件;make
命令编译源代码文件生成可执行程序;make install
或make uninstall
来安装或卸载软件。如果你的入口文件main.c
和依赖的文件不是在同一个目录中的,使用Autotools
来管理项目的时候会稍微复杂一下。
在不同的目录下,项目会生成*.a文件的静态连接(静态连接相当于将多个.o目标文件合成一个),最外层的main.c
会通过静态连接方式来实现连接。
基于前面小节的源代码,这里还会加入math数学库的使用,让例子稍显复杂来介绍不同目录下的Autotools
的使用。
include
和source
目录,并把相应的文件放进去:$ ls
include main.c source
$ ls include/
get.h sum.h val.h
$ ls source/
get.c sum.c val.c
main.c
文件,添加调用math
的abs
函数:#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "sum.h"
#include "get.h"
int main(void)
{
int x = 10;
int y = 20;
int z = sum(x, y);
puts("This is main");
printf("Z:%d\n", z);
x = 20;
z = get(x, y);
printf("Z:%d\n", z);
z = abs(-3);
printf("Z:%d\n", z);
return 0;
}
其他源代码文件均不做修改。
autoscan
命令第一步,使用autoscan
命令扫描工作目录,并生成configure.scan文件,并将其重新命名为configure.ac
:
$ autoscan
$ ls
autoscan.log configure.scan include main.c source
$ mv configure.scan configure.ac
$ cat configure.ac
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([stdlib.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT
将其修改为:
$ vim configure.ac
[study@konishi test_c3]$ cat configure.ac
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([hello], [1.0], [konishi5202@163.com])
AM_INIT_AUTOMAKE(hello, 1.0)
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
# Generate static lib
AC_PROG_RANLIB
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([stdlib.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile
source/Makefile])
AC_OUTPUT
aclocal
命令第二步,执行aclocal
命令,扫描configure.ac
文件生成aclocal.m4
文件。
$ ls
autoscan.log configure.ac include main.c source
$ aclocal
$ ls
aclocal.m4 autom4te.cache autoscan.log configure.ac include main.c source
autoconf
命令第三步,执行autoconf
命令,将configure.ac
文件中的宏展开生成configure
脚本。
$ ls
aclocal.m4 autom4te.cache autoscan.log configure.ac include main.c source
$ autoconf
$ ls
aclocal.m4 autom4te.cache autoscan.log configure configure.ac include main.c source
autoheader
命令第四部,执行autoheader
命令生成config.h.in
文件。
$ ls
aclocal.m4 autom4te.cache autoscan.log configure configure.ac include main.c source
$ autoheader
$ ls
aclocal.m4 autom4te.cache autoscan.log config.h.in configure configure.ac include main.c source
Makefile.am
文件第五步,创建Makefile.am
文件,Automake
工具会根据configure.in
中的参量把Makefile.am
转换成Makefile.in
文件,最终通过Makefile.in
生成Makefile
文件。
首先在根目录下创建Makefile.am
文件:
$ vim Makefile.am
$ cat Makefile.am
AUTOMAKE_OPTIONS = foreign
SUBDIRS = source
bin_PROGRAMS = hello
hello_SOURCES = main.c
hello_LDADD = source/libsrc.a
hello_CPPFLAGS = -I./include/
LIBS = -l m
注意上面的hello_LDADD
指定了链接文件,hello_CPPFLAGS
通过编译选项指定了编译依赖的头文件路径,LIBS
指定了链接依赖的系统库。
接着在source
目录下创建Makefile.am
文件:
$ vim source/Makefile.am
$ cat source/Makefile.am
noinst_LIBRARIES=libsrc.a
libsrc_a_SOURCES = get.c val.c sum.c
libsrc_a_CPPFLAGS = -I../include
include_HEADERS = ../include/get.h ../include/val.h ../include/sum.h
注意上面的libsrc_a_CPPFLAGS
通过编译选型指定了编译依赖的头文件路径,include_HEADERS
也可以不指定,但是后续make dist
打包发布时,就不会将include
文件夹打包进去了。当然,也可以在上一层目录的Makefile.am
文件中添加该语句:
include_HEADERS = ./include/get.h ./include/val.h ./include/sum.h
automake
命令第六步,执行automake --add-missing
命令,生成Makefile.in
文件。
$ touch NEWS README AUTHORS ChangeLog
$ automake --add-missing
configure.ac:6: warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated. For more info, see:
configure.ac:6: http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation
source/Makefile.am:2: warning: compiling 'get.c' with per-target flags requires 'AM_PROG_CC_C_O' in 'configure.ac'
$ ls
aclocal.m4 autom4te.cache ChangeLog configure depcomp install-sh Makefile.am missing README
AUTHORS autoscan.log config.h.in configure.ac include main.c Makefile.in NEWS source
接下来,就是大家非常熟悉的三部曲了:configure
、make
、make install
。
执行./configure
脚本,生成Makefile
:
$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for ranlib... ranlib
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for stdlib.h... (cached) yes
checking for unistd.h... (cached) yes
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating source/Makefile
config.status: creating config.h
config.status: executing depfiles commands
执行make命令,生成hello可执行文件:
$ make
make all-recursive
make[1]: Entering directory `/work/study/Module/autotools/test_c3'
Making all in source
make[2]: Entering directory `/work/study/Module/autotools/test_c3/source'
gcc -DHAVE_CONFIG_H -I. -I.. -I../include -g -O2 -MT libsrc_a-get.o -MD -MP -MF .deps/libsrc_a-get.Tpo -c -o libsrc_a-get.o `test -f 'get.c' || echo './'`get.c
mv -f .deps/libsrc_a-get.Tpo .deps/libsrc_a-get.Po
gcc -DHAVE_CONFIG_H -I. -I.. -I../include -g -O2 -MT libsrc_a-val.o -MD -MP -MF .deps/libsrc_a-val.Tpo -c -o libsrc_a-val.o `test -f 'val.c' || echo './'`val.c
mv -f .deps/libsrc_a-val.Tpo .deps/libsrc_a-val.Po
gcc -DHAVE_CONFIG_H -I. -I.. -I../include -g -O2 -MT libsrc_a-sum.o -MD -MP -MF .deps/libsrc_a-sum.Tpo -c -o libsrc_a-sum.o `test -f 'sum.c' || echo './'`sum.c
mv -f .deps/libsrc_a-sum.Tpo .deps/libsrc_a-sum.Po
rm -f libsrc.a
ar cru libsrc.a libsrc_a-get.o libsrc_a-val.o libsrc_a-sum.o
ranlib libsrc.a
make[2]: Leaving directory `/work/study/Module/autotools/test_c3/source'
make[2]: Entering directory `/work/study/Module/autotools/test_c3'
gcc -DHAVE_CONFIG_H -I. -I./include/ -g -O2 -MT hello-main.o -MD -MP -MF .deps/hello-main.Tpo -c -o hello-main.o `test -f 'main.c' || echo './'`main.c
mv -f .deps/hello-main.Tpo .deps/hello-main.Po
gcc -g -O2 -o hello hello-main.o source/libsrc.a -l m
make[2]: Leaving directory `/work/study/Module/autotools/test_c3'
make[1]: Leaving directory `/work/study/Module/autotools/test_c3'
运行hello可执行程序,输出:
$ ./hello
This is val method, X:10
This is sum method!
This is main
Z:30
This is get method
Z:400
Z:3
当然,你也可以通过make install/uninstall
进行安装和卸载,还可以使用make dist
对软件进行打包发布。
automake
报错当执行automake --add-missing
报如下错误:
error: required file './ltmain.sh' not found
请使用libtoolize
配置一下即可,运行如下命令:
libtoolize --automake --copy --debug --force
查看libtoolize
版本方法为:
$ libtoolize --version
libtoolize (GNU libtool) 2.4.2
Written by Gary V. Vaughan <gary@gnu.org>, 2003
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。