Home makefile学习
Post
Cancel

makefile学习

本文是一些自己学习makefile时的笔记。以下内容主要摘取自陈皓编写的跟我一起写Makefile,这是一个很好的学习资料。

makefile介绍

参考

makefile的核心规则

1
2
target : prerequisites
    command

target是目标文件,prerequisites是生成target的依赖文件。当target不存在,或prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行,command命令一定要由一个Tab键开头。

在makefile末尾一般会看到,用来删除编译产生的中间文件等:

1
2
clean :
    rm ...

这里clean 不是一个文件,它只不过是一个动作名字(伪目标),其冒号后什么也没有,那么,make就不会自动去找它的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要在make命令后明显得指出这个label的名字,如make clean

make是如何工作的

make会在当前目录下找名字叫“Makefile”或“makefile”的文件,并根据该文件一层一层地去找文件的依赖关系,直到最终编译出第一个目标文件。详细可参见这里这里

书写规则

参考

规则举例

伪目标

多目标静态模式

$@ 表示目标的集合,就像一个数组, $@ 依次取出目标,并执于命令,可用于多目标。参考这里

静态模式可以更加容易地定义多目标的规则。其语法为

1
2
<targets ...> : <target-pattern> : <prereq-patterns ...>
    <commands>

举例:

1
2
3
4
5
6
objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c
    <command>

其中%.o即为target-pattern%.cprereq-patterns%.o: %.c的含义为:将objects中所有以.o的目标,后缀换为.c组成新的集合。

使用变量

参考

变量基础

  • 变量定义

    1
    
      VAL = ...
    
  • 变量使用

    1
    2
    3
    
      $(VAL)
      
      ${VAL}
    

    变量会在使用时精确展开。

  • 定义变量值时的=:=

    • =允许使用当前尚未定义好的变量作为右值,但可能出现递归定义的问题;
    • :=强制要求只能使用前面已定义好了的变量作为右值。

变量高级用法

  • 变量替换

    1
    2
    3
    4
    5
    6
    7
    
    # 定义变量
    foo := a.o b.o
      
    # 变量替换
    bar := $(foo:.o=.c)  # bar = a.c b.c
    # 或
    bar := $(foo:%.o=%.c) # bar = a.c b.c
    
  • 变量追加

    1
    2
    
    foo := a.o b.o
    foo += c.o   # foo = a.o b.o c.o
    
  • 自动化变量

    • $@:当前规则中,目标(或目标集)。
    • $^:当前规则中,所有依赖组成的的集合。
    • $<:当前规则中,第一个依赖

    举个栗子,对

    exc: library.cpp main.cpp
    

    那么,$@ 就指代 exc$^指代library.cpp main.cpp$<指代library.cpp

    如果@$指代的目标有多个(即是一个目标集)时,则将目标依次取出展开,执行command参考

    这种方式貌似对于多个相互独立的文件分别编译非常方便,尤其当文件非常多时。

    举个栗子,对

    1
    2
    3
    4
    5
    6
    
    objects = foo.o bar.o
      
    all: $(objects)
      
    $(objects): %.o: %.c
        $(CC) -c $(CFLAGS) $< -o $@
    

    展开后对应执行

    1
    2
    3
    4
    
    foo.o : foo.c
        $(CC) -c $(CFLAGS) foo.c -o foo.o
    bar.o : bar.c
        $(CC) -c $(CFLAGS) bar.c -o bar.o
    

使用条件判断

参考

  • 关键字ifeqifneq,判断是否相等。示例:

    1
    2
    3
    4
    5
    
      ifeq ($(CC),gcc)
          $(CC) -o foo $(objects) $(libs_for_gcc)
      else
          $(CC) -o foo $(objects) $(normal_libs)
      endif
    
  • 关键字ifdefifndef,判断变量是否有值。示例:

    1
    2
    3
    4
    5
    6
    7
    8
    
    foo =
    ifdef foo
        frobozz = yes
    else
        frobozz = no
    endif
      
    # 该例中frobozz为no
    

使用函数

函数的调用语法为:

1
2
3
$(<function> <arguments>)
# 或是
${<function> <arguments>}

makefile支持的函数可参照:字符串处理函数文件名操作函数还有其他

This post is licensed under CC BY 4.0 by the author.

Customize the Favicon

g++编译学习