如何在LLVM中实现隐式extern C?调用外部C++函数遇阻求助
Let's break down your problem and walk through the solutions step by step—your errors stem from missing library loading steps for both JIT execution and static linking.
1. First: Correctly Build Your extern "C" Function as a Dynamic Library
First, ensure your function is compiled into a shared library that exposes the undecorated printd symbol (thanks to extern "C" preventing C++ name mangling).
Save your function in printd.cpp:
#include <cstdio> // Platform-specific export annotation (handles Windows/Linux/macOS) #ifdef _WIN32 #define DLLEXPORT __declspec(dllexport) #else #define DLLEXPORT #endif extern "C" DLLEXPORT double printd(double X) { fprintf(stderr, "%f\n", X); return 0; }
Compile it into a dynamic library:
Linux/macOS
g++ -shared -fPIC printd.cpp -o libmylib.so
Windows (MSVC)
cl /LD printd.cpp /link /OUT:mylib.dll
Windows (Clang)
clang -shared printd.cpp -o mylib.dll
Verify the symbol is undecorated (Linux/macOS):
nm -D libmylib.so | grep printd
You should see a line like 0000000000001129 T printd (no mangled names like _Z6printdd).
2. Fix clang Linking Errors
When linking your IR with clang, you need to specify the library path and name explicitly:
Linux/macOS
clang out.ll -L. -lmylib -o a.out
Run the executable:
./a.out
You'll see 10.000000 printed to stderr.
Windows
Link against the generated .lib (MSVC) or .dll (Clang):
# MSVC-generated library clang out.ll mylib.lib -o a.exe # Clang-generated library clang out.ll mylib.dll -o a.exe
3. Run with lli (JIT Execution)
lli doesn't load custom libraries by default. Use the --dlopen flag to tell it to load your shared library:
Linux/macOS
lli --dlopen ./libmylib.so out.ll
Windows
lli --dlopen mylib.dll out.ll
This resolves the printd symbol and runs your IR successfully.
4. Implement a Custom JIT (C++ Code)
If you're writing your own LLVM JIT code (instead of using lli), use LLVM's ORC JIT framework (ORCv2 is the current standard) to load your dynamic library. Here's a minimal example:
#include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/SourceMgr.h" using namespace llvm; using namespace llvm::orc; int main(int argc, char **argv) { InitLLVM X(argc, argv); cl::opt<std::string> InputFile(cl::Positional, cl::desc("<input LLVM IR file>")); cl::opt<std::string> LibPath("lib", cl::desc("Path to dynamic library")); cl::ParseCommandLineOptions(argc, argv, "Custom JIT for external C function\n"); // Create LLJIT instance auto JIT = LLJITBuilder().create(); if (!JIT) { errs() << "Failed to create JIT: " << toString(JIT.takeError()) << "\n"; return 1; } // Load the external library into the JIT's symbol search space if (!LibPath.empty()) { auto Err = JIT->getMainJITDylib().addGenerator( ExitOnError()(DynamicLibrarySearchGenerator::Load(LibPath))); if (Err) { errs() << "Failed to load library: " << toString(std::move(Err)) << "\n"; return 1; } } // Parse the input LLVM IR file SMDiagnostic Err; auto M = parseIRFile(InputFile, Err, JIT->getContext()); if (!M) { Err.print(argv[0], errs()); return 1; } // Add the IR module to the JIT ExitOnError()(JIT->addIRModule(std::move(M))); // Look up and execute the main function auto MainSym = ExitOnError()(JIT->lookup("main")); using MainFn = int (*)(); auto Main = reinterpret_cast<MainFn>(MainSym.getAddress()); return Main(); }
Compile this with LLVM libraries (adjust paths if your LLVM is in a non-standard location):
g++ jit_example.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core executionengine orcjit irreader` -o jit_example
Run it with your IR and library:
./jit_example out.ll --lib ./libmylib.so
内容的提问来源于stack exchange,提问作者zoecarver

