Makefile:构建自动化

我们可以用 make命令行工具替代手动敲入 “编译”、“链接”、“烧写” 这些命令,自动完成整个过程。make工具使用一个名为 Makefile的配置文件,从中读取执行动作的指令。这种自动化方式非常棒,因为这样可以把构建固件的过程、使用了哪些编译标记等也文档化。

在 https://makefiletutorial.com 上有一个非常好的给初学者的 Makefile 教程,强烈建议看一下。下面我将列出一些非常必要的概念以理解我们所使用的 Makefile。对于已经很熟悉 make的朋友,可以跳过这一部分。


(资料图片)

其实 Makefile的格式并不复杂:

action1:command ...     # Comments cango after hash symbolcommand ....    # IMPORTANT: command must be preceded with the TAB characteraction2:command ...     # Don"t forget about TAB. Spaces won"t work!

现在我们可以跟动作名(也被称作目标)一起调用 make来执行相应的动作:

$ make action1

当然,也可以在命令中定义和使用变量,动作也可以是需要创建的文件名:

firmware.elf:COMPILATION COMMAND .....

任何动作都可以有一个依赖列表。例如,firmware.elf依赖源文件 main.c,当 main.c改变时,make build就会重新构建 firmware.elf:

build: firmware.elffirmware.elf: main.cCOMPILATION COMMAND

我们已经准备好为固件编写 Makefile,定义一个 build动作 / 目标:

CFLAGS  ?=  -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion -Wformat-truncation -fno-common -Wconversion -g3 -Os -ffunction-sections -fdata-sections -I. -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 $(EXTRA_CFLAGS)LDFLAGS ?= -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.mapSOURCES = main.cbuild: firmware.elffirmware.elf: $(SOURCES)arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@

在这里我们定义了一些编译标记。?=表示这是默认值,我们可以在命令行中覆盖它们,像这样:

$ make build CFLAGS="-O2 ...."

上面的 Makefile文件中定义了 CFLAGSLDFLAGSSOURCES变量,然后我们告诉 make,当要 build时创建 firmware.elf文件,它依赖 main.c文件,使用 arm-none-eabi-gcc编译器和给定的编译标记生成它。$@特殊变量会被展开成动作 / 目标名,在这个例子中是 firmware.elf

现在调用 make试一下:

$ make buildarm-none-eabi-gcc main.c  -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion -Wformat-truncation -fno-common -Wconversion -g3 -Os -ffunction-sections -fdata-sections -I. -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16  -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=firmware.elf.map -o firmware.elf

如果我们再次运行:

$ make buildmake: Nothing to be done for `build".

make会检查 firmware.elf和依赖项 main.c的修改时间,如果是它们是最新的,则什么都不做。如果我们修改下 main.c,则会重新构建:

$ touch main.c # Simulate changes in main.c$ make build

现在,还剩下 “烧写” 这个动作 / 目标:

firmware.bin: firmware.elfarm-none-eabi-objcopy -O binary $<  $@flash: firmware.binst-flash --reset write $(TARGET).bin 0x8000000

OK,现在从终端中执行命令 make flash就会创建 firmware.bin文件,然后通过 st-link烧入板子。当 main.c改变时,这个命令也会重新构建,因为 firmware.bin依赖 firmware.elffirmware.elf又依赖 main.c。所以我们的开发循环就是这样的两步:

# Develop code in main.c$ make flash

还有一个良好实践就是在 Makefile中添加 clean动作,以删除构建生成的文件:

clean:rm -rffirmware.*
 

推荐内容