[llvm] [LLVM] Support EXPORT_SYMBOLS_FOR_PLUGINS with shared or dylib builds (PR #191424)
Tomohiro Kashiwada via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 10 07:18:17 PDT 2026
https://github.com/kikairoya created https://github.com/llvm/llvm-project/pull/191424
Resolve the incompatibilities of EXPORT_SYMBOLS_FOR_PLUGINS with `-DBUILD_SHARED_LIBS=ON` or `-DLLVM_LINK_LLVM_DYLIB=ON`:
- Static libraries linked to the target may be empty:
Added a checking if the target link any static libraries.
- `export_executable_symbols` may run before target's dependencies are fully registered:
Defer scanning the target's dependencies to just before finishing CMaking.
>From c9a0dce364c1b72af704600065bfd32fd09b0cd3 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sun, 9 Nov 2025 21:00:27 +0900
Subject: [PATCH 1/3] always specify `.exe.a` for the suffix of import library
needs for LLVM_BUILD_LLVM_DYLIB
---
llvm/cmake/modules/AddLLVM.cmake | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index 0730ba2f529ed..a24afb729a8ba 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -1217,6 +1217,14 @@ macro(add_llvm_executable name)
add_llvm_symbol_exports( ${name} ${LLVM_EXPORTED_SYMBOL_FILE} )
endif(LLVM_EXPORTED_SYMBOL_FILE)
+ # The default import library suffix that cmake uses for cygwin/mingw is
+ # ".dll.a", but for clang.exe that causes a collision with libclang.dll,
+ # where the import libraries of both get named libclang.dll.a. Use a suffix
+ # of ".exe.a" to avoid this.
+ if(CYGWIN OR MINGW)
+ set_target_properties(${name} PROPERTIES IMPORT_SUFFIX ".exe.a")
+ endif()
+
if (DEFINED LLVM_ENABLE_EXPORTED_SYMBOLS_IN_EXECUTABLES AND
NOT LLVM_ENABLE_EXPORTED_SYMBOLS_IN_EXECUTABLES AND
NOT ARG_EXPORT_SYMBOLS)
@@ -1517,13 +1525,6 @@ function(export_executable_symbols target)
# transitive link against only the libraries whose symbols
# we aren't exporting.
set_target_properties(${target} PROPERTIES INTERFACE_LINK_LIBRARIES "${other_libs}")
- # The default import library suffix that cmake uses for cygwin/mingw is
- # ".dll.a", but for clang.exe that causes a collision with libclang.dll,
- # where the import libraries of both get named libclang.dll.a. Use a suffix
- # of ".exe.a" to avoid this.
- if(CYGWIN OR MINGW)
- set_target_properties(${target} PROPERTIES IMPORT_SUFFIX ".exe.a")
- endif()
elseif(NOT (WIN32 OR CYGWIN))
# On Windows auto-exporting everything doesn't work because of the limit on
# the size of the exported symbol table, but on other platforms we can do
>From f646b5ac08aea08d96b224c293e8cefc16291f21 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Wed, 17 Dec 2025 19:02:44 +0900
Subject: [PATCH 2/3] [LLVM] Support EXPORT_SYMBOLS_FOR_PLUGINS with shared or
dylib builds
Resolve the incompatibilities of EXPORT_SYMBOLS_FOR_PLUGINS with
`-DBUILD_SHARED_LIBS=ON` or `-DLLVM_LINK_LLVM_DYLIB=ON`:
- Static libraries linked to the target may be empty:
Added a checking if the target link any static libraries.
- `export_executable_symbols` may run before target's dependencies are fully registered:
Defer scanning the target's dependencies to just before finishing CMaking.
---
llvm/cmake/modules/AddLLVM.cmake | 114 ++++++++++++++++++-------------
1 file changed, 65 insertions(+), 49 deletions(-)
diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index a24afb729a8ba..c283ad8edaa9c 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -1456,52 +1456,44 @@ function(process_llvm_pass_plugins)
endif()
endfunction()
-function(export_executable_symbols target)
- if (LLVM_EXPORTED_SYMBOL_FILE)
- # The symbol file should contain the symbols we want the executable to
- # export
- set_target_properties(${target} PROPERTIES ENABLE_EXPORTS 1)
- elseif (LLVM_EXPORT_SYMBOLS_FOR_PLUGINS)
- # Extract the symbols to export from the static libraries that the
- # executable links against.
- set_target_properties(${target} PROPERTIES ENABLE_EXPORTS 1)
- set(exported_symbol_file ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${target}.symbols)
- # We need to consider not just the direct link dependencies, but also the
- # transitive link dependencies. Do this by starting with the set of direct
- # dependencies, then the dependencies of those dependencies, and so on.
- get_target_property(new_libs ${target} LINK_LIBRARIES)
- set(link_libs ${new_libs})
- while(NOT "${new_libs}" STREQUAL "")
- foreach(lib ${new_libs})
- if(TARGET ${lib})
- # If this is a ALIAS target, continue with its aliasee instead.
- get_target_property(aliased_lib ${lib} ALIASED_TARGET)
- if(aliased_lib)
- set(new_libs ${lib_aliased_target})
- list(APPEND newer_libs ${aliased_lib})
- continue()
- endif()
+function(do_export_executable_symbols_for_plugins target exported_symbol_file)
+ # We need to consider not just the direct link dependencies, but also the
+ # transitive link dependencies. Do this by starting with the set of direct
+ # dependencies, then the dependencies of those dependencies, and so on.
+ get_target_property(new_libs ${target} LINK_LIBRARIES)
+ set(link_libs ${new_libs})
+ while(NOT "${new_libs}" STREQUAL "")
+ foreach(lib ${new_libs})
+ if(TARGET ${lib})
+ # If this is a ALIAS target, continue with its aliasee instead.
+ get_target_property(aliased_lib ${lib} ALIASED_TARGET)
+ if(aliased_lib)
+ set(new_libs ${lib_aliased_target})
+ list(APPEND newer_libs ${aliased_lib})
+ continue()
+ endif()
- get_target_property(lib_type ${lib} TYPE)
- if("${lib_type}" STREQUAL "STATIC_LIBRARY")
- list(APPEND static_libs ${lib})
- else()
- list(APPEND other_libs ${lib})
- endif()
- get_target_property(transitive_libs ${lib} INTERFACE_LINK_LIBRARIES)
- foreach(transitive_lib ${transitive_libs})
- if(TARGET ${transitive_lib} AND NOT ${transitive_lib} IN_LIST link_libs)
- list(APPEND newer_libs ${transitive_lib})
- list(APPEND link_libs ${transitive_lib})
- endif()
- endforeach(transitive_lib)
+ get_target_property(lib_type ${lib} TYPE)
+ if("${lib_type}" STREQUAL "STATIC_LIBRARY")
+ list(APPEND static_libs ${lib})
+ else()
+ list(APPEND other_libs ${lib})
endif()
- endforeach(lib)
- set(new_libs ${newer_libs})
- set(newer_libs "")
- endwhile()
- list(REMOVE_DUPLICATES static_libs)
- if (MSVC)
+ get_target_property(transitive_libs ${lib} INTERFACE_LINK_LIBRARIES)
+ foreach(transitive_lib ${transitive_libs})
+ if(TARGET ${transitive_lib} AND NOT ${transitive_lib} IN_LIST link_libs)
+ list(APPEND newer_libs ${transitive_lib})
+ list(APPEND link_libs ${transitive_lib})
+ endif()
+ endforeach(transitive_lib)
+ endif()
+ endforeach(lib)
+ set(new_libs ${newer_libs})
+ set(newer_libs "")
+ endwhile()
+ list(REMOVE_DUPLICATES static_libs)
+ if(static_libs)
+ if (MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
set(mangling microsoft)
else()
set(mangling itanium)
@@ -1520,11 +1512,35 @@ function(export_executable_symbols target)
${static_libs} ${llvm_nm_target} ${llvm_readobj_target}
VERBATIM
COMMENT "Generating export list for ${target}")
- add_llvm_symbol_exports( ${target} ${exported_symbol_file} )
- # If something links against this executable then we want a
- # transitive link against only the libraries whose symbols
- # we aren't exporting.
- set_target_properties(${target} PROPERTIES INTERFACE_LINK_LIBRARIES "${other_libs}")
+ else()
+ # When shared or dylib builds, static_libs can be empty.
+ file(GENERATE OUTPUT ${exported_symbol_file} CONTENT "")
+ endif()
+ add_llvm_symbol_exports( ${target} ${exported_symbol_file} )
+ # If something links against this executable then we want a
+ # transitive link against only the libraries whose symbols
+ # we aren't exporting.
+ set_target_properties(${target} PROPERTIES INTERFACE_LINK_LIBRARIES "${other_libs}")
+endfunction()
+
+function(export_executable_symbols target)
+ if (LLVM_EXPORTED_SYMBOL_FILE)
+ # The symbol file should contain the symbols we want the executable to
+ # export
+ set_target_properties(${target} PROPERTIES ENABLE_EXPORTS 1)
+ elseif (LLVM_EXPORT_SYMBOLS_FOR_PLUGINS)
+ # Extract the symbols to export from the static libraries that the
+ # executable links against.
+ set_target_properties(${target} PROPERTIES ENABLE_EXPORTS 1)
+ set(exported_symbol_file ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${target}.symbols)
+ # Defer the actual process of exporting since dependants might not
+ # registered yet; e.g. exporting from `clang` is called before
+ # `clang-cpp`(clang-shlib) is registered.
+ cmake_language(EVAL CODE "
+ cmake_language(DEFER DIRECTORY ${CMAKE_SOURCE_DIR}
+ CALL do_export_executable_symbols_for_plugins [[${target}]] [[${exported_symbol_file}]]
+ )
+ ")
elseif(NOT (WIN32 OR CYGWIN))
# On Windows auto-exporting everything doesn't work because of the limit on
# the size of the exported symbol table, but on other platforms we can do
>From 76bc2b763e6784b82d459530c9108560daaa96f0 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Tue, 16 Dec 2025 22:36:50 +0900
Subject: [PATCH 3/3] make export_symbols_for_plugins default if dylib or
shared
---
llvm/cmake/modules/HandleLLVMOptions.cmake | 37 +++++++++++++---------
1 file changed, 22 insertions(+), 15 deletions(-)
diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake b/llvm/cmake/modules/HandleLLVMOptions.cmake
index 5f1d68762c038..ac8da1d4cd0e4 100644
--- a/llvm/cmake/modules/HandleLLVMOptions.cmake
+++ b/llvm/cmake/modules/HandleLLVMOptions.cmake
@@ -1469,13 +1469,6 @@ if(LLVM_ENABLE_FATLTO AND ((UNIX AND NOT APPLE) OR FUCHSIA))
endif()
endif()
-# Set an AIX default for LLVM_EXPORT_SYMBOLS_FOR_PLUGINS based on whether we are
-# doing dynamic linking (see below).
-set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_AIX_default OFF)
-if (NOT (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB))
- set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_AIX_default ON)
-endif()
-
# This option makes utils/extract_symbols.py be used to determine the list of
# symbols to export from LLVM tools. This is necessary when on AIX or when using
# MSVC if you want to allow plugins. On AIX we don't show this option, and we
@@ -1483,19 +1476,33 @@ endif()
# linking (due to incompatibility). With MSVC, note that the plugin has to
# explicitly link against (exactly one) tool so we can't unilaterally turn on
# LLVM_ENABLE_PLUGINS when it's enabled.
+set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_default OFF)
+set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_OPTION ON)
if("${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
+ # Set an AIX default for LLVM_EXPORT_SYMBOLS_FOR_PLUGINS based on whether we are
+ # doing dynamic linking (see above).
+ if(NOT (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB))
+ set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_default ON)
+ endif()
set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_OPTION OFF)
-else()
- set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_OPTION ON)
+elseif(WIN32 OR CYGWIN)
+ # Set a WIN32 default for LLVM_EXPORT_SYMBOLS_FOR_PLUGINS if we are
+ # doing dynamic linking.
+ if(BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB)
+ set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_default ON)
+ endif()
endif()
CMAKE_DEPENDENT_OPTION(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS
"Export symbols from LLVM tools so that plugins can import them" OFF
- "LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_OPTION" ${LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_AIX_default})
-if(BUILD_SHARED_LIBS AND LLVM_EXPORT_SYMBOLS_FOR_PLUGINS)
- message(FATAL_ERROR "BUILD_SHARED_LIBS not compatible with LLVM_EXPORT_SYMBOLS_FOR_PLUGINS")
-endif()
-if(LLVM_LINK_LLVM_DYLIB AND LLVM_EXPORT_SYMBOLS_FOR_PLUGINS)
- message(FATAL_ERROR "LLVM_LINK_LLVM_DYLIB not compatible with LLVM_EXPORT_SYMBOLS_FOR_PLUGINS")
+ "LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_OPTION" ${LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_default})
+
+if (CYGWIN)
+ # CMake sets CMAKE_EXE_EXPORTS_${lang}_FLAG to `-Wl,--export-all-symbols`
+ # for Cygwin. This is incompatible with LLVM_EXPORT_SYMBOLS_FOR_PLUGINS
+ # tweaks, so unset them.
+ set(CMAKE_EXE_EXPORTS_ASM_FLAG "")
+ set(CMAKE_EXE_EXPORTS_C_FLAG "")
+ set(CMAKE_EXE_EXPORTS_CXX_FLAG "")
endif()
# By default we should enable LLVM_ENABLE_IDE only for multi-configuration
More information about the llvm-commits
mailing list