Skip to content

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

@zond

Description

@zond

Summary

On Windows, when building LLVM with CLANG_LINK_CLANG_DYLIB=ON, external plugins cannot register themselves 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 breaks the plugin registration mechanism that relies on static initialization.

Affected Versions

  • LLVM 19, 20, 21, and main branch (verified 2025-01-14)
  • Specifically affects Windows builds with CLANG_LINK_CLANG_DYLIB=ON

Problem Description

Issue 1: Registry symbols filtered from DLL exports

The script llvm/utils/extract_symbols.py generates .def files for Windows DLL symbol exports. At line 126, it filters symbols with this regex:

elif re.search(r"(llvm|clang)@@[A-Z][A-Z0-9_]*[A-JQ].+(X|.+@|.*Z)$", symbol):

This pattern matches MSVC-mangled function symbols but excludes static data members, which have @@0 or @@3 suffixes. The Registry<T> static members Head and Tail are therefore filtered out:

?Head@?$Registry@VPluginASTAction@clang@@@llvm@@0PEAVnode@12@EA
?Tail@?$Registry@VPluginASTAction@clang@@@llvm@@0PEAPEAVnode@12@EA

Without these symbols exported, plugins cannot access the registry's linked list.

Issue 2: Registry methods not linked into executable

Even if the symbols are exported from the DLL, the Registry<T> methods add_node() and begin() exist in libraries but aren't linked into clang.exe by default because nothing in the main executable references them. When plugins try to call these functions, they fail because the symbols aren't present in the executable's import address table.

Reproduction

  1. Build LLVM with -DCLANG_LINK_CLANG_DYLIB=ON -DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON on Windows
  2. Create an external plugin that registers via Registry<PluginASTAction>
  3. Try to load the plugin with clang.exe -Xclang -load -Xclang plugin.dll

Result: Plugin fails to register, either due to missing symbols or unresolved externals.

Expected Behavior

Plugins should be able to register themselves using the Registry<T> pattern, as they can on Linux/macOS and as documented in the LLVM plugin documentation.

Context

This issue was discovered while enabling Clang 20 support for Firefox's clang-plugin on Windows. Firefox has been working around similar issues with local patches, but this affects any downstream project trying to build Windows plugins with dynamic linking.

The Registry<T> pattern is fundamental to LLVM's plugin infrastructure and is used throughout the codebase for various plugin types (PluginASTAction, PassBuilderOptPluginPass, etc.).

Related

  • llvm/utils/extract_symbols.py - Symbol export script
  • clang/tools/driver/driver.cpp - Main executable
  • llvm/include/llvm/Support/Registry.h - Registry template definition

Metadata

Metadata

Assignees

No one assigned

    Labels

    clangClang issues not falling into any other categoryplatform:windows

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions