MakeFile构建工程

MAKEFILE 简介

在软件开发中,Make是一个构建自动化工具,它通过读取称为Makefiles的文件来自动从源代码构建 可执行程序和库,该文件指定了如何派生目标程序。尽管集成开发环境和特定于语言的编译器功能也可以用于管理构建过程,但Make仍被广泛使用,尤其是在Unix和类似Unix的操作系统中。————维基百科
make就是一个构建自动化编译的一个工具,构建在执行时的类似脚本的文件就是makefile文件。市面上有很多make工具,cmake,nmake,gmake等。

学习makefile的必要性

对于构建单个插件或者可执行文件,一般我们搭建一个工程会选择使用IDE(例如VS,Eclipese)协助我们生成makefile,这样也方便我们进行管理。这么说我们学习makefile就没有必要了吗,其实不然,学习makefile可以进行多工程的集体管理自动化生成,尤其是巨型工程,构建依赖关系,根据依赖来选择部分编译,节省编译时间,而不必全部重新编译。当然我也见过单个工程使用IDE搭建生成makefile,然后使用shell脚本依次调用每个makefile,如果不使用一些其他辅助的版本管理控制编译,那么每次都会进行全部重新编译,费时费力。

make 常用知识点

主要参考《跟我一起makefile》 链接 https://seisman.github.io/how-to-write-makefile/
当然你得了解gcc的编译相关知识,这是使用make的基础。

基本语句规则

以下是一个makefile文件的模式实例的部分,当然一般还有其他变量定义等操作:

targets : prerequisites
    command
    ...
targets1 : prerequisites1
    command1
    ...
targets2 : prerequisites2
    command2
    ...
targets
可以是一个object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。make命令不指定参数,一个makefile以从上往下第一个目标文件为最终执行目标,即targets。
prerequisites
生成该target所依赖的文件和目录或targets,例如prerequisites 的内容可以包含XX目录的XX.cpp文件XX.h文件或者targets1,targets2,是一个树状的结构,一层层传递到真实文件。
command
该target要执行的命令(任意的shell命令),以 Tab键起始,可以不断换行执行直至最后没有 Tab键起始。

这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则(需要执行的命令)定义在command中。说白一点就是说:prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。
这就是makefile的核心规则。
光使用这一条即可写出几乎所有的makefile,其他的(函数,模式规则等)基本都是一些辅助手段,进行模式的匹配减少编写makefile的文字量或者编译逻辑的变通。

常用模式规则符号

%符号-模式匹配符号

%.o : %.cpp
    command
    ...

利用%来类似通配符*来指代任意字符,上式即所有被依赖的.o文件都将依赖同名.cpp。例如 test.o -> test.cpp,test1.o -> test1.cpp,test2.o -> test2.cpp 这三个依赖只需要这一行模式规则即可表达。%后的后缀可以根据需要的匹配模式进行修改。

$@,$<符号-自动化变量

这两个符号通常成对使,用举个例子比较直观

CXX=g++
%.o : %.cpp
	$(CXX) -I./inc -c $< -o $@

接着上面的%使用模式,每个*.o文件都需要对应的*.cpp文件生成,那么要是有100个cpp文件,手写哪受得了,于是使用自动化变量来完成该项操作。
$<变量指代的是目标文件列表(%.o)的一个目标,$@变量指代的是依赖文件列表(%.cpp)的对应目标,即$<为a.o那么$@为a.cpp;
例如:%.o : %.cpp 展开为test.o -> test.cpp,test1.o -> test1.cpp,test2.o -> test2.cpp的依赖那么,上文展开后的样子如下:

test.o : test.cpp
	g++ -I./inc -c test.o -o test.cpp
test1.o : test1.cpp
	g++ -I./inc -c test1.o -o test1.cpp
test2.o : test2.cpp
	g++ -I./inc -c test2.o -o test2.cpp

$(abc:.c=.o)替换后缀

all_source_files = a.c b.cc d.c e.cxx 
source_obj1 := $(all_source_files:.cpp=.o)
source_obj2 := $(source_obj1:.c=.o)
source_obj3 := $(source_obj2:.s=.o)
source_obj4 := $(source_obj3:.S=.o)
source_obj5 := $(source_obj4:.cc=.o)
source_objs := $(source_obj5:.cxx=.o)

例如上文将all_source_files中所指代的源文件全部替换为.o结尾,以便于进行依赖编译。

makefile常用的函数

这里只罗列函数,具体的可以完善查或者文档里查询,不在赘述。

include
用于包引用其他makefile
error
打印错误并退出
ifeq else endif
判断语句
+= := ?=
各种赋值
addprefix addsuffix
前后缀添加
notdir dir
提取(非)文件夹
shell
执行shell命令
firstword
第一个词
filter filter-out
(反)过滤
basename
去后缀
subst patsubst
替换/模式替换
call
类似格式化字符串
Makefile 构建工程时,错误代码 230 并非标准的 `make` 错误代码,`make` 本身通常返回 0(成功)、1(失败)、2(严重错误)等。错误代码 230 可能是在 `make` 执行过程中,某个被调用的命令(如 `gcc`、`rm` 等)返回的。以下是一些可能的原因及解决办法: ### 命令执行失败 在 Makefile 中,可能调用了某个外部命令,该命令执行失败返回了 230。例如,在 Makefile 里调用了自定义脚本,脚本内部执行出错返回 230。 ```makefile # 假设这里调用了一个自定义脚本,脚本执行失败返回 230 target: ./custom_script.sh ``` 解决办法是检查调用的命令或脚本,查看其具体的错误信息。可以在命令前加上 `set -x` 来开启调试模式,输出详细的执行信息。 ```makefile target: set -x; ./custom_script.sh ``` ### 文件或权限问题 如果 Makefile 尝试访问或操作某个文件,但文件不存在或者没有足够的权限,也可能导致命令执行失败返回错误代码。例如,在删除文件时没有权限: ```makefile clean: rm *.out ``` 解决办法是检查文件是否存在,以及当前用户是否有足够的权限。可以使用 `ls -l` 查看文件权限,使用 `chmod` 修改权限。 ```sh chmod +x custom_script.sh ``` ### 环境变量问题 Makefile 中可能依赖某些环境变量,如果这些环境变量没有正确设置,也可能导致命令执行失败。例如: ```makefile COMPILER_FLAGS = $(MY_FLAGS) target: gcc $(COMPILER_FLAGS) source.c -o target ``` 解决办法是检查环境变量是否正确设置,可以使用 `echo` 命令输出环境变量的值进行确认。 ```sh echo $MY_FLAGS ``` ### 脚本逻辑问题 如果错误代码 230 是由自定义脚本返回的,需要检查脚本的逻辑。可能是脚本内部的条件判断、循环等逻辑出现错误。 ```sh #!/bin/bash # 假设这里的逻辑有误,导致返回 230 if [ $1 -eq 1 ]; then exit 230 fi ``` 解决办法是仔细检查脚本的逻辑,添加调试信息输出,逐步排查问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值