autotool是一种帮助用户自动管理项目生成Makefile的工具。有时候手动写Makefile可以满足自己的要求,但是随着项目增加,代码结构也变得非常复杂,这样一来手动维护每个Makefile就变得非常困难。
autotool的存在帮助降低了项目维护的难度。
autotool不是某一个工具,而是一系列工具的混合体。
autoscan
aclocal
autoconf
autoheader
automake
这一系列最终目的就是生成makefile,进而帮助项目编译。
Makefile.am文件是整个autotool自动生成makefile的灵魂,这其中不需要规定多么复杂的逻辑生成关系。这里对这个内容进行着重介绍。
终极目标
automake通过Makefile.am来生成Makefile.in。
bin_PROGRAMS(*program-list*) |
a program or programs build in the local directory that should be compiled, linked and installed. |
noinst_PROGRAMS(*program-list*) |
a program or programs build in the local directory that should be compiled, linked but not installed. |
bin_SCRIPTS(*script-list*) |
a script or scripts build in the local directory that should be installed. |
man_MANS(*page-list*) |
man pages that should be installed. |
lib_LTLIBRARIES(*lib-list*) |
a library or libraries that should be built using libtool . |
命名方案
automake使用统一的命名规则,此举可以使工具明确需要构建的内容。
PROGRAMS:(bin_PROGRAMS
sbin_PROGRAMS
noinst_PROGRAMS
etc)
PROGRAMS
—用来生成可执行二进制文件的参数,多数为C/C++,lex,yacc,或者需要依赖工具。LIBRARIES
—生成二进制文件/分发软件的中间形式文件。LISP
(yeah, right)PYTHON
JAVA
SCRIPTS
—for distribution in the package; an artificial intermediate source is established, usually the resulting script name unsurprisingly suffixed with .in.DATA
(beats me so far)MANS
—生成使用手册隐藏变量
automake会有一些预留的参数,例如AM_CFLAGS
源文件、头文件、库文件
为每个目标文件指定源文件。
生成的目标文件名称 + _ + SOURCES = 源文件列表
lockproj_SOURCES = main.c
lib_LTLIBRARIES = libpthread_rwlock_fcfs.la
libpthread_rwlock_fcfs_la_SOURCES = rwlock.c queue.c
libpthread_rwlock_fcfs_la_HEADERS = rwlock_fcfs.h
# Notice the bin_ prefix.
bin_PROGRAMS = kdialog
kdialog_SOURCES = kdialog.cpp widgets.cpp
kdialog_LDADD = $(LIB_KIO)
kdialog_LDFLAGS = $(all_libraries) $(KDE_RPATH)
AM_CPPFLAGS = $(all_includes)
METASOURCES = AUTO
bin
bin
指的是想要创建的文件,这些文件会被安装在KDE
中的bin目录。
*_PROGRAMS
指的就是想要编译的内容。
_SCRIPTS
指的是需要安装的脚本文件。
_SOURCES
对于PROGRAMS
中列举出来的所有需要编译的文件都要在这里列举。
注意不要列举头文件,和一些在构建过程中用不到的文件
_LDADD
这个参数列举了构建过程中需要链接的库文件。
如果某个库A依赖于库B,这里不必列出库B。
LDFLAGS
定义了所有编译需要的flags选项。
KDE_CXXFLAGS
一般来说是在其他flags后面作为编译选项的补充
AM_CPPFLAGS = $(all_includes)
lib_LTLIBRARIES = libkonq.la
libkonq_la_LIBADD = $(LIB_KPARTS)
libkonq_la_LDFLAGS = $(all_libraries) -version-info 6:0:2 -no-undefined
libkonq_la_SOURCES = popupmenu.cc knewmenu.cpp ...
METASOURCES = AUTO
lib
lib_
prex指的是将会被安装到lib/
目录下的lib库文件,接着就是lib的名称,后缀是.la。
_LTLIBRARIES
LibTool libraries
。换句话说,这个参数使得autotool明确了lib库是通过libtool程序生成的。
_LIBADD
指的是前缀库所以来的库。需要注意的是LDADD适用于programs,而LIBADD适用于lib。
_LDFLAGS
指的是编译时候需要的参数。
如果使用相同的编译参数、相同的代码编译成两个不同的共享库,或者是两个程序。可以将它们都附在_SOURCES
选项后。
# Just as bin_ means install to /bin and lib_ means
# install to lib/, noinst_ means not to install at all.
noinst_LTLIBRARIES = libcommon.la
libcommon_la_SOURCES = dirk.cpp coolo.cpp ...
# no need for LIBADD or LDFLAGS, strictly speaking, but it can help
# if e.g. this code needs $(LIBJPEG), all users of this convenience
# lib won‘t have to specify it.
# Then you can use the convenience lib:
mylib_la_LIBADD = libcommon.la
myprogram_LDADD = libcommon.la
如果想安装头文件:
include_HEADERS = foo.h bar.h
如果类使用的是命名空间,比如KParts,那么头文件应该被安装到kparts/foo.h
kpartsincludedir = $(includedir)/kparts
kpartsinclude_HEADERS = foo.h bar.h
第一行定义了新的路径,第二行定义了需要安装的文件。需要注意的是dir
和_HEADERS
必须一一对应。
为了向某个文件安装文件,需要使用dirname_DATA。
kde_services_DATA = foo.desktop
为了在自定文件安装文件,必须首先定义,然后才能使用。
myappfoodir = $(kde_datadir)/kmyapp
myappfoo_DATA = bar.desktop
正常情况下,只需要列出所有的子目录
SUBDIRS = foo bar
为了自动编译所有的子目录
SUBDIRS = $(AUTODIRS)
如果想编译一个可选的目录,需要使用automake的选择性条件功能,
if compile_KOPAINTER
KOPAINTERDIR = kopainter
endif
SUBDIRS = foo bar $(KOPAINTERDIR)
代码结构:
.
├── include
│ ├── abc
│ │ └── abc.h
│ └── hello
│ └── hello.h
└── src
└── hello.c
# 代码逻辑如上,src目录中有一个主体文件,include 有两个目录分别定义了不同的函数。
src/hello.c
#include <stdio.h>
#include "hello/hello.h"
#include "abc/abc.h"
void prt()
{
printf("+++++prt+++++++\n");
}
void abc()
{
printf("------abc------\n");
}
int main()
{
prt();
abc();
return 0;
}
include/abc/abc.h
#ifndef __ABC_H__
#define __ABC_H__
#include<stdio.h>
void abc();
#endif
include/hello/hello.h
#ifndef __HELLO_H__
#define __HELLO_H__
#include<stdio.h>
void prt();
#endif
回到项目中,工程个目录的src
保存着项目的主体文件。include
保存着头文件。
Makefile.am
AUTOMAKE_OPTIONS=foreign subdir-objects
SUBDIRS=src
# 表示子目录是src,也就是说除了在根目录会生成一个makefile意外,还会在
# src目录也生成一个makefile
conf_include_dir=$(top_srcdir)/include
# 需要注意的是,top_srcdir top_builddir都是预设好的autotool参数
# 表示的是工程的根目录,只不过这个根目录是用 . 表示的。
#####################################################################################
cbaincludedir = $(includedir)/abc
cbainclude_HEADERS = $(conf_include_dir)/abc/abc.h
helloincludedir = $(includedir)/hello
helloinclude_HEADERS = $(conf_include_dir)/hello/hello.h
# nameincludedir
# nameinclude_HEADERS
# 前文已经叙述过 _HEADERS 表示的是头文件,这里需要注意得使用相同名称的规则
####################################################################################
yiyi:
echo $(top_srcdir) # .
echo $(top_builddir) # .
echo $(prefix) # path/prefix
echo $(bindir) # path/prefix/bin
echo $(libdir) # path/prefix/lib
echo $(datadir) # path/prefix/share
echo $(sysconfdir) # path/prefix/etc
echo $(includedir) # path/prefix/include
echo $(srcdir) # .
# 这里打印出了预设好的一些很常用的变量
src/Makefile.am
bin_PROGRAMS= hello
# 前文叙述过,bin_PROGRAMS表示需要进行安装的二进制文件
hello_SOURCES= hello.c
# 这里表示的是用于编译的文件
AM_CPPFLAGS=-I$(top_srcdir)/include
# 还需要指明哪个是include目录。
# 需要注意的是,这里直接采用top_srcdir。
# 这个变量不建议在根目录使用
# 因为top_srcdir是. 在根目录使用会导致include目录紊乱
1.autoscan
? 第一步就是执行autoscan操作,主要目的是扫描工作目录,并且生成configure.scan文件。这个configure.scan需要改为configure.ac然后修改其中的配置。
2.mv configure.scan configure.in
3.vim configure.in
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
# 当前autotool的版本为2.69
AC_INIT(configure-test2, 2.0, aaa)
# 需要生成的工程名称configure-test2 版本为2.0 bug报告地址为aaa
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/hello.c])
# 用来侦测所指定的源码文件是否存在,来确定源码目录的有效性。此处为当前目录下的hello.c
AC_CONFIG_HEADERS([config.h])
# 用于生成config.h文件,以便autoheader使用
# Checks for programs.
AC_PROG_CC
# 用来指定编译器,如果不指定,选用默认gcc。
# 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([Makefile
src/Makefile])
# 需要输出的文件名,由于涉及嵌套的makefile.am,这里会根据scan自动生成两个makefile
4.aclocal
? 扫描configure.ac文件生成aclocal.m4文件,该文件主要用于处理本地的宏定义。
5.autoconf
? 将configure.ac的宏展开,生成configure脚本。
6.autoheader
? 生成configure.h.in文件
7.automake --add-missing
? 生成Makefile.in文件,--add-missing选项可以让automake自动添加一些必要的脚本文件,
8.configure
? 可以运行configure命令,将Makefile.in生成Makefile了
原文:https://www.cnblogs.com/AshenYi/p/14882469.html