当前位置:   article > 正文

Makefile笔记整理_makefile .phony:romfs

makefile .phony:romfs

GCC常用选项

  • -DMACRO选项
    -DOS_LINUX将宏定义OS_LINUX

  • -Idir
    添加头文件搜索目录dir

  • -Ldir
    添加链接库搜索目录dir。gcc优先使用共享程序库

  • -static
    仅选用静态程序库进行链接,如果一个目录中静态库和动态库都存在,则仅选用静态库

  • -g
    包括调试信息

  • -On
    优化程序,n代表优化级别,n常为2

  • -Wall
    打开警告信息


Makefile规则基本格式

TARGET...: DEPENDEDS...
    COMMAND
    ...
    ...
  • 1
  • 2
  • 3
  • 4

TARGET:规则定义的目标
DEPENDEDS:执行规则锁必须依赖的条件(DEPENDEDS也可以是某个TARGET,形成嵌套)
COMMAND:规则所执行的命令

Makefile中常用变量及含义

变量名含义默认值
AR生成静态库文件的程序名称ar
AS汇编编译器的名称as
CCC语言编译器的名称cc
CPPC语言预编译器的名称$(CC) -E
CXXC++语言编译器的名称g++
FCFORTRAN语言编译器的名称f77
RM删除文件程序的名称rm -f
ARFLAGS生成静态库库文件程序的选项\
ASFLAGS汇编语言编译器的编译选项\
CFLAGSC语言编译器的编译选项\
CPPFLAGSC语言预编译的编译选项\
CXXFLAGSC++语言编译器的编译选项\
FFLAGSFORTRAN语言编译器的编译选项\

Makefile中的自动变量

变量含义
$*表示目标文件的名称,不包含目标文件的扩展名(GUN make特有,其他make不一定支持)
$+所有依赖项的集合,不会去除重复的依赖项
$<表示依赖项中第一个依赖文件的名称
$?依赖项中,所有目标文件时间戳晚的依赖文件,以来稳健之间以空格分开
$@目标项中目标文件的名称
$^依赖项中,所有不重复的依赖文件,这些文件之间以空格分开

Makefile中的VPATH变量

使用方法:

VPATH=add:sub(加入addsub搜索路径)
  • 1

VPATH 只控制.c/.cpp的查找路径(将.c/.cpp文件所在文件夹添加到VPATH后只用写文件名gcc即可查找到文件),对于.h文件,需要使用-I./header。

Makefile中的= := ?= +=赋值运算符

= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值

1“=”
make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:
x = foo
y = $(x) bar
x = xyz
在上例中,y的值将会是 xyz bar ,而不是 foo bar 。

2“:=”
“:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
x := foo
y := $(x) bar
x := xyz
在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。

Makefile中的.PHONY

.PHONY:romfs   # .PHONY修饰romfs只有规则,没有依赖
romfs
  • 1
  • 2
all:main1 main2 clean
main1: main1.c
    @gcc main1.c -o main1
main2: main2.o
    @gcc main2.o -o main2
main2.o: main2.c
    @gcc -c main2.c 
clean:
    @rm -f main2.o
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

但是当我们make之后main2.o仍然存在,怎么回事呢makefile中的all和.PHONY的作用
原来这里的目标clean没有任何依赖,make执行时认为这已经到“根上”了(就是认为磁盘上有clean,就像main2.c),将其忽略(尽管它有规则)。
关键字.PHONY可以解决这问题,告诉make该目标是“假的”(磁盘上其实没有clean),这时make为生成这个目标就会将其规则执行一次。.PHONY修饰的目标就是只有规则没有依赖。
加上一句.PHONY:clean即可:

all:main1 main2 clean
main1: main1.c
    @gcc main1.c -o main1
main2: main2.o
    @gcc main2.o -o main2
main2.o: main2.c
    @gcc -c main2.c 
.PHONY:clean
clean:
    @rm -f main2.o
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Makefile中的@

makefile中@是不打印命令本身的意思 ,以下Makefile执行make clean时终端不会打印rm -f main2.o的信息。

clean:
    @rm -f main2.o
  • 1
  • 2

递归make

递归调用的方式
make可以递归调用每个子目录中的Makefile。我们可以用如下方式编译add中的文件:

add:
    cd add && $(MAKE)
  • 1
  • 2

等价于:

add:
    $(MAKE) -C add
  • 1
  • 2

上面两个例子都是先进入子目录下add中,然后执行make命令。

总控Makefile
调用“$(MAKE) -C”的Makefile叫做总控Makefile。如果总控Makefile中的一些变量需要传递给下层的Makefile,可以使用export命令,如:

export OBJSDIR=./objs
  • 1

Makefile中的函数

获取匹配模式的文件名wildcard
这个函数功能是查找当前目录下所有符合模式PATTERN的文件名,其返回值是以空格分割的、当前目录下的所有符合模式PATTERN的文件名列表。原型如下:

$(wildcard PATTERN)
  • 1

例如,如下模式返回当前目录下所有扩展名为.c的文件列表

$(wildcard *.c)
  • 1

模式替换函数patsubst
这个函数的功能是查找字符串text中按照空格分开的单词,将符合模式pattern的字符串替换成replacement。pattern中的模式可以使用通配符,%代表0到n个字符,当pattern和replacement中都有%时,符合条件的字符将被replacement中的替换。函数的返回值是替换后的新字符串。原型如下:

$(patsubst pattern,replacement,text)
  • 1

返回值:例如需要将.c文件替换成.o文件可以使用如下模式

$(patsubst %.c,%.o,$(wildcard *.c))
  • 1

输出的字符串将当前扩展名为.c的文件替换成扩展名为.o的文件列表

循环函数foreach
函数原型:

$(foreach VAR,LIST,TEXT)
  • 1

foreach将LIST字符串中的一个人空格分隔符的单词,先传给临时变量VAR,然后执行TEXT表达式,TEXT表达式处理结束后输出。其返回值是空格分割表达式TEXT的计算结果。
例如,对于存在add和sub的两个目录,设置DIRS为“add sub ./”包含目录add、sub和当前目录。表达式$(wildcard$(dir)/*.c),可以去除目录add和sub及当前目录中的所有扩展名为.c的文件。

DIRS = sub add ./

#查找所有目录下的扩展名为.c的文件,复制给变量FILES
FILES = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c)) 
  • 1
  • 2
  • 3
  • 4

其他

Makefile中的目标命令前的@、+、-号

【make中命令行前面加上减号】

就是,忽略当前此行命令执行时候所遇到的错误。

而如果不忽略,make在执行命令的时候,如果遇到error,会退出执行的,加上减号的目的,是即便此行命令执行中出错,比如删除一个不存在的文件等,那么也不要管,继续执行make。

【make中命令行前面加上at符号@】

就是,在make执行时候,输出的信息中,不要显示此行命令。

而正常情况下,make执行过程中,都是会显示其所执行的任何的命令的。如果你不想要显示某行的命令,那么就在其前面加上@符号即可。

【make中命令行前面加上加号+】

+号修饰符,要求make执行命令,即使使用了-n选项。

make –help
帮助中-n选项的含义
-n, –just-print, –dry-run, –recon
Don’t actually run any commands; just print them.

使用加号修饰符让命令始终执行。

简单的示例Makefile
all:
@echo aaaa
@+echo bbbb

使用make执行的结果为

$ make
aaaa
bbbb

使用make -n执行的结果为

echo aaaa
echo bbbb
bbbb

Makefile依赖项中的FORCE

在内核的 Makefile 中会在多处地方看到 FORCE ,比如:

# vmlinux image - including updated kernel symbols
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
  • 1
  • 2

实际上它是一个伪目标:

PHONY +=FORCE
FORCE:

# Declare the contents of the .PHONY variable as phony.  We keep that
# information in a variable so we can use it in if_changed and friends.

.PHONY: $(PHONY)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

从上面看到,FORCE 既没有依赖的规则,其底下也没有可执行的命令。

如果一个规则没有命令或者依赖,而且它的目标不是一个存在的文件名,在执行此规则时,目标总会被认为是最新的。也就是说,这个规则一旦被执行,make 就认为它所表示的目标已经被更新过。当将这样的目标(FORCE)作为一个规则的依赖时(如上的 vmlinux: ),由于依赖总被认为是被更新过的,所以作为依赖所在的规则定义的命令总会被执行。
比如上面的 vmlinux: 在每次 make 时,它下面的这些命令总会被执行:

ifdef CONFIG_HEADERS_CHECK
        $(Q)$(MAKE)-f $(srctree)/Makefile headers_check
endif
ifdef CONFIG_SAMPLES
        $(Q)$(MAKE) $(build)=samples
endif
ifdef CONFIG_BUILD_DOCSRC
        $(Q)$(MAKE) $(build)=Documentation
endif
        $(call vmlinux-modpost)
        $(call if_changed_rule,vmlinux__)
        $(Q)rm -f .old_version
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

用一个直观的例子可以清楚看到这一点,比如有 1 Makefile 文件:

helloworld:file1.o file2.o
gcc file1.o file2.o -o helloworld

file1.o:file1.c file2.h
gcc -c file1.c -o file1.o

file2.o:file2.c file2.h
gcc -c file2.c -o file2.o

clean:  
rm -rf *.o helloworld

PHONY   +=FORCE
FORCE:

.PHONY: $(PHONY)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在执行 make 后,观察文件的生成时间:

[beyes@SLinux Makefile]$ ll
total 32
-rw-rw-r--. 1 beyes beyes  129 Apr 16 19:00 file1.c
-rw-rw-r--. 1 beyes beyes  924 Apr 16 20:20 file1.o
-rw-rw-r--. 1 beyes beyes  108 Apr 16 19:01 file2.c
-rw-rw-r--. 1 beyes beyes  139 Apr 16 18:49 file2.h
-rw-rw-r--. 1 beyes beyes  880 Apr 16 20:20 file2.o
-rwxrwxr-x. 1 beyes beyes 4786 Apr 16 20:20 helloworld
-rw-rw-r--. 1 beyes beyes  246 Apr 16 20:20 Makefile
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

helloworld 文件的生成时间是 20:20
如果将上面的 Makefile 文件的 helloworld:file1.o file2.o 这一句后面加个 FORCE,那么再过几分钟后再 make 时,再观察一下 helloworld 的生成时间,可以看到是重新生成的了,当然在 make 执行时命令的输出也能知道该命令被再次执行:

[beyes@SLinux Makefile]$ ll
total 32
-rw-rw-r--. 1 beyes beyes  129 Apr 16 19:00 file1.c
-rw-rw-r--. 1 beyes beyes  924 Apr 16 20:20 file1.o
-rw-rw-r--. 1 beyes beyes  108 Apr 16 19:01 file2.c
-rw-rw-r--. 1 beyes beyes  139 Apr 16 18:49 file2.h
-rw-rw-r--. 1 beyes beyes  880 Apr 16 20:20 file2.o
-rwxrwxr-x. 1 beyes beyes 4786 Apr 16 20:26 helloworld
-rw-rw-r--. 1 beyes beyes  246 Apr 16 20:20 Makefile
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其他资料:
Makefile 使用总结:http://www.cnblogs.com/wang_yb/p/3990952.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/641020
推荐阅读
相关标签
  

闽ICP备14008679号