【问题标题】:What's the proper way to enable AddressSanitizer in CMake that works in Xcode在 Xcode 中工作的 CMake 中启用 AddressSanitizer 的正确方法是什么
【发布时间】:2017-11-03 08:46:19
【问题描述】:

我添加了 AddressSanitizer 标志如下:

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")

使用Unix Makefiles 时,一切都可以正常构建和运行。

生成 Xcode 项目时出现问题,它只是不想链接,因为它找不到 ASan 库。

我已经找到了两个解决方案,但决定不使用它们,因为它们不能仅使用 CMake 实现自动化:

  1. -Wl,-undefined,dynamic_lookup 添加到链接标志,因此它跳过链接到动态库。
  2. 直接链接libclang_rt.asan_osx_dynamic.dylib

那么这两种解决方案有什么问题呢?

  • 使用解决方案#1时,我必须在Xcode中手动打开目标方案并添加指向libclang_rt.asan_osx_dynamic.dylibDYLD_INSERT_LIBRARIES环境变量。
  • 使用解决方案 #2 时,ASan 库的路径因计算机而异。

另外,作为另一种解决方案,我尝试从 Xcode 目标方案中启用 Address Sanitizer 标志,但有趣的是它没有检测到我添加的问题,因此我没有将其列为解决方案,因为它未能通过我的测试。

任何帮助将不胜感激。

【问题讨论】:

  • 也许可以看看这个:github.com/arsenm/sanitizers-cmake
  • 如果您知道 Xcode 项目设置可以打开您想要的内容,您可以通过填充 CMAKE_XCODE_ATTRIBUTE_... 变量或使用每个目标属性 XCODE_ATTRIBUTE_... 从 CMake 进行设置。

标签: c++ cmake clang address-sanitizer


【解决方案1】:

您还需要向链接器提供标志。我是这样做的:

set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")

【讨论】:

  • 第二行在我看来是错误的。八 两边应该是CMAKE_STATIC_LINKER_FLAGS_DEBUG,或者CMAKE_LINKER_FLAGS_DEBUG。
  • 现代 CMake:string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit...")
  • @Timmmm 直接摆弄CMAKE_CXX_FLAGS 无论如何都不是现代CMake。使用check_cxx_compiler_flag 是最接近的。
  • @Timmmm 很好发现。谢谢你。我犯了复制和粘贴错误。当然,我指的是target_compile_options
  • 是的,确实更干净,但是在这种情况下,它需要您将其应用于每个目标,这相当乏味。
【解决方案2】:

由于这些天投票最多的答案是错误的方法,而且我没有得到正确的 cmake 解决方案来阅读这个线程,我想我会在写这篇文章时提到正确的方法,以便下一位读者不需要花太多时间在这上面。希望对您有所帮助。

此解决方案的想法是将-fsanitize=address 传递给编译器和链接器标志。

如果您想同时为所有目标启用此功能,您可以使用add_compile_optionsadd_link_options。如果您有多个(可能是大量的)目标,这是有道理的。

add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)

或者,您也可以使用target_compile_optionstarget_link_options 为特定目标设置这些。如果您不希望将其应用于所有目标,这可能更有意义。

target_compile_options(asan-target PRIVATE -fsanitize=address)
target_link_options(asan-target PRIVATE -fsanitize=address)

【讨论】:

  • 这是更好的答案
【解决方案3】:

我建议创建您自己的 Asan 个人资料。

get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)

if(isMultiConfig)
    if(NOT "Asan" IN_LIST CMAKE_CONFIGURATION_TYPES)
        list(APPEND CMAKE_CONFIGURATION_TYPES Asan)
    endif()
else()
    set(allowedBuildTypes Asan Debug Release RelWithDebInfo MinSizeRel)
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${allowedBuildTypes}")

    if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE IN_LIST allowedBuildTypes)
        message(FATAL_ERROR "Invalid build type: ${CMAKE_BUILD_TYPE}")
    endif()
endif()

set(CMAKE_C_FLAGS_ASAN
    "${CMAKE_C_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING
    "Flags used by the C compiler for Asan build type or configuration." FORCE)

set(CMAKE_CXX_FLAGS_ASAN
    "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING
    "Flags used by the C++ compiler for Asan build type or configuration." FORCE)

set(CMAKE_EXE_LINKER_FLAGS_ASAN
    "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING
    "Linker flags to be used to create executables for Asan build type." FORCE)

set(CMAKE_SHARED_LINKER_FLAGS_ASAN
    "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING
    "Linker lags to be used to create shared libraries for Asan build type." FORCE)

注意事项:

  1. 带有 MSVC 的 Windows 的 AddressSanitizer (ASan) 处于实验阶段,因此我没有在此处提供 MSVC 方式。

  2. CMAKE_BUILD_TYPE 不被多配置生成器(Xcode、Visual Studio 等)使用,因此我首先提供了一个示例来检查这一点。

  3. CMAKE_BUILD_TYPE 的默认值为 空字符串。并且用户可以在 cmake 命令行中将CMAKE_BUILD_TYPE 设置为任何值。因此,我们检查这两种情况,并确保我们正在处理已知的构建类型(如果提供)。

  4. 还有CMAKE_MODULE_LINKER_FLAGS你可能想要配置。

用法:

$ cmake \
    -DCMAKE_BUILD_TYPE=Asan \
    ...
    ...

【讨论】:

  • 虽然与其他一些答案相比,这似乎有点复杂,但这似乎是最好的方法。您是否偶然从《专业 CMake》一书中获得此信息?
  • 是的,我从书中采用了这个。
  • 有趣的是,这对我来说适用于 cmake 版本 3.16.3(和 cmake_minimum_required(VERSION 3.9)
【解决方案4】:

cmake 3.13
介绍xcode schema的配置

在 CMake 中

cmake_minimum_required(VERSION 3.13)
set(CMAKE_XCODE_GENERATE_SCHEME ON)
set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER ON)
set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN ON)

构建时

xcodebuild -enableAddressSanitizer YES

【讨论】:

    【解决方案5】:

    首先确保使用调试信息,例如将CMAKE_BUILD_TYPE 设置为Debug

    然后,如果您的目标是可执行文件或共享库,那么您可以设置这些 cmake 变量:

    • CMAKE_EXE_LINKER_FLAGS
    • CMAKE_EXE_LINKER_FLAGS_DEBUG
    • CMAKE_SHARED_LINKER_FLAGS
    • CMAKE_SHARED_LINKER_FLAGS_DEBUG

    即当您的目标是可执行文件时:

    set(CMAKE_BUILD_TYPE "Debug")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
    

    当您的目标是共享库时:

    set(CMAKE_BUILD_TYPE "Debug")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
    

    但是,当您的可执行文件依赖于静态库并且您想使用 asan 来检查您的静态库时,您必须这样设置:

    set(CMAKE_BUILD_TYPE "Debug")
    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
    set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
    

    【讨论】:

      【解决方案6】:

      我目前找到的最简单的解决方案是

      cmake -DCMAKE_BUILD_TYPE=ASAN .
      

      我更喜欢这个选项,因为它表达了意图(运行消毒剂)而不是修改许多标志。

      我不知道这个选项是什么时候添加的。我也找不到任何文档。

      【讨论】:

      • 您使用的是什么版本的 CMake?我在当前的 CMake 源代码中找不到对 ASAN 的任何有意义的引用。
      • 提供的链接@MartinGerhardy 在最顶部说它已经过时了。
      • 这似乎只适用于直接查询构建类型或执行类似this FindASan.cmake script的项目
      • 不适用于我的 cmake 3.18.0 cmake_minimum_required(VERSION 3.15)
      【解决方案7】:

      我发现其他答案都不起作用,你需要在你的工具链文件中设置初始化变量:

      set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address -fno-omit-frame-pointer")
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-09
        • 1970-01-01
        • 2015-05-25
        • 1970-01-01
        相关资源
        最近更新 更多