Linux 自动编译 Makefile

2015-11-03 language linux c/cpp

在 Linux 中,经常使用 GNU 构建系统,也就是利用脚本和 make 程序在特定平台上构建软件,这种方式几乎成为一种习惯,被广泛使用。

这里简单介绍下最基本的 Makefile 。

简介

在 Linux 平台下,在编译项目时通常使用 Makefile,简单来说,Makefile 是用来定义整个工程的编译规则,也就是文件的编译、链接顺序,如何生成可执行文件或者动态加载库等等。

Makefile 带来的最大好处就是 “自动化编译”,一但编辑好文件,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。

如果项目比较小,那么可以直接手动编辑该文件;不过一但项目比较大时,手动维护将变得极其复杂,为此,就可以使用 Autotools 或者 CMake 生成 Makefile 文件。

假设项目工程的使用源码结构如下。

src/
   子目录,存放工程源码;
doc/
   子目录,用来存放工程文档;
bin/
   子目录,最后生成的二进制可执行文件;
COPYRIGHT
   版权信息;
README.md
   使用 markdown 编写的自述文件;

默认,会将可执行文件安装在 /usr/bin 目录下,doc 安装到 /usr/share/doc 目录下。

Makefile

详细内容可以参考陈皓编写的《跟我一起写 Makefile》,在此就不做过多介绍了,仅简单记录下。

变量

如下是 Makefile 中内置的变量。

$@:  规则中的目标名(也就是规则名);
$<:  规则中的依赖项目,只代表规则所有依赖项目中的第一项;
$^:  规则中所有的依赖项目;
$?:  规则中时间新于目标的依赖项目。

关于变量通配符,与 shell 相同,如 1) ? 任意单个字符;2) * 任意字符的字符串;3) [set] 任何在 set 里的字符;4) [!set] 任何不在 set 里的字符。

以如下为例 touch {a,b,c}.c Makefile

.PHONY: all

src1=$(wildcard *.c)
src2=%.c
src3=*.c
objs:=$(patsubst $(src2),%.o,$(wildcard *.c))

all: $(objs)
    @echo $^
    @echo $(src1)
    @echo $(src2)
    @echo $(src3)
    @echo *.c

%o:%.c
    @echo $?

#cc    -c -o a.o a.c
#cc    -c -o c.o c.c
#cc    -c -o b.o b.c
#a.o c.o b.o
#a.c c.c b.c
#%.c
#a.c b.c c.c
#a.c b.c c.c

PHONY 伪目标

通常来说 Makefile 会检测 : 左侧的目标是不是最新的,如果是最新的则不会更新,对应规则不会执行。假设目标为 clean,本意是做编译后的清理,但是当目录下有 clean 文件时,则对应的规则将不会执行,为了解决这一问题,定义了伪目标。

当定义了伪目标之后,make 在执行规则时不会去试图去查找隐含规则来创建它,而是直接执行,这样就提高了 make 的执行效率,也不用担心由于目标和文件名重名了。

伪目标的另一种使用场合时在 make 的并行和递归执行过程中,第一个实际上时串行执行的;第二个会并行执行。

### 1
SUBDIRS=foo bar baz
subdirs:
    for dir in $(SUBDIRS)
    do
    $(MAKE) –C $$dir
    done

### 2
.PHONY:subdirs $(SUBDIRS)
SUBDIRS=foo bar baz
subdirs: $(SUBDIRS)
$(SUBDIRS):
    $(MAKE) –C $@