Makefile自动生成

编写 make 规则: 
使用 gcc 的时候,用 -M 开关,它会为每一个你给它的C文件输出一个规则,把目标文件 做为目的,而这个C文件和所有应该被 #include 的 header 文 件将做为依靠文件。注意这个规则会加入所有 header 文件,包 括被角括号(`<', `>')和双引号(`"')所包围的文件。其实系统 header 档(比如 stdio.h, stdlib.h 等等一般不会被我们更改,如果用 -MM 来代替 -M 传递给 gcc,那些用角括号包围的 header 档将不会被包括。
$@ 扩展成当前规则的目的文件名, $< 扩展成依靠列表中的第 一个依靠文件,而 $^ 扩展成整个依靠的列表。

自动生成Makefile文件的操作:


1、首先,新建一个测试项目的目录——hello:mkdir hello
然后,cd hello;编辑一个hello.c的代码文件:
#include <stdio.h>
int main()
{
     printf("hello automake!\n");
}
保存退出;

2、执行autoscan命令,在当前路径中生成了autoscan.log  configure.scan两个新文件。其中configure.scan文件的内容如下:
AC_PREREQ(2.57)
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
AC_CONFIG_SRCDIR([test.c])
AC_CONFIG_HEADER([config.h])
AC_PROG_CC
AC_OUTPUT

3、重命名configure.scan  为configure.in,编辑它的内容,修改后的内容为:
AC_PREREQ(2.57)
AC_INIT(hello)
AC_CONFIG_SRCDIR([hello.c])
#AC_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE(hello, 1.0)
AC_PROG_CC
AC_OUTPUT([Makefile])

说明:Autoconf 是用来产生 'configure'文件的工具。'configure' 是一个 shell script,它可以自动设定符合各种不同平台上Unix 系统的特性,并且根据系统参数及环境产生合适的Makefile文件或C 的头文件(header file),让原始程式可以很方便地在不同的平台上进行编译。Autoconf会读取 configure.in 文件然后产生'configure' 这个 shell script。configure.in 文件内容是一系列GNU m4 的宏,这些宏经autoconf处理后会变成检查系统特性的shell scripts。 configure.in 内宏的顺序并没有特别的规定,但是每一个configure.in 文件必須在所有宏前加入 AC_INIT 宏,然后在所有宏的最后加上 AC_OUTPUT宏。可先用 autoscan 扫描原始文件以产生一个 configure.scan 文件,再对 configure.scan 做些修改成 configure.in 文件。
AC_INIT(FILE) 
该宏用来检查源代码所在路径,autoscan 会自动产生,一般无须修改它。
AM_INIT_AUTOMAKE(PACKAGE,VERSION) 
这个是使用 Automake 所必备的宏,PACKAGE 是所要产生软件套件的名称,VERSION 是版本编号。 
AC_PROG_CC 
检查系统可用的C编译器,若源代码是用C写的就需要这个宏。
AC_OUTPUT(FILE) 
设置 configure 所要产生的文件,若是Makefile ,configure 便会把它检查出来的结果带入 Makefile.in 文件后产生合适的 Makefile。 

4、执行aclocal命令,生成了aclocal.m4文件,一般无需修改这个文件。
5、新建Makefile.am文件,编辑内容如下:
            bin_PROGRAMS=test   
            test_SOURCES=test.c
说明:
Automake 会根据 configure.in 中的宏把Makefile.am 转成 Makefile.in 文件。 Makefile.am 文件定义所要产生的目标: 
AUTOMAKE_OPTIONS
设置 automake 的选项。Automake 主要是帮助开发 GNU 软件的人员来维护软件,所以在执行 automake 时,会检查目录下是否存在标准 GNU 软件中应具备的文件,例如 'NEWS'、'AUTHOR'、'ChangeLog' 等文件。设置 foreign 时,automake 会改用一般软件的标准来检查。 
bin_PROGRAMS 
定义要产生的执行文件名。如果要产生多个执行文件,每个文件名用空白符隔开
hello_SOURCES 
定义 'hello' 这个执行程序所需要的原始文件。如果 'hello'这个程序是由多个原始文件所产生,必須把它所用到的所有原始文件都列出来,以空白符隔开。假设 'hello' 还需要 'hello.c'、'main.c'、'hello.h' 三个文件的话,则定义 
hello_SOURCES= hello.c main.c hello.h 
如果定义多个执行文件,则对每个执行程序都要定义相对的filename_SOURCES

6、 执行autoconf命令,生成autom4te.cache和configure文件;
7、执行automake -a命令,生成depcomp  ,install-sh,mkinstalldirs,COPYING,INSTALL, missing文件;
说明:
编辑好 Makefile.am 文件,就可以用 automake --add-missing来产生 Makefile.in。加上 --add-missing 选项来告诉 automake顺便假如包装一个软件所必须的文件。Automake产生生出來的 Makefile.in 文件是完全符合 GNU Makefile 的惯例,只要执行 configure这个shell script 便可以产生合适的 Makefile 文件了。 
在执行automake -a命令时可能会出现以下信息:
Makefile.am: required file `./NEWS' not found
Makefile.am: required file `./README' not found
Makefile.am: required file `./AUTHORS' not found
Makefile.am: required file `./ChangeLog' not found
这些对结果影响不大,如果不想产生这些让人误解的信息,可以手动建立这些文件:
>NEWS   
>README   
>AUTHORS   
>ChangeLog   

8、执行./configure,生成了Makefile文件
9、执行make,生成目标文件。

实战Makefile.am

Makefile.am是一种比Makefile更高层次的规则。只需指定要生成什么目标,它由什么源文件生成,要安装到什么目录等构成。

表一列出了可执行文件、静态库、头文件和数据文件,四种书写Makefile.am文件个一般格式。


表 1Makefile.am一般格式
表 1Makefile.am一般格式 

对于可执行文件和静态库类型,如果只想编译,不想安装到系统中,可以用noinst_PROGRAMS代替bin_PROGRAMS,noinst_LIBRARIES代替lib_LIBRARIES。

Makefile.am还提供了一些全局变量供所有的目标体使用:


表 2 Makefile.am中可用的全局变量
表 2 Makefile.am中可用的全局变量 

在Makefile.am中尽量使用相对路径,系统预定义了两个基本路径:


表 3Makefile.am中可用的路径变量
表 3Makefile.am中可用的路径变量 

在上文中我们提到过安装路径,automake设置了默认的安装路径:

1) 标准安装路径

默认安装路径为:$(prefix) = /usr/local,可以通过./configure --prefix=<new_path>的方法来覆盖。

其它的预定义目录还包括:bindir = $(prefix)/bin, libdir = $(prefix)/lib, datadir = $(prefix)/share, sysconfdir = $(prefix)/etc等等。

2) 定义一个新的安装路径

比如test, 可定义testdir = $(prefix)/test, 然后test_DATA =test1 test2,则test1,test2会作为数据文件安装到$(prefix)/ /test目录下。

我们首先需要在工程顶层目录下(即project/)创建一个Makefile.am来指明包含的子目录:


SUBDIRS=src/lib src/ModuleA/apple/shell src/ModuleA/apple/core 
CURRENTPATH=$(shell /bin/pwd)
INCLUDES=-I$(CURRENTPATH)/src/include -I$(CURRENTPATH)/src/ModuleA/apple/include
export INCLUDES

由于每个源文件都会用到相同的头文件,所以我们在最顶层的Makefile.am中包含了编译源文件时所用到的头文件,并导出,见蓝色部分代码。

我们将lib目录下的swap.c文件编译成libswap.a文件,被apple/shell/apple.c文件调用,那么lib目录下的Makefile.am如下所示:


noinst_LIBRARIES=libswap.a
libswap_a_SOURCES=swap.c
INCLUDES=-I$(top_srcdir)/src/includ

细心的读者可能就会问:怎么表1中给出的是bin_LIBRARIES,而这里是noinst_LIBRARIES?这是因为如果只想编译,而不想 安装到系统中,就用noinst_LIBRARIES代替bin_LIBRARIES,对于可执行文件就用noinst_PROGRAMS代替 bin_PROGRAMS。对于安装的情况,库将会安装到$(prefix)/lib目录下,可执行文件将会安装到${prefix}/bin。如果想安 装该库,则Makefile.am示例如下:


bin_LIBRARIES=libswap.a
libswap_a_SOURCES=swap.c
INCLUDES=-I$(top_srcdir)/src/include
swapincludedir=$(includedir)/swap
swapinclude_HEADERS=$(top_srcdir)/src/include/swap.h

最后两行的意思是将swap.h安装到${prefix}/include /swap目录下。

接下来,对于可执行文件类型的情况,我们将讨论如何写Makefile.am?对于编译apple/core目录下的文件,我们写成的Makefile.am如下所示:


noinst_PROGRAMS=test
test_SOURCES=test.c
test_LDADD=$(top_srcdir)/src/ModuleA/apple/shell/apple.o $(top_srcdir)/src/lib/libswap.a
test_LDFLAGS=-D_GNU_SOURCE
DEFS+=-D_GNU_SOURCE
#LIBS=-lpthread

由于我们的test.c文件在链接时,需要apple.o和 libswap.a文件,所以我们需要在test_LDADD中包含这两个文件。对于Linux下的信号量/读写锁文件进行编译,需要在编译选项中指明 -D_GNU_SOURCE。所以在test_LDFLAGS中指明。而test_LDFLAGS只是链接时的选项,编译时同样需要指明该选项,所以需要 DEFS来指明编译选项,由于DEFS已经有初始值,所以这里用+=的形式指明。从这里可以看出,Makefile.am中的语法与Makefile的语 法一致,也可以采用条件表达式。如果你的程序还包含其他的库,除了用AC_CHECK_LIB宏来指明外,还可以用LIBS来指明。

如果你只想编译某一个文件,那么Makefile.am如何写呢?这个文件也很简单,写法跟可执行文件的差不多,如下例所示:

noinst_PROGRAMS=apple
apple_SOURCES=apple.c
DEFS+=-D_GNU_SOURCE

转自:http://andychenkan.blog.163.com/blog/static/56300913200881922531784/
在使用 Makefile 进行项目构建时,自动生成依赖关系是一个重要的功能,它能够确保头文件的更改也能触发相关源文件的重新编译。这一机制通常通过编译器(如 GCC)提供的 `-MM` 选项来实现,该选项可以生成源文件所依赖的头文件列表。 为了将这些自动生成的依赖信息集成到 Makefile 中,常见的做法是为每个 `.c` 源文件生成一个对应的 `.d` 文件,其中包含其依赖关系[^1]。这些 `.d` 文件随后被包含进主 Makefile 中,使得 make 工具能够在头文件发生变化时正确地重新编译受影响的目标文件[^2]。 具体实现步骤如下: - 使用 `$(CC) -MM source.c > source.d` 命令生成每个源文件的依赖文件[^1]。 - 在 Makefile 中使用 `include` 指令引入所有 `.d` 文件,这样 make 就会读取这些依赖信息并将其纳入整个构建流程中[^4]。 - 为了确保每次构建时都能获取最新的依赖信息,可以在 Makefile 中添加一个专门用于生成依赖文件的目标(例如 `depend`),并在构建主目标之前调用它[^2]。 下面是一个简化版的 Makefile 示例,演示了如何利用 GCC 的 `-MM` 功能和 `include` 指令来自动生成和管理依赖关系: ```makefile EXE=main CC=gcc SRC=$(wildcard *.c) OBJ=$(SRC:.c=.o) CFLAGS=-g all: depend $(EXE) depend: @$(CC) -MM $(SRC) > .depend -include .depend $(EXE): $(OBJ) $(CC) $(OBJ) -o $(EXE) clean: rm -f $(EXE) $(OBJ) .depend ``` 在这个示例中,`depend` 目标负责生成 `.depend` 文件,该文件包含了所有源文件与其依赖头文件之间的关系。`-include .depend` 行确保了这些依赖信息被加载到 Makefile 中,从而允许 make 根据需要更新目标文件。 此外,需要注意的是,GCC 默认会根据输入文件名自动推导出输出对象文件的名字。因此,在某些情况下,可以省略 `-o` 参数,直接使用 `gcc -c main.c` 来编动生成 `main.o` 文件[^5]。 综上所述,通过结合使用编译器的依赖生成能力和 Makefile 的 `include` 特性,可以有效地管理和维护复杂的项目结构,保证项目的高效构建与维护。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值