diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 3d4f6a855..20da268ee 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -757,6 +757,14 @@ namespace Cpp { unsigned complete_line = 1U, unsigned complete_column = 1U); + /// Set libraries autoload. + ///\param[in] autoload - true to enable library autoload. + CPPINTEROP_API void SetLibrariesAutoload(bool autoload = true); + + /// Get libraries autoload status. + ///\returns LibraryAutoLoad state (true = libraries autoload is on). + CPPINTEROP_API bool GetLibrariesAutoload(); + } // end namespace Cpp #endif // CPPINTEROP_CPPINTEROP_H diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 15a177281..2fdaa32ce 100755 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -32,7 +32,9 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/ExecutionEngine/Orc/Core.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_os_ostream.h" @@ -40,6 +42,7 @@ #include #include #include +#include // Stream redirect. #ifdef _WIN32 @@ -64,6 +67,10 @@ namespace Cpp { using namespace llvm; using namespace std; + // Last assigned Autoload SearchGenerator + // TODO: Test fot thread safe. + class AutoLoadLibrarySearchGenerator; + static AutoLoadLibrarySearchGenerator *sAutoSG = nullptr; // Flag to indicate ownership when an external interpreter instance is used. static bool OwningSInterpreter = true; static compat::Interpreter* sInterpreter = nullptr; @@ -1137,7 +1144,6 @@ namespace Cpp { llvm::consumeError(std::move(Err)); // nullptr if missing else return llvm::jitTargetAddressToPointer(*FDAorErr); - return nullptr; } @@ -2728,7 +2734,7 @@ namespace Cpp { std::string BinaryPath = GetExecutablePath(/*Argv0=*/nullptr, MainAddr); // build/tools/clang/unittests/Interpreter/Executable -> build/ - StringRef Dir = sys::path::parent_path(BinaryPath); + Dir = sys::path::parent_path(BinaryPath); Dir = sys::path::parent_path(Dir); Dir = sys::path::parent_path(Dir); @@ -3546,4 +3552,199 @@ namespace Cpp { complete_column); } +#define DEBUG_TYPE "autoload" + + static inline std::string DemangleNameForDlsym(const std::string& name) { + std::string nameForDlsym = name; + + static bool is_demangle_active = false; + static bool demangle = false; + if (!is_demangle_active) { + auto& I = getInterp(); + llvm::orc::LLJIT& EE = *compat::getExecutionEngine(I); + auto t = EE.getTargetTriple(); + demangle = t.isOSDarwin() || t.isOSWindows(); + is_demangle_active = true; + } + + // The JIT gives us a mangled name which has an additional leading underscore + // on macOS and Windows, for instance __ZN8TRandom34RndmEv. However, dlsym + // requires us to remove it. + // FIXME: get this information from the DataLayout via getGlobalPrefix()! + if (demangle && nameForDlsym[0] == '_') + nameForDlsym.erase(0, 1); + return nameForDlsym; + } + + class AutoLoadLibrarySearchGenerator : public llvm::orc::DefinitionGenerator { + bool Enabled = false; + public: + bool isEnabled() { + return Enabled; + } + + void setEnabled(bool enabled) { + Enabled = enabled; + } + + // Lazy materialization unit class helper + class AutoloadLibraryMU : public llvm::orc::MaterializationUnit { + std::string lib; + std::string fLibrary; + llvm::orc::SymbolNameVector fSymbols; + public: + AutoloadLibraryMU(const std::string &Library, const llvm::orc::SymbolNameVector &Symbols) + : MaterializationUnit({getSymbolFlagsMap(Symbols), nullptr}), fLibrary(Library), fSymbols(Symbols) {} + + StringRef getName() const override { + return ""; + } + + void materialize(std::unique_ptr R) override { + //if (!sAutoSG || !sAutoSG->isEnabled()) { + // R->failMaterialization(); + // return; + //} + + LLVM_DEBUG(dbgs() << "Materialize " << lib << " syms=" << fSymbols); + + auto& I = getInterp(); + auto *DLM = I.getDynamicLibraryManager(); + + llvm::orc::SymbolMap loadedSymbols; + llvm::orc::SymbolNameSet failedSymbols; + bool loadedLibrary = false; + + for (const auto &symbol : fSymbols) { + std::string symbolStr = (*symbol).str(); + std::string nameForDlsym = DemangleNameForDlsym(symbolStr); + + // Check if the symbol is available without loading the library. + void *addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(nameForDlsym); + + if (!addr && !loadedLibrary) { + // Try to load the library which should provide the symbol definition. + if (DLM->loadLibrary(lib, false) != DynamicLibraryManager::LoadLibResult::kLoadLibSuccess) { + LLVM_DEBUG(dbgs() << "MU: Failed to load library " << lib); + string err = "MU: Failed to load library! " + lib; + perror(err.c_str()); + } else { + LLVM_DEBUG(dbgs() << "MU: Autoload library " << lib); + } + + // Only try loading the library once. + loadedLibrary = true; + + addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(nameForDlsym); + } + + if (addr) { + loadedSymbols[symbol] = +#if CLANG_VERSION_MAJOR < 17 + llvm::JITEvaluatedSymbol::fromPointer(addr, JITSymbolFlags::Exported); +#else + llvm::orc::ExecutorSymbolDef(llvm::orc::ExecutorAddr::fromPtr(addr), JITSymbolFlags::Exported); +#endif // CLANG_VERSION_MAJOR < 17 + } else { + // Collect all failing symbols, delegate their responsibility and then + // fail their materialization. R->defineNonExistent() sounds like it + // should do that, but it's not implemented?! + failedSymbols.insert(symbol); + } + } + + if (!failedSymbols.empty()) { + auto failingMR = R->delegate(failedSymbols); + if (failingMR) { + (*failingMR)->failMaterialization(); + } + } + + if (!loadedSymbols.empty()) { + llvm::cantFail(R->notifyResolved(loadedSymbols)); + +#if CLANG_VERSION_MAJOR > 18 + llvm::orc::SymbolDependenceGroup DepGroup; + llvm::cantFail(R->notifyEmitted({DepGroup})); +#else + llvm::cantFail(R->notifyEmitted()); +#endif + } + } + + void discard(const llvm::orc::JITDylib &JD, const llvm::orc::SymbolStringPtr &Name) override {} + + private: + static llvm::orc::SymbolFlagsMap getSymbolFlagsMap(const llvm::orc::SymbolNameVector &Symbols) { + llvm::orc::SymbolFlagsMap map; + for (const auto &symbolName : Symbols) + map[symbolName] = llvm::JITSymbolFlags::Exported; + return map; + } + }; + + llvm::Error tryToGenerate(llvm::orc::LookupState &LS, llvm::orc::LookupKind K, llvm::orc::JITDylib &JD, + llvm::orc::JITDylibLookupFlags JDLookupFlags, const llvm::orc::SymbolLookupSet &Symbols) override { + if (!isEnabled()) + return llvm::Error::success(); + LLVM_DEBUG(dbgs() << "tryToGenerate"); + + auto& I = getInterp(); + auto *DLM = I.getDynamicLibraryManager(); + + std::unordered_map found; + llvm::orc::SymbolMap NewSymbols; + for (const auto &KV : Symbols) { + const auto &Name = KV.first; + if ((*Name).empty()) + continue; + + auto lib = DLM->searchLibrariesForSymbol(*Name, /*searchSystem=*/true); // false? + if (lib.empty()) + continue; + + found[lib].push_back(Name); + + // Workaround: This getAddressOfGlobal call make first symbol search + // to work, immediatelly after library auto load. This approach do not + // use MU + //DLM->loadLibrary(lib, true); + //I.getAddressOfGlobal(*Name); + } + + for (auto &&KV : found) { + auto MU = std::make_unique(KV.first, std::move(KV.second)); + if (auto Err = JD.define(MU)) + return Err; + } + + return llvm::Error::success(); + } + + }; + + void SetLibrariesAutoload(bool autoload /* = true */) { + auto& I = getInterp(); + llvm::orc::LLJIT& EE = *compat::getExecutionEngine(I); +#if CLANG_VERSION_MAJOR < 17 + llvm::orc::JITDylib& DyLib = EE.getMainJITDylib(); +#else + llvm::orc::JITDylib& DyLib = *EE.getProcessSymbolsJITDylib().get(); +#endif // CLANG_VERSION_MAJOR + + if (!sAutoSG) { + sAutoSG = &DyLib.addGenerator(std::make_unique()); + } + sAutoSG->setEnabled(autoload); + + LLVM_DEBUG(dbgs() << "Autoload=" << (sAutoSG->isEnabled() ? "ON" : "OFF")); + } + + bool GetLibrariesAutoload() { + LLVM_DEBUG(dbgs() << "Autoload is " << (sAutoSG && sAutoSG->isEnabled() ? "ON" : "OFF")); + return sAutoSG && sAutoSG->isEnabled(); + } + +#undef DEBUG_TYPE + } // end namespace Cpp diff --git a/lib/Interpreter/DynamicLibraryManager.cpp b/lib/Interpreter/DynamicLibraryManager.cpp index 630ad23a6..38ac626d7 100644 --- a/lib/Interpreter/DynamicLibraryManager.cpp +++ b/lib/Interpreter/DynamicLibraryManager.cpp @@ -243,7 +243,7 @@ namespace Cpp { // get canonical path name and check if already loaded const std::string Path = platform::NormalizePath(foundDyLib); if (Path.empty()) { - LLVM_DEBUG(dbgs() << "cling::DynamicLibraryManager::lookupLibMaybeAddExt(): " + LLVM_DEBUG(dbgs() << "DynamicLibraryManager::lookupLibMaybeAddExt(): " << "error getting real (canonical) path of library " << foundDyLib << '\n'); return foundDyLib; } @@ -392,10 +392,9 @@ namespace Cpp { return; DyLibHandle dyLibHandle = nullptr; - for (DyLibs::const_iterator I = m_DyLibs.begin(), E = m_DyLibs.end(); - I != E; ++I) { - if (I->second == canonicalLoadedLib) { - dyLibHandle = I->first; + for (const auto& dylib : m_DyLibs) { + if (dylib.second == canonicalLoadedLib) { + dyLibHandle = dylib.first; break; } } @@ -405,7 +404,7 @@ namespace Cpp { std::string errMsg; platform::DLClose(dyLibHandle, &errMsg); if (!errMsg.empty()) { - LLVM_DEBUG(dbgs() << "cling::DynamicLibraryManager::unloadLibrary(): " + LLVM_DEBUG(dbgs() << "DynamicLibraryManager::unloadLibrary(): " << errMsg << '\n'); } diff --git a/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index ac1857fa5..a7c7ded72 100644 --- a/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -1260,7 +1260,7 @@ namespace Cpp { void DynamicLibraryManager::initializeDyld( std::function shouldPermanentlyIgnore) { - //assert(!m_Dyld && "Already initialized!"); + assert(!m_Dyld && "Already initialized!"); if (m_Dyld) delete m_Dyld; diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 972b1e475..04a6c59ed 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -38,6 +38,7 @@ endif() DEPENDS) # FIXME: Just call gtest_add_tests this function is available. #gtest_add_tests(${name} "${Arguments}" AUTO) + llvm_update_compile_flags(${name}) endfunction() add_subdirectory(CppInterOp) diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 25f59b394..fb1398371 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -20,8 +20,8 @@ target_link_libraries(CppInterOpTests ) set_output_directory(CppInterOpTests - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/CppInterOpTests/unittests/bin/$/ - LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/CppInterOpTests/unittests/bin/$/ + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin/$/ + LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin/$/ ) if(NOT WIN32) @@ -43,6 +43,15 @@ target_link_libraries(DynamicLibraryManagerTests clangCppInterOp ) +set_source_files_properties(DynamicLibraryManagerTest.cpp PROPERTIES COMPILE_DEFINITIONS + "LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\"" + ) +set_source_files_properties(DynamicLibraryManagerTest.cpp PROPERTIES COMPILE_DEFINITIONS + "CPPINTEROP_VERSION=\"${CPPINTEROP_VERSION}\"" + ) + +set_output_directory(DynamicLibraryManagerTests BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/TestSharedLib/unittests/bin/$/) + set_output_directory(DynamicLibraryManagerTests BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/TestSharedLib/unittests/bin/$/ LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/TestSharedLib/unittests/bin/$/ @@ -50,3 +59,11 @@ set_output_directory(DynamicLibraryManagerTests add_dependencies(DynamicLibraryManagerTests TestSharedLib) #export_executable_symbols_for_plugins(TestSharedLib) add_subdirectory(TestSharedLib) + +add_dependencies(DynamicLibraryManagerTests TestSharedLib1) +#export_executable_symbols_for_plugins(TestSharedLib1) +add_subdirectory(TestSharedLib1) + +add_dependencies(DynamicLibraryManagerTests TestSharedLib2) +#export_executable_symbols_for_plugins(TestSharedLib2) +add_subdirectory(TestSharedLib2) diff --git a/unittests/CppInterOp/DynamicLibraryManagerTest.cpp b/unittests/CppInterOp/DynamicLibraryManagerTest.cpp index 01624ef78..5bddb915f 100644 --- a/unittests/CppInterOp/DynamicLibraryManagerTest.cpp +++ b/unittests/CppInterOp/DynamicLibraryManagerTest.cpp @@ -2,55 +2,175 @@ #include "clang/Interpreter/CppInterOp.h" + +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +// Helper functions // This function isn't referenced outside its translation unit, but it // can't use the "static" keyword because its address is used for // GetMainExecutable (since some platforms don't support taking the // address of main, and some platforms can't implement GetMainExecutable // without being given the address of a function in the main executable). -std::string GetExecutablePath(const char* Argv0) { +std::string GetExecutablePath(const char* Argv0, void* mainAddr = nullptr) { // This just needs to be some symbol in the binary; C++ doesn't // allow taking the address of ::main however. - void* MainAddr = (void*)intptr_t(GetExecutablePath); + void* MainAddr = mainAddr ? mainAddr : (void*)intptr_t(GetExecutablePath); return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); } +// Mangle symbol name +static inline std::string MangleNameForDlsym(const std::string& name) { + std::string nameForDlsym = name; +#if defined(R__MACOSX) || defined(R__WIN32) + if (nameForDlsym[0] != '_') + nameForDlsym.insert (0, 1, '_'); +#endif //R__MACOSX + return nameForDlsym; +} + +#include "../../lib/Interpreter/CppInterOp.cpp" + + +// Tests + TEST(DynamicLibraryManagerTest, Sanity) { EXPECT_TRUE(Cpp::CreateInterpreter()); - EXPECT_FALSE(Cpp::GetFunctionAddress("ret_zero")); + EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_zero").c_str())); - std::string BinaryPath = GetExecutablePath(/*Argv0=*/nullptr); + std::string BinaryPath = GetExecutablePath(nullptr, nullptr); llvm::StringRef Dir = llvm::sys::path::parent_path(BinaryPath); Cpp::AddSearchPath(Dir.str().c_str()); + // Find and load library with "ret_zero" symbol defined and exported + // // FIXME: dlsym on mach-o takes the C-level name, however, the macho-o format // adds an additional underscore (_) prefix to the lowered names. Figure out // how to harmonize that API. -#ifdef __APPLE__ - std::string PathToTestSharedLib = - Cpp::SearchLibrariesForSymbol("_ret_zero", /*system_search=*/false); -#else std::string PathToTestSharedLib = - Cpp::SearchLibrariesForSymbol("ret_zero", /*system_search=*/false); -#endif // __APPLE__ - + Cpp::SearchLibrariesForSymbol(MangleNameForDlsym("ret_zero").c_str(), /*search_system=*/false); EXPECT_STRNE("", PathToTestSharedLib.c_str()) - << "Cannot find: '" << PathToTestSharedLib << "' in '" << Dir.str() - << "'"; - + << "Cannot find: '" << PathToTestSharedLib << "' in '" << Dir.str() << "'"; EXPECT_TRUE(Cpp::LoadLibrary(PathToTestSharedLib.c_str())); + // Force ExecutionEngine to be created. Cpp::Process(""); + // FIXME: Conda returns false to run this code on osx. -#ifndef __APPLE__ - EXPECT_TRUE(Cpp::GetFunctionAddress("ret_zero")); -#endif //__APPLE__ + EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_zero").c_str())); Cpp::UnloadLibrary("TestSharedLib"); // We have no reliable way to check if it was unloaded because posix does not // require the library to be actually unloaded but just the handle to be // invalidated... - // EXPECT_FALSE(Cpp::GetFunctionAddress("ret_zero")); + // EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_zero").c_str())); +} + +TEST(DynamicLibraryManagerTest, LibrariesAutoload) { + EXPECT_TRUE(Cpp::CreateInterpreter()); + + // Autoload by default is OFF. Symbol search must fail. + EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str())); + + // Libraries Search path by default is set to main executable directory. + std::string BinaryPath = GetExecutablePath(nullptr, nullptr); + llvm::StringRef Dir = llvm::sys::path::parent_path(BinaryPath); + Cpp::AddSearchPath(Dir.str().c_str()); + + // Find library with "ret_one" symbol defined and exported + // + // FIXME: dlsym on mach-o takes the C-level name, however, the macho-o format + // adds an additional underscore (_) prefix to the lowered names. Figure out + // how to harmonize that API. For now we use out minimal implementation of + // helper function. + std::string PathToTestSharedLib1 = + Cpp::SearchLibrariesForSymbol(MangleNameForDlsym("ret_one").c_str(), /*search_system=*/false); + // If result is "" then we cannot find this library. + EXPECT_STRNE("", PathToTestSharedLib1.c_str()) + << "Cannot find: '" << PathToTestSharedLib1 << "' in '" << Dir.str() << "'"; + + // Force ExecutionEngine to be created. + Cpp::Process(""); + + // Check default Autoload is OFF + EXPECT_FALSE(Cpp::GetLibrariesAutoload()); + // Find symbol must fail (when auotload=off) + EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str())); + + // Autoload turn ON + Cpp::SetLibrariesAutoload(true); + // Check autorum status (must be turned ON) + EXPECT_TRUE(Cpp::GetLibrariesAutoload()); + + // FIXME: Conda returns false to run this code on osx. + EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str())); + // Check for some symbols (exists and not exists) + EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_not_exist").c_str())); + EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_not_exist1").c_str())); + EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_two").c_str())); + + //Cpp::UnloadLibrary("TestSharedLib1"); + //// We have no reliable way to check if it was unloaded because posix does not + //// require the library to be actually unloaded but just the handle to be + //// invalidated... + //EXPECT_FALSE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str())); + + // Autoload turn OFF + Cpp::SetLibrariesAutoload(false); + // Check autorum status (must be turned OFF) + EXPECT_FALSE(Cpp::GetLibrariesAutoload()); + EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str())); // false if unload works + + // Autoload turn ON again + Cpp::SetLibrariesAutoload(true); + // Check autorum status (must be turned ON) + EXPECT_TRUE(Cpp::GetLibrariesAutoload()); + EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_one").c_str())); + + // Find library with "ret_1" symbol defined and exported + std::string PathToTestSharedLib2 = + Cpp::SearchLibrariesForSymbol(MangleNameForDlsym("ret_1").c_str(), /*search_system=*/false); + // If result is "" then we cannot find this library. + EXPECT_STRNE("", PathToTestSharedLib2.c_str()) + << "Cannot find: '" << PathToTestSharedLib2 << "' in '" << Dir.str() << "'"; + // Find symbol must success (when auotload=on) + EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_1").c_str())); + // Find symbol must success (when auotload=on) + EXPECT_TRUE(Cpp::GetFunctionAddress(MangleNameForDlsym("ret_2").c_str())); +} + +TEST(DynamicLibraryManagerTest, LibrariesAutoloadExtraCoverage) { + EXPECT_TRUE(Cpp::CreateInterpreter()); + + // Libraries Search path by default is set to main executable directory. + std::string BinaryPath = GetExecutablePath(nullptr, nullptr); + llvm::StringRef Dir = llvm::sys::path::parent_path(BinaryPath); + Cpp::AddSearchPath(Dir.str().c_str()); + + // Force ExecutionEngine to be created. + Cpp::Process(""); + + // Autoload turn ON + Cpp::SetLibrariesAutoload(true); + // Check autorum status (must be turned ON) + EXPECT_TRUE(Cpp::GetLibrariesAutoload()); + + // Cover: MU getName() + std::string res; + llvm::raw_string_ostream rss(res); + const llvm::orc::SymbolNameVector syms; + Cpp::AutoLoadLibrarySearchGenerator::AutoloadLibraryMU MU("test", syms); + rss << MU; + EXPECT_STRNE("", rss.str().c_str()) << "MU problem!"; + + //TODO: Test and cover also if it is possible: + // 1. Error when LoadLibrary + // 2. if (!failedSymbols.empty()) { ... + // 3. void discard(const llvm::orc::JITDylib &JD, const llvm::orc::SymbolStringPtr &Name) override {} + // 4. if (Path.empty()) { ... + // 5. platform::DLClose(dyLibHandle, &errMsg); } diff --git a/unittests/CppInterOp/TestSharedLib1/CMakeLists.txt b/unittests/CppInterOp/TestSharedLib1/CMakeLists.txt new file mode 100644 index 000000000..a5b2a3d80 --- /dev/null +++ b/unittests/CppInterOp/TestSharedLib1/CMakeLists.txt @@ -0,0 +1,11 @@ +add_llvm_library(TestSharedLib1 + SHARED + DISABLE_LLVM_LINK_LLVM_DYLIB + BUILDTREE_ONLY + TestSharedLib1.cpp) +# Put TestSharedLib1 next to the unit test executable. +set_output_directory(TestSharedLib1 + BINARY_DIR ${CMAKE_BINARY_DIR}/unittests/bin/$/ + LIBRARY_DIR ${CMAKE_BINARY_DIR}/unittests/bin/$/ + ) +set_target_properties(TestSharedLib1 PROPERTIES FOLDER "Tests") diff --git a/unittests/CppInterOp/TestSharedLib1/TestSharedLib1.cpp b/unittests/CppInterOp/TestSharedLib1/TestSharedLib1.cpp new file mode 100644 index 000000000..ef11b565a --- /dev/null +++ b/unittests/CppInterOp/TestSharedLib1/TestSharedLib1.cpp @@ -0,0 +1,5 @@ +#include "TestSharedLib1.h" + +int ret_one() { return 1; } + +int ret_two() { return 2; } diff --git a/unittests/CppInterOp/TestSharedLib1/TestSharedLib1.h b/unittests/CppInterOp/TestSharedLib1/TestSharedLib1.h new file mode 100644 index 000000000..8fa3d4f5b --- /dev/null +++ b/unittests/CppInterOp/TestSharedLib1/TestSharedLib1.h @@ -0,0 +1,13 @@ +#ifndef UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB1_H +#define UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB1_H + +// Avoid having to mangle/demangle the symbol name in tests +#ifdef _WIN32 +extern "C" __declspec(dllexport) int ret_one(); +extern "C" __declspec(dllexport) int ret_two(); +#else +extern "C" int ret_one(); +extern "C" int ret_two(); +#endif + +#endif // UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB1_H diff --git a/unittests/CppInterOp/TestSharedLib2/CMakeLists.txt b/unittests/CppInterOp/TestSharedLib2/CMakeLists.txt new file mode 100644 index 000000000..275d0af11 --- /dev/null +++ b/unittests/CppInterOp/TestSharedLib2/CMakeLists.txt @@ -0,0 +1,11 @@ +add_llvm_library(TestSharedLib2 + SHARED + DISABLE_LLVM_LINK_LLVM_DYLIB + BUILDTREE_ONLY + TestSharedLib2.cpp) +# Put TestSharedLib2 next to the unit test executable. +set_output_directory(TestSharedLib2 + BINARY_DIR ${CMAKE_BINARY_DIR}/unittests/bin/$/ + LIBRARY_DIR ${CMAKE_BINARY_DIR}/unittests/bin/$/ + ) +set_target_properties(TestSharedLib2 PROPERTIES FOLDER "Tests") diff --git a/unittests/CppInterOp/TestSharedLib2/TestSharedLib2.cpp b/unittests/CppInterOp/TestSharedLib2/TestSharedLib2.cpp new file mode 100644 index 000000000..dd7c1f0da --- /dev/null +++ b/unittests/CppInterOp/TestSharedLib2/TestSharedLib2.cpp @@ -0,0 +1,5 @@ +#include "TestSharedLib2.h" + +int ret_1() { return 1; } + +int ret_2() { return 2; } diff --git a/unittests/CppInterOp/TestSharedLib2/TestSharedLib2.h b/unittests/CppInterOp/TestSharedLib2/TestSharedLib2.h new file mode 100644 index 000000000..d0095f89d --- /dev/null +++ b/unittests/CppInterOp/TestSharedLib2/TestSharedLib2.h @@ -0,0 +1,13 @@ +#ifndef UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H +#define UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H + +// Avoid having to mangle/demangle the symbol name in tests +#ifdef _WIN32 +extern "C" __declspec(dllexport) int ret_1(); +extern "C" __declspec(dllexport) int ret_2(); +#else +extern "C" int ret_1(); +extern "C" int ret_2(); +#endif + +#endif // UNITTESTS_CPPINTEROP_TESTSHAREDLIB_TESTSHAREDLIB2_H