如果读者经常泡在 GitHub 上浏览他人的 C 语言专案,应该很常会看到名为 Makefile
的档案。
本文会介绍 Make 这套建构工具以及撰写 Makefile 档案的技巧。
Make 是一套自动化建构软件,它会读取名为 Makefile
的档案,并根据使用者输入的命令找到 target
後生成命令转交给 shell 去执行,以生成开发者需要的可执行档案。
不只如此, Make 还具有依赖关系的检查系统,可以帮助开发者高效的进行测试与编译工作。
该软件最早由贝尔实验室的 Stuart Feldman 开发,随後也被各种 UNIX Like 的分支进行无数次的改良 (包含改良演算法与功能扩充),衍生出了多种版本:
要撰写 Makefile ,我们需要先建立对 Target
、 Dependencies
与 Commands
的认知,让我们先看看基本的 Makefile 档案:
output: main.o
gcc -o output main.o
main.o: main.c def.h
gcc -c main.c
在这个 Makefile 中:
output
以及 main.o
。output
为例: 它的依赖为 main.o
。output
这个 Target 被执行,Make 会去检查 main.o 是否存在或是否被修改,如果有的话便会先执行 main.o
target 底下的命令产生 main.o
,再执行 output
底下的命令产生 output
档案。make output
或是:
make
如果不指定 target 的话,Make 会执行 Makefile 当中的第一个 Target 。
Make 也提供了巨集功能,可以帮助开发者写出更精简的 Makefile 档案。
以刚刚的 Makefile 为例,我们可以使用巨集对它稍作梳理:
OBJ = main.c def.h
output: main.o
gcc -o output main.o
main.o: $(OBJ)
gcc -c main.c
如果有撰写 C 程序的经验,想必都已经熟悉了前置处理器的使用。Make 让我们能够在 Makefile 中使用类似的条件式,以下内容取在 xv6-riscv 的 Makefile:
ifndef TOOLPREFIX
TOOLPREFIX := $(shell if riscv64-unknown-elf-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
then echo 'riscv64-unknown-elf-'; \
elif riscv64-linux-gnu-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
then echo 'riscv64-linux-gnu-'; \
elif riscv64-unknown-linux-gnu-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
then echo 'riscv64-unknown-linux-gnu-'; \
else echo "***" 1>&2; \
echo "*** Error: Couldn't find a riscv64 version of GCC/binutils." 1>&2; \
echo "*** To turn off this error, run 'gmake TOOLPREFIX= ...'." 1>&2; \
echo "***" 1>&2; exit 1; fi)
endif
包含上面使用的 ifndef
,Make 还提供了:
给开发者使用,使用这些条件式都必须在结尾处加上 endif
。
除了巨集功能,我们还可以将 Shell script 的条件式应用到 Makefile 中:
forfun:
@if [ "test" = "test" ]; then\
echo "Hello world";\
fi
需要注意的有以下几点:
;
与 \
都是必要的。接着,我们可以尝试使用这个方法简化版本推送的流程:
push:
@if [ "x$(MSG)" = 'x' ]; then\
echo "Commit message is necessary."; fi
@test "x$(MSG)" != 'x'
git commit -a -m "$(MSG)"
git push origin master
@if
帮助我们判断 MSG 是否为空@test
如果 MSG 不为空,继续执行,否则 make 会被暂停。push
target:MSG="init commit" make push
依赖介面而不是特定的 Service 昨天我们介绍了怎麽在 .NET Web API 的专案里实现依...
大家好,今天继续来开发元件,并动手解决实务上我们遇到的设定配置的问题。在昨天的练习里,我们可以使用b...
一、前言 先前有写过两篇关於 Webpack 的文章(文章1、文章2),回顾起自己学习到 Web...
1. panic是什麽? 程序在运行时,发生意料之外的程序异常。例如: 访问,不存在的array。 ...
Day 38 - 在 AWS Lambda 中使用 YOLO 推估 (Inference) 在 Da...