Как правильно включить AddressSanitizer в CMake, который работает в Xcode
Я добавил флаг AddressSanitizer следующим образом:
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
Все строит и работает нормально при использовании Unix Makefiles
,
Проблема возникает при создании проекта Xcode, он просто не хочет связываться, потому что не может найти библиотеку ASan.
Я уже нашел два решения, но решил не использовать их, потому что они не могут быть автоматизированы с помощью только CMake:
- Добавление
-Wl,-undefined,dynamic_lookup
на связанные флаги, поэтому он пропускает ссылки на динамические библиотеки. - Связать с
libclang_rt.asan_osx_dynamic.dylib
непосредственно.
Так в чем же проблема с этими двумя решениями?
- При использовании решения № 1, я должен вручную открыть целевую схему в XCode и добавить
DYLD_INSERT_LIBRARIES
переменная окружения, указывающая наlibclang_rt.asan_osx_dynamic.dylib
, - При использовании решения № 2 путь к библиотеке ASan варьируется между компьютерами.
Кроме того, в качестве другого решения я попытался включить флаг Address Sanitizer из целевой схемы XCode, но, что интересно, он не обнаружил добавленные мной проблемы, поэтому я не перечислил это как решение, потому что он не прошел мой тест.
Любая помощь будет высоко ценится.
7 ответов
Поскольку ответ с наибольшим количеством голосов - это неправильный способ сделать это в наши дни, и я не получил подходящего решения cmake для этого чтения этой темы, я подумал, что упомяну правильный способ во время написания этого, чтобы следующий читатель сделал не нужно тратить много времени на это. Надеюсь, поможет.
Идея этого решения состоит в том, чтобы пройти
-fsanitize=address
к флагам компилятора и компоновщика.
Если вы хотите включить это для всех ваших целей одновременно, вы можете использовать add_compile_options и add_link_options. Это имеет смысл, если у вас есть несколько, потенциально большое количество целей.
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
Кроме того, вы также можете использовать target_compile_options и target_link_options , чтобы установить их для конкретной цели. Это может иметь больше смысла, если вы не хотите, чтобы это применялось ко всем целям.
target_compile_options(asan-target PRIVATE -fsanitize=address)
target_link_options(asan-target PRIVATE -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")
Предлагаю создать свой Асан профиль.
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)
Ноты:
AddressSanitizer (ASan) для Windows с MSVC находится на экспериментальной стадии, поэтому я не приводил здесь способ MSVC.
CMAKE_BUILD_TYPE
не используется генераторами с несколькими конфигурациями (Xcode, Visual Studio и т. д.), поэтому я предоставил пример для первой проверки.Значение по умолчанию для
CMAKE_BUILD_TYPE
это пустая строка. И пользователь может установитьCMAKE_BUILD_TYPE
на любое значение в командной строке cmake. Поэтому мы проверяем оба случая и убеждаемся, что имеем дело с известным типом сборки (если он предусмотрен).Есть также
CMAKE_MODULE_LINKER_FLAGS
вы можете захотеть настроить.
Применение:
$ cmake \
-DCMAKE_BUILD_TYPE=Asan \
...
...
cmake 3.13
представить конфигурацию для схемы xcode
в 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
Сначала проверьте информацию об отладке, например настройку
CMAKE_BUILD_TYPE
к
Debug
.
Затем, установив одну из этих переменных, у меня это сработает:
CMAKE_EXE_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS_DEBUG
CMAKE_SHARED_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS_DEBUG
Взять
CMAKE_EXE_LINKER_FLAGS
например:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
Самое простое решение, которое я сейчас нашел, это
cmake -DCMAKE_BUILD_TYPE=ASAN .
Я предпочитаю эту опцию, так как она выражает намерение (запуск дезинфицирующих средств), а не изменяет ряд флагов.
Я не знаю, когда эта опция была добавлена. Я также не могу найти какую-либо документацию к нему.
Я обнаружил, что другие ответы не сработали, вам нужно установить переменные инициализации в файле цепочки инструментов:
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address -fno-omit-frame-pointer")