Skip to content

Conversation

zond
Copy link

@zond zond commented Oct 14, 2025

When building LLVM with CLANG_LINK_CLANG_DYLIB=ON on Windows, external plugins cannot register through llvm::Registryclang::PluginASTAction due to two issues:

  1. Static data members (Head, Tail) are filtered out during symbol export
  2. Static methods (add_node(), begin()) are not linked into the executable

This change fixes both issues:

  • Modified extract_symbols.py to recognize and export Registry::Head and Registry::Tail static members using pattern matching instead of filtering them out as non-function symbols.

  • Added code in driver.cpp that references Registry methods, forcing the linker to include these symbols in clang.exe even though they're not directly called by the driver.

Fixes #163367

…LINK_CLANG_DYLIB

When building LLVM with CLANG_LINK_CLANG_DYLIB=ON on Windows, external
plugins cannot register through llvm::Registry<clang::PluginASTAction>
due to two issues:

1. Static data members (Head, Tail) are filtered out during symbol export
2. Static methods (add_node(), begin()) are not linked into the executable

This change fixes both issues:

- Modified extract_symbols.py to recognize and export Registry<T>::Head
  and Registry<T>::Tail static members using pattern matching instead of
  filtering them out as non-function symbols.

- Added code in driver.cpp that references Registry methods, forcing the
  linker to include these symbols in clang.exe even though they're not
  directly called by the driver.

Fixes llvm#163367
Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added the clang Clang issues not falling into any other category label Oct 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 14, 2025

@llvm/pr-subscribers-clang

Author: None (zond)

Changes

When building LLVM with CLANG_LINK_CLANG_DYLIB=ON on Windows, external plugins cannot register through llvm::Registry<clang::PluginASTAction> due to two issues:

  1. Static data members (Head, Tail) are filtered out during symbol export
  2. Static methods (add_node(), begin()) are not linked into the executable

This change fixes both issues:

  • Modified extract_symbols.py to recognize and export Registry<T>::Head and Registry<T>::Tail static members using pattern matching instead of filtering them out as non-function symbols.

  • Added code in driver.cpp that references Registry methods, forcing the linker to include these symbols in clang.exe even though they're not directly called by the driver.

Fixes #163367


Full diff: https://github.com/llvm/llvm-project/pull/163391.diff

2 Files Affected:

  • (modified) clang/tools/driver/driver.cpp (+19)
  • (modified) llvm/utils/extract_symbols.py (+5)
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 7390d7d610ec0..855c8285e841c 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -55,6 +55,25 @@
 #include <set>
 #include <system_error>
 
+#if defined(CLANG_PLUGIN_SUPPORT) && defined(_WIN32)
+#include "clang/Frontend/FrontendPluginRegistry.h"
+
+// Force plugin registry symbols into clang.exe on Windows so plugins can
+// register. These methods exist in libraries but aren't linked by default
+// because they're unreferenced. Taking their addresses forces the linker to
+// include them.
+namespace {
+void ForcePluginRegistrySymbols() {
+  using PluginRegistry = llvm::Registry<clang::PluginASTAction>;
+  // Use volatile to prevent the compiler from optimizing away these references
+  volatile auto add_node_ptr = &PluginRegistry::add_node;
+  volatile auto begin_ptr = &PluginRegistry::begin;
+  (void)add_node_ptr;
+  (void)begin_ptr;
+}
+} // anonymous namespace
+#endif
+
 using namespace clang;
 using namespace clang::driver;
 using namespace llvm::opt;
diff --git a/llvm/utils/extract_symbols.py b/llvm/utils/extract_symbols.py
index 388723421d660..72f992f560c7f 100755
--- a/llvm/utils/extract_symbols.py
+++ b/llvm/utils/extract_symbols.py
@@ -105,6 +105,11 @@ def should_keep_microsoft_symbol(symbol, calling_convention_decoration):
     # Skip X86GenMnemonicTables functions, they are not exposed from llvm/include/.
     elif re.match(r"\?is[A-Z0-9]*@X86@llvm", symbol):
         return None
+    # Keep Registry<T>::Head and Registry<T>::Tail static members for plugin support.
+    # Pattern matches: ?Head@?$Registry@<template_args>@llvm@@ or ?Tail@?$Registry@...
+    elif ("?$Registry@" in symbol and "@llvm@@" in symbol and
+          (symbol.startswith("?Head@") or symbol.startswith("?Tail@"))):
+        return symbol
     # Keep mangled llvm:: and clang:: function symbols. How we detect these is a
     # bit of a mess and imprecise, but that avoids having to completely demangle
     # the symbol name. The outermost namespace is at the end of the identifier

zond added a commit to zond/firefox that referenced this pull request Oct 14, 2025
… fixes r=glandium

This change adds support for building Firefox with Clang 20, including
critical fixes for the clang-plugin dynamic linking on Windows.

Clang 20 introduced two breaking changes that prevented the clang-plugin
from loading on Windows:

1. The CLANG_ABI macro was added to Attr classes, causing inline methods
   like classof() and getAnnotation() to generate dllimport references.
   This fails because these methods are defined inline in headers, not
   exported from the DLL.

2. The extract_symbols.py script became more aggressive in filtering
   symbols, blocking Registry<T> static data members (Head/Tail) that
   don't match function signature patterns.

The fix consists of three patches for the Clang 20 build:

- add-plugin-symbols_clang_20.patch: Adds pattern matching to
  extract_symbols.py to recognize and export Registry<T>::Head and
  ::Tail static members for any Registry instantiation. This replaces
  the need for hardcoded symbol whitelists and works across different
  plugin types.

  See llvm/llvm-project#163367 and
  llvm/llvm-project#163391.

- force-plugin-symbols_clang_20.patch: Adds C++ code to driver.cpp that
  references Registry<PluginASTAction>::add_node() and ::begin() to force
  the linker to include these symbols. This replaces hardcoded mangled
  symbol names with type-safe references that work across compiler versions.

  See llvm/llvm-project#163367 and
  llvm/llvm-project#163391.

- remove-clang-abi-from-attrs_clang_20.patch: Removes the CLANG_ABI
  macro from Attr class generation to prevent dllimport issues with
  inline methods.

  See llvm/llvm-project#163349.

To test this locally:

- Install the current clang-20 inside the firefox checkout:

`./mach artifact toolchain --from-build win64-clang-20`

- Install libxml2 (necessary for clang-mt.exe):

`./mach artifact toolchain --from-build win64-libxml2`

- Install wasm32-wasi-compiler-rt-20 (necessary for WASM compilation?):

`./mach artifact toolchain --from-build wasm32-wasi-compiler-rt-20`

- Check out llvm 20.1.8 in a directory alongside the firefox checkout.
- Try to build llvm, and fail when the wasi lib is missing:

`MOZ_FETCHES_DIR=../firefox python3 ../firefox/build/build-clang/build-clang.py -c ../firefox/build/build-clang/use-clang-cl-artifact.json -c ../firefox/build/build-clang/win64.json -c ../firefox/build/build-clang/clang-20.json -c ../firefox/build/build-clang/2stages.json`

- Copy the missing wasi lib to the stage2 build directory:

```
mkdir build/stage2/clang/lib/clang/20/lib/wasm32-unknown-wasi
cp ../firefox/compiler-rt-wasm32-wasi/lib/wasi/libclang_rt.builtins-wasm32.a build/stage2/clang/lib/clang/20/lib/wasm32-unknown-wasi/libclang_rt.builtins.a
```

- Try to build llvm again and succeed:

`MOZ_FETCHES_DIR=../firefox python3 ../firefox/build/build-clang/build-clang.py -c ../firefox/build/build-clang/use-clang-cl-artifact.json -c ../firefox/build/build-clang/win64.json -c ../firefox/build/build-clang/clang-20.json -c ../firefox/build/build-clang/2stages.json`

- Update the mozconfig in the firefox checkout to turn on the clang
  plugin and use the right compiler:

```
export CC=[THE LLVM CHECKOUT DIRECTORY]/build/stage2/clang/bin/clang-cl.exe
ac_add_options --enable-clang-plugin
```

- Build firefox:

`./mach clobber && ./mach configure --enable-bootstrap=no-update && ./mach build`

Differential Revision: https://phabricator.services.mozilla.com/D268255
zond added a commit to zond/firefox that referenced this pull request Oct 15, 2025
… fixes r=glandium

This change adds support for building Firefox with Clang 20, including
critical fixes for the clang-plugin dynamic linking on Windows.

Clang 20 introduced two breaking changes that prevented the clang-plugin
from loading on Windows:

1. The CLANG_ABI macro was added to Attr classes, causing inline methods
   like classof() and getAnnotation() to generate dllimport references.
   This fails because these methods are defined inline in headers, not
   exported from the DLL.

2. The extract_symbols.py script became more aggressive in filtering
   symbols, blocking Registry<T> static data members (Head/Tail) that
   don't match function signature patterns.

The fix consists of two patches for the Clang 20 build:

- plugin-registry-symbols_clang_20-llvm-pr-163391.patch:

  Make extract_symbols.py recognize and export Registry<T>::Head and
  ::Tail static members for any Registry instantiation.

  References Registry<PluginASTAction>::add_node() and ::begin() to force
  the linker to include these symbols.

  See llvm/llvm-project#163367 and
  llvm/llvm-project#163391.

- remove-clang-abi-from-attrs_clang_20.patch: Removes the CLANG_ABI
  macro from Attr class generation to prevent dllimport issues with
  inline methods in Windows.

  See llvm/llvm-project#163349.

To test this locally:

- Install the current clang-20 inside the firefox checkout:

`./mach artifact toolchain --from-build win64-clang-20`

- Install libxml2 (necessary for clang-mt.exe):

`./mach artifact toolchain --from-build win64-libxml2`

- Install wasm32-wasi-compiler-rt-20 (necessary for WASM compilation?):

`./mach artifact toolchain --from-build wasm32-wasi-compiler-rt-20`

- Check out llvm 20.1.8 in a directory alongside the firefox checkout.
- Try to build llvm, and fail when the wasi lib is missing:

`MOZ_FETCHES_DIR=../firefox python3 ../firefox/build/build-clang/build-clang.py -c ../firefox/build/build-clang/use-clang-cl-artifact.json -c ../firefox/build/build-clang/win64.json -c ../firefox/build/build-clang/clang-20.json -c ../firefox/build/build-clang/2stages.json`

- Copy the missing wasi lib to the stage2 build directory:

```
mkdir build/stage2/clang/lib/clang/20/lib/wasm32-unknown-wasi
cp ../firefox/compiler-rt-wasm32-wasi/lib/wasi/libclang_rt.builtins-wasm32.a build/stage2/clang/lib/clang/20/lib/wasm32-unknown-wasi/libclang_rt.builtins.a
```

- Try to build llvm again and succeed:

`MOZ_FETCHES_DIR=../firefox python3 ../firefox/build/build-clang/build-clang.py -c ../firefox/build/build-clang/use-clang-cl-artifact.json -c ../firefox/build/build-clang/win64.json -c ../firefox/build/build-clang/clang-20.json -c ../firefox/build/build-clang/2stages.json`

- Update the mozconfig in the firefox checkout to turn on the clang
  plugin and use the right compiler:

```
export CC=[THE LLVM CHECKOUT DIRECTORY]/build/stage2/clang/bin/clang-cl.exe
ac_add_options --enable-clang-plugin
```

- Build firefox:

`./mach clobber && ./mach configure --enable-bootstrap=no-update && ./mach build`

Differential Revision: https://phabricator.services.mozilla.com/D268255
zond added a commit to zond/firefox that referenced this pull request Oct 16, 2025
… fixes r=glandium

This change adds support for building Firefox with Clang 20, including
critical fixes for the clang-plugin dynamic linking on Windows.

Clang 20 introduced two breaking changes that prevented the clang-plugin
from loading on Windows:

1. The CLANG_ABI macro was added to Attr classes, causing inline methods
   like classof() and getAnnotation() to generate dllimport references.
   This fails because these methods are defined inline in headers, not
   exported from the DLL.

2. The extract_symbols.py script became more aggressive in filtering
   symbols, blocking Registry<T> static data members (Head/Tail) that
   don't match function signature patterns.

The fix consists of two patches for the Clang 20 build:

- plugin-registry-symbols_clang_20-llvm-pr-163391.patch:

  Make extract_symbols.py recognize and export Registry<T>::Head and
  ::Tail static members for any Registry instantiation.

  References Registry<PluginASTAction>::add_node() and ::begin() to force
  the linker to include these symbols.

  See llvm/llvm-project#163367 and
  llvm/llvm-project#163391.

- remove-clang-abi-from-attrs_clang_20.patch: Removes the CLANG_ABI
  macro from Attr class generation to prevent dllimport issues with
  inline methods in Windows.

  See llvm/llvm-project#163349.

Differential Revision: https://phabricator.services.mozilla.com/D268255
zond added a commit to zond/firefox that referenced this pull request Oct 16, 2025
… fixes r=glandium

This change adds support for building Firefox with Clang 20, including
critical fixes for the clang-plugin dynamic linking on Windows.

Clang 20 introduced two breaking changes that prevented the clang-plugin
from loading on Windows:

1. The CLANG_ABI macro was added to Attr classes, causing inline methods
   like classof() and getAnnotation() to generate dllimport references.
   This fails because these methods are defined inline in headers, not
   exported from the DLL.

2. The extract_symbols.py script became more aggressive in filtering
   symbols, blocking Registry<T> static data members (Head/Tail) that
   don't match function signature patterns.

The fix consists of two patches for the Clang 20 build:

- plugin-registry-symbols_clang_20-llvm-pr-163391.patch:

  Make extract_symbols.py recognize and export Registry<T>::Head and
  ::Tail static members for any Registry instantiation.

  References Registry<PluginASTAction>::add_node() and ::begin() to force
  the linker to include these symbols.

  See llvm/llvm-project#163367 and
  llvm/llvm-project#163391.

- remove-clang-abi-from-attrs_clang_20.patch: Removes the CLANG_ABI
  macro from Attr class generation to prevent dllimport issues with
  inline methods in Windows.

  See llvm/llvm-project#163349.

Differential Revision: https://phabricator.services.mozilla.com/D268255
zond added a commit to zond/firefox that referenced this pull request Oct 16, 2025
… fixes r=glandium

This change adds support for building Firefox with Clang 20, including
critical fixes for the clang-plugin dynamic linking on Windows.

Clang 20 introduced two breaking changes that prevented the clang-plugin
from loading on Windows:

1. The CLANG_ABI macro was added to Attr classes, causing inline methods
   like classof() and getAnnotation() to generate dllimport references.
   This fails because these methods are defined inline in headers, not
   exported from the DLL.

2. The extract_symbols.py script became more aggressive in filtering
   symbols, blocking Registry<T> static data members (Head/Tail) that
   don't match function signature patterns.

The fix consists of two patches for the Clang 20 and trunk builds:

- plugin-registry-symbols-llvm-pr-163391.patch:

  Make extract_symbols.py recognize and export Registry<T>::Head and
  ::Tail static members for any Registry instantiation.

  References Registry<PluginASTAction>::add_node() and ::begin() to force
  the linker to include these symbols.

  See llvm/llvm-project#163367 and
  llvm/llvm-project#163391.

- remove-clang-abi-from-attrs-clang-[20|trunk].patch: Removes the CLANG_ABI
  macro from Attr class generation to prevent dllimport issues with
  inline methods in Windows.

  See llvm/llvm-project#163349.

Differential Revision: https://phabricator.services.mozilla.com/D268255
zond added a commit to zond/firefox that referenced this pull request Oct 16, 2025
… fixes r=glandium

This change adds support for building Firefox with Clang 20, including
critical fixes for the clang-plugin dynamic linking on Windows.

Clang 20 introduced two breaking changes that prevented the clang-plugin
from loading on Windows:

1. The CLANG_ABI macro was added to Attr classes, causing inline methods
   like classof() and getAnnotation() to generate dllimport references.
   This fails because these methods are defined inline in headers, not
   exported from the DLL.

2. The extract_symbols.py script became more aggressive in filtering
   symbols, blocking Registry<T> static data members (Head/Tail) that
   don't match function signature patterns.

The fix consists of two patches for the Clang 20 and trunk builds:

- plugin-registry-symbols-llvm-pr-163391.patch:

  Make extract_symbols.py recognize and export Registry<T>::Head and
  ::Tail static members for any Registry instantiation.

  References Registry<PluginASTAction>::add_node() and ::begin() to force
  the linker to include these symbols.

  See llvm/llvm-project#163367 and
  llvm/llvm-project#163391.

- remove-clang-abi-from-attrs-clang-[20|trunk].patch: Removes the CLANG_ABI
  macro from Attr class generation to prevent dllimport issues with
  inline methods in Windows.

  See llvm/llvm-project#163349.

Differential Revision: https://phabricator.services.mozilla.com/D268255
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Windows] Plugin registry symbols not exported/linked with CLANG_LINK_CLANG_DYLIB, breaking external plugins

2 participants