summaryrefslogtreecommitdiffstats
path: root/Tests/Plugin
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2019-09-19 14:10:52 (GMT)
committerBrad King <brad.king@kitware.com>2019-09-19 14:42:51 (GMT)
commitc578caa68bf7ee55077a3efa25aba46e9e1f562a (patch)
tree7609ec94c8bb5e13e018b3d8fc08b3e362afea5b /Tests/Plugin
parent56879273dc87a69e1d1491a73e0f74cd4424494c (diff)
downloadCMake-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.txt12
-rw-r--r--Tests/Plugin/include/DynamicLoader.hxx49
-rw-r--r--Tests/Plugin/src/DynamicLoader.cxx263
-rw-r--r--Tests/Plugin/src/example_exe.cxx17
-rw-r--r--Tests/Plugin/src/example_exe.h.in2
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