如何在CMake文件中添加链接器或编译标志?

我正在使用arm-linux-androideabi-g++编译器。当我尝试编译一个简单的“Hello, World!”程序时,它编译得很好。当我通过在该代码中添加一个简单的异常处理来测试它时,它也能工作(在添加-fexceptions ..我猜它默认是禁用的)。

这是一个Android设备,我只想使用CMake,而不是ndk-build

例如- first.cpp

#include <iostream>


using namespace std;


int main()
{
try
{
}
catch (...)
{
}
return 0;
}

./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions

它工作起来没有问题……

这个问题……我正在尝试用CMake文件编译该文件。

我想添加-fexceptions作为标志。我试过

set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )

而且

set ( CMAKE_C_FLAGS "fexceptions")

它仍然显示一个错误。

688540 次浏览

尝试设置变量CMAKE_CXX_FLAGS而不是CMAKE_C_FLAGS:

set (CMAKE_CXX_FLAGS "-fexceptions")

变量CMAKE_C_FLAGS只影响C编译器,但你正在编译c++代码。

将标志添加到CMAKE_EXE_LINKER_FLAGS是多余的。

注意:考虑到CMake自2012年以来的发展,这里的大多数建议现在已经过时/过时,有更好的替代方案。


假设你想添加这些标志(最好在一个常量中声明它们):

SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS    "-lgcov")

有几种方法可以添加它们:

  1. 最简单的一个(不干净,但简单方便,只适用于编译标志,C &c++):

     add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
    
  2. 附加到相应的CMake变量:

     SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
    SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
    
  3. 使用目标属性,cf. doc CMake编译标志目标属性,需要知道目标名称。

     get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS)
    if(TEMP STREQUAL "TEMP-NOTFOUND")
    SET(TEMP "") # Set to empty string
    else()
    SET(TEMP "${TEMP} ") # A space to cleanly separate from existing content
    endif()
    # Append our values
    SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" )
    set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )
    

现在我使用方法二。

在更新版本的CMake中,你可以分别用target_compile_optionstarget_link_libraries为单个目标设置编译器和链接器标志(是的,后者也设置链接器选项):

target_compile_options(first-test PRIVATE -fexceptions)

这种方法的优点是,你可以通过PUBLICPRIVATE控制选项传播到依赖于这个选项的其他目标。

从CMake 3.13开始,你也可以使用target_link_options来添加链接器选项,这使得意图更加明确。

你也可以使用LINK_FLAGS属性为特定目标添加链接器标志:

set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")

如果希望将此更改传播到其他目标,可以创建一个要链接到的虚拟目标。

指定特定于工具链的选项的首选方法是使用CMake的工具链设施。这确保在以下方面有一个清晰的划分:

  • 关于如何将源文件组织成目标文件的指令——用CMakeLists.txt文件表示,完全与工具链无关;而且
  • 特定工具链应该如何配置的细节——分离到CMake脚本文件中,可由项目的未来用户扩展,可扩展。

理想情况下,在你的CMakeLists.txt文件中应该没有编译器/链接器标志——即使在if/endif块中。您的程序应该使用默认的工具链(例如,GNU/Linux上的GCC或Windows上的MSVC)为本机平台构建,而不需要任何附加标志。

添加工具链的步骤:

  1. 创建一个具有全局工具链设置的文件,例如arm-linux-androideadi-gcc.cmake:

    set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
    set(CMAKE_CXX_FLAGS_INIT "-fexceptions")
    

    (你可以找到一个Linux交叉编译工具链文件在这里的例子。)

  2. 当你想用这个工具链生成一个构建系统时,在命令行上指定CMAKE_TOOLCHAIN_FILE参数:

    mkdir android-arm-build && cd android-arm-build
    cmake -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../arm-linux-androideadi-gcc.cmake ..
    

    (注意:不能使用相对路径。)

  3. 正常构建:

    cmake --build .
    

工具链文件使交叉编译更容易,但它们还有其他用途:

  • 单元测试的强化诊断。

    set(CMAKE_CXX_FLAGS_INIT "-Werror -Wall -Wextra -Wpedantic")
    
  • 难以配置的开发工具。

    # toolchain file for use with gcov
    set(CMAKE_CXX_FLAGS_INIT "--coverage -fno-exceptions -g")
    
  • 加强安全检查。

    # toolchain file for use with gdb
    set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=address,undefined -fsanitize-undefined-trap-on-error")
    set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address,undefined -static-libasan")
    

当我需要一个名为“no_debug”的预编译定义时,这为我工作:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")

然后从代码开始

#ifdef NO_DEBUG
.....

在CMake 3.4+中,APPEND可以与string命令一起使用来添加标志。

string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions")