Skip to content

Commit 59f8796

Browse files
authored
Initial changes for llvm shared library build using explicit visibility annotations
These are my initial build and code changes to supporting building llvm as shared library/DLL on windows(without force exporting all symbols) and making symbol visibility hidden by default on Linux which adding explicit symbol visibility macros to the whole llvm codebase. Updated cmake code to allow building llvm-shlib on windows by appending /WHOLEARCHIVE:lib to the linker options. Remove the hardcoded CMake error from using LLVM_BUILD_LLVM_DYLIB on windows. Updated CMake to define new macros to control conditional export macros in llvm/Support/Compiler.h Use /Zc:dllexportInlines- when compiling with clang-cl on windows with a opt out CMake option to disable using it. Replace some use of LLVM_EXTERNAL_VISIBILITY with new export macros. Some of the cmake and code changes are based on @tstellar's earlier PR #67502. I have Windows building using clang-cl, while for MSVC its at-least able to build libllvm, but some tests can't build because llvm iterator template metaprogramming that doesn't work well with dllexport. Linux should build without issue. My full branch is here https://github.com/fsfod/llvm-project/tree/llvm-export-api-20.0 and including all the auto generated export macros from clang tooling based system.
1 parent fb14941 commit 59f8796

File tree

14 files changed

+180
-39
lines changed

14 files changed

+180
-39
lines changed

llvm/CMakeLists.txt

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
cmake_minimum_required(VERSION 3.20.0)
44

5+
include(CMakeDependentOption)
6+
57
set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
68
include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake
79
NO_POLICY_SCOPE)
@@ -839,20 +841,40 @@ endif()
839841

840842
if(MSVC)
841843
option(LLVM_BUILD_LLVM_C_DYLIB "Build LLVM-C.dll (Windows only)" ON)
842-
# Set this variable to OFF here so it can't be set with a command-line
843-
# argument.
844-
set (LLVM_LINK_LLVM_DYLIB OFF)
845844
if (BUILD_SHARED_LIBS)
846845
message(FATAL_ERROR "BUILD_SHARED_LIBS options is not supported on Windows.")
847846
endif()
848-
else()
849-
option(LLVM_LINK_LLVM_DYLIB "Link tools against the libllvm dynamic library" OFF)
847+
else()
850848
option(LLVM_BUILD_LLVM_C_DYLIB "Build libllvm-c re-export library (Darwin only)" OFF)
851-
set(LLVM_BUILD_LLVM_DYLIB_default OFF)
852-
if(LLVM_LINK_LLVM_DYLIB OR LLVM_BUILD_LLVM_C_DYLIB)
853-
set(LLVM_BUILD_LLVM_DYLIB_default ON)
854-
endif()
855-
option(LLVM_BUILD_LLVM_DYLIB "Build libllvm dynamic library" ${LLVM_BUILD_LLVM_DYLIB_default})
849+
endif()
850+
851+
# Used to test building the llvm shared library with explicit symbol visibility on
852+
# Windows and Linux. For ELF platforms default symbols visibility is set to hidden.
853+
set(LLVM_BUILD_LLVM_DYLIB_VIS FALSE CACHE BOOL "")
854+
mark_as_advanced(LLVM_BUILD_LLVM_DYLIB_VIS)
855+
856+
set(CAN_BUILD_LLVM_DYLIB OFF)
857+
if(NOT MSVC OR LLVM_BUILD_LLVM_DYLIB_VIS)
858+
set(CAN_BUILD_LLVM_DYLIB ON)
859+
endif()
860+
861+
cmake_dependent_option(LLVM_LINK_LLVM_DYLIB "Link tools against the libllvm dynamic library" OFF
862+
"CAN_BUILD_LLVM_DYLIB" OFF)
863+
864+
set(LLVM_BUILD_LLVM_DYLIB_default OFF)
865+
if(LLVM_LINK_LLVM_DYLIB OR LLVM_BUILD_LLVM_C_DYLIB)
866+
set(LLVM_BUILD_LLVM_DYLIB_default ON)
867+
endif()
868+
cmake_dependent_option(LLVM_BUILD_LLVM_DYLIB "Build libllvm dynamic library" ${LLVM_BUILD_LLVM_DYLIB_default}
869+
"CAN_BUILD_LLVM_DYLIB" OFF)
870+
871+
cmake_dependent_option(LLVM_DYLIB_EXPORT_INLINES "Force inline members of classes to be DLL exported when
872+
building with clang-cl so the libllvm DLL is compatible with MSVC"
873+
OFF
874+
"MSVC;LLVM_BUILD_LLVM_DYLIB_VIS" OFF)
875+
876+
if(LLVM_BUILD_LLVM_DYLIB_VIS)
877+
set(LLVM_BUILD_LLVM_DYLIB ON)
856878
endif()
857879

858880
if (LLVM_LINK_LLVM_DYLIB AND BUILD_SHARED_LIBS)

llvm/cmake/modules/AddLLVM.cmake

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,10 @@ function(llvm_add_library name)
606606
endif()
607607
endforeach()
608608
endif()
609+
610+
if(ARG_DISABLE_LLVM_LINK_LLVM_DYLIB)
611+
target_compile_definitions(${obj_name} PRIVATE LLVM_BUILD_STATIC)
612+
endif()
609613
endif()
610614

611615
if(ARG_SHARED AND ARG_STATIC)
@@ -641,8 +645,36 @@ function(llvm_add_library name)
641645
endif()
642646
set_target_properties(${name} PROPERTIES FOLDER "${subproject_title}/Libraries")
643647

648+
## If were compiling with clang-cl use /Zc:dllexportInlines- to exclude inline
649+
## class members from being dllexport'ed to reduce compile time.
650+
## This will also keep us below the 64k exported symbol limit
651+
## https://blog.llvm.org/2018/11/30-faster-windows-builds-with-clang-cl_14.html
652+
if(LLVM_BUILD_LLVM_DYLIB AND NOT LLVM_DYLIB_EXPORT_INLINES AND
653+
MSVC AND CMAKE_CXX_COMPILER_ID MATCHES Clang)
654+
target_compile_options(${name} PUBLIC /Zc:dllexportInlines-)
655+
if(TARGET ${obj_name})
656+
target_compile_options(${obj_name} PUBLIC /Zc:dllexportInlines-)
657+
endif()
658+
endif()
659+
644660
if(ARG_COMPONENT_LIB)
645661
set_target_properties(${name} PROPERTIES LLVM_COMPONENT TRUE)
662+
if(LLVM_BUILD_LLVM_DYLIB OR BUILD_SHARED_LIBS)
663+
target_compile_definitions(${name} PRIVATE LLVM_EXPORTS)
664+
endif()
665+
666+
# When building shared objects for each target there are some internal APIs
667+
# that are used across shared objects which we can't hide.
668+
if (LLVM_BUILD_LLVM_DYLIB_VIS AND NOT BUILD_SHARED_LIBS AND NOT APPLE AND
669+
(NOT (WIN32 OR CYGWIN) OR (MINGW AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND
670+
NOT (${CMAKE_SYSTEM_NAME} MATCHES "AIX") AND
671+
NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
672+
673+
set_target_properties(${name} PROPERTIES
674+
C_VISIBILITY_PRESET hidden
675+
CXX_VISIBILITY_PRESET hidden
676+
VISIBILITY_INLINES_HIDDEN YES)
677+
endif()
646678
set_property(GLOBAL APPEND PROPERTY LLVM_COMPONENT_LIBS ${name})
647679
endif()
648680

@@ -741,6 +773,9 @@ function(llvm_add_library name)
741773
if (LLVM_LINK_LLVM_DYLIB AND NOT ARG_DISABLE_LLVM_LINK_LLVM_DYLIB)
742774
set(llvm_libs LLVM)
743775
else()
776+
if(ARG_DISABLE_LLVM_LINK_LLVM_DYLIB)
777+
target_compile_definitions(${name} PRIVATE LLVM_BUILD_STATIC)
778+
endif()
744779
llvm_map_components_to_libnames(llvm_libs
745780
${ARG_LINK_COMPONENTS}
746781
${LLVM_LINK_COMPONENTS}
@@ -1116,6 +1151,16 @@ macro(add_llvm_executable name)
11161151
if (ARG_EXPORT_SYMBOLS)
11171152
export_executable_symbols(${name})
11181153
endif()
1154+
1155+
if(ARG_DISABLE_LLVM_LINK_LLVM_DYLIB OR NOT LLVM_LINK_LLVM_DYLIB)
1156+
target_compile_definitions(${name} PRIVATE LLVM_BUILD_STATIC)
1157+
endif()
1158+
1159+
if(LLVM_BUILD_LLVM_DYLIB_VIS AND NOT LLVM_DYLIB_EXPORT_INLINES AND
1160+
MSVC AND CMAKE_CXX_COMPILER_ID MATCHES Clang)
1161+
# This has to match how the libraries the executable is linked to are built or there be linker errors.
1162+
target_compile_options(${name} PRIVATE /Zc:dllexportInlines-)
1163+
endif()
11191164
endmacro(add_llvm_executable name)
11201165

11211166
# add_llvm_pass_plugin(name [NO_MODULE] ...)

llvm/cmake/modules/HandleLLVMOptions.cmake

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,12 @@ if (MSVC)
754754
# any code that uses the LLVM_ALIGNAS macro), so this is must be disabled to
755755
# avoid unwanted alignment warnings.
756756
-wd4324 # Suppress 'structure was padded due to __declspec(align())'
757+
# This is triggered for every variable that is a template type of a class even
758+
# if there private when the class is dllexport'ed
759+
-wd4251 # Suppress 'needs to have dll-interface to be used by clients'
760+
# We only putting dll export on classes with out of line members so this
761+
# warning gets triggered a lot for bases we haven't exported'
762+
-wd4275 # non dll-interface class used as base for dll-interface class
757763

758764
# Promoted warnings.
759765
-w14062 # Promote 'enumerator in switch of enum is not handled' to level 1 warning.

llvm/include/llvm/ADT/Any.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
namespace llvm {
2727

28-
class LLVM_EXTERNAL_VISIBILITY Any {
28+
class LLVM_ABI Any {
2929

3030
// The `Typeid<T>::Id` static data member below is a globally unique
3131
// identifier for the type `T`. It is explicitly marked with default

llvm/include/llvm/Analysis/LazyCallGraph.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ class LazyCallGraph {
412412
/// outer structure. SCCs do not support mutation of the call graph, that
413413
/// must be done through the containing \c RefSCC in order to fully reason
414414
/// about the ordering and connections of the graph.
415-
class LLVM_EXTERNAL_VISIBILITY SCC {
415+
class LLVM_ABI SCC {
416416
friend class LazyCallGraph;
417417
friend class LazyCallGraph::Node;
418418

llvm/include/llvm/Analysis/LoopInfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ extern template class LoopBase<BasicBlock, Loop>;
3636

3737
/// Represents a single loop in the control flow graph. Note that not all SCCs
3838
/// in the CFG are necessarily loops.
39-
class LLVM_EXTERNAL_VISIBILITY Loop : public LoopBase<BasicBlock, Loop> {
39+
class LLVM_ABI Loop : public LoopBase<BasicBlock, Loop> {
4040
public:
4141
/// A range representing the start and end location of a loop.
4242
class LocRange {

llvm/include/llvm/Analysis/LoopNestAnalysis.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ using LoopVectorTy = SmallVector<Loop *, 8>;
2525
class LPMUpdater;
2626

2727
/// This class represents a loop nest and can be used to query its properties.
28-
class LLVM_EXTERNAL_VISIBILITY LoopNest {
28+
class LLVM_ABI LoopNest {
2929
public:
3030
using InstrVectorTy = SmallVector<const Instruction *>;
3131

llvm/include/llvm/CodeGen/MachineFunction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ struct LandingPadInfo {
254254
: LandingPadBlock(MBB) {}
255255
};
256256

257-
class LLVM_EXTERNAL_VISIBILITY MachineFunction {
257+
class LLVM_ABI MachineFunction {
258258
Function &F;
259259
const LLVMTargetMachine &Target;
260260
const TargetSubtargetInfo *STI;

llvm/include/llvm/IR/Function.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ class User;
6060
class BranchProbabilityInfo;
6161
class BlockFrequencyInfo;
6262

63-
class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
64-
public ilist_node<Function> {
63+
class LLVM_ABI Function : public GlobalObject, public ilist_node<Function> {
6564
public:
6665
using BasicBlockListType = SymbolTableList<BasicBlock>;
6766

llvm/include/llvm/IR/Module.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class VersionTuple;
6262
/// constant references to global variables in the module. When a global
6363
/// variable is destroyed, it should have no entries in the GlobalList.
6464
/// The main container class for the LLVM Intermediate Representation.
65-
class LLVM_EXTERNAL_VISIBILITY Module {
65+
class LLVM_ABI Module {
6666
/// @name Types And Enumerations
6767
/// @{
6868
public:

llvm/include/llvm/Support/Compiler.h

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@
110110
/// this attribute will be made public and visible outside of any shared library
111111
/// they are linked in to.
112112

113-
#if LLVM_HAS_CPP_ATTRIBUTE(gnu::visibility)
113+
#if LLVM_HAS_CPP_ATTRIBUTE(gnu::visibility) && defined(__GNUC__) && \
114+
!defined(__clang__)
114115
#define LLVM_ATTRIBUTE_VISIBILITY_HIDDEN [[gnu::visibility("hidden")]]
115116
#define LLVM_ATTRIBUTE_VISIBILITY_DEFAULT [[gnu::visibility("default")]]
116117
#elif __has_attribute(visibility)
@@ -121,18 +122,79 @@
121122
#define LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
122123
#endif
123124

124-
125-
#if (!(defined(_WIN32) || defined(__CYGWIN__)) || \
126-
(defined(__MINGW32__) && defined(__clang__)))
127-
#define LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_VISIBILITY_HIDDEN
128125
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
129126
#define LLVM_EXTERNAL_VISIBILITY LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
130127
#else
131128
#define LLVM_EXTERNAL_VISIBILITY
132129
#endif
130+
131+
#if (!(defined(_WIN32) || defined(__CYGWIN__)) || \
132+
(defined(__MINGW32__) && defined(__clang__)))
133+
#define LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_VISIBILITY_HIDDEN
134+
#define LLVM_ALWAYS_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
135+
#elif defined(_WIN32)
136+
#define LLVM_ALWAYS_EXPORT __declspec(dllexport)
137+
#define LLVM_LIBRARY_VISIBILITY
133138
#else
134139
#define LLVM_LIBRARY_VISIBILITY
135-
#define LLVM_EXTERNAL_VISIBILITY
140+
#define LLVM_ALWAYS_EXPORT
141+
#endif
142+
143+
/// LLVM_ABI is the main export/visibility macro to mark something as explicitly
144+
/// exported when llvm is built as a shared library with everything else that is
145+
/// unannotated will have internal visibility.
146+
///
147+
/// LLVM_EXPORT_TEMPLATE is used on explicit template instantiations in source
148+
/// files that were declared extern in a header. This macro is only set as a
149+
/// compiler export attribute on windows, on other platforms it does nothing.
150+
///
151+
/// LLVM_TEMPLATE_ABI is for annotating extern template declarations in headers
152+
/// for both functions and classes. On windows its turned in to dllimport for
153+
/// library consumers, for other platforms its a default visibility attribute.
154+
///
155+
/// LLVM_C_ABI is used to annotated functions and data that need to be exported
156+
/// for the libllvm-c API. This used both for the llvm-c headers and for the
157+
/// functions declared in the different Target's c++ source files that don't
158+
/// include the header forward declaring them.
159+
#ifndef LLVM_ABI_GENERATING_ANNOTATIONS
160+
// Marker to add to classes or functions in public headers that should not have
161+
// export macros added to them by the clang tool
162+
#define LLVM_ABI_NOT_EXPORTED
163+
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS) || \
164+
defined(LLVM_ENABLE_PLUGINS)
165+
// Some libraries like those for tablegen are linked in to tools that used
166+
// in the build so can't depend on the llvm shared library. If export macros
167+
// were left enabled when building these we would get duplicate or
168+
// missing symbol linker errors on windows.
169+
#if defined(LLVM_BUILD_STATIC)
170+
#define LLVM_ABI
171+
#define LLVM_TEMPLATE_ABI
172+
#define LLVM_EXPORT_TEMPLATE
173+
#elif defined(_WIN32) && !defined(__MINGW32__)
174+
#if defined(LLVM_EXPORTS)
175+
#define LLVM_ABI __declspec(dllexport)
176+
#define LLVM_TEMPLATE_ABI
177+
#define LLVM_EXPORT_TEMPLATE __declspec(dllexport)
178+
#else
179+
#define LLVM_ABI __declspec(dllimport)
180+
#define LLVM_TEMPLATE_ABI __declspec(dllimport)
181+
#define LLVM_EXPORT_TEMPLATE
182+
#endif
183+
#elif defined(__ELF__) || defined(__MINGW32__)
184+
#define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
185+
#define LLVM_TEMPLATE_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
186+
#define LLVM_EXPORT_TEMPLATE
187+
#elif defined(__MACH__) || defined(__WASM__)
188+
#define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
189+
#define LLVM_TEMPLATE_ABI
190+
#define LLVM_EXPORT_TEMPLATE
191+
#endif
192+
#else
193+
#define LLVM_ABI
194+
#define LLVM_TEMPLATE_ABI
195+
#define LLVM_EXPORT_TEMPLATE
196+
#endif
197+
#define LLVM_C_ABI LLVM_ABI
136198
#endif
137199

138200
#if defined(__GNUC__)

llvm/tools/llvm-shlib/CMakeLists.txt

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ if(LLVM_LINK_LLVM_DYLIB AND LLVM_DYLIB_EXPORTED_SYMBOL_FILE)
1111
endif()
1212

1313
if(LLVM_BUILD_LLVM_DYLIB)
14-
if(MSVC)
14+
if(MSVC AND NOT LLVM_BUILD_LLVM_DYLIB_VIS)
1515
message(FATAL_ERROR "Generating libLLVM is not supported on MSVC")
1616
endif()
1717
if(ZOS)
@@ -49,18 +49,25 @@ if(LLVM_BUILD_LLVM_DYLIB)
4949
${CMAKE_CURRENT_SOURCE_DIR}/simple_version_script.map.in
5050
${LLVM_LIBRARY_DIR}/tools/llvm-shlib/simple_version_script.map)
5151

52-
# GNU ld doesn't resolve symbols in the version script.
53-
set(LIB_NAMES -Wl,--whole-archive ${LIB_NAMES} -Wl,--no-whole-archive)
54-
if (NOT LLVM_LINKER_IS_SOLARISLD AND NOT MINGW)
55-
# Solaris ld does not accept global: *; so there is no way to version *all* global symbols
56-
set(LIB_NAMES -Wl,--version-script,${LLVM_LIBRARY_DIR}/tools/llvm-shlib/simple_version_script.map ${LIB_NAMES})
57-
endif()
58-
if (NOT MINGW AND NOT LLVM_LINKER_IS_SOLARISLD_ILLUMOS)
59-
# Optimize function calls for default visibility definitions to avoid PLT and
60-
# reduce dynamic relocations.
61-
# Note: for -fno-pic default, the address of a function may be different from
62-
# inside and outside libLLVM.so.
63-
target_link_options(LLVM PRIVATE LINKER:-Bsymbolic-functions)
52+
if(MSVC)
53+
target_link_directories(LLVM PRIVATE ${LLVM_LIBRARY_DIR})
54+
foreach(library ${LIB_NAMES})
55+
target_link_options(LLVM PRIVATE /WHOLEARCHIVE:${library}.lib)
56+
endforeach()
57+
else()
58+
# GNU ld doesn't resolve symbols in the version script.
59+
set(LIB_NAMES -Wl,--whole-archive ${LIB_NAMES} -Wl,--no-whole-archive)
60+
if (NOT LLVM_LINKER_IS_SOLARISLD AND NOT MINGW)
61+
# Solaris ld does not accept global: *; so there is no way to version *all* global symbols
62+
set(LIB_NAMES -Wl,--version-script,${LLVM_LIBRARY_DIR}/tools/llvm-shlib/simple_version_script.map ${LIB_NAMES})
63+
endif()
64+
if (NOT MINGW AND NOT LLVM_LINKER_IS_SOLARISLD_ILLUMOS)
65+
# Optimize function calls for default visibility definitions to avoid PLT and
66+
# reduce dynamic relocations.
67+
# Note: for -fno-pic default, the address of a function may be different from
68+
# inside and outside libLLVM.so.
69+
target_link_options(LLVM PRIVATE LINKER:-Bsymbolic-functions)
70+
endif()
6471
endif()
6572
endif()
6673

llvm/utils/TableGen/Basic/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ set(LLVM_LINK_COMPONENTS
88
TableGen
99
)
1010

11-
add_llvm_library(LLVMTableGenBasic OBJECT EXCLUDE_FROM_ALL
11+
add_llvm_library(LLVMTableGenBasic OBJECT EXCLUDE_FROM_ALL DISABLE_LLVM_LINK_LLVM_DYLIB
1212
CodeGenIntrinsics.cpp
1313
SDNodeProperties.cpp
1414
)

llvm/utils/TableGen/Common/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ set(LLVM_LINK_COMPONENTS
1010
TableGen
1111
)
1212

13-
add_llvm_library(LLVMTableGenCommon STATIC OBJECT EXCLUDE_FROM_ALL
13+
add_llvm_library(LLVMTableGenCommon STATIC OBJECT EXCLUDE_FROM_ALL DISABLE_LLVM_LINK_LLVM_DYLIB
1414
GlobalISel/CodeExpander.cpp
1515
GlobalISel/CombinerUtils.cpp
1616
GlobalISel/CXXPredicates.cpp

0 commit comments

Comments
 (0)