diff options
author | Brad King <brad.king@kitware.com> | 2019-09-19 14:10:52 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2019-09-19 14:42:51 (GMT) |
commit | c578caa68bf7ee55077a3efa25aba46e9e1f562a (patch) | |
tree | 7609ec94c8bb5e13e018b3d8fc08b3e362afea5b /Tests/Plugin | |
parent | 56879273dc87a69e1d1491a73e0f74cd4424494c (diff) | |
download | CMake-c578caa68bf7ee55077a3efa25aba46e9e1f562a.zip CMake-c578caa68bf7ee55077a3efa25aba46e9e1f562a.tar.gz CMake-c578caa68bf7ee55077a3efa25aba46e9e1f562a.tar.bz2 |
Tests: Decouple Plugin test from KWSys
KWSys now requires C++11 but we want this test to be able to run as
C++98. Copy the KWSys DynamicLoader implementation (with original
notice headers and license reference) and update it to work alone.
Diffstat (limited to 'Tests/Plugin')
-rw-r--r-- | Tests/Plugin/CMakeLists.txt | 12 | ||||
-rw-r--r-- | Tests/Plugin/include/DynamicLoader.hxx | 49 | ||||
-rw-r--r-- | Tests/Plugin/src/DynamicLoader.cxx | 263 | ||||
-rw-r--r-- | Tests/Plugin/src/example_exe.cxx | 17 | ||||
-rw-r--r-- | Tests/Plugin/src/example_exe.h.in | 2 |
5 files changed, 323 insertions, 20 deletions
diff --git a/Tests/Plugin/CMakeLists.txt b/Tests/Plugin/CMakeLists.txt index 8e8fa07..729bba3 100644 --- a/Tests/Plugin/CMakeLists.txt +++ b/Tests/Plugin/CMakeLists.txt @@ -10,14 +10,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/lib/plugin) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${Plugin_BINARY_DIR}/lib/static) -# We need the dynamic loader support from KWSys to load the plugin in -# the executable. -set(KWSYS_NAMESPACE kwsys) -set(KWSYS_HEADER_ROOT ${Plugin_BINARY_DIR}/include) -set(KWSYS_USE_DynamicLoader 1) -set(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_UTF8) -add_subdirectory(${Plugin_SOURCE_DIR}/../../Source/kwsys src/kwsys) - # Configure the location of plugins. configure_file(${Plugin_SOURCE_DIR}/src/example_exe.h.in ${Plugin_BINARY_DIR}/include/example_exe.h @ONLY) @@ -36,14 +28,14 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND endif() # Create an executable that exports an API for use by plugins. -add_executable(example_exe src/example_exe.cxx) +add_executable(example_exe src/example_exe.cxx src/DynamicLoader.cxx) set_target_properties(example_exe PROPERTIES ENABLE_EXPORTS 1 OUTPUT_NAME example # Test placing exe import library in unique directory. ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/exe ) -target_link_libraries(example_exe kwsys) +target_link_libraries(example_exe ${CMAKE_DL_LIBS}) # Create a plugin that uses the API provided by the executable. # This module "links" to the executable to use the symbols. diff --git a/Tests/Plugin/include/DynamicLoader.hxx b/Tests/Plugin/include/DynamicLoader.hxx new file mode 100644 index 0000000..20b37de --- /dev/null +++ b/Tests/Plugin/include/DynamicLoader.hxx @@ -0,0 +1,49 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. + See https://cmake.org/licensing#kwsys for details. */ +#ifndef DynamicLoader_hxx +#define DynamicLoader_hxx + +#include <string> + +#if defined(__hpux) +# include <dl.h> +#elif defined(_WIN32) && !defined(__CYGWIN__) +# include <windows.h> +#elif defined(__APPLE__) +# include <AvailabilityMacros.h> +# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 +# include <mach-o/dyld.h> +# endif +#elif defined(__BEOS__) +# include <be/kernel/image.h> +#endif + +class DynamicLoader +{ +public: +#if defined(__hpux) + typedef shl_t LibraryHandle; +#elif defined(_WIN32) && !defined(__CYGWIN__) + typedef HMODULE LibraryHandle; +#elif defined(__APPLE__) +# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 + typedef NSModule LibraryHandle; +# else + typedef void* LibraryHandle; +# endif +#elif defined(__BEOS__) + typedef image_id LibraryHandle; +#else // POSIX + typedef void* LibraryHandle; +#endif + + typedef void (*SymbolPointer)(); + + static LibraryHandle OpenLibrary(const std::string&); + + static int CloseLibrary(LibraryHandle); + + static SymbolPointer GetSymbolAddress(LibraryHandle, const std::string&); +}; + +#endif diff --git a/Tests/Plugin/src/DynamicLoader.cxx b/Tests/Plugin/src/DynamicLoader.cxx new file mode 100644 index 0000000..d4a2637 --- /dev/null +++ b/Tests/Plugin/src/DynamicLoader.cxx @@ -0,0 +1,263 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. + See https://cmake.org/licensing#kwsys for details. */ +#if defined(_WIN32) +# define NOMINMAX // hide min,max to not conflict with <limits> +#endif + +#include <DynamicLoader.hxx> + +#if defined(__hpux) +# include <dl.h> + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname) +{ + return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L); +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + if (!lib) { + return 0; + } + return !shl_unload(lib); +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + void* addr; + int status; + + /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default) + * TYPE_DATA Look for a symbol in the data segment (for example, + * variables). + * TYPE_UNDEFINED Look for any symbol. + */ + status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr); + void* result = (status < 0) ? (void*)0 : addr; + + // Hack to cast pointer-to-data to pointer-to-function. + return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result); +} + +#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030) +# include <mach-o/dyld.h> + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname) +{ + NSObjectFileImageReturnCode rc; + NSObjectFileImage image = 0; + + rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image); + // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file + if (rc != NSObjectFileImageSuccess) { + return 0; + } + NSModule handle = NSLinkModule(image, libname.c_str(), + NSLINKMODULE_OPTION_BINDNOW | + NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSDestroyObjectFileImage(image); + return handle; +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE); + return success; +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + void* result = 0; + // Need to prepend symbols with '_' on Apple-gcc compilers + std::string rsym = '_' + sym; + + NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str()); + if (symbol) { + result = NSAddressOfSymbol(symbol); + } + + // Hack to cast pointer-to-data to pointer-to-function. + return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result); +} + +#elif defined(_WIN32) && !defined(__CYGWIN__) +# include <windows.h> + +# include <stdio.h> + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname) +{ + DynamicLoader::LibraryHandle lh; + int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0); + wchar_t* wchars = new wchar_t[length + 1]; + wchars[0] = '\0'; + MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length); + lh = LoadLibraryW(wchars); + delete[] wchars; + return lh; +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + return (int)FreeLibrary(lib); +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + void* result; +# if defined(__BORLANDC__) || defined(__WATCOMC__) + // Need to prepend symbols with '_' + std::string ssym = '_' + sym; + const char* rsym = ssym.c_str(); +# else + const char* rsym = sym.c_str(); +# endif + result = (void*)GetProcAddress(lib, rsym); +// Hack to cast pointer-to-data to pointer-to-function. +# ifdef __WATCOMC__ + return *(DynamicLoader::SymbolPointer*)(&result); +# else + return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result); +# endif +} + +#elif defined(__BEOS__) +# include <be/kernel/image.h> +# include <be/support/Errors.h> + +static image_id last_dynamic_err = B_OK; + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname) +{ + // image_id's are integers, errors are negative. Add one just in case we + // get a valid image_id of zero (is that even possible?). + image_id rc = load_add_on(libname.c_str()); + if (rc < 0) { + last_dynamic_err = rc; + return 0; + } + + return rc + 1; +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + if (!lib) { + last_dynamic_err = B_BAD_VALUE; + return 0; + } else { + // The function dlclose() returns 0 on success, and non-zero on error. + status_t rc = unload_add_on(lib - 1); + if (rc != B_OK) { + last_dynamic_err = rc; + return 0; + } + } + + return 1; +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + // Hack to cast pointer-to-data to pointer-to-function. + union + { + void* pvoid; + DynamicLoader::SymbolPointer psym; + } result; + + result.psym = NULL; + + if (!lib) { + last_dynamic_err = B_BAD_VALUE; + } else { + // !!! FIXME: BeOS can do function-only lookups...does this ever + // !!! FIXME: actually _want_ a data symbol lookup, or was this union + // !!! FIXME: a leftover of dlsym()? (s/ANY/TEXT for functions only). + status_t rc = + get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid); + if (rc != B_OK) { + last_dynamic_err = rc; + result.psym = NULL; + } + } + return result.psym; +} + +#elif defined(__MINT__) +# define _GNU_SOURCE /* for program_invocation_name */ +# include <dld.h> +# include <errno.h> +# include <malloc.h> + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname) +{ + char* name = (char*)calloc(1, libname.size() + 1); + dld_init(program_invocation_name); + strncpy(name, libname.c_str(), libname.size()); + dld_link(libname.c_str()); + return (void*)name; +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + dld_unlink_by_file((char*)lib, 0); + free(lib); + return 0; +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + // Hack to cast pointer-to-data to pointer-to-function. + union + { + void* pvoid; + DynamicLoader::SymbolPointer psym; + } result; + result.pvoid = dld_get_symbol(sym.c_str()); + return result.psym; +} + +#else +# include <dlfcn.h> + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname) +{ + return dlopen(libname.c_str(), RTLD_LAZY); +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + if (lib) { + // The function dlclose() returns 0 on success, and non-zero on error. + return !dlclose(lib); + } + // else + return 0; +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + // Hack to cast pointer-to-data to pointer-to-function. + union + { + void* pvoid; + DynamicLoader::SymbolPointer psym; + } result; + result.pvoid = dlsym(lib, sym.c_str()); + return result.psym; +} + +#endif diff --git a/Tests/Plugin/src/example_exe.cxx b/Tests/Plugin/src/example_exe.cxx index 257a35c..fd810a9 100644 --- a/Tests/Plugin/src/example_exe.cxx +++ b/Tests/Plugin/src/example_exe.cxx @@ -1,4 +1,4 @@ -#include <kwsys/DynamicLoader.hxx> +#include "DynamicLoader.hxx" #include <example.h> @@ -24,20 +24,17 @@ extern "C" int example_exe_function() int main() { - std::string libName = EXAMPLE_EXE_PLUGIN_DIR CONFIG_DIR "/"; - libName += kwsys::DynamicLoader::LibPrefix(); - libName += "example_mod_1"; - libName += kwsys::DynamicLoader::LibExtension(); - kwsys::DynamicLoader::LibraryHandle handle = - kwsys::DynamicLoader::OpenLibrary(libName.c_str()); + std::string const libName = EXAMPLE_EXE_PLUGIN_DIR CONFIG_DIR + "/" EXAMPLE_EXE_MOD_PREFIX "example_mod_1" EXAMPLE_EXE_MOD_SUFFIX; + DynamicLoader::LibraryHandle handle = DynamicLoader::OpenLibrary(libName); if (!handle) { // Leave the .c_str() on this one. It is needed on OpenWatcom. std::cerr << "Could not open plugin \"" << libName.c_str() << "\"!" << std::endl; return 1; } - kwsys::DynamicLoader::SymbolPointer sym = - kwsys::DynamicLoader::GetSymbolAddress(handle, "example_mod_1_function"); + DynamicLoader::SymbolPointer sym = + DynamicLoader::GetSymbolAddress(handle, "example_mod_1_function"); if (!sym) { std::cerr << "Could not get plugin symbol \"example_mod_1_function\"!" << std::endl; @@ -52,6 +49,6 @@ int main() std::cerr << "Incorrect return value from plugin!" << std::endl; return 1; } - kwsys::DynamicLoader::CloseLibrary(handle); + DynamicLoader::CloseLibrary(handle); return 0; } diff --git a/Tests/Plugin/src/example_exe.h.in b/Tests/Plugin/src/example_exe.h.in index 62f0d9f..af71021 100644 --- a/Tests/Plugin/src/example_exe.h.in +++ b/Tests/Plugin/src/example_exe.h.in @@ -2,5 +2,7 @@ #define example_exe_h #define EXAMPLE_EXE_PLUGIN_DIR "@CMAKE_LIBRARY_OUTPUT_DIRECTORY@" +#define EXAMPLE_EXE_MOD_PREFIX "@CMAKE_SHARED_MODULE_PREFIX@" +#define EXAMPLE_EXE_MOD_SUFFIX "@CMAKE_SHARED_MODULE_SUFFIX@" #endif |