CMake I 编译源文件的两种方式

时间:2025-03-15 09:21:39

目录

一、try_compile命令

1.编译整个项目

2.编译源文件

二、check__source_compiles模块

三、总结


        try_compile和check_<LANG>_source_compiles都可编译源文件,并将其链接到可执行文件中。

一、try_compile命令

        在命令行输入cmake --help-command try_compile可以获得try_compile文档。

        命令 try_compile 提供了更完整的接口和两种不同的操作模式:

1. 以一个完整的CMake项目作为输入,并基于它的 配置、构建和链接。这种操作 模式提供了更好的灵活性,因为要编译项目的复杂度是可以选择的。

2. 提供了源文件,和用于包含目录、链接库和编译器标志的配置选项。

        因此, try_compile 基于在项目上调用CMake,其中 已经存在(在第一种操作模 式中),或者基于传递给 try_compile 的参数动态生成文件。

1.编译整个项目

try_compile(<resultVar> <bindir> <srcdir>
            <projectName> [<targetName>] [CMAKE_FLAGS <flags>...]
            [OUTPUT_VARIABLE <var>])
  • resultVar:存放编译结果。
  • bindir:try_compile 将在这个目录下生成中间文件。
  • srcdir:包含有及源码的完整CMake项目。
  • projectName:项目名称。
  • targetName:指定<targetName>以生成特定目标,而不是all或ALL_BUILD 。

注意:当前格式下,在运行try_compile命令后,<bindir>和<srcdir>不会被删除。

2.编译源文件

try_compile(<resultVar> <bindir> <srcfile|SOURCES srcfile...>
            [CMAKE_FLAGS <flags>...]
            [COMPILE_DEFINITIONS <defs>...]
            [LINK_OPTIONS <options>...]
            [LINK_LIBRARIES <libs>...]
            [OUTPUT_VARIABLE <var>]
            [COPY_FILE <fileName> [COPY_FILE_ERROR <var>]]
            [<LANG>_STANDARD <std>]
            [<LANG>_STANDARD_REQUIRED <bool>]
            [<LANG>_EXTENSIONS <bool>]
            )

注意:使用当前格式时,<bindir>/CMakeFiles/CMakeTmp目录下的文件会被自动删除。使用 --debug-trycompile可避免此行为。

#设置了一个临时目录, try_compile 将在这个目录下来生成中间文件
set(_scratch_dir ${CMAKE_CURRENT_BINARY_DIR}/omp_try_compile)
#尝试编译源文件 
try_compile(
    omp_taskloop_test_1 #存放编译结果
    ${_scratch_dir} 
    SOURCES
      ${CMAKE_CURRENT_SOURCE_DIR}/
    COMPILE_DEFINITIONS
      ${OpenMP_CXX_FLAGS} 
    LINK_LIBRARIES
      ${OpenMP_CXX_LIBRARIES}
    )
message(STATUS "Result of try_compile: ${omp_taskloop_test_1}")

        如果代码中有多个 try_compile 调用,一次只能调试一个:

1. 运行CMake,不使用 --debug-trycompile ,将运行所有 try_compile 命令,并清理它们的 执行目录和文件。

2. 从CMake缓存中删除保存检查结果的变量。缓存保存到 文件中。要清除变量 的内容,可以使用 -U 的CLI开关,后面跟着变量的名称,它将被解释为一个全局表达式,因此可以使用 * 和 ? :

        cmake -U <variable-name>

3. 再次运行CMake,使用 --debug-trycompile 。只有清除缓存的检查才会重新运行。这次不会清理执行目录和文件。  

二、check_<LANG>_source_compiles模块

        在命令行输入cmake --help-module CheckCXXSourceCompiles可以获得check_cxx_source_compiles文档。

    check_cxx_source_compiles(<code> <resultVar>
                             [FAIL_REGEX <regex1> [<regex2>...]])

        check_<lang>_source_compiles 命令是 try_compile 命令的简化包装。因此,它提供了一个接口:

1.  要编译的代码片段必须作为CMake变量传入。大多数情况下,这意味着必须使用 file(READ...) 来读取文件。代码片段被保存到构建目录的 CMakeFiles/CMakeTmp 子目录中。

2.  微调编译和链接,必须通过设置以下CMake变量进行:

  • CMAKE_REQUIRED_FLAGS:设置编译器标志。
  • CMAKE_REQUIRED_DEFINITIONS:设置预编译宏。
  • CMAKE_REQUIRED_INCLUDES:设置包含目录列表。
  • CMAKE_REQUIRED_LIBRARIES:设置可执行目标能够连接的库列表。

3. 调用 check_<lang>_compiles_function 之后,必须手动取消对这些变量的设置,以确保后续使用中,不会保留当前内容。 

        要使用 check_cxx_source_compiles 函数,需要包含 模块文件:

include(CheckCXXSourceCompiles)
#复制taskloop源文件的内容到_snippet
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/ _snippet)
  
set(CMAKE_REQUIRED_FLAGS ${OpenMP_CXX_FLAGS})
set(CMAKE_REQUIRED_LIBRARIES ${OpenMP_CXX_LIBRARIES})
  
#使用代码片段作为参数,调用 check_cxx_source_compiles 函数。检查结果将保存到omp_taskloop_test_2 变量中:
check_cxx_source_compiles("${_snippet}" omp_taskloop_test_2)
#取消变量的设置
unset(CMAKE_REQUIRED_FLAGS)
unset(CMAKE_REQUIRED_LIBRARIES)

message(STATUS "Result of check_cxx_source_compiles: ${omp_taskloop_test_2}")

三、总结

        try_compile 提供了灵活和干净的接口,特别是当编译的代码不是一个简短的代码时。建议在测试编译时,小代码片段时使用 check_<LANG>_source_compile 。其他情况下,选择 try_compile 。