Index: llvm/include/llvm-c/Orc.h =================================================================== --- llvm/include/llvm-c/Orc.h +++ llvm/include/llvm-c/Orc.h @@ -920,6 +920,43 @@ LLVMOrcDefinitionGeneratorRef *Result, char GlobalPrefx, LLVMOrcSymbolPredicate Filter, void *FilterCtx); +/** + * Get a LLVMOrcCreateDynamicLibararySearchGeneratorForPath that will reflect + * library symbols into the JITDylib. On success the resulting generator is + * owned by the client. Ownership is typically transferred by adding the + * instance to a JITDylib using LLVMOrcJITDylibAddGenerator, + * + * The GlobalPrefix argument specifies the character that appears on the front + * of linker-mangled symbols for the target platform (e.g. '_' on MachO). + * If non-null, this character will be stripped from the start of all symbol + * strings before passing the remaining substring to dlsym. + * + * The optional Filter and Ctx arguments can be used to supply a symbol name + * filter: Only symbols for which the filter returns true will be visible to + * JIT'd code. If the Filter argument is null then all library symbols will + * be visible to JIT'd code. Note that the symbol name passed to the Filter + * function is the full mangled symbol: The client is responsible for stripping + * the global prefix if present. + */ +LLVMErrorRef LLVMOrcCreateDynamicLibrarySearchGeneratorForPath( + LLVMOrcDefinitionGeneratorRef *Result, const char *FileName, + char GlobalPrefix, LLVMOrcSymbolPredicate Filter, void *FilterCtx); + +/** + * Get a LLVMOrcCreateStaticLibrarySearchGeneratorForPath that will reflect + * static library symbols into the JITDylib. On success the resulting + * generator is owned by the client. Ownership is typically transferred by + * adding the instance to a JITDylib using LLVMOrcJITDylibAddGenerator, + * + * Call with the optional TargetTriple argument will succeed if the file at + * the given path is a static library or a MachO universal binary containing a + * static library that is compatible with the given triple. Otherwise it will + * return an error. + */ +LLVMErrorRef LLVMOrcCreateStaticLibrarySearchGeneratorForPath( + LLVMOrcDefinitionGeneratorRef *Result, LLVMOrcObjectLayerRef ObjLayer, + const char *FileName, const char *TargetTriple); + /** * Create a ThreadSafeContext containing a new LLVMContext. * Index: llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp =================================================================== --- llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp +++ llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp @@ -619,6 +619,61 @@ return LLVMErrorSuccess; } +LLVMErrorRef LLVMOrcCreateDynamicLibrarySearchGeneratorForPath( + LLVMOrcDefinitionGeneratorRef *Result, const char *FileName, + char GlobalPrefix, LLVMOrcSymbolPredicate Filter, void *FilterCtx) { + assert(Result && "Result can not be null"); + assert(FileName && "FileName can not be null"); + assert((Filter || !FilterCtx) && + "if Filter is null then FilterCtx must also be null"); + + DynamicLibrarySearchGenerator::SymbolPredicate Pred; + if (Filter) + Pred = [=](const SymbolStringPtr &Name) -> bool { + return Filter(FilterCtx, wrap(OrcV2CAPIHelper::getRawPoolEntryPtr(Name))); + }; + + auto LibrarySymsGenerator = + DynamicLibrarySearchGenerator::Load(FileName, GlobalPrefix, Pred); + + if (!LibrarySymsGenerator) { + *Result = 0; + return wrap(LibrarySymsGenerator.takeError()); + } + + *Result = wrap(LibrarySymsGenerator->release()); + return LLVMErrorSuccess; +} + +LLVMErrorRef LLVMOrcCreateStaticLibrarySearchGeneratorForPath( + LLVMOrcDefinitionGeneratorRef *Result, LLVMOrcObjectLayerRef ObjLayer, + const char *FileName, const char *TargetTriple) { + assert(Result && "Result can not be null"); + assert(FileName && "Filename can not be null"); + assert(ObjLayer && "ObjectLayer can not be null"); + + if (TargetTriple) { + auto TT = Triple(TargetTriple); + auto LibrarySymsGenerator = + StaticLibraryDefinitionGenerator::Load(*unwrap(ObjLayer), FileName, TT); + if (!LibrarySymsGenerator) { + *Result = 0; + return wrap(LibrarySymsGenerator.takeError()); + } + *Result = wrap(LibrarySymsGenerator->release()); + return LLVMErrorSuccess; + } else { + auto LibrarySymsGenerator = + StaticLibraryDefinitionGenerator::Load(*unwrap(ObjLayer), FileName); + if (!LibrarySymsGenerator) { + *Result = 0; + return wrap(LibrarySymsGenerator.takeError()); + } + *Result = wrap(LibrarySymsGenerator->release()); + return LLVMErrorSuccess; + } +} + LLVMOrcThreadSafeContextRef LLVMOrcCreateNewThreadSafeContext(void) { return wrap(new ThreadSafeContext(std::make_unique())); } Index: llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt =================================================================== --- llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt +++ llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -14,7 +14,7 @@ native ) -add_llvm_unittest(OrcJITTests +add_llvm_unittest_with_input_files(OrcJITTests CoreAPIsTest.cpp ExecutionSessionWrapperFunctionCallsTest.cpp EPCGenericMemoryAccessTest.cpp Index: llvm/unittests/ExecutionEngine/Orc/Inputs/library_search_definition_test.c =================================================================== --- /dev/null +++ llvm/unittests/ExecutionEngine/Orc/Inputs/library_search_definition_test.c @@ -0,0 +1 @@ +int test(void) { return 1; } Index: llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp =================================================================== --- llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp +++ llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp @@ -18,12 +18,22 @@ #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Support/Error.h" +#include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Testing/Support/Error.h" #include using namespace llvm; using namespace llvm::orc; +extern const char *TestMainArgv0; + +static std::string getFilePath(std::string FileName) { + SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0); + llvm::sys::path::append(InputsDir, FileName); + return std::string(InputsDir); +} + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef) // OrcCAPITestBase contains several helper methods and pointers for unit tests @@ -277,6 +287,49 @@ ASSERT_EQ(ExpectedAddr, OutAddr); } +TEST_F(OrcCAPITestBase, DynamiLibraryDefinitionGenerators) { + LLVMOrcDefinitionGeneratorRef Gen; + if (LLVMErrorRef E = LLVMOrcCreateDynamicLibrarySearchGeneratorForPath( + &Gen, + getFilePath("libdynamic_library_search_definition_test.dylib") + .c_str(), + '_', NULL, NULL)) + FAIL() << "Error loading dynamic library: " << toString(E); + + LLVMOrcJITDylibAddGenerator(MainDylib, Gen); + LLVMOrcJITTargetAddress TestFnAddr; + if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "test")) + FAIL() << "The DefinitionGenerator did not create symbol \"test\" " + << "(triple = " << TargetTriple << "): " << toString(E); + + using TestFunctionType = int (*)(void); + auto *TestFn = (TestFunctionType)(TestFnAddr); + int Result = TestFn(); + ASSERT_EQ(1, Result); +} + +TEST_F(OrcCAPITestBase, StaticLibraryDefinitionGenerators) { + LLVMOrcDefinitionGeneratorRef Gen; + LLVMOrcObjectLayerRef ObjLinkingLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit); + + if (LLVMErrorRef E = LLVMOrcCreateStaticLibrarySearchGeneratorForPath( + &Gen, ObjLinkingLayer, + getFilePath("libstatic_library_search_definition_test.a").c_str(), + NULL)) + FAIL() << "Error loading static library: " << toString(E); + + LLVMOrcJITDylibAddGenerator(MainDylib, Gen); + LLVMOrcJITTargetAddress TestFnAddr; + if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "test")) + FAIL() << "The DefinitionGenerator did not create symbol \"test\" " + << "(triple = " << TargetTriple << "): " << toString(E); + + using TestFunctionType = int (*)(void); + auto *TestFn = (TestFunctionType)(TestFnAddr); + int Result = TestFn(); + ASSERT_EQ(1, Result); +} + TEST_F(OrcCAPITestBase, ResourceTrackerDefinitionLifetime) { // This test case ensures that all symbols loaded into a JITDylib with a // ResourceTracker attached are cleared from the JITDylib once the RT is