Pull to refresh
17
0
Константин @lerom

User

Send message
По моему, все понятно, последовательно и логично изложено, имеются исходники и листинти. От «ученика» необходимо только желание разобраться. Хорошая статья.
К сожалению, наблюдается тенденция к ухудшению поиска в Яндексе. Мне больше нравился Яндеск, но все чаше приходиться пользоваться Гуглом, т.к. поиск в нем оказывается релевантнее.
Библиотеки с открытым кодом, такие как boost или QT, которые считаются неотъемлемой частью разработки и которые используют огромное количество людей, не лишены ошибок. Но все, кто используют библиотеки, являются одновременно огромной армией тестеров, находящих коллизии и баги. Поэтому используя открытые и широко распространенные библиотеки, мы получаем все таки достаточно надежные инструменты для программирования.
Работу с числами с плавающей запятой, обеспечивает математический сопроцессор (FPU). FPU имеет специальные регистры, организованные в кольцевой стек. Вершиной стека является регистр ST(0). Возвращаемое значение функции epsilon() попадaет не в eax, а в ST(0) FPU.
1. Линковка с lib не получиться, если, например, lib создана в С++ Builder, а dll необходимо подключить в MSVC.

2. >Чем не устраивает LoadLibrary/GetProcAddress

Устраивает, но вот код с LoadLibrary/GetProcAddress

typedef void  (__stdcall  *init_fn)    ();
typedef void  (__stdcall  *decode_fn)  ();
typedef void  (__stdcall  *free_fn)    ();
 
int main()
{	
 
	HMODULE LibHandle = LoadLibraryA("decode.dll");
	if ( LibHandle == NULL )
	{
		std::cout << "error: Can't load library!";
		return -1;
	}
 
	init_fn init     = reinterpret_cast<init_fn>(::GetProcAddress(lib, "init"));
	decode_fn decode = reinterpret_cast<decode_fn>(::GetProcAddress(lib, "decode"));
	free_fn free     = reinterpret_cast<free_fn>(::GetProcAddress(lib, "free"));
 
	//Или другим способом определяем какая функция не загрузилась
	if (init == 0 || decode == 0 || free == 0) 
	{
		FreeLibrary(LibHandle); 
		std::cout << "error: Can't load function!"; 
		return -1;
	}
	
	init();
	decode();
	free();
	
	FreeLibrary(LibHandle);
 
	return 0;
}
 


А вот с использованием DynLib

#include <dl/include.hpp>
DL_BLOCK
(
	DL_C_LIBRARY( lib )
	(
		( void, __stdcall, (init),   () )
		( void, __stdcall, (decode), () )
		( void, __stdcall, (free),   () )
	)
)
 
int main()
{
	try
	{
		lib some("decode.dll"); 
		some.init();
		some.decode();
		some.free();
	}
	catch (std::exception const& e)
	{
		std::cout << "error: " << e.what();
	}
}
 


> Я просмотрел мельком код и ничего не понял.

Попрбуйте на практике, хотя бы повторить пример из статьи, и все встанет на свои места.
> Я так понимаю, что под Linux, например, бросать исключение, пересекающее границу динамической библиотеки, в случае, если одна библиотека собрана GCC4, а другая GCC3, также опасно, или нет?

Не работал под Linux. Не знаю. Но, имхо, правила применимости те же (возможно, есть еще что).
> а для мсовских либ можно и обертки сишные сделать
А можно воспользоваться DL_C_LIBRARY ;)
>А какие в винде проблемы с исключениями?
С какими: SEH или исключения C++?

С SEH проблем нет, а вот с С++ есть (при межмодульном взаимодействии EXE-DLL, DLL-DLL):
1) у каждого компилятора может быть своя реализация механизма исключений;
2) типы данных (в данном случае внутренне представление классов исключений может быть по-разному определено);
3) даже, если компилятор один и внутреннее представление одно и то же, менеджер памяти может быть разным.
>Кстати, а какая проблема с пространствами имен то…
Разные компиляторы — разная декорация имен функций.
Такой вариант рассматривался. И его проще реализовать. Но при таком варианте требуется как-то прикручивать кодогенератор (препроцессор) к среде (настраивать систему сборки). Это, конечно, не проблема, но хотелось чего-то, что будет работать в рамках возможностей языка C++.
Код необычен, это правда. Кто работал с BOOST.PREPROCESSOR поймет почему он такой. Кто не работал, тому он не покажется очень сложным. А кто не хочет — это уж его проблемы. Читайте второй абзац топика — мы делимся уже полученным результатом.

Страшно что? Количество кода или его внешний вид. Количество кода минимально, если у Вас есть варианты сделать тоже самое, но с меньшим количеством кода (без применения дополнительных преобразователей исходного текста, типа moc-компилятора в QT и пр.) приложите, пожалуйста, код. Внешний вид странноват, уже сказано. Но он читаем и понятен.

Основная идея создания данной библиотеки — возможность использования классов в межмодульном взаимодействии. Может в документации это и не отражено, но интерфейс DL_INTERFACE предназначен не только для экспорта классов из DLL, но и как общий интерфейс, который может реализовывать классы EXE и передавать их в DLL. (про плагины — это ответ на вопрос о динамической линковке, читайте внимательно).

Есть категория людей, которая:
а) не использует исключения при написании DLL (или использует, но не знает что, с ними нужно делать на границах DLL-EXE, DLL-DLL);
б) не использует классы в межмодульном взаимодействии;
в) для всего проекта всегда использует один и тот же компилятор, всегда с одними и теми же настройками, и, к тому же, всегда используется динамический рантайм.
г) не использует пространства имен — единственное средство С++, позволяющее хоть как-то получить подобие модулей в программе.

Для такой категории людей библиотека DynLib, действительно, не подходит, а добавляет только дополнительный «оверхед».
ПО для данных ОС почти не пишем. Но об этом подумаем.
> Т.е. мы говорим о модулях, написанных на разных компиляторах?

Именно так (и только о компиляторах C++).
DLL, собранные с использованием DL_LIBRARY и DL_EXPORT, всегда в таблице экспорта содержат только одну функцию (_dynamic_library@0 — MSVC и dynamic_library@0 — GCC). При проектировании DynLib одним из ключевых моментов было избавить пользователя библиотеки от лишних (и зачастую рутинных) действий при написании своей DLL, в частности убрать необходимость задавать def-файл. Два разных имени одной и той же функции — следствие реализации разных способов именования функций при экспорте для разных компиляторов без def-файла.

Все функции, которые описаны в DL_LIBRARY находятся в ::dlx::library<dl_library>::ftable.

> Т.е. никакого C-интерфейса нет и кроме как через эту обёртку длл-ку не заиспользовать

Как раз наоборот, все функции библиотеки и интерфейсов передаются через C-совместимые типы через структуры, напоминающие VTable в языке C++.
Но, действительно, подключение и использование таких DLL без DynLib потребует описания необходимых С-структур самостоятельно.
На данный момент используется упрощенная схема.
в каждой экспортируемой библиотекой функции и в каждом методе интерфейса вставляется следующий код:
try
{
    // прямой вызов функции объекта (библиотеки)
}
catch ( ... )
{
    return create_error_info();
}


Функция create_error_info определена следующим образом:
error_info* create_error_info()
{
    try
    {
        throw;
    }
    catch (std::exception const& e)
    {
        return create_info( typeid(e).name(), e.what() );
    }
    catch (...)
    {
        return create_info( "unknown", "not available" );
    }
}


Несложно определить, что для этого используется RTTI для получения имени класса исключения и строка, возвращаемая через метод what(). Это, конечно, не лучший способ общего решения (особенно для тех компиляторов, в которых typeid(...).name() возвращает нечитаемое имя класса).

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

Если это действительно необходимо, то, по возможности, будем улучшать DynLib.
Я думал, что размещение текста лицензии в заголовочных файлах будет достаточно. Разве не так?
В основном, для возможности использовать несколько DLL, имеющих один и тот же интерфейс, в приложениях, использующих так называемую «плагинную» схему.

Применительно к DLL, созданным с применением DL_LIBRARY и DL_EXPORT — это скрытие информации об экспортируемых функциях. Такие DLL в своей таблице экспорта содержат упоминание только об одной функции dynamic_library.
1

Information

Rating
Does not participate
Location
Россия
Registered
Activity