You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下用Clang编译LLVM Pass时出现未定义符号错误

问题:LLVM外部Pass编译链接报错(未定义符号)

尝试编写一个独立于LLVM源码树的简单LLVM Pass,但编译时出现大量lld-link未定义符号错误。以下是项目配置、代码及错误信息:

项目根目录CMakeLists.txt

cmake_minimum_required(VERSION 3.25)

project(LLVM1Proj)

# Set flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")

# Include LLVM library
find_package(LLVM REQUIRED CONFIG)

list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")

include(AddLLVM)

# Enable isolated passes
set(LLVM_ENABLE_PLUGINS ON)

separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})
include_directories(${LLVM_INCLUDE_DIRS})

add_subdirectory("easypass")

add_executable(LLVM1 "main.cpp")

llvm_map_components_to_libnames(llvm_libs support core irreader)

target_link_libraries(LLVM1 ${llvm_libs})

easypass子目录CMakeLists.txt

add_llvm_library(easypass MODULE
  easypass.cpp
  PLUGIN_TOOL
  opt
  )

easypass.cpp代码

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

namespace {

    class Easy : public llvm::FunctionPass {
    public:
    
        static char ID;

        Easy() : FunctionPass(ID) {}

        bool runOnFunction(llvm::Function &F) override {
        
            llvm::errs() << "Hello: ";
            llvm::errs().write_escaped(F.getName()) << '\n';
        
            return false;
        
        }



    };

}

char Easy::ID = 0;

static llvm::RegisterPass<Easy> X("Easy", "Easy pass", false);

static llvm::RegisterStandardPasses Y(
    llvm::PassManagerBuilder::EP_EarlyAsPossible,
    [](const llvm::PassManagerBuilder &Builder,
       llvm::legacy::PassManagerBase &PM) { PM.add(new Easy()); });

生成的编译命令

cmd.exe /C "cd . && C:\PROGRA~1\MICROS~1\2022\COMMUN~1\VC\Tools\Llvm\x64\bin\clang.exe -fuse-ld=lld-link -nostartfiles -nostdlib -std=c++17 -O0 -g -Xclang -gcodeview -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd -D_DEBUG -D_DLL -D_MT -Xclang --dependent-lib=msvcrtd -g -Xclang -gcodeview  -Wl,--gc-sections -shared -o easypass\easypass.dll  -Xlinker /MANIFEST:EMBED -Xlinker /implib:easypass\easypass.lib -Xlinker /pdb:easypass\easypass.pdb -Xlinker /version:0.0 easypass/CMakeFiles/easypass.dir/easypass.cpp.obj  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -loldnames  && cd ."

编译错误信息

[build] lld-link: warning: ignoring unknown argument '--gc-sections'
[build] lld-link: error: undefined symbol: public: static class llvm::PassRegistry * __cdecl llvm::PassRegistry::getPassRegistry(void)
[build] >>> referenced by C:\Program Files (x86)\LLVM\include\llvm\PassSupport.h:101
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: __cdecl llvm::RegisterPass<class `anonymous namespace'::Easy>::RegisterPass<class `anonymous namespace'::Easy>(class llvm::StringRef, class llvm::StringRef, bool, bool))
[build] 
[build] lld-link: error: undefined symbol: public: void __cdecl llvm::PassRegistry::registerPass(class llvm::PassInfo const &, bool)
[build] >>> referenced by C:\Program Files (x86)\LLVM\include\llvm\PassSupport.h:101
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: __cdecl llvm::RegisterPass<class `anonymous namespace'::Easy>::RegisterPass<class `anonymous namespace'::Easy>(class llvm::StringRef, class llvm::StringRef, bool, bool))
[build] 
[build] lld-link: error: undefined symbol: public: static int __cdecl llvm::PassManagerBuilder::addGlobalExtension(enum llvm::PassManagerBuilder::ExtensionPointTy, class std::function<void __cdecl(class llvm::PassManagerBuilder const &, class llvm::legacy::PassManagerBase &)>)
[build] >>> referenced by C:\Program Files (x86)\LLVM\include\llvm\Transforms\IPO\PassManagerBuilder.h:221
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: __cdecl llvm::RegisterStandardPasses::RegisterStandardPasses(enum llvm::PassManagerBuilder::ExtensionPointTy, class std::function<void __cdecl(class llvm::PassManagerBuilder const &, class llvm::legacy::PassManagerBase &)>))
[build] 
[build] lld-link: error: undefined symbol: public: static void __cdecl llvm::PassManagerBuilder::removeGlobalExtension(int)
[build] >>> referenced by C:\Program Files (x86)\LLVM\include\llvm\Transforms\IPO\PassManagerBuilder.h:228
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: __cdecl llvm::RegisterStandardPasses::~RegisterStandardPasses(void))
[build] 
[build] lld-link: error: undefined symbol: class llvm::raw_fd_ostream & __cdecl llvm::errs(void)
[build] >>> referenced by C:\Development\Projects\LLVM1\easypass\easypass.cpp:19
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: virtual bool __cdecl `anonymous namespace'::Easy::runOnFunction(class llvm::Function &))
[build] >>> referenced by C:\Development\Projects\LLVM1\easypass\easypass.cpp:20
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: virtual bool __cdecl `anonymous namespace'::Easy::runOnFunction(class llvm::Function &))
[build] 
[build] lld-link: error: undefined symbol: public: class llvm::StringRef __cdecl llvm::Value::getName(void) const
[build] >>> referenced by C:\Development\Projects\LLVM1\easypass\easypass.cpp:20
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: virtual bool __cdecl `anonymous namespace'::Easy::runOnFunction(class llvm::Function &))
[build] 
[build] lld-link: error: undefined symbol: public: class llvm::raw_ostream & __cdecl llvm::raw_ostream::write_escaped(class llvm::StringRef, bool)
[build] >>> referenced by C:\Development\Projects\LLVM1\easypass\easypass.cpp:20
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: virtual bool __cdecl `anonymous namespace'::Easy::runOnFunction(class llvm::Function &))
[build] 
[build] lld-link: error: undefined symbol: public: virtual __cdecl llvm::Pass::~Pass(void)
[build] >>> referenced by C:\Program Files (x86)\LLVM\include\llvm\Pass.h:308
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: virtual __cdecl llvm::FunctionPass::~FunctionPass(void))
[build] 
[build] lld-link: error: undefined symbol: public: class llvm::raw_ostream & __cdecl llvm::raw_ostream::write(unsigned char)
[build] >>> referenced by C:\Program Files (x86)\LLVM\include\llvm\Support\raw_ostream.h:192
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: class llvm::raw_ostream & __cdecl llvm::raw_ostream::operator<<(char))
[build] 
[build] lld-link: error: undefined symbol: public: class llvm::raw_ostream & __cdecl llvm::raw_ostream::write(char const *, unsigned __int64)
[build] >>> referenced by C:\Program Files (x86)\LLVM\include\llvm\Support\raw_ostream.h:217
[build] >>>               easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(public: class llvm::raw_ostream & __cdecl llvm::raw_ostream::operator<<(class llvm::StringRef))
[build] 
[build] lld-link: error: undefined symbol: public: virtual class llvm::StringRef __cdecl llvm::Pass::getPassName(void) const
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::Pass::`vftable')
[build] 
[build] lld-link: error: undefined symbol: public: virtual void __cdecl llvm::Pass::print(class llvm::raw_ostream &, class llvm::Module const *) const
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::Pass::`vftable')
[build] 
[build] lld-link: error: undefined symbol: public: virtual class llvm::Pass * __cdecl llvm::FunctionPass::createPrinterPass(class llvm::raw_ostream &, class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>> const &) const
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] 
[build] lld-link: error: undefined symbol: public: virtual void __cdecl llvm::FunctionPass::assignPassManager(class llvm::PMStack &, enum llvm::PassManagerType)
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] 
[build] lld-link: error: undefined symbol: public: virtual void __cdecl llvm::Pass::preparePassManager(class llvm::PMStack &)
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::Pass::`vftable')
[build] 
[build] lld-link: error: undefined symbol: public: virtual enum llvm::PassManagerType __cdecl llvm::FunctionPass::getPotentialPassManagerType(void) const
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] 
[build] lld-link: error: undefined symbol: public: virtual void __cdecl llvm::Pass::getAnalysisUsage(class llvm::AnalysisUsage &) const
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::Pass::`vftable')
[build] 
[build] lld-link: error: undefined symbol: public: virtual void __cdecl llvm::Pass::releaseMemory(void)
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::Pass::`vftable')
[build] 
[build] lld-link: error: undefined symbol: public: virtual void * __cdecl llvm::Pass::getAdjustedAnalysisPointer(void const *)
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::Pass::`vftable')
[build] 
[build] lld-link: error: undefined symbol: public: virtual class llvm::ImmutablePass * __cdecl llvm::Pass::getAsImmutablePass(void)
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const `anonymous namespace'::Easy::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::FunctionPass::`vftable')
[build] >>> referenced by easypass/CMakeFiles/easypass.dir/easypass.cpp.obj:(const llvm::Pass::`vftable')
[build] 
[build] lld-link: error: too many errors emitted, stopping now (use /errorlimit:0 to see all errors)
[build] clang: error: linker command failed with exit code 1

解决方案

问题核心是Pass模块未链接必要的LLVM组件库,同时CMake配置存在顺序错误,以下是修复步骤:

1. 修正根目录CMakeLists.txt

  • 移除手动设置的CMAKE_CXX_FLAGS:AddLLVM模块会自动配置符合LLVM要求的编译标准,手动设置可能导致版本不匹配
  • 将LLVM_ENABLE_PLUGINS移至find_package之前:该选项必须在查找LLVM包前设置才会生效
cmake_minimum_required(VERSION 3.25)

project(LLVM1Proj)

# 必须在find_package前启用插件支持
set(LLVM_ENABLE_PLUGINS ON)

# Include LLVM library
find_package(LLVM REQUIRED CONFIG)

list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")

include(AddLLVM)

separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})
include_directories(${LLVM_INCLUDE_DIRS})

add_subdirectory("easypass")

add_executable(LLVM1 "main.cpp")

llvm_map_components_to_libnames(llvm_libs support core irreader)

target_link_libraries(LLVM1 ${llvm_libs})

2. 修正easypass子目录CMakeLists.txt

添加Pass依赖的LLVM组件库,通过llvm_map_components_to_libnames映射所需库,再链接到模块:

llvm_map_components_to_libnames(llvm_libs
  core
  support
  passes
  ipo
)

add_llvm_library(easypass MODULE
  easypass.cpp
  PLUGIN_TOOL
  opt
)

target_link_libraries(easypass PRIVATE ${llvm_libs})

3. 代码可选优化

当前代码本身无错误,但如果使用LLVM 14+版本,Legacy Pass Manager已被标记为过时,建议迁移到新的Pass Manager框架;不过修复链接问题后,现有代码可正常编译运行。


内容的提问来源于stack exchange,提问作者theokipullup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 11:20:27