Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Mangled Import

Boost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 11. Boost.DLL

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

В этом разделе описывается экспериментальная особенность, позволяющая импортировать искалеченные символы из дл. Хотя эта функция уникальна для этой библиотеки и выглядит довольно многообещающе, она не подвергается жесткой проверке и, следовательно, не считается стабильной.

В качестве краткого примера мы можем легко импортировать следующие функции:

//library.dll
namespace foo {
int    bar(int);
double bar(double);
}

И импорт выглядит так:

auto f1 = import_mangled<int(int)>("library.dll", "foo::bar");
auto f2 = import_mangled<double(double)>("library.dll", "foo::bar");
cout << f1(42)  << endl;
cout << f2(3.2) << endl;

В настоящее время реализованы Itanium ABI и MSVC ABI. MSVC ABI требует поддержки boost.spirit.x3, что позволяет использовать только MSVC 2015. API Itanium требует C++11.

  • Гцк
  • Клэнг
  • MSVC 2015
  • Intel C++

API Itanium не импортирует функции возврата или глобальные переменные.

Ядром искалеченного импорта является классsmart_library. Он может импортировать функции и переменные в их искаженной форме; для этого смарт-библиотека считывает весь контур библиотеки и распутывает каждую точку входа в нее. Это также означает, что этот класс должен быть построен только один раз.

Для импорта всех методов в следующей библиотеке мы будем использоватьsmart_library.

Первое, что нужно сделать при создании собственных плагинов, это определить интерфейс плагина. Существует пример абстрактного класса, который будет нашим API плагина:

#include <string>
namespace space {
class BOOST_SYMBOL_EXPORT my_plugin
{
    std::string _name;
public:
   std::string name() const;
   float  calculate(float x, float y);
   int    calculate(int, x,  int y);
   static std::size_t size();
   my_plugin(const std::string & name);
   my_plugin();
   ~my_plugin_api();
   static int value;
};
}

Итак, теперь у нас есть определение для плагина, поэтому мы используем его в следующем полнофункциональном примере. Имейте в виду, что существует более удобное решение для импортных функций-членов, которое будет рассмотрено позже. Этот пример показывает, однако, чтоsmart_libпредоставляет в качестве функций.

Сначала мы создали умную библиотеку. Имейте в виду, что класс псевдонимов необходим для обеспечения алии типа для my_plugin.

#include <boost/dll/smart_library.hpp> // for import_alias
#include <iostream>
#include <memory>
namespace dll = boost::dll;
struct alias;
int main(int argc, char* argv[]) {
    boost::filesystem::path lib_path(argv[1]);   // argv[1] contains path to directory with our plugin library
    dll::smart_lib lib(lib_path);                // smart library instance

Для того чтобы создать класс, нужно будет выделить память. Это, конечно, означает, что нам нужно знать размер; к сожалению, он не экспортируется в dll, поэтому мы добавили функцию статического размера для экспорта. Статические используются как простые функции.

Поэтому мы импортируем его, называем и выделяем память.

auto size_f = lib.get_function<std::size_t()>("space::my_plugin::size"); //get the size function
auto size = size_f();             // get the size of the class
std::unique_ptr<char[], size> buffer(new char[size]);    //allocate a buffer for the import
alias & inst = *reinterpret_cast<alias*>(buffer.get()); //cast it to our alias type.

Теперь у нас есть размер памяти и ссылка на наш тип псевдонима. Для того чтобы его использовать, нужно зарегистрировать тип как псевдоним. Это позволит смарт-библиотеке определить имя типа.

lib.add_type_alias("space::my_plugin"); //add an alias, so i can import a class that is not declared here

Для того чтобы использовать класс, нам, конечно, нужно его инициализировать, т.е. назвать конструктором. Itanium ABI может также использовать распределительный конструктор. Вот почему конструктор может иметь две функции; поскольку мы уже выделили память, мы используем стандартную версию конструктора из строки. Поэтому мы выбираем конструктора, передавая подпись.

auto ctor = lib.get_constructor<alias(const std::string&)>(); //get the constructor
ctor.call_standard(&inst, "MyName"); //call the non-allocating constructor. The allocating-constructor is a non-portable feature

Так как класс теперь инициализируется, мы можем назвать метод имени. Если функция является константой и/или летучим параметром типа, принятый в качестве типа, должен иметь те же квалификаторы.

auto name_f = lib.get_mem_fn<const alias, std::string()>("name");//import the name function
std::cout <<  "Name Call: " << (inst.*name_f)() << std::endl;

Перегруженные функции могут быть импортированы только отдельно.

//import both calculate functions
auto calc_f = lib.get_mem_fn<alias, float(float, float)>("calculate");
auto calc_i = lib.get_mem_fn<alias, int(int, int)>      ("calculate");
std::cout << "calc(float): " << (inst.*calc_f)(5., 2.) << std::endl;
std::cout << "calc(int)  : " << (inst.*calc_f)(5,   2) << std::endl;

Импорт статической переменной выполняется как с простой переменной.

auto & var = lib.get_variable<int>("space::my_plugin::value");
cout << "value " << var << endl;

С тех пор, как мы закончили, мы называем дескруктора класса.

    auto dtor = lib.get_destructor<alias>(); //get the destructor
    dtor.call_standard(&inst);
    std::cout << "plugin->calculate(1.5, 1.5) call:  " << plugin->calculate(1.5, 1.5) << std::endl;
}

Назад к вершине

Теперь показано, как искалеченные и методы могут быть импортированы. Это, однако, довольно универсальный способ, поэтому обеспечивается более простой интерфейс, который также позволяет получить доступ к type_info объекта.

Мы возьмем тот же класс и импортируем те же методы, но сделаем это с помощью импортных функций.

Мы поместили библиотеку в общий указатель, потому что каждый импорт будет содержать такой указатель. То есть мы не хотим его копировать.

#include <boost/dll/smart_library.hpp>
#include <boost/dll/import_mangled.hpp>
#include <boost/dll/import_class.hpp>
int main(int argc, char* argv[]) {
    boost::filesystem::path lib_path(argv[1]);   // argv[1] contains path to directory with our plugin library
    smart_library lib(lib_path);// smart library instance

Как и в предыдущем примере, нам нужен размер класса.

auto size_f = import_mangled<std::size_t()>("space::my_plugin::size"); //get the size function
auto size = (*size_f)();             // get the size of the class

С другой стороны, мы также можем легко импортировать переменные с этой функцией.

auto value = import_mangled<int>(lib, "space::my_plugin::value");

Мы делаем форвардную декларацию по первому вызову и напрямую обращаемся к конструктору. Это довольно просто и позволяет вызвать конструктора напрямую. Деструктор будет вызываться автоматически.

auto cl = import_class<class alias, const std::string&>(lib, "space::my_plugin::some_class", size, "MyName");

Для запуска функции сначала потребуется импортировать ее.

auto name = import_mangled<const alias, std::string()>(lib, "name");
std::cout << "Name: " << (cl->*name)() << std::endl;

Для перегруженных функций мы можем импортировать их как группы, что даст нам объект, содержащий перегрузки.

auto calc = import_mangled<alias, float(float, float), int(int, int)>(lib, "calculate");
std::cout << "Calc(float): " (cl->*calc)(5.f, 2.f) << std::endl;
std::cout << "Calc(int):   " (cl->*calc)(5, 2)     << std::endl;

Кроме того, мы можем получить доступ к такой информации.

std::type_info &ti = cl.get_type_info();

Назад к вершине

В примере не рассматривался вопрос о том, как он обрабатывается, если квалификация отличается для перегруженной функции. Это можно сделать, пройдя класс снова с другой квалификацией - подпись функции всегда выберет последнюю предоставленную.

Если это есть в нашем плагине:

struct plugin
{
    void f(int);
    void f(double);
    void f(int) const;
    void f() const;
    void f() volatile;
    void f(int) volatile;
    void f(double); const volatile;
};

Мы можем импортировать их все сразу, со следующей командой:

auto f = import_class<
    alias, f(int), f(double), //not qualified
    const alias, f(int), f(), //const
    volatile alias, f(), f(int), //volatile
    const volatile alias, f(double)//const volatile
    >(lib, "f");


PrevUpHomeNext

Статья Mangled Import раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 11. Boost.DLL может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 11. Boost.DLL ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 17:54:24/0.0081379413604736/0