Skip to content

Commit

Permalink
Update llvm::Registry to work for LLVM shared library builds on windo…
Browse files Browse the repository at this point in the history
…ws (llvm#109024)

This is part of the effort to support for enabling plugins on windows by
adding better support for building llvm and clang as a DLL.

Since windows doesn't implicitly import and merge exported symbols
across shared libraries like other platforms we need to explicitly add a
extern template declaration for each instantiation of llvm::Registry to
force the registry symbols to be dllimport'ed.
I've added a new visibility macro that doesn't switch between dllimport
and dllexport on windows since the existing macro would be in the wrong
mode for llvm::Registry's declared in Clang. This PR also depends Clang
symbol visibility macros that will be added by llvm#108276

---------

Co-authored-by: Saleem Abdulrasool <compnerd@compnerd.org>
  • Loading branch information
fsfod and compnerd authored Oct 16, 2024
1 parent 3860e29 commit 00cd1a0
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 30 deletions.
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/ParsedAttrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Support/Compiler.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Registry.h"
#include <climits>
Expand Down Expand Up @@ -175,4 +176,8 @@ const std::list<std::unique_ptr<ParsedAttrInfo>> &getAttributePluginInstances();

} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI Registry<clang::ParsedAttrInfo>;
} // namespace llvm

#endif // LLVM_CLANG_BASIC_PARSEDATTRINFO_H
5 changes: 5 additions & 0 deletions clang/include/clang/Frontend/FrontendPluginRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H

#include "clang/Frontend/FrontendAction.h"
#include "clang/Support/Compiler.h"
#include "llvm/Support/Registry.h"

namespace clang {
Expand All @@ -23,4 +24,8 @@ using FrontendPluginRegistry = llvm::Registry<PluginASTAction>;

} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI Registry<clang::PluginASTAction>;
} // namespace llvm

#endif // LLVM_CLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H
5 changes: 5 additions & 0 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "clang/Lex/PPEmbedParameters.h"
#include "clang/Lex/Token.h"
#include "clang/Lex/TokenLexer.h"
#include "clang/Support/Compiler.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
Expand Down Expand Up @@ -3060,4 +3061,8 @@ using PragmaHandlerRegistry = llvm::Registry<PragmaHandler>;

} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI Registry<clang::PragmaHandler>;
} // namespace llvm

#endif // LLVM_CLANG_LEX_PREPROCESSOR_H
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
#define LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H

#include "clang/Support/Compiler.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/Support/Registry.h"

Expand Down Expand Up @@ -42,4 +43,9 @@ using CompilationDatabasePluginRegistry =
} // namespace tooling
} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI
Registry<clang::tooling::CompilationDatabasePlugin>;
} // namespace llvm

#endif // LLVM_CLANG_TOOLING_COMPILATIONDATABASEPLUGINREGISTRY_H
6 changes: 6 additions & 0 deletions clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
#define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H

#include "clang/Support/Compiler.h"
#include "clang/Tooling/Execution.h"
#include "llvm/Support/Registry.h"

Expand All @@ -20,4 +21,9 @@ using ToolExecutorPluginRegistry = llvm::Registry<ToolExecutorPlugin>;
} // namespace tooling
} // namespace clang

namespace llvm {
extern template class CLANG_TEMPLATE_ABI
Registry<clang::tooling::ToolExecutorPlugin>;
} // namespace llvm

#endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/GCMetadataPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class StackMaps;
/// defaults from Registry.
using GCMetadataPrinterRegistry = Registry<GCMetadataPrinter>;

extern template class LLVM_TEMPLATE_ABI Registry<GCMetadataPrinter>;

/// GCMetadataPrinter - Emits GC metadata as assembly code. Instances are
/// created, managed, and owned by the AsmPrinter.
class GCMetadataPrinter {
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/IR/GCStrategy.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ class GCStrategy {
/// GCMetadataPrinterRegistery as well.
using GCRegistry = Registry<GCStrategy>;

extern template class LLVM_TEMPLATE_ABI Registry<GCStrategy>;

/// Lookup the GCStrategy object associated with the given gc name.
std::unique_ptr<GCStrategy> getGCStrategy(const StringRef Name);

Expand Down
11 changes: 11 additions & 0 deletions llvm/include/llvm/Support/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@
/// exported when llvm is built as a shared library with everything else that is
/// unannotated will have internal visibility.
///
/// LLVM_ABI_EXPORT is for the special case for things like plugin symbol
/// declarations or definitions where we don't want the macro to be switching
/// between dllexport and dllimport on windows based on what codebase is being
/// built, it will only be dllexport. For non windows platforms this macro
/// behaves the same as LLVM_ABI.
///
/// LLVM_EXPORT_TEMPLATE is used on explicit template instantiations in source
/// files that were declared extern in a header. This macro is only set as a
/// compiler export attribute on windows, on other platforms it does nothing.
Expand All @@ -179,6 +185,7 @@
#define LLVM_ABI
#define LLVM_TEMPLATE_ABI
#define LLVM_EXPORT_TEMPLATE
#define LLVM_ABI_EXPORT
#elif defined(_WIN32) && !defined(__MINGW32__)
#if defined(LLVM_EXPORTS)
#define LLVM_ABI __declspec(dllexport)
Expand All @@ -189,19 +196,23 @@
#define LLVM_TEMPLATE_ABI __declspec(dllimport)
#define LLVM_EXPORT_TEMPLATE
#endif
#define LLVM_ABI_EXPORT __declspec(dllexport)
#elif defined(__ELF__) || defined(__MINGW32__) || defined(_AIX)
#define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
#define LLVM_TEMPLATE_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
#define LLVM_EXPORT_TEMPLATE
#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
#elif defined(__MACH__) || defined(__WASM__)
#define LLVM_ABI LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
#define LLVM_TEMPLATE_ABI
#define LLVM_EXPORT_TEMPLATE
#define LLVM_ABI_EXPORT LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
#endif
#else
#define LLVM_ABI
#define LLVM_TEMPLATE_ABI
#define LLVM_EXPORT_TEMPLATE
#define LLVM_ABI_EXPORT
#endif
#define LLVM_C_ABI LLVM_ABI
#endif
Expand Down
64 changes: 34 additions & 30 deletions llvm/include/llvm/Support/Registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,13 @@ namespace llvm {
Registry() = delete;

friend class node;
static node *Head, *Tail;
// These must be must two separate declarations to workaround a 20 year
// old MSVC bug with dllexport and multiple static fields in the same
// declaration causing error C2487 "member of dll interface class may not
// be declared with dll interface".
// https://developercommunity.visualstudio.com/t/c2487-in-dllexport-class-with-static-members/69878
static node *Head;
static node *Tail;

public:
/// Node in linked list of entries.
Expand All @@ -76,7 +82,13 @@ namespace llvm {
/// add a node to the executable's registry. Therefore it's not defined here
/// to avoid it being instantiated in the plugin and is instead defined in
/// the executable (see LLVM_INSTANTIATE_REGISTRY below).
static void add_node(node *N);
static void add_node(node *N) {
if (Tail)
Tail->Next = N;
else
Head = N;
Tail = N;
}

/// Iterators for registry entries.
///
Expand All @@ -95,7 +107,7 @@ namespace llvm {

// begin is not defined here in order to avoid usage of an undefined static
// data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
static iterator begin();
static iterator begin() { return iterator(Head); }
static iterator end() { return iterator(nullptr); }

static iterator_range<iterator> entries() {
Expand Down Expand Up @@ -124,36 +136,28 @@ namespace llvm {
}
};
};

} // end namespace llvm

#ifdef _WIN32
/// Instantiate a registry class.
///
/// This provides template definitions of add_node, begin, and the Head and Tail
/// pointers, then explicitly instantiates them. We could explicitly specialize
/// them, instead of the two-step process of define then instantiate, but
/// strictly speaking that's not allowed by the C++ standard (we would need to
/// have explicit specialization declarations in all translation units where the
/// specialization is used) so we don't.
#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
namespace llvm { \
template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
template<typename T> \
void Registry<T>::add_node(typename Registry<T>::node *N) { \
if (Tail) \
Tail->Next = N; \
else \
Head = N; \
Tail = N; \
} \
template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
return iterator(Head); \
} \
template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
template \
void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
namespace llvm { \
template <typename T> \
typename Registry<T>::node *Registry<T>::Head = nullptr; \
template <typename T> \
typename Registry<T>::node *Registry<T>::Tail = nullptr; \
template class LLVM_ABI_EXPORT Registry<REGISTRY_CLASS::type>; \
}
#else
#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
namespace llvm { \
template <typename T> \
typename Registry<T>::node *Registry<T>::Head = nullptr; \
template <typename T> \
typename Registry<T>::node *Registry<T>::Tail = nullptr; \
template class Registry<REGISTRY_CLASS::type>; \
}
#endif

#endif // LLVM_SUPPORT_REGISTRY_H

0 comments on commit 00cd1a0

Please sign in to comment.