把Linux软件开发里的核心环节说成编译的时候,那驾驭这个环节的蓝图就是Makefile ,它不是简单几条命令凑一块儿,是一种将源代码稳妥转变为可执行程序的工程办法,能把源代码高效地转变成可执行程序 ,弄懂且写出Makefile ,可让你摆脱手动编译的繁杂linux重启命令,践行自动化构建,这对管理不管啥规模的项目都相当关键 。
如何编写一个简单的Makefile
完成一个具备基本特征表现的Makefile,其重点核心之处在于能够充分领会目标、依赖以及命令这三者相互之间所存在的关系比如若要针对main.c以及utils.c这两个属于源文件范畴的文件去生成一个可执行程序名为app的话那么你能够去定义一个目标为app这个目标它所依赖的文件是main.o以及utils.o然而生成这个可执行程序的命令是gcc -o app main.o utils.o。紧接着,你得针对每个.o文件,去界定怎样从相对应的.c文件予以生成,就如同那样:main.o: main.c,而相关命令则是这样表示:命其为gcc -c main.c。

不过是仅仅将规则陈列出来,这并不是足够的呀,一个具备实用性的、较为简单的Makefile,通常情况下是会涵盖clean目标的,其目的在于删去除编译进程当中所产生的中间文件,就好比是rm -f <b>.o app这般。如此一来,一旦你有重新构建的需求之时,仅仅将要执行make clean && make,便能够获取到一个干干净净的编译环境了。变量同样也是简单Makefile的得力助手呢,借助像CC=gcc以及CFLAGS=-Wall这样的变量,能够使得你的脚本变得更清晰,而且更加易于进行修改哟。
Makefile中的变量如何使用
提升Makefile可维护性以及灵活性的关键工具是变量。像CC(即C编译器)、CFLAGS(也就是C编译选项)这类常见的预定义变量,在规则里能够直接对它们加以引用,比如说$(CC) $(CFLAGS) -c $ 。< -o $@。自定义变量同样重要,比如SRCS = main.c utils.c,你可以用OBJS = $(SRCS:.c=.o)轻松得到对应的目标文件列表,这大大简化了后续规则的编写。

除了基本的赋值,变量还有不同的赋值运算符。递归赋值(=)会在变量被展开时才求值,可能包含后续定义的变量;直接赋值(:=)则立即展开右侧表达式。条件赋值(?=)仅在变量未定义时赋值。在命令部分,你还需注意区分Makefile变量与Shell变量,前者使用$(VAR),后者则需用$$VAR来转义美元符号。
<b>为什么make命令找不到我的Makefile</b>
当你碰到“make: </b><b></b> No targets specified and no makefile found. Stop.”这类错误之时,首先得去查验当下目录里是不是存在名为Makefile抑或是makefile的文件,Linux环境下的make命令依照默认设置会按照这般顺序去寻觅这俩文件,其中一种颇为常见的疏漏情形是文件命名有所差错,比如说写成了MakeFile或者makefiles.txt,而以上这些状况均会致使查找遭遇失败情形发生。

假如文件命名无误,那么或许是文件权限和隐藏字符方面的问题;采用ls -la命令去查看目录,证实文件确实存在且你具备读取权限;有时从Windows系统拷贝文件会萌生出回车符问题,能够尝试运用dos2unix命令来转换文件格式;另外,你还能够使用make -f 文件名去显式指定一个非标准名称的Makefile文件,这属于一种快速的验证以及解决办法。
<b>如何用Makefile管理多个目录的源码</b>
针对源码分散于不同子目录中的项目,有个成效显著的办法,就是于每个子目录里放置一个子Makefile,其作用是负责编译该目录下的代码。在项目根目录的顶层Makefile当中,你能够运用make -C subdir这般的命令,用以递归调用子目录的构建进程。该方法职责明晰,每个目录自行管理自身的编译细节 。
还有一种流行且更具自动化特点的方法,是运用变量去统一管理路径 。 比如说 ,定义 SRC_DIR = src 以及 OBJ_DIR = obj 。 而后在规则里借助模式匹配以及路径替换函数 ,像 $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c 。 如此一来 ,所有的目标文件都会集中输出至 obj 目录下 。 避免了对源码目录的污染 。还使得项目的结构变得更加清晰 ,并且易于清理 。

<b>Makefile的模式规则是什么</b>
Makefile里用于定义通用编译规则的有力工具是模式规则,它借助通配符%去匹配一系列文件。定义如何从.c文件生成.o文件是最常见的例子linux系统编程,即%.o: %.c。当make发觉需要某个.o文件却没有具体规则时,就会试着应用这条模式规则,%的部分会被自动替换成对应的文件名。
于模式规则的命令部分之中linux运行makefile,你能够运用自动化变量去指代那些匹配到的部分,其中,$@所代表的是目标文件名,$。<代表第一个依赖文件名,$^代表所有依赖文件列表。例如,规则%.o: %.c对应的命令可以写为$(CC) -c $< -o $@。这使得规则非常简洁和通用,无需为每个源文件重复编写雷同的编译命令,极大地提升了Makefile的编写效率。
Makefile执行出错如何调试

一旦make运行出现失败状况 ,千万别慌张 。首先呢 ,要认真去阅读make输出给出的错误信息 ,其一般会直接指明是某一条命令执行遭遇失败 ,并且还会附带Shell返回的错误代码 。此时你能够试着在单独的终端里去运行那条出现错误的编译命令 ,通常情况下能获取到更为详细的错误提示 ,从而能够准确找出是语法存在错误 ,还是缺少头文件 ,亦或是库链接出现了问题 。
把善于运用make的那些内置的调试选项当成是高效进行排错的最为关键的因素,make -n或者是make --just-print会仅仅是显示那些即将要去执行的命令,却不会实际去运行它们,这样做能够协助你去检查命令流是不是正确的linux运行makefile,make -d会输出极为详细的调试方面的信息,其中涵盖了依赖关系检查、文件重建决策等一系列的全过程,在Makefile里临时性地添加echo命令用来打印关键变量的值,这同样是能快速了解当前构建状态的较为实用的一种技巧。
当你着手编写或者维护一个具备复杂性的项目的Makefile之际,所碰到的最为让人头疼不已的依赖关系诸多麻烦状况里,究竟是那种情形呢?是循环依赖这种状况,还是自动生成头文件相关的依赖追踪这种情况呢?亦或是别的什么样子的情况呢?欢迎于评论区之中分享你自身的相关经历呀以及对应的解决方案呢,如果觉得这篇文章是有帮助作用的,也请进行点赞操作与分享给更多数量的小伙伴呀。
