autotools:autoconf/automake生成Makefile流程详解

 

生成Makefile文件详解,主要流程如下:

 

 项目维护者手动修改的文件除了可选的NEWS README AUTHORS ChangeLog文件之外,就是一个 configure.ac 文件 和 每个源码文件夹下的 Makefile.am 文件了,父目录Make file.am中“SUBDIRS = 子目录”定义子目录,。

1. 在工程根目录下, 运行 autoscan 生成 configure.ac

对源文件创建后,我们就可以在工程根目录下,通过autoscan命令对该目录进行扫描,生成configure.scan文件。这里configure.scan其实是一个模板文件,我们需要手动修改一下其内容,并将其改名为configure.ac.

首先切换到该目录,然后执行命令,具体如下:

vmuser@ubuntu:~/user/vmuser/myproject/ autoscan
vmuser@ubuntu:~/user/vmuser/myproject/ mv configure.scan  configure.ac
后缀*代表执行过程,[]代表可选项
your source files --> [autoscan*] --> [configure.scan] --> configure.ac

 编辑 configure.ac

1) AC_INIT 里面的参数: AC_INIT(main,1.0, suntroop@google.com);   #定义软件包"全"名称,版本号,联系方式。
2) 添加宏 AM_INIT_AUTOMAKE;  #指定包名称和版本
3) 在 AC_OUTPUT 后添加输出文件Makefile。
针对交叉编译环境,使用如下宏定义:
AC_PROG_CXX(arm-linux-gnueabihf-g++)
AC_PROG_CC(arm-linux-gnueabihf-gcc)
 
#                                               -*- 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_INIT(main, 1.0, suntroop@google.com)
AC_CONFIG_SRCDIR([TestPrepare/test_prepare.c])
# 生成config.h文件保存configure.ac定义的宏,此文件可被源文件包含 AC_CONFIG_HEADERS([config.h])
# 用来存储本地宏文件,.m4的文件都将被保存进此目录,acloacl命令会自动创建此目录
AC_CONFIG_MACRO_DIRS([m4])
# 用来存储一些辅助脚本文件
AC_CONFIG_AUX_DIR([build-aux])
# 初始化automake
AM_INIT_AUTOMAKE(hello, 1.0)
# Checks for programs.
#AC_PROG_CC(arm-linux-gcc)
AC_PROG_CC(gcc)
#AC_PROG_LIBTOOL
AC_PROG_RANLIB
AX_CHECK_DOCBOOK


# 初始化要连接的obj目录
AC_CONFIG_LIBOBJ_DIR([src])

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h termios.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_C_INLINE
AC_TYPE_SSIZE_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T
AC_TYPE_UINT8_T

# Checks for library functions.
AC_FUNC_MALLOC
AC_CHECK_FUNCS([gettimeofday inet_ntoa memset select socket])

#多个目录包含Makefile.am
AC_CONFIG_FILES([Makefile test_example/Makefile
test_src/Makefile])
AC_OUTPUT
#单个目录包含Makefile.am,使用 AC_OUTPUT(Makefile),不使用 AC_CONFIG_FILES

2. 在工程根目录下, 运行 aclocal 生成 aclocal.m4

执行aclocal命令即可生成文件aclocal.m4,该文件是一个宏定义文件,该文件内容的生成依赖于configure.ac文件。

aclocal会根据confgure.ac文件的内容,搜索本地的m4文件(通常在类似目录下面/usr/share/aclocal-1.15/),然后生成一个在本目录下面使用的aclocal.m4文件

vmuser@ubuntu:~/user/vmuser/myproject/ aclocal
vmuser@ubuntu:~/user/vmuser/myproject/ file aclocal.m4
aclocal.m4: M4 macro processor script, ASCII text

 

   [acinclude.m4] ----.
                      |
     [local macros] --+--> aclocal* --> aclocal.m4
                      |
    configure.ac  ----'

  

 

3. 在工程根目录下, 运行 autoheader 生成 config.h.in

vmuser@ubuntu:~/user/vmuser/myproject/ autoheader
vmuser@ubuntu:~/user/vmuser/myproject/ file config.h.in
config.h.in: C source, ASCII text
     configure.ac --.
                    |   .------> autoconf* -----> configure
     [aclocal.m4] --+---+
                    |   `-----> [autoheader*] --> [config.h.in]
     [acsite.m4] ---'

  

 

这个文件config.h.in是一个模板文件,后面会利用该文件生成config.h文件。该文件包含一些宏定义

 

4. 在工程根目录下, 手动创建 Makefile.am

生成Makefile.in文件之前, 需要首先手动的创建一个Makefile.am文件,该文件用于描述源文件与目标文件的关系。本文对应的Makefile.am文件如下所示:

 

vmuser@ubuntu:~/user/vmuser/myproject/ touch Makefile.am
vmuser@ubuntu:~/user/vmuser/myproject/ file Makefile.am 

 

  编辑 Makefile.am, 如果要生成多个目标文件,需要在这里写多个源文件与目标文件的对应关系。这种情况是非常常见的,比如一些复杂的项目中通常会包含主程序,测试程序,静态/动态库等等。

详见:附录B 

 

AUTOMAKE_OPTIONS = foreign                
bin_PROGRAMS = main                           # 生成的可执行文件名称
main_SOURCES = plc_main.c calendar.c sort.c   # 程序依赖的源文件

INCLUDES = = -I/usr/local/libmemcached/include/ #表示连接时所需要的头文件
SUBDIRS = etc man                               # 表示在处理目录之前,要递归处理哪些子目录
SUBDIRS += subst

5. 在工程根目录下, 运行 automake 生成 Makefile.in

vmuser@ubuntu:~/user/vmuser/myproject/ automake --add-missing
vmuser@ubuntu:~/user/vmuser/myproject/ file Makefile.in
Makefile.in: makefile script, ASCII text, with very long lines
     configure.ac --.
                    +--> automake* --> Makefile.in
     Makefile.am ---'

  

使用命令 “ automake --add-missing ” 或 “ automake  -a ”,automake 会根据 Makefile.am 产生一些文件,包括最重要的Makefile.in 文件

 

6. 在工程根目录下, 运行 autoconf 生成 configure

生成configure文件的方法很简单,我们执行如下命令即可:

vmuser@ubuntu:~/user/vmuser/myproject/ autoconf 
vmuser@ubuntu:~/user/vmuser/myproject/ file configure
configure: POSIX shell script, ASCII text executable

 

     configure.ac --.
                    |   .------> autoconf* -----> configure
     [aclocal.m4] --+---+
                    |   `-----> [autoheader*] --> [config.h.in]
     [acsite.m4] ---'

  

 

7. 在工程根目录下, 运行 ./configure 生成 Makefile

生成Makefile文件的方法很简单,我们执行如下命令即可:

vmuser@ubuntu:~/user/vmuser/myproject/ ./configure  
vmuser@ubuntu:~/user/vmuser/myproject/ file Makefile
Makefile: ASCII text, with very long lines
vmuser@ubuntu:~/user/vmuser/myproject/ ./configure --help 
                            .-------------> [config.cache]
     configure* ------------+-------------> config.log
                            |
     [config.h.in] -.       v            .-> [config.h] -.
                    +--> config.status* -+               +--> make*
     Makefile.in ---'                    `-> Makefile ---'

  

8. 在工程根目录下, 运行 make && make install 生成 目标文件

生成Makefile文件的方法很简单,我们执行如下命令即可:

vmuser@ubuntu:~/user/vmuser/myproject/ make && make install
vmuser@ubuntu:~/user/vmuser/myproject/ make clean           //只清除之前编译的可执行文件及配置文件。
vmuser@ubuntu:~/user/vmuser/myproject/ make disclean //清除所有生成的文件。
vmuser@ubuntu:~/user/vmuser/myproject/ make uninstall //卸载

 当configure.ac 和 Makefile.am 发生改变时,需要更新 “已经生成的配置文件”, 此时需要使用 autoreconf命令。

9. 在工程根目录下, 运行 autoreconf  -ivf   整体更新配置文件生成configure

 autoreconf  重复运行 autoconf, autoheader, aclocal, automake, libtoolize, and autopoint (when appropriate) 在特殊目录及其子目录下更新GNU构建系统。默认只更新老的文件。不会传递–autoconf-dir=dir 或 --localdir=dir。

 最终更新Makefile.in、configure编译脚本等文件。但是不会执行./configure 。所以需要手动执行:   ./configure && make && make install

 

vmuser@ubuntu:~/user/vmuser/myproject/  autoreconf -ivf 
vmuser@ubuntu:~/user/vmuser/myproject/  ./configure  && make && make install
autoreconf 选项 含义
-v 详细报告处理
-d 不删除临时文件
-f 认为所有的文件都是过期的文件,强制执行
-i 复制辅助文件
-s 创建符号链接,而不是复制
-W<分类> 报告语法错误的信息
-m 当可以使用时,重新运行命令./configure和make
--no-recursive 不重建子包
-B<目录> 将目录作为搜索路径
-I<目录> 追加目录作为搜索路径

 

 

 

 附录 A   configure配置脚本常用选项:

--host

指需要运行的位置,默认为build,也就是本机编译出来的程序,由本机使用.     比如当本机编译出来的程序, 要在arm板上运行时, 就要设为 arm-linux

例如: 

./configure  --host=arm-linux            //默认:  ./configure --target=build 

--target 

指运行目标,比如gdb程序,通过在pc本机里运行,来调试开发板里的应用程序,所以--host设为build,--target设为arm-linux

例如:        

  ./configure --target=arm-linux      

 --prefix

安装路径前缀,指使用make install 后,生成的安装路径在哪

例如:        

./configure  --prefix=/work/my_bin    
./configure --prefix=$PWD/tmp     //安装在./tmp目录下  

PS:若该软件根目录下的Makefile里,有"--prefix ="之类的字段,也可以直接在安装处指定路径,比如:

#make  install  prefix=$PWD/tmp      //指定安装在./tmp目录下

CFLAGS

指定头文件(.h文件)的路径,一般是用来安装了库包后,安装目录下会有两个文件(include和lib),再来安装应用程序包时,就需要指定(include)头文件路径

例如:

./configure  CFLAGS=”-I/usr/include -std=c99”             //-I: include -std=c99 -std=gnu99, -std=c11 or -std=gnu11 

LDFLAGS

指定库文件的路径,一般是用来安装了库包后, 安装目录下会有两个文件(include和lib),再来安装应用程序包时,就需要指定(lib)库文件路径

例如:

./configure  LDFLAGS=”-L/usr/include”       //-L: lib

CC 

指定编译器,默认为gcc、cc或者HOST-gcc

例如:

./configure  CC=arm-linux-gcc              //ln -s /cross-tools/bin/arm-linux-gnueabihf-gcc   /usr/bin/x86_64-linux-gnu-gcc
./configure  --cc=arm-linux-gcc            //或者  --cc=gcc   或者  --cc=/usr/bin/x86_64-linux-gnu-gcc

 

AR 

指定编译器,默认为gcc、cc或者HOST-gcc

例如:

./configure  AR=arm-linux-gcc              //ln -s /cross-tools/bin/arm-linux-gnueabihf-ar   /usr/bin/arm-linux-gcc
./configure  --ar=arm-linux-ar            //或者  --ar=ar    或者 --ar=/usr/bin/x86_64-linux-gnu-ar

 

 附录B  Makefile.am常用语法

AUTOMAKE_OPTIONS = foreign //设置automake的选项,automake提供了三种软件等级:foreign、gnu和gnits,当当前库文件编译所需源文件不在当前目录时要设置参数subdir-objects

目标1:bin目录可执行程序

bin_PROGRAMS = XXX YYY     #编译并安装, 生成的目标“可执行应用程序”名称,如果有多个,用空格隔开,与configure.ac中AC_INIT对应库名对应
noinst_PROGRAMS = XXX      #只编译不安装,“可执行应用程序”名称

noinst_HEADERS = xxx.h     #只编译不安装,所需要的目标“头文件”。这个表示该头文件只是参加可执行文件的编译,而不用安装到安装目录下。如果需要安装到系统中,可以用include_HEADERS来代替
INCLUDES=-I$(top_srcdir)/Core/inc/       #链接时,所需要的“头文件所在路径” 
XXX_SOURCES = Main/main.c Ether/ether_server.c  test.h  #编译时,生成目标文件所需要的“源代码文件” 
XXX_CFLAGS   = -g -O2 -std=c99 -I$(top_srcdir)/Core/inc/
#编译时,C预处理/编译“选项”, 
XXX_CPPFLAGS
= -DCONFIG_DIR=\"$(sysconfdir)\" -DLIBRARY_DIR=\"$(pkglibdir)\" #编译时,C/C++预处理/编译“选项”,一般用来指定所需要头文件目录

INCLUDES
=-I$(top_srcdir)/Core/inc/ #链接时,所需要的“头文件所在路径”
XXX_LDADD
= $(top_srcdir)/Core/lib/libecpucore.a #链接时,。所需要的“静态库”名称
XXX_LDFLAGS
=-D_GNU_SOURCE #链接时,所需要的库文件的标识, 如-l,-shared等“选项”
LIBS
= -lpthread -ldl #链接时,所需要的“动态库”名称
DEFS
+=-D_GNU_SOURCE

 样例:

AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = ecpu.bin

INCLUDES = -I$(top_srcdir)/CANopen/inc/ -I$(top_srcdir)/CANopen/inc/linux/ \
-I$(top_srcdir)/CANopen/dictionary/ -I$(top_srcdir)/CANopen/hardware/

ecpu_bin_CFLAGS = --static -g -O2 -std=c99 -I$(top_srcdir)/Core/inc/ -I$(top_srcdir)/Ether/
ecpu_bin_SOURCES = Main/main.c Ether/cu_com.c Ether/ssw_com.c Ether/ether_server.c SerialPort/rs485.c \ 
MoveControl
/Schedule/mod_state.c \
MoveControl
/Schedule/schedule_move.c \
MoveControl
/Schedule/test_list.c \
MoveControl
/Schedule/test_order.c
SUBDIRS = CANopen
ecpu_bin_LDADD = $(top_srcdir)/Core/lib/libecpucore.a $(top_srcdir)/CANopen/libcanopen.a 

LIBS=-lpthread -ldl

 

 

 

目标2:lib目录静态库文件

lib_LIBRARIES=libXXX.a                     #编译并安装, 生成的目标“静态库”名称
noinst_LIBRARIES = libXXX.a                #只编译不安装,生成的目标“静态库”名称
libXXX_a_SOURCES = tinyxml2.h tinyxml2.cpp #编译时,生成目标文件所需要的“源代码文件”

 样例:

noinst_LIBRARIES = libcanopen.a

noinst_HEADERS = hardware/canopen_cfg.h
INCLUDES=-I$(top_srcdir)/CANopen/inc/  -I$(top_srcdir)/CANopen/inc/linux/   \
-I$(top_srcdir)/CANopen/dictionary/ -I$(top_srcdir)/CANopen/hardware/
     
libcanopen_a_CFLAGS = -std=c99 
libcanopen_a_SOURCES = hardware/canopen_cfg.h dictionary/Master.c dictionary/Master.h dictionary/Master.od \ 
hardware
/can0.c hardware/can0.h hardware/timer0.c hardware/ timer0.h \
src
/dcf.c src/emcy.c src/lifegrd.c src/lss.c src/nmtMaster.c src/nmtSlave.c \
src/objacces.c src/pdo.c src/sdo.c src/states.c src/sync.c src/timer.c

 

 

 

目标3:lib目录动态库文件

https://www.freesion.com/article/52611144144/

 

目标4:include目录头文件

include_HEADERS = XXX.h         #编译并安装, 所需要的“头文件”。这个表示哪些头文件将在执行make install命令之后被安装到系统include目录下                                

 

目标5:data目录数据文件

data_DATA = XXXX YYYY           #编译并安装,所需要的目标数据文件,不能执行。

  

 

变量:

SUBDIRS=src/lib src/ModuleA/apple/shell src/ModuleA/apple/core   #表示编译当前目录之前,先编译哪些子目录,多个目录用空格分开
CURRENTPATH=$(shell /bin/pwd)                                    #表示当前目录
INCLUDES=-I$(top_srcdir)/Core/inc/       #链接时,所需要的“头文件所在路径” 
export INCLUDES
$(top_builddir)      #表示生成目标文件的最上层目录,用于引用.o等编译出来的目标文件。
$(top_srcdir)        #表示工程的最顶层目录,其实也是第一个Makefile.am的入口目录,用于引用源程序

 

 

./configure –-prefix=/usr/local/app/ 其实在调用这个之后,就定义了一个变量$(prefix), 表示安装的路径:

bindir     = $(prefix)/bin
libdir     = $(prefix)/lib
datadir    = $(prefix)/share
sysconfdir = $(prefix)/etc
includedir = $(prefix)/include

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2022-11-28 22:23  suntroop  阅读(1009)  评论(0)    收藏  举报