Cmake用法

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)
posted @ 2024-11-25 18:30  反光  阅读(166)  评论(0)    收藏  举报