Skip to content

Update llvm::Registry to work for LLVM shared library builds on windows #109024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 16, 2024
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this being added? I'm weary of any macro that is always export only because the value needs to switch between the definition and reference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its macro I mentioned earlier initial explanation about being used in Clang and LLVM, it should never be used for things that could be references.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is subtle enough that we may need some documentation comments explaining when and how someone should use this. (Most reviewers aren't going to be well-versed in how shared libraries work on Windows.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment to try and explains its use and behaviour.

#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
Loading