yano
yano

Reputation: 4453

Xcode Address Sanitizer with ccache

I'm trying to use the Address Sanitizer in Xcode, but I'm also using ccache to accelerate my builds. To do this, I've set the CC flag at the Xcode-project-level to point to a script I'm storing at ~/projects/support/cmake/ccache-clang. The script reads

#!/bin/sh
if type -p /usr/local/bin/ccache >/dev/null 2>&1; then
  export CCACHE_CPP2=true
  exec /usr/local/bin/ccache "${DEVELOPER_DIR}/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" "$@"
else
  exec "${DEVELOPER_DIR}/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" "$@"
fi

so the desired effect is achieved (ccache is used if installed on the dev's system). This is working well.

Now the problem comes when we turn on the Address Sanitizer for a given scheme. The build completes successfully, but then we finally see this error when we try to run:

Error: Check dependencies

Could not determine version of clang to find its Address Sanitizer library: ~/projects/support/cmake/ccache-clang

Perhaps this is due to some hacky implementation in Xcode where it tries to parse the compiler's path to determine the version?

Wondering how I can modify my script to allow Address Sanitizer to work. The current work around is to remove the overridden CC flag when we need to do sanitizer work.

Using Xcode 8.3.1

Upvotes: 6

Views: 1681

Answers (2)

Hsilgos
Hsilgos

Reputation: 91

I was able to make it work. Tested with Xcode 14.2 and 15.3

  1. The script ccache-clang must be renamed to clang and clang++ (i.e. clang++ is copy of clang). It seems that Xcode first of all tries to detect compiler's name: clang, gcc, etc., so naming the script like this makes Xcode to decide that this is clang. Also I use CMAKE_XCODE_ATTRIBUTE_ properties to set CC, CXX, etc.:
set(CMAKE_XCODE_ATTRIBUTE_CC         "${CMAKE_BINARY_DIR}/clang")
set(CMAKE_XCODE_ATTRIBUTE_CXX        "${CMAKE_BINARY_DIR}/clang++")
set(CMAKE_XCODE_ATTRIBUTE_LD         "${CMAKE_BINARY_DIR}/clang")
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_BINARY_DIR}/clang++")
  1. Libraries which are necessary for sanitisers must be copied into bin directory during CMake configuration. Something like:
set (_toolchain_root "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain")
# Following libraries are for iOS/Simulator.
# For MacOS it should be libclang_rt.*an_osx*_dynamic.dylib
file (GLOB_RECURSE _asan_libs
      "${_toolchain_root}/*/libclang_rt.*an_ios*_dynamic.dylib")

foreach (_asan_lib IN LISTS _asan_libs)
  file (RELATIVE_PATH _asan_relative_to_toolchain
        "${_toolchain_root}/usr/" "${_asan_lib}")
  configure_file ("${_asan_lib}"
                  "${CMAKE_BINARY_DIR}/../${_asan_relative_to_toolchain}"
                  COPYONLY)
endforeach ()

After this I was able to enable sanitisers from Xcode, compile and run the app.

UPD: The demo project for iOS and MacOS is here https://github.com/Hsilgos/xcode-ccache-demo

Upvotes: 2

user10063119
user10063119

Reputation:

Link the Asan library directly instead of the checking the box in the scheme.

The linker and compiler flags should contain the following.

-fsanitize=address -fno-omit-frame-pointer

If it cannot find the library, find the path to the asan dynamic library which is usually in

${CMAKE_LINKER}/../../lib/clang/version/lib/darwin/libclang_rt.asan_osx_dynamic.dylib

and add it to linker flags.

Upvotes: 2

Related Questions