|
| 1 | +# Provides phlex_apply_optimizations(target), which applies safe, |
| 2 | +# performance-oriented compiler flags to a Phlex shared library target. |
| 3 | +# Also defines the PHLEX_HIDE_SYMBOLS and PHLEX_ENABLE_IPO options and |
| 4 | +# documents how they interact. |
| 5 | +# |
| 6 | +# Two flags are applied (subject to compiler support and platform): |
| 7 | +# |
| 8 | +# -fno-semantic-interposition (GCC >= 9, Clang >= 8) |
| 9 | +# The compiler may assume that exported symbols in this shared library are |
| 10 | +# not overridden at runtime by LD_PRELOAD or another DSO. This is the |
| 11 | +# natural complement of -fvisibility=hidden: once the exported-symbol |
| 12 | +# surface is bounded by explicit export macros, treating those symbols as |
| 13 | +# non-interposable allows the compiler to inline, devirtualise, and |
| 14 | +# generate direct (non-PLT) calls for same-DSO accesses to exported |
| 15 | +# functions. |
| 16 | +# |
| 17 | +# External plugins continue to call Phlex symbols through the standard |
| 18 | +# PLT/GOT mechanism; only code compiled as part of a Phlex shared library |
| 19 | +# itself benefits. |
| 20 | +# |
| 21 | +# Applied only when PHLEX_HIDE_SYMBOLS=ON (export macros are present and |
| 22 | +# the exported-symbol set is well-defined). |
| 23 | +# |
| 24 | +# -fno-plt (GCC >= 7.3, Clang >= 4, ELF platforms) |
| 25 | +# Calls FROM a Phlex library TO symbols in other shared libraries (TBB, |
| 26 | +# Boost, spdlog, ...) bypass the PLT stub and load the target address |
| 27 | +# directly from the GOT. This replaces one level of indirection on every |
| 28 | +# cross-DSO call after first resolution. Semantics are unchanged; only |
| 29 | +# the dispatch mechanism differs. |
| 30 | +# |
| 31 | +# Not applied on Apple platforms: Mach-O uses two-level namespaces and the |
| 32 | +# PLT abstraction does not map directly to ELF semantics. |
| 33 | +# |
| 34 | +# Intentionally excluded: |
| 35 | +# -ffast-math / -funsafe-math-optimizations |
| 36 | +# Physics and numerical code relies on well-defined floating-point |
| 37 | +# semantics (NaN propagation, exact rounding, signed-zero behaviour). |
| 38 | +# These flags may silently produce incorrect numerical results and are |
| 39 | +# therefore not enabled. |
| 40 | +# |
| 41 | +# Options and their interaction with CMAKE_BUILD_TYPE |
| 42 | +# |
| 43 | +# Both PHLEX_HIDE_SYMBOLS and PHLEX_ENABLE_IPO are defined here so that their |
| 44 | +# defaults can be derived together. The effective defaults are: |
| 45 | +# |
| 46 | +# CMAKE_BUILD_TYPE PHLEX_ENABLE_IPO PHLEX_HIDE_SYMBOLS |
| 47 | +# ───────────────── ─────────────── ───────────────── |
| 48 | +# Release ON ON |
| 49 | +# RelWithDebInfo ON ON |
| 50 | +# Debug / sanitizer OFF OFF |
| 51 | +# not set OFF OFF |
| 52 | +# |
| 53 | +# Both options can be overridden independently on the command line: |
| 54 | +# |
| 55 | +# -DPHLEX_HIDE_SYMBOLS=ON -DPHLEX_ENABLE_IPO=ON → LTO + -fno-semantic-interposition |
| 56 | +# (maximum optimization) |
| 57 | +# -DPHLEX_HIDE_SYMBOLS=OFF -DPHLEX_ENABLE_IPO=ON → LTO only; -fno-semantic-interposition |
| 58 | +# is NOT applied (valid, useful for |
| 59 | +# benchmarking against the ON case) |
| 60 | +# -DPHLEX_HIDE_SYMBOLS=ON -DPHLEX_ENABLE_IPO=OFF → -fno-semantic-interposition only |
| 61 | +# -DPHLEX_HIDE_SYMBOLS=OFF -DPHLEX_ENABLE_IPO=OFF → no special optimization flags |
| 62 | +# |
| 63 | +# The per-target flags in phlex_apply_optimizations() self-adjust automatically |
| 64 | +# to reflect whichever combination is in effect. |
| 65 | +# |
| 66 | +# PHLEX_ENABLE_IPO (default ON for Release/RelWithDebInfo, OFF otherwise) |
| 67 | +# When ON, enables interprocedural optimization (LTO) for Release and |
| 68 | +# RelWithDebInfo configurations. LTO is safe with or without symbol hiding |
| 69 | +# because export attributes preserve the complete exported-symbol set. |
| 70 | +# External plugins compiled without LTO link against the normal |
| 71 | +# exported-symbol table and are unaffected. |
| 72 | +# |
| 73 | +# PHLEX_HIDE_SYMBOLS (default ON for Release/RelWithDebInfo, OFF otherwise) |
| 74 | +# When ON: hidden-by-default visibility; export macros mark the public API. |
| 75 | +# When OFF: all symbols visible; _internal targets become thin INTERFACE |
| 76 | +# aliases of their public counterparts. |
| 77 | + |
| 78 | +include_guard() |
| 79 | + |
| 80 | +include(CheckCXXCompilerFlag) |
| 81 | + |
| 82 | +# Probe flag availability once at module-load time (results are cached in the |
| 83 | +# CMake cache and reused across reconfigures). |
| 84 | + |
| 85 | +if(NOT APPLE) |
| 86 | + check_cxx_compiler_flag("-fno-plt" PHLEX_CXX_HAVE_NO_PLT) |
| 87 | + |
| 88 | + # Apple/Clang accepts -fno-semantic-interposition but the Apple toolchain |
| 89 | + # driver treats it as unused for Mach-O builds. |
| 90 | + check_cxx_compiler_flag("-fno-semantic-interposition" PHLEX_CXX_HAVE_NO_SEMANTIC_INTERPOSITION) |
| 91 | +endif() |
| 92 | + |
| 93 | +# --------------------------------------------------------------------------- |
| 94 | +# Interprocedural optimization (LTO) — defined first so its value can inform |
| 95 | +# the PHLEX_HIDE_SYMBOLS default below. |
| 96 | +# --------------------------------------------------------------------------- |
| 97 | +cmake_policy(SET CMP0069 NEW) |
| 98 | +include(CheckIPOSupported) |
| 99 | + |
| 100 | +if(CMAKE_BUILD_TYPE MATCHES "^(Release|RelWithDebInfo)$") |
| 101 | + set(_phlex_ipo_default ON) |
| 102 | +else() |
| 103 | + set(_phlex_ipo_default OFF) |
| 104 | +endif() |
| 105 | + |
| 106 | +option( |
| 107 | + PHLEX_ENABLE_IPO |
| 108 | + [=[Enable interprocedural optimization (LTO) for Release and RelWithDebInfo |
| 109 | +builds. Defaults to ON when CMAKE_BUILD_TYPE is Release or RelWithDebInfo. |
| 110 | +Can be combined with PHLEX_HIDE_SYMBOLS=ON for maximum optimization, or with |
| 111 | +PHLEX_HIDE_SYMBOLS=OFF to benchmark LTO benefit without symbol hiding.]=] |
| 112 | + "${_phlex_ipo_default}" |
| 113 | +) |
| 114 | + |
| 115 | +# --------------------------------------------------------------------------- |
| 116 | +# Symbol hiding — default follows CMAKE_BUILD_TYPE independently of IPO. |
| 117 | +# The two options are orthogonal: both ON/OFF combinations are valid and |
| 118 | +# produce different optimization profiles for benchmarking. |
| 119 | +# --------------------------------------------------------------------------- |
| 120 | +if(CMAKE_BUILD_TYPE MATCHES "^(Release|RelWithDebInfo)$") |
| 121 | + set(_phlex_hide_default ON) |
| 122 | +else() |
| 123 | + set(_phlex_hide_default OFF) |
| 124 | +endif() |
| 125 | + |
| 126 | +option( |
| 127 | + PHLEX_HIDE_SYMBOLS |
| 128 | + [=[Hide non-exported symbols in shared libraries (ON = curated API with |
| 129 | +hidden-by-default visibility; OFF = all symbols visible). Defaults to ON for |
| 130 | +Release/RelWithDebInfo builds. |
| 131 | +When ON, -fno-semantic-interposition is also applied (when supported) because |
| 132 | +the exported-symbol surface is explicitly bounded by export macros. This flag |
| 133 | +is independent of PHLEX_ENABLE_IPO; either option may be set without the other. |
| 134 | +Setting OFF while PHLEX_ENABLE_IPO=ON is valid and useful for comparing LTO |
| 135 | +performance with and without symbol hiding.]=] |
| 136 | + "${_phlex_hide_default}" |
| 137 | +) |
| 138 | + |
| 139 | +# --------------------------------------------------------------------------- |
| 140 | +# Activate LTO (if enabled and supported) |
| 141 | +# --------------------------------------------------------------------------- |
| 142 | +if(PHLEX_ENABLE_IPO) |
| 143 | + check_ipo_supported(RESULT _phlex_ipo_supported OUTPUT _phlex_ipo_output LANGUAGES CXX) |
| 144 | + if(_phlex_ipo_supported) |
| 145 | + # Set defaults for all targets created in this scope and below. The |
| 146 | + # *_RELEASE and *_RELWITHDEBINFO variants leave Debug/Coverage/sanitizer |
| 147 | + # builds unaffected (those configs override optimization independently). |
| 148 | + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) |
| 149 | + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) |
| 150 | + message(STATUS "Phlex: LTO enabled for Release and RelWithDebInfo builds") |
| 151 | + else() |
| 152 | + message(WARNING "Phlex: PHLEX_ENABLE_IPO=ON but LTO is not supported: ${_phlex_ipo_output}") |
| 153 | + endif() |
| 154 | +endif() |
| 155 | + |
| 156 | +# --------------------------------------------------------------------------- |
| 157 | +function(phlex_apply_optimizations target) |
| 158 | + # -fno-semantic-interposition pairs with PHLEX_HIDE_SYMBOLS: the compiler |
| 159 | + # may only treat exported symbols as non-interposable once the exported- |
| 160 | + # symbol surface has been explicitly bounded by export macros. |
| 161 | + if(PHLEX_HIDE_SYMBOLS AND PHLEX_CXX_HAVE_NO_SEMANTIC_INTERPOSITION) |
| 162 | + target_compile_options("${target}" PRIVATE "-fno-semantic-interposition") |
| 163 | + endif() |
| 164 | + |
| 165 | + # -fno-plt reduces cross-DSO call overhead on ELF (Linux) platforms. |
| 166 | + if(PHLEX_CXX_HAVE_NO_PLT) |
| 167 | + target_compile_options("${target}" PRIVATE "-fno-plt") |
| 168 | + endif() |
| 169 | +endfunction() |
0 commit comments