目录
在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:
CMakeLists.txt由命令、注释和空格组成:
CMakeLists.txt 编写完成后需要使用 cmake 或 ccmake 命令生成Makefile 。 ccmake 与命令 cmake 的不同之处在于 ccmake 提供了一个图形化的操作界面。cmake 命令的执行方式如下:
cmake [options]
通常推荐的使用方式是在工程目录下创建一个文件夹,如:build,然后cd到build执行cmake .. ,这样的好处是编译的产出易于清除:
mkdir build
cd build
cmake ..
make
将指定的源文件生成链接文件,然后添加到工程中去。
add_library( [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2] [...]
)
add_library(${PROJECT_NAME} SHARED
src/hello.cpp inc/world.cpp
)
添加头文件路径
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
它相当于g++选项中的-I参数的作用,也相当于环境变量中增加路径到CPLUS_INCLUDE_PATH变量的作用。
# eg:
include_directories(../../../thirdparty/comm/include)
添加需要链接的库文件路径,该指令有时候不一定需要。因为find_package和find_library指令可以得到库文件的绝对路径。不过你自己写的动态库文件放在自己新建的目录下时,可以用该指令指定该目录的路径以便工程能够找到。
link_directories(directory1 directory2 ...)
它相当于g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用。
# eg:
link_directories("/home/server/third/lib")
查找库所在路径
A short-hand signature is:
find_library ( name1 [path1 path2 ...])
The general signature is:
find_library (
name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
[HINTS path1 [path2 ... ENV var]]
[PATHS path1 [path2 ... ENV var]]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[DOC "cache documentation string"]
[NO_DEFAULT_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_CMAKE_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_SYSTEM_PATH]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
例子如下:
# eg:
FIND_LIBRARY(RUNTIME_LIB rt /usr/lib /usr/local/lib NO_DEFAULT_PATH)
cmake会在目录中查找,如果所有目录中都没有,值RUNTIME_LIB就会被赋为NO_DEFAULT_PATH
添加需要链接的库文件路径
link_libraries(library1 library2 ...)
# eg:
# 直接是全路径
link_libraries(“/home/server/third/lib/libcommon.a”)
# 下面的例子,只有库名,cmake会自动去所包含的目录搜索
link_libraries(iconv)
# 传入变量
link_libraries(${RUNTIME_LIB})
# 也可以链接多个
link_libraries("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" "/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")
可以链接一个,也可以多个,中间使用空格分隔。
将目标文件与库文件进行链接
target_link_libraries( [item1] [item2] [...]
[debug|optimized|general] [- ] ...
)
其中
# eg:
# 以下写法都可以:
target_link_libraries(myProject comm) # 连接libhello.so库,默认优先链接动态库
target_link_libraries(myProject libcomm.a) # 显示指定链接静态库
target_link_libraries(myProject libcomm.so) # 显示指定链接动态库 # 再如:
target_link_libraries(myProject libcomm.so) #这些库名写法都可以。
target_link_libraries(myProject comm)
target_link_libraries(myProject -lcomm)
为工程生成目标文件
add_executable( [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...]
)
# eg:
add_executable(demo main.cpp )
为构建添加一个子路径
add_subdirectory(source_dir [binary_dir]
[EXCLUDE_FROM_ALL])
这条命令的作用是为构建添加一个子路径。source_dir选项指定了CMakeLists.txt源文件和代码文件的位置。如果source_dir是一个相对路径,那么source_dir选项会被解释为相对于当前的目录,但是它也可以是一个绝对路径。binary_dir选项指定了输出文件的路径。如果binary_dir是相对路径,它将会被解释为相对于当前输出路径,但是它也可以是一个绝对路径。如果没有指定binary_dir,binary_dir的值将会是没有做任何相对路径展开的source_dir,这也是通常的用法。在source_dir指定路径下的也应该有一个CMakeLists.txt,而且当执行命令add_subdirectory时会进入source_dir,并执行此路径下的CMakeLists.txt。
如果指定了EXCLUDE_FROM_ALL选项,在子路径下的目标默认不会被包含到父路径的ALL目标里,并且也会被排除在IDE工程文件之外。用户必须显式构建在子路径下的目标,比如一些示范性的例子工程就是这样。典型地,子路径应该包含它自己的project()命令调用,这样会在子路径下产生一份完整的构建系统(比如VS IDE的solution文件)。注意,目标间的依赖性的优先级要高于这种排除行为。如果一个被父工程构建的目标依赖于在这个子路径下的目标,被依赖的目标会被包含到父工程的构建系统中,以优先满足依赖性的要求。
查找在某个路径下的所有源文件
aux_source_directory( )
搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的
从一个包围该命令的foreach或while循环中跳出
break()
INSTALL指令用于定义安装规则,安装的内容可以包括目标二进制、动态库、静态库以及文件、目录、脚本等。
目标文件的安装:
INSTALL(TARGETS targets...
[[ARCHIVE|LIBRARY|RUNTIME]
[DESTINATION ]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT ]
[OPTIONAL] ]
[...]
)
TARGETS后面跟的就是通过ADD_EXECUTABLE或者ADD_LIBRARY定义的目标文件,可能是可执行二进制、动态库、静态库。
目标类型也就相对应的有三种,ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME特指可执行目标二进制。
DESTINATION定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候CMAKE_INSTALL_PREFIX其实就无效了。如果你希望使用CMAKE_INSTALL_PREFIX来定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是${CMAKE_INSTALL_PREFIX}/
# eg:
INSTALL(TARGETS myrun mylib mystaticlib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION libstatic
)
即:可执行二进制myrun安装到${CMAKE_INSTALL_PREFIX}/bin目录
动态库libmylib安装到${CMAKE_INSTALL_PREFIX}/lib目录
静态库libmystaticlib安装到${CMAKE_INSTALL_PREFIX}/libstatic目录
特别注意的是你不需要关心TARGETS具体生成的路径,只需要写上TARGETS名称就可以
了。
普通文件的安装:
INSTALL(FILES files... DESTINATION
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT ]
[RENAME ]
[OPTIONAL]
)
# 可用于安装一般文件,并可以指定访问权限,文件名是此指令所在路径下的相对路径。
# 如果默认不定义权限PERMISSIONS,安装后的权限为,OWNER_WRITE,OWNER_READ,
# GROUP_READ,和WORLD_READ,即644权限。
非目标文件的可执行程序安装(比如脚本之类):
INSTALL(PROGRAMS files... DESTINATION
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT ]
[RENAME ]
[OPTIONAL]
)
跟上面的FILES指令使用方法一样,唯一的不同是安装后权限为:
OWNER_EXECUTE, GROUP_EXECUTE, 和WORLD_EXECUTE,即755权限
目录的安装:
INSTALL(DIRECTORY dirs... DESTINATION
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT ]
[[PATTERN | REGEX ]
[EXCLUDE] [PERMISSIONS permissions...]]
[...]
)
这里主要介绍其中的DIRECTORY、PATTERN以及PERMISSIONS参数。
DIRECTORY后面连接的是所在Source目录的相对路径,但务必注意:
abc和abc/有很大的区别。 abc意味着abc这个目录会安装在目标路径下; abc/意味着abc这个目录的内容会被安装在目标路径下;
如果目录名不以/结尾,那么这个目录将被安装为目标路径下的abc,如果目录名以/结尾,代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。
PATTERN用于使用正则表达式进行过滤,PERMISSIONS用于指定PATTERN过滤后的文件权限。
看一个例子:
INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj
PATTERN "CVS" EXCLUDE
PATTERN "scripts/*"
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
GROUP_EXECUTE GROUP_READ
)
这条指令的执行结果是:
将icons目录安装到
安装时cmake脚本的执行:
INSTALL([[SCRIPT ] [CODE ]] [...])
# SCRIPT参数用于在安装时调用cmake脚本文件(也就是.cmake文件)
# CODE参数用于执行CMAKE指令,必须以双引号括起来。比如:
INSTALL(CODE "MESSAGE(\"Sample install message.\")")
file(GLOB
[LIST_DIRECTORIES true|false]
[RELATIVE ]
[CONFIGURE_DEPENDS]
[...]
)
file(GLOB_RECURSE
[FOLLOW_SYMLINKS]
[LIST_DIRECTORIES true|false]
[RELATIVE ]
[CONFIGURE_DEPENDS]
[...]
)
产生一个匹配
如果 CONFIGURE_DEPENDS 标志位被指定,CMake 将在编译时给主构建系统添加逻辑来检查目标,以重新运行 GLOB 标志的命令。如果任何输出被改变,CMake都将重新生成这个构建系统。
注意:我们不推荐使用 GLOB 来从源文件树收集源文件列表。如果当源文件添加或删除时没有 CMakeLists.txt 文件被修改,那么在 CMake 重新生成时并不会识别出它们。CONFIGURE_DEPENDS 标志位可能不会再所有生成器上可靠的工作,如果一个新的生成器在以后被添加,并不会被支持。如果项目使用它将会被卡主。即使 CONFIGURE_DEPENDS 可靠的工作,在每个重新构建的过程中做检查也十分浪费性能。
GLOB_RECURSE 将会递归所有匹配文件夹的子文件夹和匹配的文件。子文件夹为符号链接时只有当 FOLLOW_SYMLINKS 被指定或规则 CMP0009 没有设置为 NEW 时才会被递归。
默认 GLOB_RECURSE 省略结果列表中的目录,设置 LIST_DIRECTORIES 为 true 来添加目录到结果列表中。如果 FOLLOW_SYMLINKS 被指定或规则 CMP0009 没有设置为 OLD 。LIST_DIRECTORIES 将符号链接作为路径。
递归文件名包括的例子:
/dir/*.py - match all python files in /dir and subdirectories
https://www.jianshu.com/p/ed151fdcf473
https://cmake.org/cmake/help/latest/command/file.html
https://www.cnblogs.com/binbinjx/p/5626916.html
https://blog.csdn.net/bigdog_1027/article/details/79113342
https://blog.csdn.net/guoyajie1990/article/details/78138636