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

时间:2012-08-02 18:52:12

标签: cmake

我正在使用arm-linux-androideabi-g++编译器。当我尝试编译一个简单的“你好,世界!”程序编译好。当我通过在该代码中添加一个简单的异常处理来测试它时它也有效(在添加-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")

它仍然显示错误。

7 个答案:

答案 0 :(得分:210)

假设您要添加这些标志(最好将它们声明为常量):

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

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

  1. 最简单的(不干净,但简单方便,只适用于编译标记,C&amp; 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. 使用目标属性,参见doc CMake compile flag target property并且需要知道目标名称。

    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} )
    
  4. 现在我使用方法2.

答案 1 :(得分:129)

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

target_compile_options(first-test PRIVATE -fexceptions)

此方法的优势在于,您可以通过PUBLICPRIVATE控制将选项传播到依赖于此目标的其他目标。

从CMake 3.13开始,您还可以使用target_link_options添加链接器选项,使意图更加清晰。

答案 2 :(得分:36)

尝试设置变量CMAKE_CXX_FLAGS而不是CMAKE_C_FLAGS

set (CMAKE_CXX_FLAGS "-fexceptions")

变量CMAKE_C_FLAGS仅影响C编译器,但您正在编译C ++代码。

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

答案 3 :(得分:4)

指定特定于工具链的选项的首选方法是使用CMake的toolchain facility。这样可以确保在以下各项之间进行清晰的划分:

  • 关于如何将源文件组织为目标的说明-在 CMakeLists.txt 文件中表示,完全与工具链无关。和
  • 详细说明应如何配置某些工具链-分为CMake脚本文件,可由项目的未来用户扩展,并且可扩展。

理想情况下,即使在if / endif块内, CMakeLists.txt 文件中也不应包含编译器/链接器标志。并且您的程序应使用默认工具链(例如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交叉编译工具链文件here。)

  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")
    

答案 4 :(得分:1)

您还可以使用LINK_FLAGS属性将链接器标志添加到特定目标:

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

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

答案 5 :(得分:0)

签出ucm_add_flagsucm_add_linker_flagsucm宏(我的一组有用的CMake宏) - 它们处理附加的编译器/链接器标记。

答案 6 :(得分:0)

当我需要一个名为“NO_DEBUG”的预编译定义时,这对我有用:

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

然后从代码

#ifdef NO_DEBUG
.....