[http://www.ruanyifeng.com/blog/2015/02/make.html](http://www.ruanyifeng.com/blog/2015/02/make.html)<br /> GNU Make是一种流行的、常用的用于构建C语言软件的程序。用于构建Linux内核和其他常用的GNU/Linux程序和软件库。
大多数嵌入式软件开发人员在职业生涯中的某个时候都会使用GNU Make,要么使用它来编译小型库,要么构建整个项目。尽管有很多很多的选项可以替代Make,但是由于它的特性集和广泛的支持,它仍然通常被选择为新软件的构建系统。
什么是GNU Make?
GNU Make是一个可以自动运行shell命令并帮助执行重复任务的程序。它通常用于将文件转换成其他形式,例如`将源代码文件编译成程序或库`。
它通过跟踪先决条件和执行命令层次结构来生成目标来实现这一点。
尽管GNU Make手册很长,但我建议阅读一下,因为它是我找到的最好的参考:www.gnu.org/software/ma…
何时选择Make
Make适用于构建小型C/ c++项目或库,这些项目或库将包含在另一个项目的构建系统中。大多数构建系统都有办法集成基于make的子项目。
对于较大的项目,您会发现更现代的构建系统更易于使用。
在以下情况下,我建议使用非Make的构建系统:
当正在构建的目标(或文件)数量为(或最终将为)数百时。 需要一个“配置”步骤,它设置和保存变量、目标定义和环境配置。 该项目将保持内部或私有,将不需要由终端用户构建。 您会发现调试是一项令人沮丧的工作。 您需要构建的是跨平台的,可以在macOS、Linux和Windows上构建。 在这些情况下,您可能会发现使用CMake、Bazel、Meson或其他现代构建系统是一种更愉快的体验。
调用Make
运行make将从当前目录加载一个名为Makefile的文件,并尝试更新默认目标(稍后会详细介绍目标),Make将依次搜索名为GNUmakefile、makefile和makefile的文件。<br /> 你可以使用-f/——file参数指定一个特定的makefile:<br /> $ make -f foo.mk
makefile
# makefile
FOO = 1
BAR = $(FOO) # 将FOO变量指针赋值给BAR
FOO = 2
# $(info…)函数用于打印表达式,在调试makefile时非常方便!*’
# 未显式、隐式或未自动设置的变量将计算为空字符串
# 输出内容 "BAR=2"
$(info BAR=$(BAR))
FOO = 1
BAR := $(FOO)
FOO = 2
# 输出内容 BAR=1
$(info BAR=$(BAR))
# 设置一个临时的环境变量用于测试
# export TEXT_ENV=ABC
# echo $TEXT_ENV
$(info TEXT_ENV variable = $(TEXT_ENV))
# 如果你使用?=赋值语法,Make只会在变量没有值的情况下赋值
YOLO ?= "hello there!"
# 执行此语句
# make
# 输出内容 YOLO variable = "hello there!"
# 执行此语句
# YOLO="abc" make
# 输出内容 YOLO variable = "abc"
$(info YOLO variable = $(YOLO))
# 注意打印这个错误,Make打印“No targets”错误,因为我们的makefile没有列出目标!
# make: *** No targets. Stop.
TEXT += -efg
# 执行此语句
# TEXT='abc' make
# 输出内容 TEXT variable = abc -efg
$(info TEXT variable = $(TEXT))
# 隐式变量
# 这些都是由Make预先定义的(除非用同名的任何其他变量类型重写)。一些常见的例子:
# $(CC) - the C compiler (gcc)
# $(AR) - archive program (ar)
# $(CFLAGS) - flags for the C compiler
# Full list here:
# 内置变量
# $(CC) 指向当前使用的编译器,$(MAKE) 指向当前使用的Make工具
# https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
$(info CC variable = $(CC)) # 有默认值
$(info AR variable = $(AR)) # 有默认值
$(info CFLAGS variable = $(CFLAGS)) # 可能有默认值
# <target> : <prerequisites>
# [tab] <commands>
# .PHONY 声明不指向文件 如果当前目录中,正好有一个文件叫做test,那么这个命令不会执行。
# 因为Make发现clean文件已经存在,就认为没有必要重新构建了,就不会执行指定的rm命令。
.PHONY: test
test:
# 注意命令这里,命令前面必须使用tab键,而不能是空格
echo $@
@echo $$PORT # 输出环境变量
假定当前目录下有 f1.c 和 f2.c 两个源码文件,需要将它们编译为对应的对象文件。
%.o: %.c
等同于下面的写法。
f1.o: f1.c
f2.o: f2.c