The class the::core::Library supports the handling of shared libraries (DLLs, SO, DyLibs).
This class can be used to charge any shared library and to access any address in it.
Both Unix (Linux and Mac OS X) and Windows, if a shared library has dependencies and it is loaded, these other libraries will find themselves on a path (path) that the operating system recognizes as valid, so they are implicitly loaded. For that, some environment variables can be adjusted to say the list of folders that contain shared libraries on each operating system:
In general, no operating system supports dynamic loading of libraries simultaneously by multiple threads. Thus, the Library class performs a serialization of the call load method.
Another utility class of this package is the LibraryManager class, a singleton that can be used by applications to observe the shared libraries managed by the application. This singleton does not control the lifetime of shared libraries, only makes a reference to them. These references will be automatically removed when the object of the Library class representing the shared library is destroyed (out of scope).
The API for managing libraries in TerraLib is defined by the Library class, shown below:
namespace te { namespace core { /*! \class Library \brief A class for handling shared libraries (DLLs, SO, DyLibs). \warning Shared libraries should not be loaded concurrently by multiple threads. */ class Library : public boost::noncopyable { public: //! Load a new shared library. /*! The file name may be a relative or absolute path. If just the name of the shared library is given the class will look for the library in the operational system specific locations. \param slib_file_name The library file name. The file name may contain the full library path. \param delay_load If true the client object must call explicitly the load method before trying to access any symbol in the library. \exception LibraryLoadException It can throw an exception if delay_load is set to false and the library can not be loaded. \exception LibraryNameException It throws an exception if library name is empty or just white-spaces. */ Library(const std::string& slib_file_name, const bool& delay_load = false); //! The destructor automatically unloads from memory the shared library if it was not unloaded explicitly. ~Library(); //! Load the shared library to memory. /*! If the shared library was already loaded this method doesn't perform operations. \exception LibraryLoadException If the shared library can not be loaded to memory. \note Not thread-safe. */ void load(); //! Force the unload of the shared library from memory. /*! If the library wasn't previously loaded or if it was already unloaded this method doesn't perform operations. \exception LibraryUnloadException If the library can not be unload from memory this method raises an exception. \note Not thread-safe. */ void unload(); //! Return true if the shared library is loaded otherwise return false. bool isLoaded() const; //! Return the shared library file name as informed in the constructor. const std::string& getFileName() const; //! Return the address where the given symbol is loaded into memory. /*! \param symbol The name of the symbol inside the library you are searching for. It may be for instance a function name. \return The address where the symbol is loaded. \exception LibrarySymbolNotFoundException It throws an exception if it is not possible to locate the given symbol. \note Not thread-safe. */ void* getAddress(const char* symbol) const; //! Given a shared library name without file extensions, prefixes and nor suffixes it will construct a library name according to the specifc platform. static std::string getNativeName(const std::string& name); //! Add the informed dir to the path used by the operational system to lookup for shared libraries. /*! \param dir_name A directory to be added to the lookup of shared libraries. \exception LibraryInvalidSearchPathException It throws an exception if the path couldn't be added to the search path. \note Not thread-safe. \note For Linux and Mac OS X this method doesn't perform operations. */ static void addSearchDir(const std::string& dir_name); //! Comes back the application lookup path to the original state, before any add_search_dir has been called. /*! \exception LibraryResetSearchPathException It throws an exception if the path couldn't be reset. \note Not thread-safe. \note For Linux and Mac OS X this method doesn't perform operations. */ static void resetSearchPath(); //! Returns the system lookup path. /*! \exception LibrarySearchPathException It throws an exception if the path couldn't be reset. \note Not thread-safe. */ static std::string getSearchPath(); }; } // end namespace core } // end namespace te
The LibraryManager class, shown below, is a singleton that can be used to record all shared libraries loaded by a system (application). Pay attention to the fact that this singleton will not take the library property much less will share it, it will only observe the loaded libraries. Therefore, you should control the lifetime of shared libraries.
namespace te { namespace core { /*! \typedef void (*StartupFptr)(void); \brief This is the type for call back functions that makes the startup of a module. */ typedef boost::function0<void> StartupFnct; /*! \typedef void (*CleanupFptr)(void); \brief This is the type for call back functions that makes the cleanup of a module. */ typedef boost::function0<void> CleanupFnct; struct LibraryEntry { std::string m_name; StartupFnct m_startFptr; CleanupFnct m_cleanupFptr; bool m_initialized; }; /*! \class LibraryManager \brief A singleton that can be used to observe the available libraries in the system. This singleton doesn't control the libraries lifetime, it just make smart references to them. These references will be automatically removed when a library goes out of scope (or been destroyed). Actually it works like an observer of known libraries. */ class LibraryManager { public: /*! \brief It inserts a LibraryEntry to the manager. \param entry LibraryEntry to be managed. \exception te::InvalidArgumentException If a LibraryEntry with the given name is already registered. */ void insert(const LibraryEntry& entry); /*! \brief It removes a LibraryEntry from the manager. \param name The name of the LibraryEntry. \exception te::OutOfRangeException If a LibraryEntry with the given name is not registered., \exception te::Exception If trying to remove a initialized library. */ void remove(const std::string& name); /*! \brief Return a null pointer if a library doesnt't exist. \param name The LibraryEntry name. \return a const reference to the LibraryEntry \exception te::OutOfRangeException If a LibraryEntry with the given name is not registered. */ const LibraryEntry& get(const std::string& name); /*! \brief The current state of the LibraryEntry. \param name The name of the LibraryEntry. \return true if the LibraryEntry is initialized or false if isn't. \exception te::OutOfRangeException If a LibraryEntry with the given name is not registered. */ bool isInitialized(const std::string& name); /*! \brief Checks if a LibraryEntry exists from a given name \param name The name of the LibraryEntry \return true if the LibraryEntry exist or false if doesn't. */ bool exists(const std::string& name); /*! \brief It returns a reference to the singleton instance. \return A reference to the singleton instance. */ static LibraryManager& instance(); }; } // end namespace core } // end namespace te
This example constructs a dynamic library that contains the implementation of a function for calculating the factor of an integer and an executable program that performs the dynamic load library generated.
The generated library has the following name: terralib_example_core_lib_function.
Here is an example that shows how to load a shared library:
// TerraLib #include <terralib/core/lib/Exception.h> #include <terralib/core/lib/Library.h> #include <terralib/core/utils/Platform.h> // STL #include <cstdlib> #include <iostream> #include <string> int main() { try { // Get the shared library file name according to the operational system. std::string lName = te::core::Library::getNativeName("terralib_example_core_lib_function"); std::string lPath = te::core::FindInTerraLibPath("example"); #if TE_PLATFORM == TE_PLATFORMCODE_MSWINDOWS if(!lPath.empty()) te::core::Library::addSearchDir(lPath); #else lName = lPath + "/" + lName; #endif // The library is located at the same directory as the executable. */ te::core::Library l1(lName); // Testing if the shared library was loaded. if(l1.isLoaded()) std::cout << std::endl << "Shared library " << l1.getFileName() << " loaded!" << std::endl; // Getting a pointer to a function in the library. void* t = l1.getAddress("fatorial"); // Testing the pointer. if(t != nullptr) { std::cout << "Function fatorial found!" << std::endl; } else { std::cout << "Function fatorial not found!" << std::endl; return EXIT_FAILURE; } typedef int (*fatorial_fptr)(int); fatorial_fptr fat = reinterpret_cast<fatorial_fptr>(t); std::cout << "Fatorial 5: " << fat(5) << std::endl; // Unloading the shared library. l1.unload(); std::cout << "Library unloaded!" << std::endl << std::endl; } catch(const te::core::LibraryLoadException& e) { if(const std::string* d = boost::get_error_info<te::ErrorDescription>(e)) std::cout << std::endl << "Fail to load library: " << *d; return EXIT_FAILURE; } catch(const te::core::LibraryUnloadException& e) { if(const std::string* d = boost::get_error_info<te::ErrorDescription>(e)) std::cout << std::endl << "Fail to unload library: " << *d; return EXIT_FAILURE; } catch(const te::core::LibrarySymbolNotFoundException& e) { if(const std::string* d = boost::get_error_info<te::ErrorDescription>(e)) std::cout << std::endl << "Fail to load symbol: " << *d; return EXIT_FAILURE; } catch(const te::Exception& e) { if(const std::string* d = boost::get_error_info<te::ErrorDescription>(e)) std::cout << std::endl << "Unknown error: " << *d; return EXIT_FAILURE; } catch(const std::exception& e) { std::cout << std::endl << "Unknown error: " << e.what(); return EXIT_FAILURE; } catch(...) { std::cout << std::endl << "Unknown error!"; return EXIT_FAILURE; } return EXIT_SUCCESS; }