Autotools 总结
一、项目背景
最近在做忙一个项目的客户端,想要兼容:
CentOS: 6.X 7.X
Redhat : 6.X 7.X
Ubuntu: 12.4 14.4 16.4
Debin 7.x 8.x 9.x
windows server: 2008 2012 2016
中标麒麟: V6.8 V7.0
Unix: freeBSD solaris
c/go跨平台编译实现是用autotools的工具实现,出现很多版本不兼容的问题(这或许就是Linux系列的弊端吧,不能向下兼容),在这里做个总结,方便继续客户端适配中挣扎!!!
二、工作原理
autotools包括: autoscan、aclocal、autoconf、autoheader、automake 、m4
1.autoscan (autoconf): 扫描源代码以搜寻普通的可移植性问题,比如检查编译器,库,头文件等,生成文件configure.scan,它是configure.ac的一个雏形。
2.aclocal (automake):根据已经安装的宏,用户定义宏和acinclude.m4文件中的宏将configure.ac文件所需要的宏集中定义到文件 aclocal.m4中。aclocal是一个perl 脚本程序,它的定义是:“aclocal - create aclocal.m4 by scanning configure.ac”
用户输入文件 可选的输入 处理 输出文件
================ ============== ======= ============
acinclude.m4 - - - - -.
V
.-------,
configure.ac ------------------------>|aclocal|
{user macro files} ->| |------> aclocal.m4
`-------'
3.autoheader(autoconf): 根据configure.ac中的某些宏,比如cpp宏定义,运行m4,声称config.h.in
用户输入文件 可选的输入 处理 输出文件
================ ============== ======= ============
aclocal.m4 - - - - - - - .
|
V
.----------,
configure.ac ----------------------->|autoheader|----> autoconfig.h.in
`----------'
4.automake: automake将Makefile.am中定义的结构建立Makefile.in,然后configure脚本将生成的Makefile.in文件转换为Makefile。如果在configure.ac中定义了一些特殊的宏,比如AC_PROG_LIBTOOL,它会调用libtoolize,否则它会自己产生config.guess和config.sub
用户输入文件 可选的输入 处理 输出文件
================ ============== ======= ============
.--------,
| | - - -> COPYING
| | - - -> INSTALL
| |------> install-sh
| |------> missing
|automake|------> mkinstalldirs
configure.ac ----------------------->| |
Makefile.am ----------------------->| |------> Makefile.in
| |------> stamp-h.in
.---+ | - - -> config.guess
| | | - - -> config.sub
| `------+-'
| | - - - -> config.guess
|libtoolize| - - - -> config.sub
| |--------> ltmain.sh
| |--------> ltconfig
`----------'
5.autoconf:将configure.ac中的宏展开,生成configure脚本。这个过程可能要用到aclocal.m4中定义的宏。
用户输入文件 可选的输入 处理 输出文件
================ ============== ======= ============
aclocal.m4 - - - - - -.
V
.--------,
configure.ac ----------------------->|autoconf|------> configure ----->autoconfig.h,Makefile
流程图:
生成makefile的流程:
-
运行autoscan命令
-
将configure.scan 文件重命名为configure.in,并修改configure.in文件
-
在project目录下新建Makefile.am文件,并在core和shell目录下也新建makefile.am文件
-
在project目录下新建NEWS、 README、 ChangeLog 、AUTHORS文件
-
将/usr/share/automake-1.X/目录下的depcomp和complie文件拷贝到本目录下
-
运行aclocal命令,扫描 configure.ac 文件生成 aclocal.m4文件
-
运行autoconf命令,生成configure 文件
-
运行automake -a命令
-
运行autoheader命令, 生成config.h.in文件
-
运行./confiugre脚本,生成Makefile 文件
-
运行make编译
-
运行make install 安装
我们要做的就是:
三、使用方法
# Process this file with autoconf to produce a configure script.
# -*- 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([config.h.in])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
# Checks for libraries.
# FIXME: Replace `main' with a function in `-laudit':
AC_CHECK_LIB([audit], [main])
# FIXME: Replace `main' with a function in `-lmnl':
AC_CHECK_LIB([mnl], [main])
# FIXME: Replace `main' with a function in `-lnetfilter_conntrack':
AC_CHECK_LIB([netfilter_conntrack], [main])
# FIXME: Replace `main' with a function in `-lnfnetlink':
AC_CHECK_LIB([nfnetlink], [main])
# FIXME: Replace `main' with a function in `-losl':
AC_CHECK_LIB([osl], [main])
# FIXME: Replace `main' with a function in `-loslstub':
AC_CHECK_LIB([oslstub], [main])
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([src/Makefile])
AC_OUTPUT
以上是执行makescan后生成的模板,我们要在这个基础之上进行修改,我们看到这个模板的布局是:
AC_INIT
测试程序
测试函数库
测试头文件
测试类型定义
测试结构
测试编译器特性
测试库函数
测试系统调用
AC_OUTPUT
修改方法:
宏 | 描述 | 修改内容 |
---|---|---|
AC_PREREQ([2.69]) | autoconf的版本 | 2.69以上的修改格式是.ac,2.68及下的为.in |
AC_INIT | 强制初始化 | 修改autoconf包的名称,版本,bug报告的emall |
AC_CONFIG_SRCDIR | 安全检查要发布的源文件,目的确定源码目录的有效性 | |
AC_CONFIG_HEADERS | 生成config.h文件保存configure.ac定义的宏,给autoheader使用 | |
AC_PROG_CXX | 用来指定编译器,如果不指定,默认g++ | |
AC_PROG_CC | 用来指定编译器,如果不指定,默认gcc | |
AC_CHECK_LIB | 检查链接库 | |
AC_CONFIG_FILES | 用于生成相应的Makefile文件 | |
AC_OUTPUT | 设定 configure 所要产生的文件 |
Makefile.am需要指定要生成什么目标,它由什么源文件生成,要安装到什么目录。
Makefile.am一般格式
Makefile.am中可用的全局变量
Makefile.am中可用的路径变量
例子1:
#AUTOMAKE_OPTIONS是设置automake的选项. 由于GNU对自己发布的软件有严格的规范, 比如必须附带许可证声明文件COPYING等,否则automake执行时会报错. automake提供了3中软件等级:foreign, gnu和gnits, 供用户选择。默认级别是gnu. 在本例中, 使用了foreign等级, 它只检测必须的文件
AUTOMAKE_OPTIONS = foreign
aclocaldir = .
#aclocal_DATA = aclocal.m4 accmself.m4
#处理本目录要先处理src目录
SUBDIRS = src
dist_man_MANS = **.1
#打包的文件
EXTRA_DIST = ${dist_man_MANS}
nodist_ACM4 = ${aclocal_DATA}
installlib2go instlib2go il2go:
cp -f src/**.h go/include
cp -f src/**.h go/include
cp -f src/***.0.0.so go/libs
ln -sf **.so go/libs/**.1
#Don't copy liboslstub.h, we only use CGO on Linux
#for efficiency issue.
intsallstublib2go inststublib2go istb2go:
cp -f src/.libs/liboslstub-1.0.0.so go/libs
ln -sf liboslstub-1.0.0.so go/libs/liboslstub.so.1
例子2:
#对于可执行文件和静态库类型,如果只想编译,不想安装到系统中,可以用noinst_PROGRAMS代替bin_PROGRAMS,noinst_LIBRARIES代替lib_LIBRARIES。
AUTOMAKE_OPTIONS=foreign
#INCLUDES=
CFLAGS += -g -Wall -fPIC
CFLAGS +=
CFLAGS +=
#ARCH = $(shell arch)
#CFLAGS +=
# Build and install a static library
#库文件
lib_LIBRARIES =
# Build and install a dynamic library
#libtool库文件
lib_LTLIBRARIES = libosl.la
# Build, but don't install a static library
#只编译不安装
noinst_LIBRARIES = libosl.a
# Build and install an osl controller binary
#定义要产生的执行文件名. 如果要产生多个执行文件, 每个文件名用空格隔开。
bin_PROGRAMS = oslc
# Build, but don't install the test programs and a profiled version of libosl
#只编译不安装的可执行文件
noinst_PROGRAMS = test_osl \
test_oslstub \
test_mhash \
# Defines the headers that get installed with the program
#头文件
include_HEADERS =
# 定义这个可执行程序所需的原始文件。如果这个程序是由多个源文件所产生的, 则必须把它所用到的所有源文件都列出来,并用空格隔开。如果要定义多个可执行程序,那么需要对每个可执行程序建立对应的file_SOURCES。
BUILT_SOURCES = page_size.h
#执行的时候需要删除的文件
DISTCLEANFILES = gpgsize page_size.h
# Specify the sources and various flags for the dynamic library binary
libosl_la_SOURCES= \
os_include.h \
sys_include.h \
usr_include.h \
global.h \
debug.c \
debug.h \
libosl_la_CFLAGS = -DCT_CONN_EVENT_POLL -DDROP_EVENT_POLL \
-DTP_DIR_AWARE -fPIC
#链接时库文件选项标志位
libosl_la_LDFLAGS= -g -shared -fPIC -pthread -lmnl -lnfnetlink \
-lnetfilter_conntrack -laudit -release 1.0.0
#链接时需要的库文件
test_mhash_LDADD =
# remove this line when release
libosl_la_CFLAGS += -DOSL_TEST
# Specify which tests to run during a "make check"
TESTS =
#dist_man_MANS = libosl.1
这些宏有的根据名字就知道做什么用,但有的还需要查数据手册,把常用的给列出来,方便快速查找:
configure.ac宏定义说明
宏 | 作用 | 示例 |
---|---|---|
AC_PREREQ | autoconf最低版本 | AC_PREREQ([2.69]) |
AC_INIT | 初始化包信息,将会自动生成PACKAGE_NAME、PACKAGE_VERSION、PACKAGE_BUGREPORT宏 | AC_INIT([Porject], [1.0], [fwdssg.love@163.com]) |
AC_CONFIG_SRCDIR | 通过检测目录中必定存在的文件来判断目录是否存在 | AC_CONFIG_SRCDIR([src/main.cpp]) |
AC_CONFIG_HEADERS | 生成config.h文件保存configure.ac定义的宏,此文件可被源文件包含 | AC_CONFIG_HEADERS([config.h]) |
AC_CONFIG_MACRO_DIRS | 指定本地宏文件的存放目录,.m4后缀的文件都将被保存进此目录,acloacl命令会自动创建此目录 | AC_CONFIG_MACRO_DIRS([m4]) |
AC_CONFIG_AUX_DIR | 指定辅助脚本文件的存放目录 | AC_CONFIG_AUX_DIR([build-aux]) |
AC_MSG_CHECKING | 打印"checking XXX …" | AC_MSG_CHECKING([for native Win32]) |
AC_MSG_RESULT | 打印checking结果并另起新行 | AC_MSG_RESULT([$os_win32]) |
AC_PROG_INSTALL | 生成安装脚本 install-sh | AC_PROG_INSTALL |
AC_PROG_LIBTOOL | 使得configure能够支持–enable-shared、–disable-shared、–enable-static、–disable-static、–with-pic和–without-pic参数 | AC_PROG_LIBTOOL |
AC_PROG_CXX | 自动检测要使用的C++编译器 | AC_PROG_CXX |
AC_PROG_CC | 自动检测要使用的C编译器 | AC_PROG_CC |
AC_CHECK_HEADERS | 检测系统头文件是否存在 | AC_CHECK_HEADERS([sys/socket.h netinet/in.h arpa/inet.h]) |
AC_SUBST | 输出能够被Makefile.am使用的变量 | AC_SUBST(GLIB2_CFLAGS) |
AC_CONFIG_SUBDIRS | configure子目录 | AC_CONFIG_SUBDIRS([spice-common]) |
PKG_CHECK_MODULES | 检测对应模块是否存在 | PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= 0.12.11]) |
AC_CHECK_FUNCS | 检测对应函数是否可用 | AC_CHECK_FUNCS([setlocale]) |
AC_ARG_ENABLE | 为configure添加–XX选项 | AC_ARG_ENABLE([gstaudio],AS_HELP_STRING([–enable-gstaudio=@<:@yes/auto/no@:>@], [Enable the GStreamer 1.0 audio backend @<:@default=auto@:>@]),[],[enable_gstaudio=“auto”]) |
AC_OUTPUT | 运行configure后生成的config脚本需要处理的文件,将Makefile.in变成Makefile | AC_OUTPUT([Makefile]) |
AM_INIT_AUTOMAKE | 初始化automake | AM_INIT_AUTOMAKE([subdir-objects -Wno-portability]) |
AM_GNU_GETTEXT | 初始化gettext | AM_GNU_GETTEXT([external]) |
AM_GNU_GETTEXT_VERSION | 指定gettext最低版本 | AM_GNU_GETTEXT_VERSION([0.19.7]) |
IT_PROG_INTLTOOL | 初始化并指定libtool最低版本 | IT_PROG_INTLTOOL([0.35.0]) |
AM_CONDITIONAL | 根据条件来定义宏 | AM_CONDITIONAL([OS_WIN32],[test "KaTeX parse error: Expected 'EOF', got '#' at position 21: …n32" = "yes"]) #̲如果os_win32的值为yes则#define OS_WIN32宏 |
Makefile.am宏定义说明
宏 | 作用 | 示例 |
---|---|---|
ACLOCAL_AMFLAGS | 指定宏文件的存放目录,与AC_CONFIG_MACRO_DIRS成配合使用 | ACLOCAL_AMFLAGS = -I m4 |
SUBDIRS | 指定需要递归automake的子文件夹,即存在Makefile.am的子文件夹 | SUBDIRS = spice-common src man po doc data |
EXTRA_DIST | 指定要被打包的额外文件,即执行make dist 时需要被放入压缩包的文件,一般是不需要参与编译但是又需要被使用的文件,比如图片目录里的图片 | EXTRA_DIST = $(PACKAGE).spec |
DISTCLEAN_FILES | 执行make distclean 时候需要删除的文件,一般是EXTRA_DIST中的.in文件生成的不需要打包的中间文件 | DISTCLEAN_FILES = $(PACKAGE).spec |
MAINTAINERCLEANFILES | 执行make maintainer-clean时候需要删除的文件,即执行autoreconf -vfi 、intltoolize --force 以及configure 或执行autogen.sh 后能够重新生成的文件都要放入其中 | MAINTAINERCLEANFILES = $(srcdir)/AUTHORS |
dist-hook | 执行make dist 时需要执行的脚本 | dist-hook: gen-ChangeLog gen-AUTHORS |
bin_PROGRAMS | 要生成的可执行文件 | bin_PROGRAMS = spicy |
XX_SOURCES | 编译可执行文件所需的源文件 | spicy_SOURCES = spicy.c |
XX_LIBADD | 链接参数,即pkg-config --libs 的结果 | spicy_stats_LDADD = libspice-client-glib-2.0.la |
XX_CFLAGS | 编译参数,即pkg-config --cflags 的结果和-D 之类的宏定义 | libvirt_viewer_la_CFLAGS = -DLOCALE_DIR=""./…/share/locale"" $(GLIB2_CFLAGS) |
nodist_XX_SOURCES | 执行make dist 时不需要被打包的源文件,一般是根据其他源文件通过脚本临时生成的中间源文件,比如使用glib-genmarshal 生成的文件 | nodist_libspice_client_glib_2_0_la_SOURCES = spice-marshal.c spice-marshal.h |
LDADD | 无法被configure找到但是又需要链接的库或资源文件,例如临时生成的windows下使用的rc文件 | LDADD += virt-viewer_rc.$(OBJEXT) |
dist_XX_DATA | 程序运行需要的数据文件,比如图标、配置文件等 | dist_cfg_DATA = xx.cfg |
dist_bin_SCRIPTS | 程序的脚本文件,将被安装到bin目录 | dist_bin_SCRIPTS = xx.sh |
四、总结
1.既然称之为工具就是让别人容易使用,只需要编写两个文件(config.ac, Makefile.ac),分工configure检查编译的文件和环境是否具备,Makefile.ac就需要你对你的工程要编译成什么要清晰的了解
2.太多的宏不好记,就查询数据手册,只要写过一个工程,以后的工程跟这个都很类似,知道它的原理,结合自己的项目要求改吧改吧就能出来
3.希望自己的总结,能给有需要的小伙伴提供思路!送人玫瑰,手留余香!!!
参考:
autotool的处理流程: https://blog.csdn.net/gcc_sky/article/details/16362933
怎么构建项目: https://blog.csdn.net/xlxxcc/article/details/51112826
https://www.ibm.com/developerworks/cn/linux/l-makefile/
automake手册: http://www.gnu.org/software/automake/manual/automake.html
常用宏参考: https://www.cnblogs.com/silvermagic/p/7665868.html
https://blog.csdn.net/SUKHOI27SMK/article/details/8594823
怎么使用automake和autoconf: https://www.cnblogs.com/chekliang/p/3224978.html
csdn.net/xlxxcc/article/details/51112826>
https://www.ibm.com/developerworks/cn/linux/l-makefile/
automake手册: http://www.gnu.org/software/automake/manual/automake.html
常用宏参考: https://www.cnblogs.com/silvermagic/p/7665868.html
https://blog.csdn.net/SUKHOI27SMK/article/details/8594823
怎么使用automake和autoconf: https://www.cnblogs.com/chekliang/p/3224978.html