xref: /llvm-project/libcxx/cmake/Modules/HandleLibCXXABI.cmake (revision 21da4e7f51c7adfd0b1c5defc8bd0d16ea1ce759)
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