资源:
https://github.com/xiaoweiChen/CMake-Cookbook
生成器表达式章节:参考
find_package和pkg_check_modules
1. 一些命令
cmake -S . -B build # 自动创建 build 文件夹
cmake -S . -B build && cmake --build build --target all -- -j$(nproc)
cmake --help-command ADD_SUBDIRECTORY
apt rdepends qtbase5-dev-tools # 查找哪些软件依赖于这个 from: dpkg -S qdbusxml2cpp
cmake 的 clean 方式:参考
优雅的构建CMake项目:参考
集成GTest:参考,相关命令:enable_testing() add_test() 详细参考
在cmake中优雅的使用pkgconfig:参考
cmake的函数以及参数传递:参考
alex@alex-PC:~/Desktop/Test/translator/example1$ dpkg -S Qt5LinguistTools qttools5-dev:amd64: /usr/lib/x86_64-linux-gnu/cmake/Qt5LinguistTools/Qt5LinguistToolsMacros.cmake qttools5-dev:amd64: /usr/lib/x86_64-linux-gnu/cmake/Qt5LinguistTools/Qt5LinguistToolsConfig.cmake qttools5-dev:amd64: /usr/lib/x86_64-linux-gnu/cmake/Qt5LinguistTools/Qt5LinguistToolsConfigVersion.cmake qttools5-dev:amd64: /usr/lib/x86_64-linux-gnu/cmake/Qt5LinguistTools
安装路径的指定:知乎
安装权限的指定:参考
现代cmake技巧:参考
cmake生成器表达式:参考 生成器表达式的简单示例:参考 参考 参考 参考 官方参考 详参
include_directories 和 link_directories :参考(LINK_DIRECTORIES放在ADD_EXECUTABLE之前)
GNU开发工具——CMake构建Qt工程实践
编译 Debug 或 Release 版本的坑:参考
strip --strip-unneeded
install -m 644 -p
在编译时下载:参考
对于龙芯的支持:参考
添加单元测试: 参考
打印所有可见变量:参考
cmake_minimum_required(VERSION 3.7)
打印可见变量及其值
message("内置变量 -----------------------------------------------------------------------------------") get_cmake_property(_variableNames VARIABLES) foreach (_variableName ${_variableNames}) message(STATUS "${_variableName}=${${_variableName}}") endforeach()
message("环境变量 -----------------------------------------------------------------------------------") 打印环境变量及其值 execute_process(COMMAND "${CMAKE_COMMAND}" "-E" "environment")
使用Qt的私有库,重要参考:
The package qt5-base:x86-windows provides CMake targets: find_package(Qt5AccessibilitySupport CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::AccessibilitySupport Qt5::AccessibilitySupport Qt::AccessibilitySupportPrivate Qt5::AccessibilitySupportPrivate) find_package(Qt5Bootstrap CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::Bootstrap Qt5::Bootstrap Qt::BootstrapPrivate Qt5::BootstrapPrivate) find_package(Qt5Concurrent CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::Concurrent Qt5::Concurrent Qt::ConcurrentPrivate Qt5::ConcurrentPrivate) find_package(Qt5Core CONFIG REQUIRED) # Note: 2 target(s) were omitted. target_link_libraries(main PRIVATE Qt::Core Qt5::Core Qt::WinMain Qt5::WinMain) find_package(Qt5DBus CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::DBus Qt5::DBus Qt::DBusPrivate Qt5::DBusPrivate) find_package(Qt5DeviceDiscoverySupport CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::DeviceDiscoverySupport Qt5::DeviceDiscoverySupport Qt::DeviceDiscoverySupportPrivate Qt5::DeviceDiscoverySupportPrivate) find_package(Qt5EdidSupport CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::EdidSupport Qt5::EdidSupport Qt::EdidSupportPrivate Qt5::EdidSupportPrivate) find_package(Qt5EventDispatcherSupport CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::EventDispatcherSupport Qt5::EventDispatcherSupport Qt::EventDispatcherSupportPrivate Qt5::EventDispatcherSupportPrivate) find_package(Qt5FbSupport CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::FbSupport Qt5::FbSupport Qt::FbSupportPrivate Qt5::FbSupportPrivate) find_package(Qt5FontDatabaseSupport CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::FontDatabaseSupport Qt5::FontDatabaseSupport Qt::FontDatabaseSupportPrivate Qt5::FontDatabaseSupportPrivate) find_package(Qt5Gui CONFIG REQUIRED) # Note: 9 target(s) were omitted. target_link_libraries(main PRIVATE Qt::Gui Qt5::Gui Qt::GuiPrivate Qt5::GuiPrivate) find_package(Qt5Network CONFIG REQUIRED) # Note: 1 target(s) were omitted. target_link_libraries(main PRIVATE Qt::Network Qt5::Network Qt::NetworkPrivate Qt5::NetworkPrivate) find_package(Qt5OpenGL CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::OpenGL Qt5::OpenGL Qt::OpenGLPrivate Qt5::OpenGLPrivate) find_package(Qt5OpenGLExtensions CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::OpenGLExtensions Qt5::OpenGLExtensions Qt::OpenGLExtensionsPrivate Qt5::OpenGLExtensionsPrivate) find_package(Qt5PlatformCompositorSupport CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::PlatformCompositorSupport Qt5::PlatformCompositorSupport Qt::PlatformCompositorSupportPrivate Qt5::PlatformCompositorSupportPrivate) find_package(Qt5PrintSupport CONFIG REQUIRED) # Note: 1 target(s) were omitted. target_link_libraries(main PRIVATE Qt::PrintSupport Qt5::PrintSupport Qt::PrintSupportPrivate Qt5::PrintSupportPrivate) find_package(Qt5Sql CONFIG REQUIRED) # Note: 3 target(s) were omitted. target_link_libraries(main PRIVATE Qt::Sql Qt5::Sql Qt::SqlPrivate Qt5::SqlPrivate) find_package(Qt5Test CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::Test Qt5::Test Qt::TestPrivate Qt5::TestPrivate) find_package(Qt5ThemeSupport CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::ThemeSupport Qt5::ThemeSupport Qt::ThemeSupportPrivate Qt5::ThemeSupportPrivate) find_package(Qt5Widgets CONFIG REQUIRED) # Note: 1 target(s) were omitted. target_link_libraries(main PRIVATE Qt::Widgets Qt5::Widgets Qt::WidgetsPrivate Qt5::WidgetsPrivate) find_package(Qt5WindowsUIAutomationSupport CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::WindowsUIAutomationSupport Qt5::WindowsUIAutomationSupport Qt::WindowsUIAutomationSupportPrivate Qt5::WindowsUIAutomationSupportPrivate) find_package(Qt5Xml CONFIG REQUIRED) target_link_libraries(main PRIVATE Qt::Xml Qt5::Xml Qt::XmlPrivate Qt5::XmlPrivate)
cmake 中 ts 转 qm 文件: 参考 参考 参考 官方(翻译) git-example qt国际化 参考
添加 ui 文件、资源文件等:参考
cmake 中使用 Qt 的 private module:参考 官方 参考 参考 这有个不错的示例
# qtbase 中搜索 CorePrivate 这个:
set_target_properties(QtLibraryInfo PROPERTIES COMPILE_OPTIONS $<TARGET_PROPERTY:Qt::Core,INTERFACE_COMPILE_OPTIONS> COMPILE_DEFINITIONS $<TARGET_PROPERTY:Qt::Core,INTERFACE_COMPILE_DEFINITIONS> INCLUDE_DIRECTORIES $<TARGET_PROPERTY:Qt::Core,INTERFACE_INCLUDE_DIRECTORIES> INCLUDE_DIRECTORIES $<TARGET_PROPERTY:Qt::CorePrivate,INTERFACE_INCLUDE_DIRECTORIES> )
参考(不错的文章)
add_subdirectory(添加一个子目录并构建该子目录):参考
include_directories() 用于添加 Headers 搜索路径( -I 标志), add_subdirectory() 在这种情况下没有区别 .
include_directories 和 target_include_directories 区别: 参考 和生成器使用
find_package( Threads REQUIRED )
target_link_libraries(demo ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
set_and_check 代替普通的
target_include_directories(t x y) # 添加 x y 到目标的包含路径 t
# 这种方法的优点是你可以控制选项传播到依赖于这个PUBLIC和PRIVATE的其他目标. same as CMAKE_EXE_LINKER_FLAGS :
target_compile_options(first-test PRIVATE -fexceptions)
target_compile_options add_compile_options reference
自动处理版本号:参考
cmake_minimum_required(VERSION 3.10) if(NOT DTK_CORE_VERSION) set(DTK_CORE_VERSION 5.4.3) endif() project(dtkcore VERSION ${DTK_CORE_VERSION} LANGUAGES CXX) message("CMAKE_PROJECT_NAME = ${CMAKE_PROJECT_NAME}") message("PROJECT_VERSION = ${PROJECT_VERSION}") message("PROJECT_VERSION_MAJOR = ${PROJECT_VERSION_MAJOR}") message("PROJECT_VERSION_MINOR = ${PROJECT_VERSION_MINOR}") message("PROJECT_VERSION_PATCH = ${PROJECT_VERSION_PATCH}") message("PROJECT_VERSION_TWEAK = ${PROJECT_VERSION_TWEAK}") # cmake -DDTK_CORE_VERSION=10.2.1.3 CMakeLists.txt # cmake -S . -B build
外部传入字符串:参考
同时编译动态、静态库的方法
cmake的RPATH:
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) SET(CMAKE_INSTALL_RPATH "\${ORIGIN}/lib") #指定运行时动态库的加载路径,ORIGIN指运行文件所在目录
3. 常用
cmake gui:参考
if (UNIX) set(CMAKE_CXX_FLAGS "-pthread") set(CMAKE_CXX_FLAGS "-dl") endif (UNIX)
ADD_DEFINITIONS(-DXXX -DXXX)
4. 安装
cmake -DCMAKE_INSTALL_PREFIX=<你想要安装的路径>
set(CMAKE_INSTALL_PREFIX /usr/local)
install(TARGETS test DESTINATION bin) #将test安装到/usr/local/bin目录下
关于 EXPORT 和 configuration :参考,结合这个一起看
5. 动态、静态的生成
BUILD_SHARED_LIBS这个开关用来控制默认的库编译方式,如果不进行设置,
使用ADD_LIBRARY 并没有指定库类型的情况下,默认编译生成的库都是静态库。
如果 SET(BUILD_SHARED_LIBS ON) 后,默认生成的为动态库。
6. 其它
CMake 的查找规则:参考
PUBLIC_HEADER 主要是用于mac系统安装的:参考
CMake 里面使用sed命令
execute_process(COMMAND sh -c "sed -i 's#\\;#\\\n#g' ${CMAKE_CURRENT_LIST_DIR}/dtkcore_config.h" )
对于关键字的解释:
依赖关系 | 描述 |
PRIVATE | 我需要,但是依赖者不需要 |
PUBLIC | 我和依赖者都需要 |
INTERFACE | 我不需要,但是依赖者需要 |
生成器表达式中使用C++11:
实例代码:
编译时执行命令从ts文件生成qm文件:
cmake_minimum_required(VERSION 3.10) # git clean -dfx . && cmake CMakeLists.txt && make && find . -name "*.qm" project(generate_qm) if (NOT TARGET Qt5::release) add_executable(Qt5::lrelease IMPORTED) set(imported_location "/usr/bin/lrelease") if (NOT EXISTS "${imported_location}") message(FATAL_ERROR "/usr/bin/lrelease does not exist. please install dependences qttools5-dev-tools.") endif() set_target_properties(Qt5::lrelease PROPERTIES IMPORTED_LOCATION ${imported_location} ) endif() set(Qt5_LRELEASE_EXECUTABLE Qt5::lrelease) function(DTK_CREATE_QM_FROM_TS QM_FILE_LIST) set(options) set(oneValueArgs) set(multiValueArgs OPTIONS) cmake_parse_arguments(_LRELEASE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) set(LRELEASE_FILES ${_LRELEASE_UNPARSED_ARGUMENTS}) set(QM_FILES_OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/qm_files) # foreach(TS_FILE_PATH ${LRELEASE_FILES}) # message(STATUS ${TS_FILE_PATH}) # get_filename_component(FILE_NAME_NO_SUFFIX ${TS_FILE_PATH} NAME_WE) # set(QM_FILE_LOCATION ${QM_FILES_OUTPUT_PATH}/${FILE_NAME_NO_SUFFIX}.qm) # # message("${Qt5_LRELEASE_EXECUTABLE} ARGS ${TS_FILE_PATH} -qm ${QM_FILE_LOCATION} ????") # # add_custom_command(OUTPUT ${QM_FILE_LOCATION} # # COMMAND ${Qt5_LRELEASE_EXECUTABLE} ARGS ${TS_FILE_PATH} -qm ${QM_FILE_LOCATION} # # DEPENDS ${QM_FILE_LOCATION} VERBATIM # # ) # list(APPEND ${QM_FILE_LIST} ${QM_FILE_LOCATION}) # endforeach() dtk_add_translation(${QM_FILE_LIST} ${LRELEASE_FILES}) set(${QM_FILE_LIST} ${${QM_FILE_LIST}} PARENT_SCOPE) file(MAKE_DIRECTORY "${QM_FILES_OUTPUT_PATH}") endfunction() function(DTK_ADD_TRANSLATION _qm_files) set(options) set(oneValueArgs) set(multiValueArgs OPTIONS) cmake_parse_arguments(_LRELEASE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) set(_lrelease_files ${_LRELEASE_UNPARSED_ARGUMENTS}) foreach(_current_FILE ${_lrelease_files}) get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE) get_filename_component(qm ${_abs_FILE} NAME) # everything before the last dot has to be considered the file name (including other dots) string(REGEX REPLACE "\\.[^.]*$" "" FILE_NAME ${qm}) get_source_file_property(output_location ${_abs_FILE} OUTPUT_LOCATION) if(output_location) file(MAKE_DIRECTORY "${output_location}") set(qm "${output_location}/${FILE_NAME}.qm") else() set(qm "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.qm") endif() add_custom_command(OUTPUT ${qm} COMMAND ${Qt5_LRELEASE_EXECUTABLE} ARGS ${_LRELEASE_OPTIONS} ${_abs_FILE} -qm ${qm} DEPENDS ${_abs_FILE} VERBATIM ) list(APPEND ${_qm_files} ${qm}) endforeach() set(${_qm_files} ${${_qm_files}} PARENT_SCOPE) endfunction() file(GLOB LANGUAGE_TS_FILES "*.ts") dtk_create_qm_from_ts(QM_FILES ${LANGUAGE_TS_FILES} ) add_custom_target(${PROJECT_NAME} ALL DEPENDS ${QM_FILES})
原来使用这个函数,只要把Translate加到target中或者depends中就能生成:
file(GLOB_RECURSE LANGUAGE_TS_FILES "*.ts") qt5_create_translation(Translate # main.cpp # 扫描源文件,如果有 tr 的也会被替换 # dialog.ui # en.ts ${LANGUAGE_TS_FILES} )
遇到的重要问题记录:
使用 link_directories 链接本地库可以比 add_directories 提供更好的编译并行性能。
技巧,同一个目录生成多个可执行文件:
cmake_minimum_required(VERSION 3.14) # https://stackoverflow.com/questions/35696103/cmake-wildcard-for-target-objects project(myTestDemo) set(CMAKE_CXX_STANDARD 11) set(CMAKE_INCLUDE_CURRENT_DIR ON) add_library(Client OBJECT main1.cpp) add_library(Server OBJECT main2.cpp) function(DTK_ADD_EXECUTABLE _target) foreach(_source IN ITEMS ${ARGN}) if (NOT TARGET "${_source}") list(APPEND _source_list "${_source}") else() get_target_property(_type "${_source}" TYPE) if (_type STREQUAL "OBJECT_LIBRARY") list(APPEND _source_list "$<TARGET_OBJECTS:${_source}>") else() message(SEND_ERROR "my_add_executable: '${_source}' given as parameter is not a object-library target.") endif() endif() endforeach() add_executable(${_target} ${_source_list}) endfunction() dtk_add_executable(target1 main1.cpp ) # 非main的对象写在后面 Client、Server dtk_add_executable(target2 main2.cpp ) add_custom_target(target3) add_dependencies(target3 target1 target2)
生成代码测试覆盖率:
CMAKE_EXE_LINKER_FLAGS 的坑:参考
添加子文件夹:
gerrit链接
# https://stackoverflow.com/questions/8934295/add-source-in-a-subdirectory-to-a-cmake-project # https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/ # 正规写法: https://www.jianshu.com/p/cbee27847638 cmake_minimum_required(VERSION 3.10) project(dtkcore VERSION 5.5) set(CMAKE_CXX_STANDARD 11) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(REQUIRED_QT_VERSION 5.11.3) find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core DBus Xml Concurrent) include_directories(base filesystem log settings util) find_library(QGSETTINGS_LIB gsettings-qt) set(Qt_LIBS Qt5::Core Qt5::DBus Qt5::Xml Qt5::Concurrent ) add_library(${PROJECT_NAME} STATIC SHARED ${HEADERS} ${SOURCES} ${RESOURCES} ${QMLS} ${QGSETTINGS_LIB}) add_subdirectory("log") add_subdirectory("base") add_subdirectory("util") add_subdirectory("settings") add_subdirectory("filesystem") set(HEADERS dtkcore_global.h dsysinfo.h dsecurestring.h ddesktopentry.h ) set(SOURCES dsysinfo.cpp dsecurestring.cpp ddesktopentry.cpp dtkcore_global.cpp ) set(RESOURCES util/util.qrc ) target_link_libraries(${PROJECT_NAME} PRIVATE ${Qt_LIBS} pthread)
set(HEADERS ${HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/dbasefilewatcher.h ${CMAKE_CURRENT_SOURCE_DIR}/dfilesystemwatcher.h ${CMAKE_CURRENT_SOURCE_DIR}/dfilewatcher.h ${CMAKE_CURRENT_SOURCE_DIR}/dfilewatchermanager.h ${CMAKE_CURRENT_SOURCE_DIR}/dpathbuf.h ${CMAKE_CURRENT_SOURCE_DIR}/dstandardpaths.h ${CMAKE_CURRENT_SOURCE_DIR}/dtrashmanager.h ${CMAKE_CURRENT_SOURCE_DIR}/private/dbasefilewatcher_p.h ${CMAKE_CURRENT_SOURCE_DIR}/private/dfilesystemwatcher_linux_p.h # DFileWatcher # DBaseFileWatcher # DFileSystemWatcher # DFileWatcherManager # DPathBuf # DStandardPaths # DTrashManager ) set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/dbasefilewatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dfilewatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dfilewatchermanager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dstandardpaths.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dpathbuf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dfilesystemwatcher_linux.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dtrashmanager_linux.cpp ) target_sources(${PROJECT_NAME} PRIVATE ${HEADERS} ${SOURCES})