1#=============================================================================== 2# Define targets for linking against the selected ABI library 3# 4# After including this file, the following targets are defined: 5# - libcxx-abi-headers: An interface target that allows getting access to the 6# headers of the selected ABI library. 7# - libcxx-abi-shared: A target representing the selected shared ABI library. 8# - libcxx-abi-static: A target representing the selected static ABI library. 9# 10# Furthermore, some ABI libraries also define the following target: 11# - libcxx-abi-shared-objects: An object library representing a set of object files 12# constituting the ABI library, suitable for bundling 13# into a shared library. 14# - libcxx-abi-static-objects: An object library representing a set of object files 15# constituting the ABI library, suitable for bundling 16# into a static library. 17#=============================================================================== 18 19include(GNUInstallDirs) 20 21# This function copies the provided headers to a private directory and adds that 22# path to the given INTERFACE target. That target can then be linked against to 23# get access to those headers (and only those). 24# 25# The problem this solves is that when building against a system-provided ABI library, 26# the ABI headers might live side-by-side with an actual C++ Standard Library 27# installation. For that reason, we can't just add `-I <path-to-ABI-headers>`, 28# since we would end up also adding the system-provided C++ Standard Library to 29# the search path. Instead, what we do is copy just the ABI library headers to 30# a private directory and add just that path when we build libc++. 31function(import_private_headers target include_dirs headers) 32 foreach(header ${headers}) 33 set(found FALSE) 34 foreach(incpath ${include_dirs}) 35 if (EXISTS "${incpath}/${header}") 36 set(found TRUE) 37 message(STATUS "Looking for ${header} in ${incpath} - found") 38 get_filename_component(dstdir ${header} PATH) 39 get_filename_component(header_file ${header} NAME) 40 set(src ${incpath}/${header}) 41 set(dst "${LIBCXX_BINARY_DIR}/private-abi-headers/${dstdir}/${header_file}") 42 43 add_custom_command(OUTPUT ${dst} 44 DEPENDS ${src} 45 COMMAND ${CMAKE_COMMAND} -E make_directory "${LIBCXX_BINARY_DIR}/private-abi-headers/${dstdir}" 46 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst} 47 COMMENT "Copying C++ ABI header ${header}") 48 list(APPEND abilib_headers "${dst}") 49 else() 50 message(STATUS "Looking for ${header} in ${incpath} - not found") 51 endif() 52 endforeach() 53 if (NOT found) 54 message(WARNING "Failed to find ${header} in ${include_dirs}") 55 endif() 56 endforeach() 57 58 # Work around https://gitlab.kitware.com/cmake/cmake/-/issues/18399 59 add_library(${target}-generate-private-headers OBJECT ${abilib_headers}) 60 set_target_properties(${target}-generate-private-headers PROPERTIES LINKER_LANGUAGE CXX) 61 62 target_link_libraries(${target} INTERFACE ${target}-generate-private-headers) 63 target_include_directories(${target} INTERFACE "${LIBCXX_BINARY_DIR}/private-abi-headers") 64endfunction() 65 66# This function creates an imported static library named <target>. 67# It imports a library named <name> searched at the given <path>. 68function(import_static_library target path name) 69 add_library(${target} STATIC IMPORTED GLOBAL) 70 find_library(file 71 NAMES "${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX}" 72 PATHS "${path}" 73 NO_CACHE) 74 set_target_properties(${target} PROPERTIES IMPORTED_LOCATION "${file}") 75endfunction() 76 77# This function creates an imported shared (interface) library named <target> 78# for the given library <name>. 79function(import_shared_library target name) 80 add_library(${target} INTERFACE IMPORTED GLOBAL) 81 set_target_properties(${target} PROPERTIES IMPORTED_LIBNAME "${name}") 82endfunction() 83 84# Link against a system-provided libstdc++ 85if ("${LIBCXX_CXX_ABI}" STREQUAL "libstdc++") 86 if(NOT LIBCXX_CXX_ABI_INCLUDE_PATHS) 87 message(FATAL_ERROR "LIBCXX_CXX_ABI_INCLUDE_PATHS must be set when selecting libstdc++ as an ABI library") 88 endif() 89 90 add_library(libcxx-abi-headers INTERFACE) 91 import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}" 92 "cxxabi.h;bits/c++config.h;bits/os_defines.h;bits/cpu_defines.h;bits/cxxabi_tweaks.h;bits/cxxabi_forced.h") 93 target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBSTDCXX" "-D__GLIBCXX__") 94 95 import_shared_library(libcxx-abi-shared stdc++) 96 target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers) 97 98 import_static_library(libcxx-abi-static "${LIBCXX_CXX_ABI_LIBRARY_PATH}" stdc++) 99 target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers) 100 101# Link against a system-provided libsupc++ 102elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libsupc++") 103 if(NOT LIBCXX_CXX_ABI_INCLUDE_PATHS) 104 message(FATAL_ERROR "LIBCXX_CXX_ABI_INCLUDE_PATHS must be set when selecting libsupc++ as an ABI library") 105 endif() 106 107 add_library(libcxx-abi-headers INTERFACE) 108 import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}" 109 "cxxabi.h;bits/c++config.h;bits/os_defines.h;bits/cpu_defines.h;bits/cxxabi_tweaks.h;bits/cxxabi_forced.h") 110 target_compile_definitions(libcxx-abi-headers INTERFACE "-D__GLIBCXX__") 111 112 import_shared_library(libcxx-abi-shared supc++) 113 target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers) 114 115 import_static_library(libcxx-abi-static "${LIBCXX_CXX_ABI_LIBRARY_PATH}" supc++) 116 target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers) 117 118# Link against the in-tree libc++abi 119elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libcxxabi") 120 add_library(libcxx-abi-headers INTERFACE) 121 target_link_libraries(libcxx-abi-headers INTERFACE cxxabi-headers) 122 target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXX_BUILDING_LIBCXXABI") 123 124 if (TARGET cxxabi_shared) 125 add_library(libcxx-abi-shared INTERFACE) 126 target_link_libraries(libcxx-abi-shared INTERFACE cxxabi_shared) 127 128 # When using the in-tree libc++abi as an ABI library, libc++ re-exports the 129 # libc++abi symbols (on platforms where it can) because libc++abi is only an 130 # implementation detail of libc++. 131 target_link_libraries(libcxx-abi-shared INTERFACE cxxabi-reexports) 132 133 # Populate the OUTPUT_NAME property of libcxx-abi-shared because that is used when 134 # generating a linker script. 135 get_target_property(_output_name cxxabi_shared OUTPUT_NAME) 136 set_target_properties(libcxx-abi-shared PROPERTIES "OUTPUT_NAME" "${_output_name}") 137 endif() 138 139 if (TARGET cxxabi_static) 140 add_library(libcxx-abi-static ALIAS cxxabi_static) 141 endif() 142 143 if (TARGET cxxabi_shared_objects) 144 add_library(libcxx-abi-shared-objects ALIAS cxxabi_shared_objects) 145 endif() 146 147 if (TARGET cxxabi_static_objects) 148 add_library(libcxx-abi-static-objects ALIAS cxxabi_static_objects) 149 endif() 150 151# Link against a system-provided libc++abi 152elseif ("${LIBCXX_CXX_ABI}" STREQUAL "system-libcxxabi") 153 if(NOT LIBCXX_CXX_ABI_INCLUDE_PATHS) 154 message(FATAL_ERROR "LIBCXX_CXX_ABI_INCLUDE_PATHS must be set when selecting system-libcxxabi as an ABI library") 155 endif() 156 157 add_library(libcxx-abi-headers INTERFACE) 158 import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}" "cxxabi.h;__cxxabi_config.h") 159 target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXX_BUILDING_LIBCXXABI") 160 161 import_shared_library(libcxx-abi-shared c++abi) 162 target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers) 163 164 import_static_library(libcxx-abi-static "${LIBCXX_CXX_ABI_LIBRARY_PATH}" c++abi) 165 target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers) 166 167# Link against a system-provided libcxxrt 168elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libcxxrt") 169 if(NOT LIBCXX_CXX_ABI_INCLUDE_PATHS) 170 message(STATUS "LIBCXX_CXX_ABI_INCLUDE_PATHS not set, using /usr/include/c++/v1") 171 set(LIBCXX_CXX_ABI_INCLUDE_PATHS "/usr/include/c++/v1") 172 endif() 173 add_library(libcxx-abi-headers INTERFACE) 174 import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}" 175 "cxxabi.h;unwind.h;unwind-arm.h;unwind-itanium.h") 176 target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXXRT") 177 178 import_shared_library(libcxx-abi-shared cxxrt) 179 target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers) 180 181 import_static_library(libcxx-abi-static "${LIBCXX_CXX_ABI_LIBRARY_PATH}" cxxrt) 182 target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers) 183 184# Link against a system-provided vcruntime 185# FIXME: Figure out how to configure the ABI library on Windows. 186elseif ("${LIBCXX_CXX_ABI}" STREQUAL "vcruntime") 187 add_library(libcxx-abi-headers INTERFACE) 188 add_library(libcxx-abi-shared INTERFACE) 189 add_library(libcxx-abi-static INTERFACE) 190 191# Don't link against any ABI library 192elseif ("${LIBCXX_CXX_ABI}" STREQUAL "none") 193 add_library(libcxx-abi-headers INTERFACE) 194 target_compile_definitions(libcxx-abi-headers INTERFACE "-D_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY") 195 196 add_library(libcxx-abi-shared INTERFACE) 197 target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers) 198 199 add_library(libcxx-abi-static INTERFACE) 200 target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers) 201endif() 202