网站首页 > 博客文章 正文
私信我或关注微信号:狮范课,回复:学习,获取免费学习资源包。
make通常被视为一种软件构建工具,主要经由读取一种名为makefile 或 Makefile的文件来实现软件的自动化建构。它会通过一种被称之为target概念来检查相关文件之间的依赖关系,这种依赖关系的检查系统非常简单,主要通过对比文件的修改时间来实现。在大多数情况下,我们主要用它来编译源代码,生成结果代码,然后把结果代码连接起来生成可执行文件或者库文件。
特别是在类Unix系统下的软件编译,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下的GNU make。
Makefile基本格式如下
1 2 3 4 5 6 7 target ... : prerequisites ... command ...... ...... ###target - 目标文件, 可以是 Object File, 也可以是可执行文件 ###prerequisites - 生成 target 所需要的文件或者目标 ###command - make需要执行的命令 (任意的shell命令), 必须以[tab]开头
Makefile基本规则
1 2 3 4 5 显示规则 :: 说明如何生成一个或多个目标文件(包括 生成的文件, 文件的依赖文件, 生成的命令) 隐晦规则 :: make的自动推导功能所执行的规则 变量定义 :: Makefile中定义的变量 文件指示 :: Makefile中引用其他Makefile; 指定Makefile中有效部分; 定义一个多行命令 注释 :: Makefile只有行注释 "#", 如果要使用或者输出"#"字符, 需要进行转义, "\#"
make基本的工作方式
1 2 3 4 5 6 7 1.读入主Makefile (主Makefile中可以引用其他Makefile) 2.读入被include的其他Makefile 3.初始化文件中的变量 4.推导隐晦规则, 并分析所有规则 5.为所有的目标文件创建依赖关系链 6.根据依赖关系, 决定哪些目标要重新生成 7.执行生成命令
示例
[free@hurd]$ vim foo1.c #include <stdio.h> void foo1() { printf("This is foo1!\n"); } [free@hurd]$ vim foo2.c #include <stdio.h> void foo2() { printf("This is foo2!\n"); } [free@hurd]$ vim main.c #include <stdio.h> int main(void) { foo1(); foo2(); printf("This is main!\n"); return 0; } [free@hurd]$ vim Makefile main: foo1.c foo2.c main.c gcc foo1.c foo2.c main.c -o main ###这是一个最简单的Makefile ###生成目标main依赖foo1.c foo2.c main.c ###执行命令gcc foo1.c foo2.c main.c -o main;完成目标 [free@hurd]$ make gcc foo1.c foo2.c main.c -o main [free@hurd]$ ls foo1.c foo2.c main main.c Makefile [free@hurd]$ ./main This is foo1! This is foo2! This is main! ###成功执行,现在改进Makefile [free@hurd]$ vim Makefile main: main.o foo1.o foo2.o gcc main.o foo1.o foo2.o -o main main.o: main.c gcc -c main.c foo1.o: foo1.c gcc -c foo1.c foo2.o: foo2.c gcc -c foo2.c ###改写后各种依赖更清楚 ###只要有一项更改,重新make只重新编译更新的部分,其他不变 [free@hurd]$ make gcc -c main.c gcc -c foo1.c gcc -c foo2.c gcc main.o foo1.o foo2.o -o main [free@hurd]$ ./main This is foo1! This is foo2! This is main! ###成功执行,继续改进Makefile [free@hurd]$ vim Makefile target= main src= $(shell find . -name "*.c") obj= $(src:%.c=%.o) $(target): $(obj) gcc $^ -o $@ %.o: %.c gcc -c lt; -o $@ ###这里引入了变量,其实和C语言中的宏类似 ###$(shell ****)使用了shell命令,将搜索到的结果传给src ###$(src:%.c=%.o)是进行字符替换,将所有的*.c字符串替换成*.o字符串,传给obj ###$^:所有依赖目标的集合 ###$@:目标集合 ###lt;:第一个依赖目标. 如果依赖目标是多个, 逐个表示依赖目标 ###改进后,更加精炼清晰,而且方便以后拓展构建 [free@hurd]$ make gcc -c foo2.c -o foo2.o gcc -c main.c -o main.o gcc -c foo1.c -o foo1.o gcc foo2.o main.o foo1.o -o main [free@hurd]$ ./main This is foo1! This is foo2! This is main! ###成功执行,进一步改进Makefile [free@hurd]$ vim Makefile CC = gcc CFLAGS = -Wall CXXFLAGS = CPPFLAGS = LDFLAGS = target = main src = $(shell find . -name "*.c") obj = $(src:%.c=%.o) $(target): $(obj) $(CC) $^ $(CFLAGS) -o $@ %.o : %.c $(CC) -c lt; $(CFLAGS) $(CPPFALGS) -o $@ .PHONY:clean clean: -rm -rf $(obj) $(target) install: mkdir target mv main target test: @echo $(src) @echo $(obj) ###改进后基本看不到源文件的影子,慢慢走向通用化更易于拓展 ###此处还添加了伪目标 ###.PHONY意思表示clean是一个"伪目标";而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。不成文的规矩是——"clean从来都是放在文件的最后" ###"伪目标"并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。只有通过显示地指明这个“目标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义了 ###为了避免和文件重名的这种情况,可以使用一个特殊的标记".PHONY"来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是"伪目标"
Makefile 命令前缀
1 2 3 4 不用前缀 :: 输出执行的命令以及命令执行的结果, 出错的话停止执行 前缀 @ :: 只输出命令执行的结果, 出错的话停止执行 前缀 - :: 命令执行有错的话, 忽略错误, 继续执行 ###例如上面的-rm、@echo
make 退出码
1 2 3 0 :: 表示成功执行 1 :: 表示make命令出现了错误 2 :: 使用了 "-q" 选项, 并且make使得一些目标不需要更新
make 常用参数
参数含义–debug[=]输出make的调试信息, options 可以是 a, b, v-j –jobs同时运行的命令的个数, 也就是多线程执行 Makefile,比如常用的make -j8-r –no-builtin-rules禁止使用任何隐含规则-R –no-builtin-variabes禁止使用任何作用于变量上的隐含规则-B –always-make假设所有目标都有更新, 即强制重编译
命令变量 和 命令参数变量
变量名含义RMrm -fARarCCccCXXg++ARFLAGSAR命令的参数CFLAGSC语言编译器的参数CXXFLAGSC++语言编译器的参数CPPFLAGS预处理阶段的参数LDFLAGS传递给连接器的参数LIBS链接库的参数
1 2 3 4 5 6 7 8 9 10 11 [free@hurd]$ vim Makefile all: @echo $(RM) @echo $(AR) @echo $(CC) @echo $(CXX) [free@hurd]$ make rm -f ar cc g++
自动变量
以上只是简单介绍了 Makefile,足以应付一些小项目,但当遇到一些工程级的大项目手写 Makefile 变得十分困难繁琐,而且不难以跨平台,我们需要其他的工具来生成 Makefile。
CMake是一个比make更高级的编译配置工具,它可以根据不同平台、不同的编译器,生成相应的Makefile或者vcproj项目。通过编写CMakeLists.txt,可以控制生成的Makefile,从而控制编译过程。CMake自动生成的Makefile不仅可以通过make命令构建项目生成目标文件,还支持安装(make install)、测试安装的程序是否能正确执行(make test,或者ctest)、生成当前平台的安装包(make package)、生成源码包(make package_source)、产生Dashboard显示数据并上传等高级功能,只要在CMakeLists.txt中简单配置,就可以完成很多复杂的功能,包括写测试用例。如果有嵌套目录,子目录下可以有自己的CMakeLists.txt。
在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:
- 编写 CMake 配置文件 CMakeLists.txt
- 执行命令 cmake PATH 或者 ccmake PATH 生成 Makefile 。其中, PATH 是 CMakeLists.txt 所在的目录
- 使用 make 命令进行编译。
示例
###这是一个简单的C快速排序程序 [free@hurd]$ vim test.c #include <stdio.h> #include <stdlib.h> #include <time.h> void swap(int *x, int *y) { int tmp; tmp = *x; *x = *y; *y = tmp; return ; } void display_arr(int *arr, int len) { int i; for(i = 0; i < len; i++) { printf("%d\t", arr[i]); if((i + 1) % 10 == 0) printf("\n"); } printf("\n"); return ; } void genereate(int *arr, int len, int maxnum) { int i; srand(time(NULL)); for(i = 0; i < len; i++) { arr[i] = rand()%maxnum; } return ; } void sort(int *arr, int left, int right) { if(left < right) { int i, j; i = left + 1; j = right; while(i < j) { if(arr[i] > arr[left]) { swap(&arr[i], &arr[j]); j--; } else i++; } if(arr[i] >= arr[left]) i--; swap(&arr[left], &arr[i]); sort(arr, left, i); sort(arr, j, right); } } int main(int argc, char *argv[]) { if(argc != 3) { fprintf(stderr,"\e[1;31mUsage: ./a.out len maxnum\e[0m"); exit(1); } int len, maxnum; len = atoi(argv[1]); maxnum = atoi(argv[2]); if(len <= 0) { fprintf(stderr,"\e[1;31mThe array of length error\e[0m\n"); exit(1); } if(maxnum <= 0) { fprintf(stderr, "\e[1;31mThe maxnum is error\e[0m\n"); exit(1); } int arr[len]; printf("\e[1;32m排序前的随机数组: \e[0m\n"); genereate(arr, len, maxnum); display_arr(arr, len); printf("\e[1;32m排序后的有序数组: \e[0m\n"); sort(arr, 0, len - 1); display_arr(arr, len); exit(0); } ###编写CMakeLists.txt [free@hurd]$ vim CMakeLists.txt # CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 项目信息 project (cmake_test) # 指定生成目标 add_executable(test test.c) ###CMakeLists.txt 的语法比较简单,由命令、注释和空格组成,其中命令是不区分大小写的。符号 # 后面的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔 ###cmake_minimum_required:指定运行此配置文件所需的 CMake 的最低版本; ###project:参数值是 cmake_test,该命令表示项目的名称是 cmake_test ###add_executable:将名为 test.c 的源文件编译成一个名称为 test 的可执行文件 [free@hurd]$ cmake . -- The C compiler identification is GNU 4.8.4 -- The CXX compiler identification is GNU 4.8.4 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Configuring done -- Generating done -- Build files have been written to: /home/free/cmake ###得到生成的Makefile,并执行make [free@hurd]$ make Scanning dependencies of target test [100%] Building C object CMakeFiles/test.dir/test.c.o Linking C executable test [100%] Built target test [free@hurd]$ ./test 20 255 排序前的随机数组: 71 130 200 244 31 149 206 241 4 34 127 11 251 167 233 68 250 231 247 14 排序后的有序数组: 4 11 14 31 34 68 71 127 130 149 167 200 206 231 233 241 244 247 250 251 ###下面对test.c进行拆分,将单独的函数抽取出来 [free@hurd]$ ls CMakeCache.txt CMakeFiles cmake_install.cmake CMakeLists.txt display_arr.c genereate.c Makefile sort.c swap.c test test.c [free@hurd]$ vim CMakeLists.txt # CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 项目信息 project (cmake_test) # 指定生成目标 add_executable(test test.c display_arr.c genereate.c sort.c swap.c) ###唯一的改动只是在 add_executable 命令中增加了其他的 .c源文件 ###如果源文件很多,把所有源文件的名字都加进去将是一件烦人的工作;更省事的方法是使用 aux_source_directory 命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名 ###可以做如下修改 [free@hurd]$ vim CMakeLists.txt # CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 项目信息 project (cmake_test) # 查找当前目录下的所有源文件 # 并将名称保存到 DIR_SRCS 变量 aux_source_directory(. DIR_SRCS) # 指定生成目标 add_executable(test ${DIR_SRCS}) ###CMake 会将当前目录所有源文件的文件名赋值给变量 DIR_SRCS ,再指示变量 DIR_SRCS 中的源文件需要编译成一个名称为 test 的可执行文件 [free@hurd]$ cmake . -- Configuring done -- Generating done -- Build files have been written to: /home/free/cmake [free@hurd]$ make Scanning dependencies of target test [ 20%] Building C object CMakeFiles/test.dir/display_arr.c.o [ 40%] Building C object CMakeFiles/test.dir/test.c.o [ 60%] Building C object CMakeFiles/test.dir/swap.c.o [ 80%] Building C object CMakeFiles/test.dir/genereate.c.o [100%] Building C object CMakeFiles/test.dir/sort.c.o Linking C executable test [100%] Built target test
来源网络,侵权联系删除
私信我或关注微信号:狮范课,回复:学习,获取免费学习资源包。
猜你喜欢
- 2024-10-12 FLAC 1.4相隔近十年发布新版 包含AArch64优化及更快的x86_64 FMA
- 2024-10-12 Qt6重磅更新:新版本的Qt 6 将通过包管理器提供附加库
- 2024-10-12 Centos7.4 如何使用cmake编译安装mysql
- 2024-10-12 CMake中find_path / find_library对于cache变量的选择
- 2024-10-12 热更新再牛,也少不了Android 增量更新
- 2024-10-12 C/C++开发工具CLion V2022.1正式发布——增强了远程开发
- 2024-10-12 CentOS8下YUM升级gcc(centos8 gcc版本)
- 2024-10-12 基于MSYS2的MINGW64 GCC和CMake在Win下VSCode里搭建SDL2开发环境
- 2024-10-12 cmake 的兄弟:xmake应用(cmake mdk)
- 2024-10-12 Android NDK开发扫盲及最新CMake的编译使用
你 发表评论:
欢迎- 最近发表
-
- 给3D Slicer添加Python第三方插件库
- Python自动化——pytest常用插件详解
- Pycharm下安装MicroPython Tools插件(ESP32开发板)
- IntelliJ IDEA 2025.1.3 发布(idea 2020)
- IDEA+Continue插件+DeepSeek:开发者效率飙升的「三体组合」!
- Cursor:提升Python开发效率的必备IDE及插件安装指南
- 日本旅行时想借厕所、买香烟怎么办?便利商店里能解决大问题!
- 11天!日本史上最长黄金周来了!旅游万金句总结!
- 北川景子&DAIGO缘定1.11 召开记者会宣布结婚
- PIKO‘PPAP’ 洗脑歌登上美国告示牌
- 标签列表
-
- ifneq (61)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)