
## Purpose Introduce a new `LLVM_ABI_FRIEND` macro to `llvm/Support/Compiler.h` for annotating `friend` function declarations for DLL export. ## Overview 1. Add a new `LLVM_ABI_FRIEND` macro, which behaves identically to the existing `LLVM_ABI` macro on Windows and compiles to nothing on other platforms. 2. Update existing documentation to describe proper usage of the `LLVM_ABI_FRIEND` annotation. ## Background * MSVC issues a warning when it encounters a `friend` function declaration that does not match the DLL import/export annotation of the original function. * When compiling ELF and Mach-O shared libraries, `friend` function declarations with visibility annotations produce compilation errors (GCC) and warnings (Clang). * Additional context on the effort to annotate LLVM's public interface is in [this discourse](https://discourse.llvm.org/t/psa-annotating-llvm-public-interface/85307).
378 lines
12 KiB
ReStructuredText
378 lines
12 KiB
ReStructuredText
LLVM Interface Export Annotations
|
|
=================================
|
|
Symbols that are part of LLVM's public interface must be explicitly annotated
|
|
to support shared library builds with hidden default symbol visibility. This
|
|
document provides background and guidelines for annotating the codebase.
|
|
|
|
LLVM Shared Library
|
|
-------------------
|
|
LLVM builds as a static library by default, but it can also be built as a shared
|
|
library with the following configuration:
|
|
|
|
::
|
|
|
|
LLVM_BUILD_LLVM_DYLIB=On
|
|
LLVM_LINK_LLVM_DYLIB=On
|
|
|
|
There are three shared library executable formats we're interested in: PE
|
|
Dynamic Link Library (.dll) on Windows, Mach-O Shared Object (.dylib) on Apple
|
|
systems, and ELF Shared Object (.so) on Linux, BSD and other Unix-like systems.
|
|
|
|
ELF and Mach-O Shared Object files can be built with no additional setup or
|
|
configuration. This is because all global symbols in the library are exported by
|
|
default -- the same as when building a static library. However, when building a
|
|
DLL for Windows, the situation is more complex:
|
|
|
|
- Symbols are not exported from a DLL by default. Symbols must be annotated with
|
|
``__declspec(dllexport)`` when building the library to be externally visible.
|
|
|
|
- Symbols imported from a Windows DLL should generally be annotated with
|
|
``__declspec(dllimport)`` when compiling clients.
|
|
|
|
- A single Windows DLL can export a maximum of 65,535 symbols.
|
|
|
|
Because of the requirements for Windows DLLs, additional work must be done to
|
|
ensure the proper set of public symbols is exported and visible to clients.
|
|
|
|
Annotation Macros
|
|
-----------------
|
|
The distinct DLL import and export annotations required for Windows DLLs
|
|
typically lead developers to define a preprocessor macro for annotating exported
|
|
symbols in header public files. The custom macro resolves to the _export_
|
|
annotation when building the library and the _import_ annotation when building
|
|
the client.
|
|
|
|
We have defined the `LLVM_ABI` macro in `llvm/Support/Compiler.h
|
|
<https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Support/Compiler.h#L152>`__
|
|
for this purpose:
|
|
|
|
.. code:: cpp
|
|
|
|
#if defined(LLVM_EXPORTS)
|
|
#define LLVM_ABI __declspec(dllexport)
|
|
#else
|
|
#define LLVM_ABI __declspec(dllimport)
|
|
#endif
|
|
|
|
Windows DLL symbol visibility requirements are approximated on ELF and Mach-O
|
|
shared library builds by setting default symbol visibility to hidden
|
|
(``-fvisibility-default=hidden``) when building with the following
|
|
configuration:
|
|
|
|
::
|
|
|
|
LLVM_BUILD_LLVM_DYLIB_VIS=On
|
|
|
|
For an ELF or Mach-O platform with this setting, the ``LLVM_ABI`` macro is
|
|
defined to override the default hidden symbol visibility:
|
|
|
|
.. code:: cpp
|
|
|
|
#define LLVM_ABI __attribute__((visibility("default")))
|
|
|
|
In addition to ``LLVM_ABI``, there are a few other macros for use in less
|
|
common cases described below.
|
|
|
|
Export macros are used to annotate symbols only within their intended shared
|
|
library. This is necessary because of the way Windows handles import/export
|
|
annotations.
|
|
|
|
For example, ``LLVM_ABI`` resolves to ``__declspec(dllexport)`` only when
|
|
building source that is part of the LLVM shared library (e.g. source under
|
|
``llvm-project/llvm``). If ``LLVM_ABI`` were incorrectly used to annotate a
|
|
symbol from a different LLVM project (such as Clang) it would always resolve to
|
|
``__declspec(dllimport)`` and the symbol would not be properly exported.
|
|
|
|
Annotating Symbols
|
|
------------------
|
|
Functions
|
|
~~~~~~~~~
|
|
Exported function declarations in header files must be annotated with
|
|
``LLVM_ABI``.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
LLVM_ABI void exported_function(int a, int b);
|
|
|
|
Global Variables
|
|
~~~~~~~~~~~~~~~~
|
|
Exported global variables must be annotated with ``LLVM_ABI`` at their
|
|
``extern`` declarations.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
LLVM_ABI extern int exported_global_variable;
|
|
|
|
Classes, Structs, and Unions
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Classes, structs, and unions can be annotated with ``LLVM_ABI`` at their
|
|
declaration, but this option is generally discouraged because it will
|
|
export every class member, vtable, and type information. Instead, ``LLVM_ABI``
|
|
should be applied to individual class members that require export.
|
|
|
|
In the most common case, public and protected methods without a body in the
|
|
class declaration must be annotated with ``LLVM_ABI``.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
class ExampleClass {
|
|
public:
|
|
// Public methods defined externally must be annotatated.
|
|
LLVM_ABI int sourceDefinedPublicMethod(int a, int b);
|
|
|
|
// Methods defined in the class definition do not need annotation.
|
|
int headerDefinedPublicMethod(int a, int b) {
|
|
return a + b;
|
|
}
|
|
|
|
// Constructors and destructors must be annotated if defined externally.
|
|
ExampleClass() {}
|
|
LLVM_ABI ~ExampleClass();
|
|
|
|
// Public static methods defined externally must be annotatated.
|
|
LLVM_ABI static int sourceDefinedPublicStaticMethod(int a, int b);
|
|
};
|
|
|
|
Additionally, public and protected static fields that are not initialized at
|
|
declaration must be annotated with ``LLVM_ABI``.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
class ExampleClass {
|
|
public:
|
|
// Public static fields defined externally must be annotated.
|
|
LLVM_ABI static int mutableStaticField;
|
|
LLVM_ABI static const int constStaticField;
|
|
|
|
// Static members initialized at declaration do not need to be annotated.
|
|
static const int initializedConstStaticField = 0;
|
|
static constexpr int initializedConstexprStaticField = 0;
|
|
};
|
|
|
|
Private methods may also require ``LLVM_ABI`` annotation in certain cases. This
|
|
situation occurs when a method defined in a header calls the private method. The
|
|
private method call may be from within the class, a parent class, or a friend
|
|
class.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
class ExampleClass {
|
|
private:
|
|
// Private methods must be annotated if referenced by a public method defined a
|
|
// header file.
|
|
LLVM_ABI int privateMethod(int a, int b);
|
|
|
|
public:
|
|
// Inlineable method defined in the class definition calls a private method
|
|
// defined externally. If the private method is not annotated for export, this
|
|
// method will fail to link.
|
|
int publicMethod(int a, int b) {
|
|
return privateMethod(a, b);
|
|
}
|
|
};
|
|
|
|
There are less common cases where you may also need to annotate an inline
|
|
function even though it is fully defined in a header. Annotating an inline
|
|
function for export does not prevent it being inlined into client code. However,
|
|
it does ensure there is a single, stable address for the function exported from
|
|
the shared library.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
// Annotate the function so it is exported from the library at a fixed
|
|
// address.
|
|
LLVM_ABI inline int inlineFunction(int a, int b) {
|
|
return a + b;
|
|
}
|
|
|
|
Similarly, if a stable pointer-to-member function address is required for a
|
|
method in a C++ class, it may be annotated for export.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
class ExampleClass {
|
|
public:
|
|
// Annotate the method so it is exported from the library at a fixed
|
|
// address.
|
|
LLVM_ABI inline int inlineMethod(int a, int b) {
|
|
return a + b;
|
|
}
|
|
};
|
|
|
|
.. note::
|
|
|
|
When an inline function is annotated for export, the header containing the
|
|
function definition **must** be included by at least one of the library's
|
|
source files or the function will never be compiled with the export
|
|
annotation.
|
|
|
|
Friend Functions
|
|
~~~~~~~~~~~~~~~~
|
|
Friend functions declared in a class, struct or union should be annotated with
|
|
``LLVM_ABI_FRIEND`` if the corresponding function declaration is annotated with
|
|
``LLVM_ABI``. This requirement applies even when the class containing the friend
|
|
declaration is annotated with ``LLVM_ABI``.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
// An exported function that has friend access to ExampleClass internals.
|
|
LLVM_ABI int friend_function(ExampleClass &obj);
|
|
|
|
class ExampleClass {
|
|
// Friend declaration of a function must be annotated the same as the actual
|
|
// function declaration.
|
|
LLVM_ABI_FRIEND friend int friend_function(ExampleClass &obj);
|
|
};
|
|
|
|
.. note::
|
|
|
|
Annotating the friend declaration avoids an “inconsistent dll linkage”
|
|
compiler error when building a DLL for Windows. The ``LLVM_ABI_FRIEND``
|
|
annotation is a no-op when building ELF or Mach-O shared libraries.
|
|
|
|
Virtual Table and Type Info
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
Classes and structs with exported virtual methods, or child classes that export
|
|
overridden virtual methods, must also export their vtable for ELF and Mach-O
|
|
builds. This can be achieved by annotating the class rather than individual
|
|
class members.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
class ParentClass {
|
|
public:
|
|
virtual int virtualMethod(int a, int b);
|
|
virtual int anotherVirtualMethod(int a, int b);
|
|
virtual ~ParentClass();
|
|
};
|
|
|
|
// Annotating the class exports vtable and type information as well as all
|
|
// class members.
|
|
class LLVM_ABI ChildClass : public ParentClass {
|
|
public:
|
|
// Inline method override does not require the class be annotated.
|
|
int virtualMethod(int a, int b) override {
|
|
return ParentClass::virtualMethod(a, b);
|
|
}
|
|
|
|
// Overriding a virtual method from the parent requires the class be
|
|
// annotated. The parent class may require annotation as well.
|
|
int pureVirtualMethod(int a, int b) override;
|
|
~ChildClass();
|
|
};
|
|
|
|
If annotating a type with ``LLVM_ABI`` causes compilation issues such as those
|
|
described
|
|
`here <https://devblogs.microsoft.com/oldnewthing/20190927-00/?p=102932>`__,
|
|
the class may require modification. Often, explicitly deleting the copy
|
|
constructor and copy assignment operator will resolve the issue.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
#include <vector>
|
|
|
|
class LLVM_ABI ExportedClass {
|
|
public:
|
|
// Explicitly delete the copy constructor and assignment operator.
|
|
ExportedClass(ExportedClass const&) = delete;
|
|
ExportedClass& operator=(ExportedClass const&) = delete;
|
|
};
|
|
|
|
Templates
|
|
~~~~~~~~~
|
|
Most template classes are entirely header-defined and do not need to be exported
|
|
because they will be instantiated and compiled into the client as needed. Such
|
|
template classes require no export annotations. However, there are some less
|
|
common cases where annotations are required for templates.
|
|
|
|
Specialized Template Functions
|
|
++++++++++++++++++++++++++++++
|
|
As with any other exported function, an exported specialization of a template
|
|
function not defined in a header file must have its declaration annotated with
|
|
``LLVM_ABI``.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
template <typename T> T templateMethod(T a, T b) {
|
|
return a + b;
|
|
}
|
|
|
|
// The explicitly specialized definition of templateMethod for int is located in
|
|
// a source file. This declaration must be annotated with LLVM_ABI to export it.
|
|
template <> LLVM_ABI int templateMethod(int a, int b);
|
|
|
|
Similarly, an exported specialization of a method in a template class must have
|
|
its declaration annotated with ``LLVM_ABI``.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
template <typename T> class TemplateClass {
|
|
public:
|
|
int method(int a, int b) {
|
|
return a + b;
|
|
}
|
|
};
|
|
|
|
// The explicitly specialized definition of method for int is defined in a
|
|
// source file. The declaration must be annotated with LLVM_ABI to export it.
|
|
template <> LLVM_ABI int TemplateStruct<int>::method(int a, int b);
|
|
|
|
Explicitly Instantiated Template Classes
|
|
++++++++++++++++++++++++++++++++++++++++
|
|
Explicitly instantiated template classes must be annotated with
|
|
template-specific annotations at both declaration and definition.
|
|
|
|
An extern template instantiation in a header file must be annotated with
|
|
``LLVM_TEMPLATE_ABI``. This will typically be located in a header file.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
template <typename T> class TemplateClass {
|
|
public:
|
|
TemplateClass(T val) : val_(val) {}
|
|
|
|
T get() const { return val_; }
|
|
|
|
private:
|
|
const T val_;
|
|
};
|
|
|
|
// Explicitly instantiate and export TempalateClass for int type.
|
|
extern template class LLVM_TEMPLATE_ABI TemplateClass<int>;
|
|
|
|
The corresponding definition of the template instantiation must be annotated
|
|
with ``LLVM_EXPORT_TEMPLATE``. This will typically be located in a source file.
|
|
|
|
.. code:: cpp
|
|
|
|
#include "TemplateClass.h"
|
|
|
|
// Explicitly instantiate and export TempalateClass for int type.
|
|
template class LLVM_EXPORT_TEMPLATE TemplateClass<int>;
|