Last active
July 15, 2025 11:24
-
-
Save hoyhoy/dc46c8edbf442fd51f44e51d542d185c to your computer and use it in GitHub Desktop.
Compiler Address Sanitizer, Memory Sanitizer, Thread Sanitizer and Ccache Using Jinja2-enabled profiles with Conan 2.0.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {# █████████████████████████████████████████████████████████████████ #} | |
| {# █ @hoyhoy - 1/12/2024 █ #} | |
| {# █████████████████████████████████████████████████████████████████ #} | |
| {# █ Jinja2 Profile Example to Auto-generate Compiler Sanitizer █ #} | |
| {# █ Flags for a custom llvm build on MacOS and Linux █ #} | |
| {# █████████████████████████████████████████████████████████████████ #} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {# █ $CONAN_HOME/profiles/common/clang_local.j2 █ #} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {% set compiler.name = "clang" %} | |
| {% set compiler.version = detect_api.detect_compiler()[1].major %} | |
| {% set llvm_root = "/usr/local" %} | |
| {% set ccache_bin = "/opt/ccache/bin" %} | |
| {% set llvm_bin = llvm_root ~ "/bin" %} | |
| {% set llvm_lib = llvm_root ~ "/lib" %} | |
| {% set llvm_system = platform.system().lower() %} | |
| {% set compiler.system = llvm_system %} | |
| {% set compiler.llvm_root = llvm_root %} | |
| {% set compiler.llvm_bin = llvm_root ~ "bin" %} | |
| {% set compiler.lib_dir = llvm_lib %} | |
| {% set compiler.include_dir = llvm_root ~ "/include" %} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {# █ The only reason these ccaache symlinks are necessary is █ #} | |
| {# █ because conan2 doesn't support adding a compiler launcher █ #} | |
| {# █ to the CMakeToolChain() directly. I suggest adding these. █ #} | |
| {# █ to conan3. (NOTE: THESE SETTINGS DO NOT EXIST BUT THEY SHOULD! █ #} | |
| {# █ █ #} | |
| {# █ - tools.build:compiler_executables.cmake_cxx_compiler_launcher █ #} | |
| {# █ - tools.build:compiler_executables.cmake_c_compiler_launcher █ #} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {# █ $CMAKE_MODULE_PATH/ccache.cmake █ #} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {# █ A CMakeLists.txt as a Jinja2 comment? Sure why not? █ #} | |
| {# █ This is how to auto-detect ccache using cmake! █ #} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {# #} | |
| {# include_guard(GLOBAL) #} | |
| {# if (NOT "$ENV{CCACHE_DISABLE}" STREQUAL "1") #} | |
| {# find_program(CCACHE_PROGRAM ccache) #} | |
| {# if (CCACHE_PROGRAM) #} | |
| {# set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") #} | |
| {# set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") #} | |
| {# endif () #} | |
| {# endif () #} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {# █ $CONAN_HOME/profiles/common/clang_local.j2 (continues...) █ #} | |
| {# ██████████████████████████████████████████████████████████████████ #} | |
| {% set compiler.cc = ccache_bin ~ "/clang" %} | |
| {% set compiler.cxx = ccache_bin ~ "/clang++" %} | |
| {% set compiler.cc = llvm_bin ~ "/clang" %} | |
| {% set compiler.cxx = llvm_bin ~ "/clang++" %} | |
| {% set compiler.ld = llvm_bin ~ "/lld" %} | |
| {% set compiler.ar = llvm_bin ~ "/llvm-ar" %} | |
| {% set compiler.as = llvm_bin ~ "/llvm-as" %} | |
| {% set compiler.nm = llvm_bin ~ "/llvm-nm" %} | |
| {% set compiler.ranlib = llvm_bin ~ "/llvm-ranlib" %} | |
| {% set compiler.symbolizer = llvm_bin ~ "/llvm-symbolizer" %} | |
| {% set compiler.cppstd = "17" %} | |
| {% set compiler.definitions = [ "_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION" ] %} | |
| {% set compiler.ldflags = [ "-L" ~ llvm_lib, "-fuse-ld=lld", "-Wl,-rpath," ~ llvm_lib ] %} | |
| {% set compiler.flags = [] %} | |
| {% set compiler.address_sanitizer = { | |
| flags: [ | |
| "-fsanitize=address", | |
| "-fsanitize-address-use-after-scope", | |
| "-fsanitize-address-use-after-return=always" | |
| ], | |
| ldflags: [ "-fsanitize=address", ] | |
| } | |
| %} | |
| {% set compiler.thread_sanitizer = { | |
| flags: [ | |
| "-fsanitize=address" | |
| ], | |
| ldflags: [ "-fsanitize=thread" ] | |
| } | |
| %} | |
| {% set compiler.memory_sanitizer = { | |
| flags: [ | |
| "-fsanitize=mmory" | |
| ], | |
| ldflags: [ "-fsanitize=memory" ] | |
| } | |
| %} | |
| {% set compiler.debug_flags = [ "-g", "-glldb", "-gcolumn-info" ] %} | |
| {% set compiler.disabled_warnings = [ "-Wno-everything" ] %} | |
| {% set _ = profile.settings.update({ | |
| "compiler": compiler.name, | |
| "compiler.libcxx": "libc++", | |
| "compiler.cppstd": compiler.cppstd, | |
| "compiler.version": compiler.version, | |
| "compiler.warnings": "All", | |
| "compiler.warnings_as_errors": True | |
| }) | |
| %} | |
| {% set compiler.dependency_options = { | |
| "flags": compiler.flags + compiler.disabled_warnings | |
| } | |
| %} | |
| {% if build_type == "Debug" %} | |
| {% set _ = compiler.dependency_options["flags"].append(compiler.debug_flags) %} | |
| {% if compiler.sanitizer == "address" %} | |
| {% set _ = compiler.dependency_options.flags.append(compiler.address_sanitizer["compiler_flags"]) %} | |
| {% set _ = compiler.ldflags.extend(compiler.dependency_options["flags"]) %} | |
| {% elif compiler.sanitizer == "memory" %} | |
| {% set _ = compiler.dependency_options.flags.append(compiler.memory_sanitizer["compiler_flags"]) %} | |
| {% set _ = compiler.ldflags.extend(compiler.dependency_options["flags"]) %} | |
| {% elif compiler.sanitizer == "thread" %} | |
| {% set _ = compiler.dependency_options.flags.append(compiler.memory_sanitizer["compiler_flags"]) %} | |
| {% set _ = compiler.ldflags.extend(compiler.dependency_options["flags"]) %} | |
| {% endif %} | |
| {% endif %} | |
| {% set compiler.optimized_flags = ["-O3", "-march=native", "-funroll-loops", "-finline-functions", "-mtune=native" ] %} | |
| {% set _ = profile.build_configuration.update({ | |
| "tools.build:compiler_executables": { "c" : compiler.cc, "cpp": compiler.cxx }, | |
| "tools.build:defines": compiler.definitions, | |
| "tools.build:exelinkflags": compiler.ldflags, | |
| "tools.build:compiler_executables": { "c" : compiler.cc, "cpp": compiler.cxx }, | |
| "tools.build:cflags": compiler.dependency_options["flags"] + compiler.optimized_flags, | |
| "tools.build:cxxflags": compiler.dependency_options["flags"] + compiler.optimized_flags, | |
| "tools.build:defines": compiler.definitions, | |
| "myapp/*:tools.build:cflags": compiler.flags, | |
| "myapp/*:tools.build:cxxflags": compiler.flags, | |
| "tools.build:exelinkflags": compiler.ldflags | |
| }) | |
| %} | |
| {% set _ = profile.build_configuration.update({ | |
| "tools.build:compiler_executables": { "c" : compiler.cc, "cpp": compiler.cxx }, | |
| "tools.build:defines": compiler.definitions, | |
| "tools.build:exelinkflags": compiler.ldflags | |
| }) | |
| %} | |
| {% set _ = profile.configuration.update({ | |
| "tools.build:compiler_executables": { "c" : compiler.cc, "cpp": compiler.cxx }, | |
| "tools.build:cflags": compiler.dependency_options["flags"], | |
| "tools.build:cxxflags": compiler.dependency_options["flags"], | |
| "tools.build:defines": compiler.definitions, | |
| "myapp/*:tools.build:cflags": compiler.flags, | |
| "myapp/*:tools.build:cxxflags": compiler.flags, | |
| "tools.build:exelinkflags": compiler.ldflags | |
| }) | |
| %} | |
| {% set _ = profile.environment.update({ | |
| "CPATH": compiler.include_dir, | |
| "CC": compiler.cc, | |
| "CXX": compiler.cxx, | |
| "LD": compiler.ld, | |
| "AS": compiler.as, | |
| "AR": compiler.ar, | |
| "NM": compiler.nm, | |
| "RANLIB": compiler.ranlib, | |
| "LINKER": compiler.ld, | |
| "LLVM_DIR": compiler.llvm_root, | |
| "LLVM_PATH": compiler.llvm_bin, | |
| "LD_LIBRARY_PATH": compiler.libpath, | |
| "LIBPATH": compiler.libpath, | |
| "FIPSLD_CC": compiler.cc, | |
| "FIPSLD_CXX": compiler.cxx, | |
| "FIPS_LD": compiler.ld, | |
| "FIPS_CXXLD": compiler.ld, | |
| "ASAN_SYMBOLIZER_PATH": compiler.symbolizer, | |
| "MSAN_SYMBOLIZER_PATH": compiler.symbolizer, | |
| "TSAN_SYMBOLIZER_PATH": compiler.symbolizer | |
| }) | |
| %} | |
| {# I then include clang_local.j2 into my default host profile.... #} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {# █ CONAN_HOME/profiles/default █ #} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {% with | |
| profile = namespace( | |
| build_type = "Debug", | |
| settings = {}, | |
| options = {}, | |
| devtest_mode = {}, | |
| sanitizer = None, | |
| configuration = {}, | |
| build_configuration = {}, | |
| environment = {}), | |
| os = namespace(), | |
| compiler = namespace() | |
| %} | |
| {% include "common/native.j2" %} | |
| {% include "common/clang_local.j2" %} | |
| {% include "common/dependencies.j2" %} | |
| {% include "common/boost.j2" %} | |
| [settings] | |
| build_type={{profile.build_type}} | |
| {% for s,value in profile.settings.items() %} | |
| {{s}}={{value}} | |
| {% endfor %} | |
| [options] | |
| {% for option,value in profile.options.items() -%} | |
| {{option}}={{value}} | |
| {% endfor %} | |
| tools.cmake.cmake_layout:build_folder_vars=["settings.build_type"] | |
| [conf] | |
| {% for option,value in profile.configuration.items() -%} | |
| {{option}}={{value}} | |
| {% endfor %} | |
| [buildenv] | |
| {% for option,value in profile.environment.items() -%} | |
| {{option}}={{value}} | |
| {% endfor %} | |
| b2/*:CXXFLAGS={{compiler.optimized_flags ~ " " ~ " ".join(compiler.ldflags) }} | |
| {% endwith %} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {# █ $CONAN_HOME/profiles/native.j2 █ #} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {# █ Automatically generate os, and os version █ #} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {% set current_os = detect_api.detect_os() %} | |
| {% set _ = profile.settings.update({ | |
| "os": current_os, | |
| "arch": platform.machine() | |
| }) | |
| %} | |
| {% if current_os == "Macos" %} | |
| {# why isn't a function to emit the version string built-in to conan2? #} | |
| {% set _ = profile.settings.update({ | |
| "os.version": ".".join(platform.mac_ver()[0].split(".")[0:2]) | |
| }) | |
| %} | |
| {% endif %} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {# █ $CONAN_HOME/profiles/common/boost.j2 █ #} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {# █ Boost has so many flags, it gets its own include file! █ #} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {% set _ = profile.options.update({ | |
| "boost/*:extra_b2_flags": "cxxflags=-Wno-everything cxxflags=-D_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION", | |
| "boost/*:without_thread": False, | |
| "boost/*:without_log": False, | |
| "boost/*:without_locale": False, | |
| "boost/*:without_random": False, | |
| "boost/*:without_date_time": False, | |
| "boost/*:without_container": False, | |
| "boost/*:without_regex": False, | |
| "boost/*:without_filesystem": False, | |
| "boost/*:without_math": False, | |
| "boost/*:without_atomic": False, | |
| "boost/*:without_chrono": False, | |
| "boost/*:without_exception": False, | |
| "boost/*:without_system": False, | |
| "boost/*:without_context": True, | |
| "boost/*:without_contract": True, | |
| "boost/*:without_coroutine": True, | |
| "boost/*:without_fiber": True, | |
| "boost/*:without_graph": True, | |
| "boost/*:without_graph_parallel": True, | |
| "boost/*:without_iostreams": True, | |
| "boost/*:without_json": True, | |
| "boost/*:without_mpi": True, | |
| "boost/*:without_nowide": True, | |
| "boost/*:without_program_options": True, | |
| "boost/*:without_python": True, | |
| "boost/*:without_serialization": True, | |
| "boost/*:without_stacktrace": True, | |
| "boost/*:without_test": True, | |
| "boost/*:without_timer": True, | |
| "boost/*:without_type_erasure": True, | |
| "boost/*:without_wave": True, | |
| "boost/*:without_url": True, | |
| "boost/*:shared": False, | |
| "boost/*:i18n_backend_icu": True, | |
| "boost/*:i18n_backend_iconv": "off", | |
| "boost/*:bzip2": False | |
| }) | |
| %} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {# █ $CONAN_HOME/profiles/common/dependencies.j2 █ #} | |
| {# ██████████████████████████████████████████████████████████████ #} | |
| {% set _ = profile.options.update({ | |
| "icu/*:shared": False, | |
| "*:fPIC": True, | |
| "libxml2/*:include_utils": True, | |
| "libxml2/*:shared": False, | |
| "libxml2/*:iconv": False, | |
| "libxml2/*:icu": False, | |
| "hiredis/*:with_ssl": True, | |
| "azure-storage-cpp/*:shared": False, | |
| "cpprestsdk/*:shared": False, | |
| "openssl/*:no_ssl3": True, | |
| "openssl/*:no_rc5": True, | |
| "openssl/*:shared": False, | |
| "openssl/*:no_zlib": True, | |
| "openssl/*:no_fips": False | |
| }) | |
| %} | |
| {# Custom options per-os! #} | |
| {% set current_os = detect_api.detect_os() %} | |
| {% if current_os == "Windows" %} | |
| {% set _ = profile.options.update({ | |
| "cpprestsdk/*:http_client_impl": "asio", | |
| "cpprestsdk/*:http_listener_impl": "asio" | |
| }) %} | |
| {% endif %} |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Didn’t seem to matter for ASAN with all of our dependencies and we have quite a few.
Our app’s
CMakelists.txtdoes setCMAKE_SHARED_LINKER_FLAGSoutside of conan, but not for sanitization purposes.The regular ldflags are applied to the shared libraries as well. IIRC,
CMAKE_SHARED_LINKER_FLAGSis just added on top of the regularLDFLAGSfor shared libraries. I don’t think Gnu Make even has an environment variable for this.