TerraLib and TerraView Wiki Page

This is an old revision of the document!


TerraLib.Core: Library

A classe te::core::Library fornece suporte à manipulação de bibliotecas compartilhadas (DLLs, SO, DyLibs).

Esta classe pode ser utilizada para carregar qualquer biblioteca compartilhada e para acessar qualquer endereço dentro dela.

Tanto nos ambiente Unix (Linux e Mac OS X) ou Windows, se uma biblioteca compartilhada possuir dependências e for carregada, essas outras bibliotecas deverão encontrar-se em um caminho (path) que o sistema operacional reconheça como válido para que elas sejam implicitamente carregadas. Para isso algumas variáveis de ambiente podem ser ajustadas para dizer a lista de pastas que contém bibliotecas compartilhadas em cada sistema operacional:

  • No Mac OS X, as variáveis de ambiente PATH, DYLD_LIBRARY_PATH, DYLD_FALLBACK_LIBRARY_PATH e DYLD_FRAMEWORK_FALLBACK_PATH podem ser ajustadas para conter a lista de pastas que contém bibliotecas compartilhadas.
  • No Linux, as variáveis de ambiente PATH e LD_LIBRARY_PATH podem ser ajustadas para conter a lista de pastas que contém bibliotecas compartilhadas.
  • No Windows, a variável de ambiente PATH pode ser ajustada para conter a lista de pastas que contém bibliotecas compartilhadas.

Em geral, nenhum sistema operacional suporta a carga dinâmica de bibliotecas de forma simultânea por múltiplas threads. Desta forma, a classe Library realiza uma serialização à chamada do método load.

Outra classe utilitária deste pacote é a classe LibraryManager, um singleton que pode ser utilizado pelas aplicações para observar as bibliotecas compartilhadas gerenciadas pela aplicação. Este singleton não controla o tempo de vida das bibliotecas compartilhadas, apenas faz uma referência a elas. Essas referências serão automaticamente removidas quando o objeto da classe Library representando a biblioteca compartilhada for destruído (sair de escopo).

API

C++

A API para gerenciamento de bibliotecas na TerraLib é definida pela classe Library, mostrada abaixo:

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 TECOREEXPORT 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

A classe LibraryManager, mostrada abaixo, é um singleton que pode ser utilizado para registrar todas as bibliotecas compartilhadas carregadas por um sistema (aplicação). Atente-se ao fato de que este singleton não irá tomar a propriedade da biblioteca muito menos irá compartilhá-la, ele apenas irá observar as bibliotecas carregadas. Por isso, você deverá controlar o tempo de vida das bibliotecas compatilhadas.

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 TECOREEXPORT 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

Exemplos

Este exemplo constrói uma biblioteca dinâmica que contém a implementação de uma função para cálculo do fatorial de um número inteiro e um programa executável que realiza a carga dinâmica da biblioteca gerada.

A biblioteca gerada possui o seguinte nome: terralib_example_core_lib_function.

A seguir um exemplo que mostra como carregar uma biblioteca compartilhada:

// 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;
}

Referências