CMake CheatSheet Link1 Link2 1. 常用:readlink获取工作目录全路径 WD=$(readlink -f "`dirname $0`") # 取当前shell脚本的全路径,不包括最后的/ 注意: 不要在cmake中用相对路径,用${CMAKE_CURRENT_SOURCE_DIR}等组合出全路径使用 2. DEBUG or Release Win和Linux系统,可以通过cmake -DCMAKE_BUILD_TYPE=Release/Debug设置编译目标 Xcode系统,上述变量可能没有效果,经测试可以使用CMAKE_CONFIGURATION_TYPES 3. 实例 cmake_minimum_required (VERSION 3.1) # 指定需要的 CMake 的最低版本 project (project) # 指定项目的名称 set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_CXX_STANDARD 11) # CMAKE_BINARY_DIR就是build目录,即这次build的顶层目录 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # 设置 ARCHIVE 目标的输出路径 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # 设置 LIBRARY 目标的输出路径 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # 设置 RUNTIME 目标的输出路径 set(CMAKE_CXX_STANDARD 11) # initialize the CXX_FLAGS on all targets, -std=c++11,一些C++高级特性 # [option](https://cmake.org/cmake/help/v3.4/command/option.html?highlight=option) option(DEBUG "To log messges for debugging" 1) if(DEBUG) add_definitions(-DDEBUG) endif() # Then, we can use "DEBUG=${DEBUG:-1}, cmake -DDEBUG=${DEBUG}" to turn on/off the flag if(UNIX OR APPLE) # UNIX-like 的系统,包括 Apple OS X 和 CygWin 或 Apple 系统 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -DUSE_OPENCV=1 -std=c++11 -static-libstdc++") endif() # 其中,如果系统canot find libstdc++.a,需要安装yum install glibc-static libstdc++-static # -static-libstdc++ 参考:https://github.com/rordenlab/dcm2niix/issues/137 # 只将Release版本,设置为-Ofast set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast") # 缩减so或者exe的大小 add_definitions(-fvisibility=hidden -fvisibility-inlines-hidden) # 6.8-> 6.1M set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections") # 6.1 -> 5.4M if (UNIX AND NOT APPLE) link_libraries("-Wl, --gc-sections") elseif (APPLE) link_libraries("-Wl, -dead_strip") endif() # 输出信息:message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] “message to display” …) message(STATUS "root path:${CMAKE_FIND_ROOT_PATH}") # CMAKE_FIND_ROOT_PATH指定了一个或者多个优先于其他搜索路径的搜索路径。默认为空 include(cmake/other.cmake) # Load and run CMake code from the file given # CMake module path for custom module finding set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) # 定义自己的cmake子模块所在的路径,find_package来这里找,然后可以用INCLUDE命令来调用模块 if(DEFINED BUILD_ANDROID) # 跨平台编译android程序,BUILD_ANDROID被android.toolchain.cmake置为true set(ENABLE_JNI 1) set(BUILD_SHARED_LIBS 1) # 控制默认的库编译方式。若未设置,使用ADD_LIBRARY时又没指定库类型,默认生成静态库;设置1为动态库 list(APPEND CMAKE_FIND_ROOT_PATH ${OWN_ANDROID_PATH}/) # list命令,用来操作列表,CMAKE_FIND_ROOT_PATH查找路径 endif() # find_package为外部工程加载设置 if(ENABLE_OPENCV) find_package(OpenCV REQUIRED) # CMake搜索所有名为Find<package>.cmake的文件 # If no Find.cmake is found and the MODULE option is not given the command proceeds to Config mode:package-config.cmake类似文件 include_directories(${OpenCV_INCLUDE_DIRS}) # 被编译器用来查找 include 文件 message(STATUS "opencv:${OpenCV_INCLUDE_DIRS} ${OpenCV_LIBS} ") set(project_lib ${project_lib} ${OpenCV_LIBS}) # 存储lib到统一的变量里 endif() # eigen find_package(Eigen REQUIRED) # 也可以使用target_include_directories,只为某一个target添加include目录 include_directories(SYSTEM ${EIGEN_INCLUDE_DIR}) # SYSTEM:to use system include directories on some platforms add_definitions(-DUSE_EIGEN) # 用于添加预编译,定义标志 # Qt5: [link](https://zhuanlan.zhihu.com/p/34667993) find_package(Qt5 COMPONENTS Widgets REQUIRED) # 如果提示找不到qt,请打印${CMAKE_PREFIX_PATH} ${Qt5_DIR},分析下config file的路径中是否有Qt5WidgetsConfig.cmake if (Qt5_FOUND) set(CMAKE_AUTOMOC ON) # qt wrapper around c++, like QObject, CMAKE会自动生成moc文件 else() message(STATUS "QT not found, build without QT demo.") endif() # then we can use ${Qt5Widgets_INCLUDE_DIRS} and ${Qt5Widgets_LIBRARIES} # caffe # [link](https://cmake.org/cmake/help/v3.4/command/find_package.html?highlight=find_package) find_package(Caffe REQUIRED) # 若找到,则name_FOUND被自动置为1 find_library(CAFFE_LIB_PATH ${Caffe_LIBRARIES}) # 查找library的绝对路径,存入变量 message(STATUS "caffe:${Caffe_LIBRARIES} ${Caffe_FOUND} ${CAFFE_LIB_PATH}") # protobuf find_package(Protobuf REQUIRED) include_directories(${PROTOBUF_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS myown.proto) message(STATUS "pb:${PROTOBUF_LIBRARIES}") # then we can add ${PROTO_SRCS} ${PROTO_HDRS} to add_library; and #include "myown.pb.h" in main.cpp set(project_src a.cpp b.cpp c.cpp) # 用于指定从一组源文件中编译出一个库文件 libproject.so add_library(project ${OTHER_SRCS} ${project_src}) # 有STATIC/SHARED/OBJECT等方式(https://cmake.org/cmake/help/v3.4/command/add_library.html?highlight=add_library) # OBJECT方式不创建实际的lib文件,跟直接src放进去相同,会初始化objs中的全局变量 # 用于指定project需要链接的库, 这里target必须已被创建,链接的item可以是已经存在的target(依赖关系会自动添加) TARGET_LINK_LIBRARIES(project ${project_lib} ${CMAKE_OTHER_LIBS} ) # 编译出可执行文件,就叫main add_executable(main main.cpp ) set(main_lib project) # main依赖于main_lib=project,就是libproject.so TARGET_LINK_LIBRARIES(main ${main_lib}) # 如果运行时需要动态库,可以这么拷贝:copy the dlls to runtime dir file(GLOB RUNTIME_DLLS "${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_ARCH}/*.dll") foreach(file_i ${RUNTIME_DLLS}) add_custom_command(TARGET main POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${file_i} ${CMAKE_BINARY_DIR}/) endforeach() # 如果copy目标文件夹不存在,则需要先新建 # COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/${dstdir} if(ENABLE_JNI) add_subdirectory(src/jni) # 添加一个需要进行构建的子目录,里边编辑子CMakeLists.txt # 子CMakeLists.txt可以这么写: set(JAVA_INCLUDE_PATH2 NotNeeded) # 如果报错Could NOT find JNI (missing: JAVA_INCLUDE_PATH2,JAVA_AWT_INCLUDE_PATH) set(JAVA_AWT_INCLUDE_PATH NotNeeded) find_package(JNI REQUIRED) include_directories(${JNI_INCLUDE_DIRS}) endif() if(DEFINED BUILD_ANDROID) set(INSTALL_DIST_PATH ${PROJECT_SOURCE_DIR}/dist/android/${ANDROID_ABI}) else(NOT DEFINED BUILD_ANDROID) set(INSTALL_DIST_PATH ${PROJECT_SOURCE_DIR}/dist/${CMAKE_SYSTEM_NAME}) # CMAKE_SYSTEM_NAME=`uname -s` endif(DEFINED BUILD_ANDROID) install(TARGETS project DESTINATION ${INSTALL_DIST_PATH}) # 指定install的时候,执行的命令,跟make时没关系 # 将需要的lib也install到目标目录 # [link](https://cmake.org/cmake/help/v3.4/command/install.html#installing-files) install(FILES ${CAFFE_LIB_PATH} DESTINATION ${INSTALL_DIST_PATH}) # install高级用法 # copy so/dlls to another project if (UNIX AND NOT APPLE) # in linux docker: can change to other path to install if(NOT DEFINED Dst_Install_DIR) set(Dst_Install_DIR /home/a) endif() set(CMAKE_INSTALL_PREFIX ${Dst_Install_DIR}) # 自动安装到lib/linux目录下 install(TARGETS main_lib ARCHIVE DESTINATION lib/linux/ LIBRARY DESTINATION lib/linux/) # Install headers Install(FILES "${project_DIR}/a.h" DESTINATION include/a) elseif (MSVC) set(Dst_Install_DIR D:/Work/b) set(CMAKE_INSTALL_PREFIX ${Dst_Install_DIR}) install(TARGETS main_lib ARCHIVE DESTINATION lib/${CMAKE_ARCH}/ RUNTIME DESTINATION bin/${CMAKE_ARCH}/) # Install pdbs install(FILES $<TARGET_PDB_FILE:main_lib> DESTINATION lib/${CMAKE_ARCH}/ OPTIONAL) # Install headers Install(FILES "${project_DIR}/a.h" DESTINATION include) else() # mac set(Dst_Install_DIR /Users/b/b) set(CMAKE_INSTALL_PREFIX ${Dst_Install_DIR}) install(TARGETS main_lib ARCHIVE DESTINATION lib/mac/ LIBRARY DESTINATION lib/mac/) # Install headers Install(FILES "${project_DIR}/a.h" DESTINATION include/b) endif() # 设置一些Options. Turn on with 'cmake -Dmyvarname=ON'. option(BUILD_TESTS "Build all tests." 0) # 可定义一些编译开关ON/OFF,最后给出默认值如0 ######################## # 可以定义子函数 # Short command for adding unit-test # Usage: # add_unit_test(test_case_name <src_file>) ######################## function(add_unit_test test_case_name) add_executable(${test_case_name} ${ARGN}) # ARGN隐式参数,如果是多个src_file参数 # Standard linking to gtest stuff. target_link_libraries(${test_case_name} ${GTEST_BOTH_LIBRARIES}) # Extra linking for the project. target_link_libraries(${test_case_name} ${main_lib}) # This is so you can do 'make test' to see all your tests run, instead of # manually running the executable runUnitTests to see those specific tests. # [link](https://cmake.org/cmake/help/v3.4/command/add_test.html?highlight=add_test) add_test(NAME ${test_case_name} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test_case_name}) endfunction() if (BUILD_TESTS) enable_testing() # add_subdirectory(tests) # 可在tests目录添加CMakeLists.txt, 并添加以下add_test等内容 find_package(GTest REQUIRED) include_directories(${GTEST_INCLUDE_DIRS}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/test) # 放到test目录 # Add Unit Tests Here add_unit_test(TestName test/testMain.cpp src/a.cpp) endif() # foreach/string regex/interface用法 FOREACH(FFMPEG_MODULE ${FFMPEG_LIBS}) STRING(REGEX REPLACE "(.*)/(.*).(dylib|so)$" "\\2" FFMPEG_MODULE_OUT ${FFMPEG_MODULE}) add_library(${FFMPEG_MODULE_OUT} SHARED IMPORTED) set_target_properties(${FFMPEG_MODULE_OUT} PROPERTIES IMPORTED_LOCATION ${FFMPEG_MODULE} ) set(ffmpeg_import_libs ${ffmpeg_import_libs} ${FFMPEG_MODULE}) ENDFOREACH() add_library(ffmpeg INTERFACE IMPORTED GLOBAL) target_link_libraries(ffmpeg INTERFACE ${ffmpeg_import_libs}) target_include_directories(ffmpeg INTERFACE ${FFMPEG_INCLUDE}) target_compile_definitions(ffmpeg INTERFACE ENABLE_FFMPEG=1)