使用Conan集成LLVM-13时链接Support库遇未定义引用错误求助
我正在使用LLVM conan包构建编译器,此前一切正常,但调用llvm::sys::getDefaultTargetTriple和llvm::TargetRegistry::lookupTarget时出现未定义引用错误。这两个函数来自LLVM Support库,且llvm::sys::getDefaultTargetTriple是自动生成的(本地能找到对应的.inc源文件)。构建日志显示Conan已指示CMake链接LLVM Support库(含-lLLVMSupport参数)。
当前环境是LLVM-13.0.0和gcc-12.0.1,之前GCC5搭配LLVM3/4时出现过类似问题,已修改Conan profile的C++ ABI设置但暂未生效,可能会尝试重新构建LLVM。
急需解决以下问题:
- 如何手动获取当前操作系统对应的目标三元组字符串?LLVM文档显示它基于宏,用
gcc -dumpmachine是否可行? - 手动生成“target”的可行性如何?
- 核心问题:如何修复链接错误,成功链接
llvm::sys::getDefaultTargetTriple和llvm::TargetRegistry::lookupTarget?
root@3129d254c74c:~/workdir/compilerbuild# ninja warp_compiler [2/2] Linking CXX executable bin/warp_compiler FAILED: bin/warp_compiler : && /usr/bin/c++ CMakeFiles/warp_compiler.dir/Compiler/Compile.cpp.o CMakeFiles/warp_compiler.dir/Compiler/FunctionParser.cpp.o CMakeFiles/warp_compiler.dir/Compiler/Main.cpp.o -o bin/warp_compiler -L/root/.conan/data/cpputest/4.0/_/_/package/7f06ab4d29b1f14af224d13dc05f362c6832ed41/lib -L/root/.conan/data/llvm-core/13.0.0/_/_/package/6efbb14f313e71b5e1dbf77c1c011f47614b7c7c/lib -L/root/.conan/data/libxml2/2.9.10/_/_/package/c4a7cacf01760cbd7354b11a55bf653f7df2bf5d/lib -L/root/.conan/data/zlib/1.2.12/_/_/package/2a19826344ff00be1c04403f2f8e7008ed3a7cc6/lib -L/root/.conan/data/libiconv/1.17/_/_/package/2a19826344ff00be1c04403f2f8e7008ed3a7cc6/lib -Wl,-rpath,/root/.conan/data/cpputest/4.0/_/_/package/7f06ab4d29b1f14af224d13dc05f362c6832ed41/lib:/root/.conan/data/llvm-core/13.0.0/_/_/package/6efbb14f313e71b5e1dbf77c1c011f47614b7c7c/lib:/root/.conan/data/libxml2/2.9.10/_/_/package/c4a7cacf01760cbd7354b11a55bf653f7df2bf5d/lib:/root/.conan/data/zlib/1.2.12/_/_/package/2a19826344ff00be1c04403f2f8e7008ed3a7cc6/lib:/root/.conan/data/libiconv/1.17/_/_/package/2a19826344ff00be1c04403f2f8e7008ed3a7cc6/lib lib/liblibwarp.a -lCppUTestExt -lCppUTest -lLLVMTableGenGlobalISel -lLLVMTableGen -lLLVMFileCheck -lLLVMAArch64AsmParser -lLLVMAArch64CodeGen -lLLVMAArch64Disassembler -lLLVMAArch64Desc -lLLVMAArch64Info -lLLVMAArch64Utils -lLLVMAMDGPUAsmParser -lLLVMAMDGPUCodeGen -lLLVMMIRParser -lLLVMAMDGPUDisassembler -lLLVMAMDGPUDesc -lLLVMAMDGPUInfo -lLLVMAMDGPUUtils -lLLVMARMAsmParser -lLLVMARMCodeGen -lLLVMARMDisassembler -lLLVMARMDesc -lLLVMARMInfo -lLLVMARMUtils -lLLVMAVRAsmParser -lLLVMAVRCodeGen -lLLVMAVRDesc -lLLVMAVRDisassembler -lLLVMAVRInfo -lLLVMBPFAsmParser -lLLVMBPFCodeGen -lLLVMBPFDesc -lLLVMBPFDisassembler -lLLVMBPFInfo -lLLVMCoverage -lLLVMDWARFLinker -lLLVMDWP -lLLVMDebugInfoGSYM -lLLVMDlltoolDriver -lLLVMFrontendOpenACC -lLLVMFuzzMutate -lLLVMHexagonCodeGen -lLLVMHexagonAsmParser -lLLVMHexagonDisassembler -lLLVMHexagonDesc -lLLVMHexagonInfo -lLLVMInterfaceStub -lLLVMInterpreter -lLLVMLTO -lLLVMExtensions -lLLVMLanaiCodeGen -lLLVMLanaiAsmParser -lLLVMLanaiDisassembler -lLLVMLanaiDesc -lLLVMLanaiInfo -lLLVMLibDriver -lLLVMOption -lLLVMLineEditor -lLLVMMCA -lLLVMMCJIT -lLLVMMSP430AsmParser -lLLVMMSP430CodeGen -lLLVMMSP430Desc -lLLVMMSP430Disassembler -lLLVMMSP430Info -lLLVMMipsAsmParser -lLLVMMipsCodeGen -lLLVMMipsDesc -lLLVMMipsDisassembler -lLLVMMipsInfo -lLLVMNVPTXCodeGen -lLLVMNVPTXDesc -lLLVMNVPTXInfo -lLLVMObjectYAML -lLLVMOrcJIT -lLLVMPasses -lLLVMCoroutines -lLLVMipo -lLLVMFrontendOpenMP -lLLVMIRReader -lLLVMAsmParser -lLLVMInstrumentation -lLLVMLinker -lLLVMVectorize -lLLVMObjCARCOpts -lLLVMExecutionEngine -lLLVMRuntimeDyld -lLLVMJITLink -lLLVMOrcTargetProcess -lLLVMOrcShared -lLLVMPowerPCAsmParser -lLLVMPowerPCCodeGen -lLLVMPowerPCDesc -lLLVMPowerPCDisassembler -lLLVMPowerPCInfo -lLLVMRISCVAsmParser -lLLVMRISCVCodeGen -lLLVMRISCVDisassembler -lLLVMRISCVDesc -lLLVMRISCVInfo -lLLVMSparcAsmParser -lLLVMSparcCodeGen -lLLVMSparcDesc -lLLVMSparcDisassembler -lLLVMSparcInfo -lLLVMSymbolize -lLLVMDebugInfoPDB -lLLVMSystemZAsmParser -lLLVMSystemZCodeGen -lLLVMSystemZDisassembler -lLLVMSystemZDesc -lLLVMSystemZInfo -lLLVMWebAssemblyAsmParser -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyDesc -lLLVMWebAssemblyInfo -lLLVMWebAssemblyUtils -lLLVMWindowsManifest -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMCFGuard -lLLVMGlobalISel -lLLVMX86Desc -lLLVMX86Disassembler -lLLVMX86Info -lLLVMXCoreCodeGen -lLLVMAsmPrinter -lLLVMDebugInfoDWARF -lLLVMDebugInfoMSF -lLLVMSelectionDAG -lLLVMCodeGen -lLLVMBitWriter -lLLVMScalarOpts -lLLVMAggressiveInstCombine -lLLVMInstCombine -lLLVMTransformUtils -lLLVMTarget -lLLVMAnalysis -lLLVMProfileData -lLLVMXCoreDesc -lLLVMXCoreDisassembler -lLLVMMCDisassembler -lLLVMXCoreInfo -lLLVMXRay -lLLVMObject -lLLVMMCParser -lLLVMMC -lLLVMDebugInfoCodeView -lLLVMBitReader -lLLVMCore -lLLVMRemarks -lLLVMBitstreamReader -lLLVMTextAPI -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle -lxml2 -lz -liconv -lcharset -ldl -lrt -lm -lpthread && : /usr/bin/ld: CMakeFiles/warp_compiler.dir/Compiler/Compile.cpp.o: in function `Warp::SyntaxTranslation::LLVM::initialize_target(llvm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, llvm::TargetOptions, llvm::Optional<llvm::Reloc::Model>)': Compile.cpp:(.text+0x1534): undefined reference to `llvm::TargetRegistry::lookupTarget(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)' /usr/bin/ld: CMakeFiles/warp_compiler.dir/Compiler/Main.cpp.o: in function `main': Main.cpp:(.text+0xf46): undefined reference to `llvm::sys::getDefaultTargetTriple[abi:cxx11]()' collect2: error: ld returned 1 exit status ninja: build stopped: subcommand failed.
1. 手动获取目标三元组字符串
gcc -dumpmachine完全可行,输出结果与LLVM目标三元组格式一致。也可以在代码中直接使用__TARGET_TRIPLE__宏获取编译时的目标三元组;如果需要运行时获取,调用gcc -dumpmachine并捕获输出是最简单的临时方案。
2. 手动生成Target的可行性
完全可行,但需要编写大量样板代码:
- 手动填充
TargetRegistry::Target结构体的所有字段,包括目标名称、三元组、代码生成器、汇编器等指针。 - 调用
TargetRegistry::RegisterTarget完成目标注册,逻辑与LLVM内置目标的注册流程一致。 - 缺点是需要维护与LLVM版本匹配的代码,无法复用LLVM内置目标实现,仅适合临时应急,不推荐长期使用。
3. 修复链接错误的核心方案
方案1:调整库链接顺序
LLVM库依赖关系严格,链接顺序错误会导致未定义引用。从你的链接命令看,-lLLVMSupport放在最后,而llvm::TargetRegistry依赖LLVMTarget库,LLVMTarget又依赖LLVMSupport。将依赖链靠前的库放在链接命令的后面,比如把-lLLVMSupport移到-lLLVMTarget之前,或者直接使用llvm-config --libs输出的官方推荐链接顺序。
方案2:确保C++ ABI兼容性
修改Conan profile后需彻底生效:
- 确认profile中设置
compiler.cppstd与LLVM构建时的C标准一致(比如C17),且compiler.libcxx=libstdc++11(gcc-12默认使用该ABI,但需确认LLVM包是用此ABI编译的)。 - 清空Conan缓存和本地构建目录,重新执行
conan install和构建命令,确保新的profile设置被应用。
方案3:确认LLVM包的目标注册代码
部分LLVM包可能未编译所需目标或未启用初始化代码:
- 检查Conan的LLVM包配置,确认启用了你需要的目标架构(如X86、ARM等)。
- 在代码中手动初始化目标注册,比如添加
extern "C" void LLVMInitializeX86TargetInfo();并调用该函数(对应你的目标架构),确保目标被注册到TargetRegistry中。
方案4:使用llvm-config生成链接参数
放弃Conan自动生成的链接参数,改用llvm-config --libs core support target获取正确的链接库列表和顺序,替换到CMake的链接命令中,这是最可靠的方案之一。
内容的提问来源于stack exchange,提问作者cgbsu

