cmake使用示例与整理总结 http://blog.csdn.net/wzzfeitian/article/details/40963457/ 对应的demo:https://github.com/carl-wang-cn/demo/tree/master/cmake
CMakeList学习 参考资源http://www.cnblogs.com/wengzilin/p/4466708.html 官方文档:https://cmake.org/cmake/help/v3.0/manual/cmake-commands.7.html 编写CMakeLists.txt 1、指定版本及工程名 cmake_minimum_required(VERSION 2.8) project(TEST) 2、添加一些option选项 option(BUILD_ANDROID "whether to build on android platform" OFF) #BUILD_ANDROID自己定义的,可以通过if判断使用 if (BUILD_ANDROID) message(STATUS "BUILD_ANDROID status is : " ${BUILD_ANDROID}) 3、获取依赖模块文件路径(非系统目录下,一般需要指定) 假设当前项目在文件夹test下,然后在test下建立的这个CMakeList,那么这个目录DEP_HOME 就在于test同一级目录下的dependence_modes文件夹下 即:~mydir$ test dependence_modes #在mydir目录下有两个文件夹,test和dependence_modes,dependence_modes是对应的依赖工程 ## locate dependence mode and add cmake modules path get_filename_component(DEP_HOME ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) #获得当前项目test所在的目录,这里是”mydir“ set(DEP_HOME "${DEP_HOME}/dependence_modes") if (EXISTS ${DEP_HOME}) message(STATUS "Found dependence_modes: ${DEP_HOME}") include_directories(SYSTEM ${DEP_HOME}) ##可以将DEP_HOME目录添加到SYSTEM目录 else() message(FATAL_ERROR "dependence_modes not found.") endif() 4、设置所有cmake模块的路径,CMAKE_MODULE_PATH是cmake的自动的变量,find_package的时候,也可以通过其指定搜索路径 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${DEP_HOME}/cmake) #如果DEP_HOME中有对应的cmake需要依赖调用,则需要添加进来 message(STATUS "CMAKE_MODULE_PATH: " ${CMAKE_MODULE_PATH})
find_path(TEST_PATH NAMES test.h PATHS /usr/local/include /usr/hostname/test DOC "this is a test for find_path") message(${TEST_PATH})
输出为:
//this is a test for find_path
TEST_PATH:PATH=/usr/hostname/test
5、消息机制
message(FATAL_ERROR "dependence_modes not found.") #发错错误消息,并退出
message(STATUS "BUILD_ANDROID status is : " ${BUILD_ANDROID}) #显示当前状态
6、指定头文件和源文件 include_directories 一般用于指定目录,或者添加目录 ##以下语句为将CMAKE_CURRENT_SOURCE_DIR当前目录添加到当前项目的搜索目录 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
后面可以添加:
include_directories(CMAKE_CURRENT_SOURCE_DIR ${DEP_HOME}) ##将DEP_HOME目录添加到当前目录中
file(GLOB_RECURSE box2d_source_files "${CMAKE_CURRENT_SOURCE_DIR}/Box2D/*.cpp") set 将一个CMAKE变量设置为给定值。 (属性的设置及set的一些说明可以看官方文档或者博客http://www.cnblogs.com/coderfenghc/archive/2012/10/20/2712806.html) set(<variable> <value> [[CACHE <type> <docstring> [FORCE]] | PARENT_SCOPE]) 将变量<variable>的值设置为<value>。在<variable>被设置之前,<value>会被展开。如果有CACHE选项,那么<variable>就会添加到cache中; 这时<type>和<docstring>是必需的。 <type>被CMake GUI用来选择一个窗口,让用户设置值。<type>可以是下述值中的一个: FILEPATH = 文件选择对话框。 PATH = 路径选择对话框。 STRING = 任意的字符串。 BOOL = 布尔值选择复选框。 INTERNAL = 不需要GUI输入端。(适用于永久保存的变量)。 如果在一个变量中添加东西可以使用set,SET 命令用于将文件组成一个列表。 例如:在 MY_SOURCE_FILES中添加源文件 set(MY_SOURCE_FILES Hell.c File2.c File3.c)
set(MY_SOURCE_FILES ${MY_SOURCE_FILES} test_image_src.cpp)
或者list(APPEND MY_SOURCE_FILES test_image_src.cpp)
) 如果有多个变量添加,可以使用for循环,例如:
SET(test
${PROJECT_SOURCE_DIR}/test/test1.cpp
${PROJECT_SOURCE_DIR}/test/test2.cpp
${PROJECT_SOURCE_DIR}/test/test3.cpp
)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) //设置执行文件输出路径
FOREACH (test ${tests})
STRING(REGEX MATCH "[^/]+$" test_file ${test})
STRING(REPLACE ".cpp" "" test_basename ${test_file})
ADD_EXECUTABLE(test_${test_basename} ${test})
TARGET_LINK_LIBRARIES(test_${test_basename}
${TEST_LINK_LIBS}
)
ENDFOREACH()
2、添加环境变量(可选, added by 编程小翁, 博客园) add_definitions( -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_REENTRANT -DENV_UNIX -DBREAK_HANDLER -DUNICODE -D_UNICODE) 如果需要判断平台,可以这么写: IF(APPLE) add_definitions(-DENV_MACOSX) FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation) ENDIF(APPLE) 其中 FIND_LIBRARY还可以指定对应的路径,例如: #look for the Tcl library FIND_LIBRARY(TCL_LIBRARY NAMES tcl tc184 tc183 tc 182 tc 180 PATHS /usr/lib /usr/local/lib) IF (TCL_LIBRARY) TARGET_ADD_LIBRARY (Hello TCL_LIBRARY) ENDIF(TCL_LIBRARY)
link_directories(${LINK_DIR}) //添加链接库时的 搜索路径
configure_file(<input> <output> [COPYONLY] [ESCAPE_QUOTES] [@ONLY] [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
Copy a file to another location and modify its contents.
例如在当前目录下定义了foo.h.in的头文件,头文件内容如下:
#ifndef FOO_H
#define FOO_H
#cmakedefine FOO_ENABLE
#cmakedefine FOO_STRING "@FOO_STRING@"
#cmakedefine01 FOO_ENABLE
#endif
如果cmakelist 中配置了configure_file(./foo.h.in ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
并且在cmakelist中使用:
option(FOO_ENABLE "whether open FOO" ON)
if(FOO_ENABLE)
set(FOO_STRING "new_string")
endif
最后会在build目录下的当前cmake_current_binary_dir目录下生成头文件foo.h,内容为:
#ifndef FOO_H
#define FOO_H
#define FOO_ENABLE
#define FOO_STRING new_string
#define FOO_ENABLE 1
#endif
否则就是以下内容:
#ifndef FOO_H
#define FOO_H
/* undefine FOO_ENABLE */
/* undefine FOO_STRING */
#define FOO_ENABLE 0
#endif
然后需要include_directories(${CMAKE_CURRENT_BINARY_DIR})
3、库自动链接,查找库 find_package(LibXML++ REQUIRED) #如果包是可选的,可以忽略REQUIRED关键字 不管使用哪一种模式,只要找到包,就会生成以下变量,然后可以在其他地方中使用: <NAME>_FOUND <NAME>_INCLUDE_DIRS or <NAME>_INCLUDES <NAME>_LIBRARIES or <NAME>_LIBRARIES or <NAME>_LIBS <NAME>_DEFINITIONS if(LibXML++_FOUND) include_directories(${LibXML++_INCLUDE_DIRS}) set(LIBS ${LIBS} ${LibXML++_LIBRARIES}) message(STATUS "LibXML++ lib DIR is: " ${LibXML++_INCLUDE_DIRS}) #输出对应的库路径, endif() 可以详细见:http://www.yeolar.com/note/2014/12/16/cmake-how-to-find-libraries/ “CMAKE 如何查找链接库” 另外,还可以设置需要连接的库的前缀、后缀 set(CMAKE_IMPORT_LIBRARY_PREFIX "lib") #指定连接库的前缀名字有lib set(CMAKE_IMPORT_LIBRARY_SUFFIX ".dll") #指定连接库的后缀名字有lib 4、设置生成库的名字跟类型
举例: add_library(Box2D STATIC ${box2d_source_files}) 这里add_library表示最终编译为一个库,static表示是静态库,如果想编译动态库,可以修改为shared. 至此,一个静态库的配置就完成了。当然,因为这个库没有包括其它外部的头文件,所以会比较简单。 5、Get a specific component of a full filename. get_filename_component(<VAR> <FileName> <COMP> [CACHE]) Set <VAR> to a component of <FileName>, where <COMP> is one of: DIRECTORY = Directory without file name NAME = File name without directory EXT = File name longest extension (.b.c from d/a.b.c) NAME_WE = File name without directory or longest extension ABSOLUTE = Full path to file REALPATH = Full path to existing file with symlinks resolved PATH = Legacy alias for DIRECTORY (use for CMake <= 2.8.11) 举例: file(GLOB_RECURSE examples_srcs "${PROJECT_SOURCE_DIR}/examples/*.cpp") foreach(source_file ${examples_srcs}) # get file name get_filename_component(name ${source_file} NAME_WE) # get folder name get_filename_component(path ${source_file} PATH) get_filename_component(folder ${path} NAME_WE) add_executable(${name} ${source_file}) target_link_libraries(${name} ${Caffe_LINK}) caffe_default_properties(${name}) # set back RUNTIME_OUTPUT_DIRECTORY set_target_properties(${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/examples/${folder}") caffe_set_solution_folder(${name} examples) # install install(TARGETS ${name} DESTINATION bin) if(UNIX OR APPLE) # Funny command to make tutorials work # TODO: remove in future as soon as naming is standartaized everywhere set(__outname ${PROJECT_BINARY_DIR}/examples/${folder}/${name}${CAffe_POSTFIX}) add_custom_command(TARGET ${name} POST_BUILD COMMAND ln -sf "${__outname}" "${__outname}.bin") endif() endforeach() 6、一个完整的CMakeList,如果还有新的CMakeList.txt需要包含进来, 可以使用add_subdirectory(${sub_cmakelistpath}) cmake_minimum_required(VERSION 3.2) #1、添加头文件目录,可以多引用,但是不能缺,因为缺了就编译不过 include_directories( "../../../myWindows" "../../../" "../../../include_windows" ) #2、添加环境变量,请结合实际项目要求,不是必须的 add_definitions( -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_REENTRANT -DENV_UNIX -DBREAK_HANDLER -DUNICODE -D_UNICODE) IF(APPLE) add_definitions(-DENV_MACOSX) FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation ) #FIND_LIBRARY命令用于寻找在一些指定目录下的特定的相关COREFOUNDATION_LIBRARY库文件,还可以指定对应的库路径 #3、源文件 file(GLOB_RECURSE src_files "../../../../C/7zCrc.c" "../../../../C/7zCrcOpt.c" "../../../../C/7zStream.c" "../../../../C/Aes.c") #4、设置生成静态库以及名称 add_library(myLibName STATIC ${src_files}) IF(APPLE) TARGET_LINK_LIBRARIES(myLibName ${COREFOUNDATION_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) ELSE(APPLE) IF(HAVE_PTHREADS) TARGET_LINK_LIBRARIES(myLibName ${CMAKE_THREAD_LIBS_INIT}) ENDIF(HAVE_PTHREADS) ENDIF(APPLE) #5、生成执行文件 add_executable(${exename} folder/${src_files}) target_link_libraries(${exename} ${TESTS_LINK_LIBS}) 7、属性设置 set_property set_source_files_properties set_target_properties 举例:set_target_properties(target1 target2 ... PROPERTIES prop1 value1 prop2 value2 ...) 例如设置生成库属性,举例: add_library(libname_static STATIC ${LIBNAME_${ARCH}_SRC}) #生成静态库 set_target_properties(libname_static PROPERTIES OUTPUT_NAME "librename") #设置输出名字 set_target_properties(libname_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) #设置为使用clean时,可清除 8、make install install(DIRECTORY ${src_dir} DESTINATION ${dst_dir} #把src_dir 安装到dst_dir目录下 FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ) 9、交叉编译用得比较多的部分 set(CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/sysroot") 列出文件系统搜索的“根目录列表”.常常在交叉编译时使用得比较多. CMake将把这个“根目录列表”中作为可选的搜索的目录,并且通过 find_package(), find_library() 等方式来搜索对应的文件和库 https://cmake.org/cmake/help/v3.1/variable/CMAKE_FIND_ROOT_PATH_MODE_PROGRAM.html set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) This variable controls whether the CMAKE_FIND_ROOT_PATH and CMAKE_SYSROOT are used by find_program(). If set to ONLY, then only the roots in CMAKE_FIND_ROOT_PATH will be searched. If set to NEVER, then the roots in CMAKE_FIND_ROOT_PATH will be ignored and only the host system root will be used. If set to BOTH, then the host system paths and the paths in CMAKE_FIND_ROOT_PATH will be searched. set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) This variable controls whether the CMAKE_FIND_ROOT_PATH and CMAKE_SYSROOT are used by find_library(). If set to ONLY, then only the roots in CMAKE_FIND_ROOT_PATH will be searched. If set to NEVER, then the roots in CMAKE_FIND_ROOT_PATH will be ignored and only the host system root will be used. If set to BOTH, then the host system paths and the paths in CMAKE_FIND_ROOT_PATH will be searched. 同理:CMAKE_FIND_ROOT_PATH_MODE_INCLUDE COMPILER设置: set(CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-gcc") set(CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-g++") ##可以打印对应的信息 Compiler setting message(STATUS "CMAKE_SYSTEM_NAME: " ${CMAKE_SYSTEM_NAME}) ##linux MAC 等等 message(STATUS "CXX_COMPILER_ID: " ${CMAKE_CXX_COMPILER_ID}) ##GNU Clang 等等 message(STATUS "CXX_COMPILER_VERSION: " ${CMAKE_CXX_COMPILER_VERSION}) ## NDK 4.9.1 message(STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR}) ##x86_64等等 ##判断CMAKE_CXX_COMPILER_ID "GNU" "Clang"等等 if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") message(STATUS "CXX_COMPILER_ID: " ${CMAKE_CXX_COMPILER_ID}) endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -fPIC -Wall -std=c++11") ## -O3 -fPIC -Wall -std=c++11 获取CMake主机名: if(CMAKE_HOST_SYSTEM_NAME MATCHES Linux*) set(TARGET_OS linux) elseif(CMAKE_HOST_SYSTEM_NAME MATCHES Darwin*) set(TARGET_OS mac) elseif(CMAKE_HOST_SYSTEM_NAME MATCHES Windows*) set(TARGET_OS windows) else() message(FATAL_ERROR "Host system does not support!") endif()
http://www.cnblogs.com/coderfenghc/archive/2012/07/08/2581734.html
CMD#28: file
文件操作命令file(WRITE filename "message to write"... )
file(APPEND filename "message to write"... )
file(READ filename variable [LIMIT numBytes] [OFFSET offset] [HEX])
file(STRINGS filename variable [LIMIT_COUNT num]
[LIMIT_INPUT numBytes] [LIMIT_OUTPUT numBytes]
[LENGTH_MINIMUM numBytes] [LENGTH_MAXIMUM numBytes]
[NEWLINE_CONSUME] [REGEX regex]
[NO_HEX_CONVERSION])
file(GLOB variable [RELATIVE path] [globbing expressions]...)
file(GLOB_RECURSE variable [RELATIVE path]
[FOLLOW_SYMLINKS] [globbing expressions]...)
file(RENAME <oldname> <newname>)
file(REMOVE [file1 ...])
file(REMOVE_RECURSE [file1 ...])
file(MAKE_DIRECTORY [directory1 directory2 ...])
file(RELATIVE_PATH variable directory file)
file(TO_CMAKE_PATH path result)
file(TO_NATIVE_PATH path result)
file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log]
[EXPECTED_MD5 sum] [SHOW_PROGRESS])
WRITE选项将会写一条消息到名为filename的文件中。如果文件已经存在,该命令会覆盖已有的文件;如果文件不存在,它将创建该文件。
APPEND选项和WRITE选项一样,将会写一条消息到名为filename的文件中,只是该消息会附加到文件末尾。
READ选项将会读一个文件中的内容并将其存储在变量里。读文件的位置从offset开始,最多读numBytes个字节。如果指定了HEX参数,二进制代码将会转换为十六进制表达方式,并存储在变量里。
STRINGS将会从一个文件中将一个ASCII字符串的list解析出来,然后存储在variable变量中。文件中的二进制数据会被忽略。回车换行符会被忽略。它也可以用在Intel的Hex和Motorola的S-记录文件;读取它们时,它们会被自动转换为二进制格式。可以使用NO_HEX_CONVERSION选项禁止这项功能。LIMIT_COUNT选项设定了返回的字符串的最大数量。LIMIT_INPUT设置了从输入文件中读取的最大字节数。LIMIT_OUTPUT设置了在输出变量中存储的最大字节数。LENGTH_MINIMUM设置了要返回的字符串的最小长度;小于该长度的字符串会被忽略。LENGTH_MAXIMUM设置了返回字符串的最大长度;更长的字符串会被分割成不长于最大长度的字符串。NEWLINE_CONSUME选项允许新行被包含到字符串中,而不是终止它们。REGEX选项指定了一个待返回的字符串必须满足的正则表达式。典型的使用方式是:
file(STRINGS myfile.txt myfile)
该命令在变量myfile中存储了一个list,该list中每个项是输入文件中的一行文本。
GLOB选项将会为所有匹配查询表达式的文件生成一个文件list,并将该list存储进变量variable里。文件名查询表达式与正则表达式类似,只不过更加简单。如果为一个表达式指定了RELATIVE标志,返回的结果将会是相对于给定路径的相对路径。文件名查询表达式的例子有:
*.cxx - 匹配所有扩展名为cxx的文件。
*.vt? - 匹配所有扩展名是vta,...,vtz的文件。
f[3-5].txt - 匹配文件f3.txt, f4.txt, f5.txt。
GLOB_RECURSE选项将会生成一个类似于通常的GLOB选项的list,只是它会寻访所有那些匹配目录的子路径并同时匹配查询表达式的文件。作为符号链接的子路径只有在给定FOLLOW_SYMLINKS选项或者cmake策略CMP0009被设置为NEW时,才会被寻访到。参见cmake --help-policy CMP0009 查询跟多有用的信息。
使用递归查询的例子有:
/dir/*.py - 匹配所有在/dir及其子目录下的python文件。
MAKE_DIRECTORY选项将会创建指定的目录,如果它们的父目录不存在时,同样也会创建。(类似于mkdir命令——译注)
RENAME选项对同一个文件系统下的一个文件或目录重命名。(类似于mv命令——译注)
REMOVE选项将会删除指定的文件,包括在子路径下的文件。(类似于rm命令——译注)
REMOVE_RECURSE选项会删除给定的文件以及目录,包括非空目录。(类似于rm -r 命令——译注)
RELATIVE_PATH选项会确定从direcroty参数到指定文件的相对路径。
TO_CMAKE_PATH选项会把path转换为一个以unix的 / 开头的cmake风格的路径。输入可以是一个单一的路径,也可以是一个系统路径,比如"$ENV{PATH}"。注意,在调用TO_CMAKE_PATH的ENV周围的双引号只能有一个参数(Note the double quotes around the ENV call TO_CMAKE_PATH only takes one argument. 原文如此。quotes和后面的takes让人后纠结,这句话翻译可能有误。欢迎指正——译注)。
TO_NATIVE_PATH选项与TO_CMAKE_PATH选项很相似,但是它会把cmake风格的路径转换为本地路径风格:windows下用,而unix下用/。
DOWNLOAD 将给定的URL下载到指定的文件中。如果指定了LOG var选项,下载日志将会被输出到var中。如果指定了STATUS var选项,下载操作的状态会被输出到var中。该状态返回值是一个长度为2的list。list的第一个元素是操作的数字返回值,第二个返回值是错误的字符串值。错误信息如果是数字0,操作中没有发生错误。如果指定了TIMEOUT time选项,在time秒之后,操作会超时退出;time应该是整数。如果指定了EXPECTED_MD5 sum选项,下载操作会认证下载的文件的实际MD5和是否与期望值匹配。如果不匹配,操作将返回一个错误。如果指定了SHOW_PROGRESS选项,进度信息会以状态信息的形式被打印出来,直到操作完成。
file命令还提供了COPY和INSTALL两种格式:
file(<COPY|INSTALL> files... DESTINATION <dir>
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]
[FILES_MATCHING]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]] [...])
COPY版本把文件、目录以及符号连接拷贝到一个目标文件夹。相对输入路径的评估是基于当前的源代码目录进行的,相对目标路径的评估是基于当前的构建目录进行的。复制过程将保留输入文件的时间戳;并且如果目标路径处存在同名同时间戳的文件,复制命令会把它优化掉。赋值过程将保留输入文件的访问权限,除非显式指定权限或指定NO_SOURCE_PERMISSIONS选项(默认是USE_SOURCE_PERMISSIONS)。参见install(DIRECTORY)命令中关于权限(permissions),PATTERN,REGEX和EXCLUDE选项的文档。
INSTALL版本与COPY版本只有十分微小的差别:它会打印状态信息,并且默认使用NO_SOURCE_PERMISSIONS选项。install命令生成的安装脚本使用这个版本(它会使用一些没有在文档中涉及的内部使用的选项。)