Bläddra i källkod

LSSTD-1: Add symbol loading to RuntimeLibraryLoader class

- add loading & providing symbol functionalities
- add close library functionality
- add test coverage for newly implemented functionalities
Patrick-Christopher Mattulat 2 år sedan
förälder
incheckning
054c0311d8

+ 14 - 2
include/ls_std/os/library/RuntimeLibraryLoader.hpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2022-09-06
- * Changed:         2022-09-06
+ * Changed:         2022-10-20
  *
  * */
 
@@ -11,6 +11,7 @@
 #define LS_STD_RUNTIME_LIBRARY_LOADER_HPP
 
 #include "RuntimeLibraryLoaderParameter.hpp"
+#include <unordered_map>
 
 namespace ls::std::os
 {
@@ -18,9 +19,13 @@ namespace ls::std::os
   {
     public:
 
-      explicit RuntimeLibraryLoader(ls::std::os::RuntimeLibraryLoaderParameter _parameter);
+      explicit RuntimeLibraryLoader(ls::std::os::RuntimeLibraryLoaderParameter _parameter); // TODO: rename class to RuntimeLibrary? Should there be a validator check for file extensions?
       ~RuntimeLibraryLoader() = default;
 
+      bool close();
+      void* getSymbol(const ::std::string& _symbolName);
+      bool hasSymbol(const ::std::string& _symbolName);
+      bool loadSymbol(const ::std::string& _symbolName);
       bool open();
 
     private:
@@ -29,8 +34,15 @@ namespace ls::std::os
       void* handle{};
       #endif
       ls::std::os::RuntimeLibraryLoaderParameter parameter{};
+      #if defined(unix) || defined(__APPLE__)
+      ::std::unordered_map<::std::string, void*> symbols{};
+      #endif
 
       #if defined(unix) || defined(__APPLE__)
+      [[nodiscard]] bool _close();
+      [[nodiscard]] void* _getSymbolUnix(const ::std::string& _symbolName);
+      [[nodiscard]] bool _hasSymbolUnix(const ::std::string& _symbolName);
+      [[nodiscard]] bool _loadSymbolUnix(const ::std::string& _symbolName);
       [[nodiscard]] bool _openUnix();
       #endif
       #ifdef _WIN32

+ 73 - 1
source/ls_std/os/library/RuntimeLibraryLoader.cpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2022-09-06
- * Changed:         2022-09-06
+ * Changed:         2022-10-20
  *
  * */
 
@@ -21,6 +21,34 @@ ls::std::os::RuntimeLibraryLoader::RuntimeLibraryLoader(ls::std::os::RuntimeLibr
   }
 }
 
+bool ls::std::os::RuntimeLibraryLoader::close()
+{
+  return this->_close();
+}
+
+void *ls::std::os::RuntimeLibraryLoader::getSymbol(const ::std::string &_symbolName)
+{
+  #if defined(unix) || defined(__APPLE__)
+  return this->_getSymbolUnix(_symbolName);
+  #endif
+}
+
+bool ls::std::os::RuntimeLibraryLoader::hasSymbol(const ::std::string &_symbolName)
+{
+  return this->_hasSymbolUnix(_symbolName);
+}
+
+bool ls::std::os::RuntimeLibraryLoader::loadSymbol(const ::std::string &_symbolName)
+{
+  bool loaded{};
+
+  #if defined(unix) || defined(__APPLE__)
+  loaded = this->_loadSymbolUnix(_symbolName);
+  #endif
+
+  return loaded;
+}
+
 bool ls::std::os::RuntimeLibraryLoader::open()
 {
   bool opened;
@@ -36,6 +64,50 @@ bool ls::std::os::RuntimeLibraryLoader::open()
 }
 
 #if defined(unix) || defined(__APPLE__)
+
+bool ls::std::os::RuntimeLibraryLoader::_close()
+{
+  bool closed{};
+
+  if (this->handle != nullptr)
+  {
+    closed = dlclose(this->handle) == 0;
+  }
+
+  return closed;
+}
+
+void *ls::std::os::RuntimeLibraryLoader::_getSymbolUnix(const ::std::string &_symbolName)
+{
+  void* symbol{};
+
+  if (this->_hasSymbolUnix(_symbolName))
+  {
+    symbol = this->symbols.at(_symbolName);
+  }
+
+  return symbol;
+}
+
+bool ls::std::os::RuntimeLibraryLoader::_hasSymbolUnix(const ::std::string &_symbolName)
+{
+  return this->symbols.find(_symbolName) != this->symbols.end();
+}
+
+bool ls::std::os::RuntimeLibraryLoader::_loadSymbolUnix(const ::std::string& _symbolName)
+{
+  bool loaded{};
+
+  if (!this->_hasSymbolUnix(_symbolName))
+  {
+    void* symbol = dlsym(this->handle, _symbolName.c_str());
+    this->symbols.insert(::std::pair<::std::string, void*>(_symbolName, symbol));
+    loaded = symbol != nullptr;
+  }
+
+  return loaded;
+}
+
 bool ls::std::os::RuntimeLibraryLoader::_openUnix()
 {
   this->handle = dlopen(this->parameter.path.c_str(), RTLD_LAZY);

+ 58 - 1
test/cases/os/library/RuntimeLibraryLoaderTest.cpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2022-09-06
- * Changed:         2022-09-06
+ * Changed:         2022-10-20
  *
  * */
 
@@ -11,6 +11,7 @@
 #include <ls_std/ls_std_os.hpp>
 #include <ls_std/ls_std_core.hpp>
 #include "TestHelper.hpp"
+#include <ls_std/ls_std_time.hpp>
 
 namespace
 {
@@ -52,6 +53,62 @@ namespace
                  }, ls::std::core::IllegalArgumentException);
   }
 
+  TEST_F(RuntimeLibraryLoaderTest, close)
+  {
+    ls::std::os::RuntimeLibraryLoader loader{createParameter()};
+    ASSERT_TRUE(loader.open());
+    ASSERT_TRUE(loader.close());
+  }
+
+  TEST_F(RuntimeLibraryLoaderTest, close_no_handle)
+  {
+    ls::std::os::RuntimeLibraryLoader loader{createParameter()};
+    ASSERT_FALSE(loader.close());
+  }
+
+  TEST_F(RuntimeLibraryLoaderTest, getSymbol)
+  {
+    // TODO: also provide a debug library for loading - currently debug execution is not working due to lack of debug information
+
+    ls::std::os::RuntimeLibraryLoader loader{createParameter()};
+    ASSERT_TRUE(loader.open());
+    ASSERT_TRUE(loader.loadSymbol("_ZN2ls3std4time4DateC1Ev"));
+
+    using constructorType = ls::std::time::Date();
+    ::std::function<ls::std::time::Date()> date{reinterpret_cast<constructorType*>(loader.getSymbol("_ZN2ls3std4time4DateC1Ev"))};
+
+    ASSERT_TRUE(date().getDay() > 0);
+    ASSERT_TRUE(date().getHour() > 0);
+  }
+
+  TEST_F(RuntimeLibraryLoaderTest, getSymbol_no_symbol)
+  {
+    ls::std::os::RuntimeLibraryLoader loader{createParameter()};
+
+    ASSERT_TRUE(loader.open());
+    ASSERT_TRUE(loader.getSymbol("_ZN2ls3std4time4DateC1Ev") == nullptr);
+  }
+
+  TEST_F(RuntimeLibraryLoaderTest, hasSymbol_not_found)
+  {
+    ls::std::os::RuntimeLibraryLoader loader{createParameter()};
+    ASSERT_FALSE(loader.hasSymbol("getTimeStamp"));
+  }
+
+  TEST_F(RuntimeLibraryLoaderTest, loadSymbol)
+  {
+    ls::std::os::RuntimeLibraryLoader loader{createParameter()};
+    ASSERT_TRUE(loader.open());
+    ASSERT_TRUE(loader.loadSymbol("_ZN2ls3std4time4Date6getDayEv"));
+  }
+
+  TEST_F(RuntimeLibraryLoaderTest, loadSymbol_symbol_not_available)
+  {
+    ls::std::os::RuntimeLibraryLoader loader{createParameter()};
+    ASSERT_TRUE(loader.open());
+    ASSERT_FALSE(loader.loadSymbol("_ZN2ls3std4time4Date6getLeapEv"));
+  }
+
   TEST_F(RuntimeLibraryLoaderTest, open)
   {
     ls::std::os::RuntimeLibraryLoader loader{createParameter()};