cmake
1.常見用法
cd some_software-1.4.2
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/opt/the/prefix
cmake --build .
cmake --build . --target install
cmake --build . --target myexe --config Release
2.構建變數
CMAKE_PREFIX_PATH 搜尋路徑 dependent packages
CMAKE_MODULE_PATH 搜尋其他 CMake 模組的路徑
CMAKE_BUILD_TYPE 構建配置,例如 Debug或Release,確定除錯/最佳化標誌。這僅與單配置構建系統(例如Makefile和Ninja)相關。多配置構建系統(例如 Visual Studio 和 Xcode 的構建系統)會忽略此設定。
CMAKE_INSTALL_PREFIX 使用 install構建目標安裝軟體的位置
CMAKE_TOOLCHAIN_FILE 包含交叉編譯資料的檔案,例如 toolchains and sysroots。
BUILD_SHARED_LIBS 是否構建共享庫而不是靜態庫add_library() 不使用型別的命令
CMAKE_EXPORT_COMPILE_COMMANDS 生成一個compile_commands.json 用於基於 clang 的工具的檔案
CMAKE_EXPORT_BUILD_DATABASE 生成一個build_database.json 用於基於 clang 的工具的檔案
3.基本cmake包
//CMakeLists.txt
# 需要的cmake版本宣告
cmake_minimum_required(VERSION 3.15)
# 專案名稱和版本
project(Tutorial VERSION 1.0)
# 生成可執行檔案
add_executable(Tutorial tutorial.cxx)
//tutorial.cxx
#include <iostream>
int main(int argc, char* argv[])
{
std::cout << "hello" << std::endl;
return 0;
}
4.程式碼中使用專案版本號
TutorialConfig.h會生成到PROJECT_BINARY_DIR目錄中
//CMakeLists.txt
configure_file(TutorialConfig.h.in TutorialConfig.h)
#將PROJECT_BINARY_DIR新增到包含檔案的搜尋路徑中
#這樣我們就能找到TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
//TutorialConfig.h.in
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
//tutorial.cxx
#include <iostream>
#include <string>
#include "TutorialConfig.h"
int main(int argc, char* argv[])
{
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
return 0;
}
5.建立動態庫
// MathFunctions/CMakeLists.txt
# 宣告動態庫
add_library(MathFunctions MathFunctions.cxx)
# 宣告動態庫的介面目錄(動態庫使用者需要使用的目錄(生成時不需要))
target_include_directories(MathFunctions
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)
CMakeLists.txt
add_subdirectory(MathFunctions)
6.連結動態庫
CMakeLists.txt
# 連結動態庫名稱
target_link_libraries(Tutorial PUBLIC MathFunctions)
tutorial.cxx
#include "MathFunctions.h"
7.cmake 選項
MathFunctions/CMakeLists.txt
# 宣告選項 預設為ON
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# 選項邏輯
if (USE_MYMATH)
# 產生編譯宏
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
include(MakeTable.cmake) # generates Table.h
# library that just does sqrt
add_library(SqrtLibrary STATIC
mysqrt.cxx
${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
# state that we depend on our binary dir to find Table.h
target_include_directories(SqrtLibrary PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
# state that SqrtLibrary need PIC when the default is shared libraries
set_target_properties(SqrtLibrary PROPERTIES
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
)
# link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
MathFunctions/MathFunctions.cxx
//程式碼中的選項宏
#include <cmath>
#ifdef USE_MYMATH
# include "mysqrt.h"
#endif
#ifdef USE_MYMATH
return detail::mysqrt(x);
#else
return std::sqrt(x);
#endif
8.設定 C++ 標準
add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
9.向目標新增編譯選項
CMakeLists.txt
# 設定變數
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
# 向目標新增編譯選項
# BUILD_INTERFACE限制該設定只有在構建時候生效
target_compile_options(tutorial_compiler_flags INTERFACE
"$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
"$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)
10.安裝
MathFunctions/CMakeLists.txt
# 安裝動態庫
set(installable_libs MathFunctions tutorial_compiler_flags)
if(TARGET SqrtLibrary)
list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs}
EXPORT MathFunctionsTargets
DESTINATION lib)
# 安裝標頭檔案
install(FILES MathFunctions.h DESTINATION include)
CMakeLists.txt
# add the install targets
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include
)
11.測試
CMakeLists.txt
# 生成並安裝測試程式
add_executable(Tutorial tutorial.cxx)
set_target_properties(Tutorial PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
# add the install targets
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include
)
# 啟動測試功能
enable_testing()
# does the application run
add_test(NAME Runs COMMAND Tutorial 25)
# 檢測列印輸出是否包含指定正規表示式
add_test(NAME Usage COMMAND Tutorial)
set_tests_properties(Usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
)
# define a function to simplify adding tests
function(do_test target arg result)
add_test(NAME Comp${arg} COMMAND ${target} ${arg})
set_tests_properties(Comp${arg}
PROPERTIES PASS_REGULAR_EXPRESSION ${result}
)
endfunction()
# do a bunch of result based tests
do_test(Tutorial 4 "4 is 2")
do_test(Tutorial 9 "9 is 3")
do_test(Tutorial 5 "5 is 2.236")
do_test(Tutorial 7 "7 is 2.645")
do_test(Tutorial 25 "25 is 5")
do_test(Tutorial -25 "-25 is (-nan|nan|0)")
do_test(Tutorial 0.0001 "0.0001 is 0.01")
# 測試程式的輸出語句
std::cout << "The square root of " << inputValue << " is " << outputValue
<< std::endl;
12.測試儀表盤
CMakeLists.txt
include(CTest)
CTestConfig.cmake
set(CTEST_PROJECT_NAME "CMakeTutorial")
set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
set(CTEST_DROP_SITE_CDASH TRUE)
ctest [-VV] -D Experimental
ctest [-VV] -C Debug -D Experimental
13.新增系統自檢
在專案中新增一些依賴於目標平臺可能沒有的功能的程式碼
MathFunctions/CMakeLists.txt
#檢查是否可以構建 C++ 原始碼
include(CheckCXXSourceCompiles)
#檢查是否可以構建特定 C++ 原始碼
check_cxx_source_compiles("
#include <cmath>
int main() {
std::log(1.0);
return 0;
}
" HAVE_LOG)
check_cxx_source_compiles("
#include <cmath>
int main() {
std::exp(1.0);
return 0;
}
" HAVE_EXP)
#根據檢查結果修改編譯流程
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(SqrtLibrary
PRIVATE "HAVE_LOG" "HAVE_EXP"
)
endif()
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
MathFunctions/mysqrt.cxx
#include <cmath>
#if defined(HAVE_LOG) && defined(HAVE_EXP)
double result = std::exp(std::log(x) * 0.5);
std::cout << "Computing sqrt of " << x << " to be " << result
<< " using log and exp" << std::endl;
#else
double result = x;
// do ten iterations
for (int i = 0; i < 10; ++i) {
if (result <= 0) {
result = 0.1;
}
double delta = x - (result * result);
result = result + 0.5 * delta / result;
std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
}
#endif
14.新增自定義命令和生成檔案
MathFunctions/MakeTable.cmake
# 我們新增MakeTable的可執行檔案
add_executable(MakeTable MakeTable.cxx)
target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
# 新增生成原始碼的命令
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
)
MathFunctions/CMakeLists.txt
# 包含自定義命令檔案
include(MakeTable.cmake)
#目標依賴於生成的檔案
add_library(SqrtLibrary STATIC
mysqrt.cxx
${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
# 在CMAKE_CURRENT_BINARY_DIR查詢標頭檔案
target_include_directories(SqrtLibrary PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
15.打包安裝程式
CMakeLists.txt
# setup installer
include(InstallRequiredSystemLibraries)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
set(CPACK_GENERATOR "TGZ")
set(CPACK_SOURCE_GENERATOR "TGZ")
include(CPack)
打包命令
# 打包生成軟體包
cpack
# -G選項選擇生成器 -C多配置構建
cpack -G ZIP -C Debug
16.選擇靜態或共享庫
CMakeLists.txt
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
MathFunctions/CMakeLists.txt
#設定目標庫的屬性(位置無關程式碼)
set_target_properties(SqrtLibrary PROPERTIES
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
)
#設定宏,用於windows程式庫的生成
target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
MathFunctions/MathFunctions.h
根據宏定義切換連結方式
#if defined(_WIN32)
# if defined(EXPORTING_MYMATH)
# define DECLSPEC __declspec(dllexport)
# else
# define DECLSPEC __declspec(dllimport)
# endif
#else // non windows
# define DECLSPEC
#endif
namespace mathfunctions {
double DECLSPEC sqrt(double x);
}
17.匯出給其他cmake專案使用
17.1匯出安裝 *Targets.cmake檔案
MathFunctions/CMakeLists.txt
# 這裡應保證不匯出當前計算機固有關聯的路徑(使用BUILD_INTERFACE、INSTALL_INTERFACE分別描述)
target_include_directories(MathFunctions
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)
# install(TARGETS) 增加EXPORT關鍵字生成CMake檔案MathFunctionsTargets.cmake
install(TARGETS MathFunctions
EXPORT MathFunctionsTargets
DESTINATION lib)
# 安裝生成的MathFunctionsTargets.cmake檔案
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
DESTINATION lib/cmake/MathFunctions
)
17.2匯出安裝兩個Config cmake檔案
Config.cmake.in
@PACKAGE_INIT@
include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )
CMakeLists.txt
include(CMakePackageConfigHelpers)
# 生成MathFunctionsConfig.cmake
# 根據Config.cmake.in生成包含匯出的配置檔案MathFunctionsConfig.cmake
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
INSTALL_DESTINATION "lib/cmake/MathFunctions"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
# 生成MathFunctionsConfigVersion.cmake
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
COMPATIBILITY AnyNewerVersion
)
# 安裝兩個config檔案
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake
DESTINATION lib/cmake/MathFunctions
)
17.3 匯出MathFunctionsTargets.cmake
通常,專案在被外部專案使用之前會先進行構建和安裝。但是,在某些情況下,最好直接從構建樹中匯出目標。然後,引用構建樹的外部專案可以使用這些目標,而無需進行安裝。
CMakeLists.txt
export(EXPORT MathFunctionsTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
)
17.4 匯出Targets檔案NAMESPACE用法
此命令生成MathFunctionsTargets.cmake檔案並安排將其安裝到${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions。該檔案包含適合下游使用的程式碼,用於從安裝樹匯入安裝命令中列出的所有目標。
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
NAMESPACE MathFunctions::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
)
17.5 匯入target檔案
include(${INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions/MathFunctionsTargets.cmake)
add_executable(myexe src1.c src2.c )
target_link_libraries(myexe PRIVATE MathFunctions::MathFunctions)
18.打包debug和release
18.1區分除錯庫的字尾
CMakeLists.txt
set(CMAKE_DEBUG_POSTFIX d)
add_library(tutorial_compiler_flags INTERFACE)
add_executable(Tutorial tutorial.cxx)
set_target_properties(Tutorial PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)
18.2 設定庫版本
MathFunctions/CMakeLists.txt
set_property(TARGET MathFunctions PROPERTY VERSION "1.0.0")
set_property(TARGET MathFunctions PROPERTY SOVERSION "1")
18.3 構建debug和release庫
cd debug
cmake -DCMAKE_BUILD_TYPE=Debug ..
cmake --build .
cd ../release
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
18.4 debug+release打包
打包指令碼
MultiCPackConfig.cmake
MultiCPackConfig.cmake
include("release/CPackConfig.cmake")
set(CPACK_INSTALL_CMAKE_PROJECTS
"debug;Tutorial;ALL;/"
"release;Tutorial;ALL;/"
)
打包命令
cpack --config MultiCPackConfig.cmake
19.匯入cmake包
19.1一般匯入
find package的用法
find_package(Catch2)
find_package(GTest REQUIRED)
find_package(Boost 1.79 COMPONENTS date_time)
find package完整使用方式
cmake_minimum_required(VERSION 3.10)
project(MyExeProject VERSION 1.0.0)
# Make project-provided Find modules available
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(SomePackage REQUIRED)
add_executable(MyExe main.cpp)
target_link_libraries(MyExe PRIVATE SomePrefix::LibName)
19.2匯入並使用git包
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
FIND_PACKAGE_ARGS NAMES GTest
)
FetchContent_MakeAvailable(googletest)
add_executable(ThingUnitTest thing_ut.cpp)
target_link_libraries(ThingUnitTest GTest::gtest_main)
include(FetchContent)
FetchContent_Declare(
Catch2
URL https://intranet.mycomp.com/vendored/Catch2_2.13.4_patched.tgz
URL_HASH MD5=abc123...
OVERRIDE_FIND_PACKAGE
)
# The following is automatically redirected to FetchContent_MakeAvailable(Catch2)
find_package(Catch2)
19.3匯入多種配置的庫
find_library(math_REL NAMES m)
find_library(math_DBG NAMES md)
add_library(math STATIC IMPORTED GLOBAL)
set_target_properties(math PROPERTIES
IMPORTED_LOCATION "${math_REL}"
IMPORTED_LOCATION_DEBUG "${math_DBG}"
IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
)
add_executable(myexe src1.c src2.c)
target_link_libraries(myexe PRIVATE math)
20.匯入其他
匯入可執行檔案
匯入一個可生成原始碼的可執行檔案,然後編譯生成的原始碼
add_executable(myexe IMPORTED)
set_property(TARGET myexe PROPERTY
IMPORTED_LOCATION "../InstallMyExe/bin/myexe")
add_custom_command(OUTPUT main.cc COMMAND myexe)
add_executable(mynewexe main.cc)
匯入動態庫
add_library(foo STATIC IMPORTED)
set_property(TARGET foo PROPERTY
IMPORTED_LOCATION "/path/to/libfoo.a")
add_executable(myexe src1.c src2.c)
target_link_libraries(myexe PRIVATE foo)
windows 匯入
add_library(bar SHARED IMPORTED)
set_property(TARGET bar PROPERTY
IMPORTED_LOCATION "c:/path/to/bar.dll")
set_property(TARGET bar PROPERTY
IMPORTED_IMPLIB "c:/path/to/bar.lib")
add_executable(myexe src1.c src2.c)
target_link_libraries(myexe PRIVATE bar)