Make这个词,英语的意思是"制作"。Make命令直接用了这个意思,就是要做出某个文件。比如,要做出文件a.txt,就可以执行下面的命令。
$ make a.txt
但是,如果你真的输入这条命令,它并不会起作用。因为Make命令本身并不知道,如何做出a.txt,需要有人告诉它,如何调用其他命令完成这个目标。
比如,假设文件 a.txt 依赖于 b.txt 和 c.txt ,是后面两个文件连接(cat命令)的产物。那么,make 需要知道下面的规则。
[root@JD maketest]# vi b.txt bbbbbbb [root@JD maketest]# vi c.txt cccccc [root@JD maketest]# vi rules.txt [root@JD maketest]# make -f rules.txt rules.txt:2: *** missing separator. Stop. [root@JD maketest]# vi rules.txt a.txt: b.txt c.txt cat b.txt c.txt >a.txt [root@JD maketest]# make -f rules.txt cat b.txt c.txt >a.txt [root@JD maketest]# ll total 16 -rw-r--r-- 1 root root 15 Feb 19 11:25 a.txt -rw-r--r-- 1 root root 8 Feb 19 11:19 b.txt -rw-r--r-- 1 root root 7 Feb 19 11:19 c.txt -rw-r--r-- 1 root root 43 Feb 19 11:25 rules.txt [root@JD maketest]# cat a.txt bbbbbbb cccccc
注意
a.txt: b.txt c.txt cat b.txt c.txt >a.txt
cat b.txt c.txt >a.txt前面用TAB键,而不是空格空格空格,否则报错
Makefile文件
Makefile文件由一系列规则(rules)构成。每条规则的形式如下。
<target> : <prerequisites>
[tab] <commands>
上面第一行冒号前面的部分,叫做"目标"(target),冒号后面的部分叫做"前置条件"(prerequisites);第二行必须由一个tab键起首,后面跟着"命令"(commands)。
"目标"是必需的,不可省略;"前置条件"和"命令"都是可选的,但是两者之中必须至少存在一个。
每条规则就明确两件事:构建目标的前置条件是什么,以及如何构建。下面就详细讲解,每条规则的这三个组成部分。
CMake
CMake是这样一个工具工具:它首先允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到“Write once, run everywhere”。显然,CMake 是一个比上述几种 make 更高级的编译配置工具。一些使用 CMake 作为项目架构系统的知名开源项目有 VTK、ITK、KDE、OpenCV、OSG 等。
载解压设置环境变量
CMake常用变量
环境变量名 | 描述 |
---|---|
CMAKE_BINARY_DIR, PROJECT_BINARY_DIR, <projectname> _BINARY_DIR |
如果是 in source 编译,指得就是工程顶层目录,如果是 out-of-source 编译,指的是工程编译发生的目录。PROJECT_BINARY_DIR 跟其他指令稍有区别,现在,你可以理解为他们是一致的。 |
CMAKE_SOURCE_DIR, PROJECT_SOURCE_DIR, <projectname> _SOURCE_DIR |
工程顶层目录。 |
CMAKE_CURRENT_SOURCE_DIR | 当前处理的 CMakeLists.txt 所在的路径,比如上面我们提到的 src 子目录。 |
CMAKE_CURRRENT_BINARY_DIR | 如果是 in-source 编译,它跟 CMAKE_CURRENT_SOURCE_DIR 一致,如果是 out-of-source 编译,他指的是 target 编译目录。 |
EXECUTABLE_OUTPUT_PATH , LIBRARY_OUTPUT_PATH | 最终目标文件存放的路径。 |
PROJECT_NAME | 通过 PROJECT 指令定义的项目名称。 |
静态连接库
简介: 静态连接就是,使用普通的函数库,在程序连接时将库中的代码拷贝到可执行文件中。
存在问题:假设有多个程序同时执行,并且同时调用了同一个库文件,这是内存中就会保留着许多重复的代码副本。造成内存浪费。
出现现象:出现警告对话框:“系统资源不足,请关闭部分Windows应用程序....”
动态链接库
简介:动态链接就是,只有程序在执行时才将库中的代码装入内存,对于同一个动态链接库,无论有多少个程序在调用,内存中都只有一个动态库的副本。当动态库不再被任何程序使用,系统就会将它调出内存,这样就减少了应用程序对内存的要求。
优点:动态链接库是一种程序模块,不仅可以包含可执行的代码,通常还包含各种类型的预定义的数据和资源,扩大了库文件的使用范围。 还有利于软件产品国际化。
CMake 常用指令
- ADD_DEFINITIONS
语法 : ADD_DEFINITIONS(-DENABLE_DEBUG -DABC)
向 C/C++编译器添加 -D
定义. 如果你的代码中定义了#ifdef ENABLE_DEBUG #endif
,这个代码块就会生效。
- ADD_DEPENDENCIES
语法: ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)
定义 target 依赖的其他 target, 确保在编译本 target 之前,其他的 target 已经被构建。
- ADD_EXECUTABLE
语法 : ADD_EXECUTABLE(<name> [source1] [source2 ...])
利用源码文件生成目标可执行程序。
- ADD_LIBRARY
语法 : ADD_LIBRARY(<name> [STATIC | SHARED | MODULE] [source1] [source2 ...])
根据源码文件生成目标库。
STATIC
,SHARED
或者 MODULE
可以指定要创建的库的类型。 STATIC库是链接其他目标时使用的目标文件的存档。 SHARED库是动态链接的,并在运行时加载
- ADD_SUBDIRECTORY
语法 : ADD_SUBDIRECTORY(NAME) 添加一个文件夹进行编译,该文件夹下的 CMakeLists.txt 负责编译该文件夹下的源码. NAME是想对于调用add_subdirectory的CMakeListst.txt的相对路径.
- ENABLE_TESTING
语法: ENABLE_TESTING() .
控制 Makefile 是否构建 test 目标,涉及工程所有目录。 一般情况这个指令放在工程的主CMakeLists.txt 中.
- ADD_TEST
语法 : ADD_TEST(testname Exename arg1 arg2 ...)
testname
是自定义的 test 名称,Exename
可以是构建的目标文件也可以是外部脚本等等。 后面连接传递给可执行文件的参数。 如果没有在同一个 CMakeLists.txt 中打开ENABLE_TESTING()
指令, 任何 ADD_TEST
都是无效的。
- AUX_SOURCE_DIRECTORY
语法 : AUX_SOURCE_DIRECTORY(dir VARIABLE)
作用是发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。因为目前 cmake 还不能自动发现新添加的源文件。
比如 :
AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(main ${SRC_LIST})
- CMAKE_MINIMUM_REQUIRED
语法 : CMAKE_MINIMUM_REQUIRED
定义 cmake 的最低兼容版本 比如 CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR)
如果 cmake 版本小与 2.5,则出现严重错误,整个过程中止。
- EXEC_PROGRAM
在 CMakeLists.txt 处理过程中执行命令,并不会在生成的 Makefile 中执行。 具体语法为:
EXEC_PROGRAM(Executable [directory in which to run] [ARGS <arguments to executable>] [OUTPUT_VARIABLE <var>] [RETURN_VALUE <var>])
用于在指定的目录运行某个程序,通过 ARGS 添加参数,如果要获取输出和返回值,可通过OUTPUT_VARIABLE 和 RETURN_VALUE 分别定义两个变量.
这个指令可以帮助你在 CMakeLists.txt 处理过程中支持任何命令,比如根据系统情况去修改代码文件等等。
- FILE 指令
文件操作指令
语法:
FILE(WRITE filename "message to write"... ) FILE(APPEND filename "message to write"... ) FILE(READ filename variable) FILE(GLOB variable [RELATIVE path] [globbing expression_r_rs]...) FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expression_r_rs]...) FILE(REMOVE [directory]...) FILE(REMOVE_RECURSE [directory]...) FILE(MAKE_DIRECTORY [directory]...) FILE(RELATIVE_PATH variable directory file) FILE(TO_CMAKE_PATH path result) FILE(TO_NATIVE_PATH path result)
CMake 控制指令
- IF 指令
if(<condition>) <commands> elseif(<condition>) # optional block, can be repeated <commands> else() # optional block <commands> endif() ##### IF(var),如果变量不是:空,0,N, NO, OFF, FALSE, NOTFOUND 或<var>_NOTFOUND 时,表达式为真。 IF(NOT var ),与上述条件相反。 IF(var1 AND var2),当两个变量都为真是为真。 IF(var1 OR var2),当两个变量其中一个为真时为真。 IF(COMMAND cmd),当给定的 cmd 确实是命令并可以调用是为真。 IF(EXISTS dir)或者 IF(EXISTS file),当目录名或者文件名存在时为真。 IF(file1 IS_NEWER_THAN file2),当 file1 比 file2 新,或者 file1/file2 其中有一个不存在时为真,文件名请使用完整路径。 IF(IS_DIRECTORY dirname),当 dirname 是目录时,为真。 IF(variable MATCHES regex) IF(string MATCHES regex)
- FOREACH 指令
语法:
foreach(<loop_var> <items>) <commands> endforeach()
其中<items>
是以分号或空格分隔的项目列表。记录foreach匹配和匹配之间的所有命令endforeach而不调用。 一旦endforeach评估,命令的记录列表中的每个项目调用一次<items>
。在每次迭代开始时,变量loop_var将设置为当前项的值。
- WHILE 指令
语法:
while(<condition>) <commands> endwhile()
while和匹配之间的所有命令 endwhile()被记录而不被调用。 一旦endwhile()如果被评估,则只要为<condition>
真,就会调用记录的命令列表。