Подключение опенсорсных библиотек

  !   Данная информация предназначена только только для IT-специалистов по системной интеграции модулей БИОСОФТ-М. (см. Руководства пользователя к программным продуктам)

Подавляющее большинство простых open source библиотек для форматов графических файлов, парсинга текстовых, математики, сжатия, скриптинга, шифрации и т.п. спокойно вставляются в проект любой IDE (Visual Studio, Borland, Eclipse-gcc), в собственный makefile, Jam и подобные после минимальных типовых адаптаций.

Это упрощает их интеграцию в свой С++ проект, дает возможность легко править их и отлаживать, компилируя все в удобной среде, общей с основным проектом.

См. так же GCCzlibjslibpng7zlzmapcresqlitelibcurlwgetlibtiffjpegliblibvorbisXMLbisonflex

Инструкции по интеграции прилагаемые к библиотеке

Пока выкидываем, если они вообще есть. Часто их нет, подразумевается опытный программист. Обычно подразумевается компиляция через makefile, иногда с дополнительным скриптами и генераторами которые нам нафик не надо тянуть в нашу среду. Они полезны авторам для сопровождения, а нам нужен готовый C исходник скомпиленный как удобно нам.

Сливаем в свои исходники

Распаковываем .z.gz.tar.bzip... или как там он скачался. Все распакованное кладем в свой проект.Сохраняем архив на будущее. (Может быть трудно найти потом)Создаем в исходниках папку с номером версии (1.2.3.4) чтобы видно было ее удобно.

Читаем лицензию

BSD, MIT, Apache, PHP, Mozilla, public domain и подобные либо не требуют ничего, либо упоминания. LGPL сразу оформляем в DLL отдельный от коммерческих модулей. GPL в отдельный .exe для поставки только независимо от коммерческого продукта.

Компилируем

Типовые препоны:

Инклуды

В прилагаемый make-файлах пути для поиска #include часто прописаны в явную (-I, INCLUDE=...). Из сообщений о не найденных инклудах очевидно что не найдено, прописываем пути ко всем src/include и вокруг. От лишних дефолтных путей как правило проблем не бывает. Могут быть проблемы если гадкий автор создает несколько хидеров с одним именем и выбирает их в зависимости от платформы. Убираем лишние платформы тогда.

Исходники для левых платформ и компиляторов

Выявляются по ссылкам на инклуды которых явно нет в системе, именам папочек в которых они находятся (amiga, sun, dos...). Иногда по заведомо отсутствующим ключевым словам и некомпилябельным декларациям.

В данном сценарии подключения следует оставлять файлы только необходимых платформ (win32, linux) а остальные просто удалять.

Нормальная библиотека выбирает хидеры для платформ по встроенным макросам компилятора. Все тогда адаптируется само. Для замороченного опен сорса библиотеки иногда скрипты генерят хидер со всеми декларациями. Т.к. скрипты мейкфайла мы похерили, впиндюрив в свой проект .c/.cpp файлы, то составляем хидер с необходимыми декларациями #define для нашего компилятора и для фичей нам полезных.

Догадаться какие макросы нам нужны не сложно зная нашу среду программирования и найдя список этих макросов в конфигурационных скриптах:

/* C/C++ version */
#define C_CHAR_UNSIGNED
#define C_RIGHTSHIFT_UNSIGNED
 
/* target OS */
#define ENVIRONMENT_PATH_SEPARATOR ';'
 
/* system headers our compiler has */
#define HAVE_WINDOWS_H
#define HAVE_WINSOCK_H
#define HAVE_ALLOCA_H
#define HAVE_BZERO
#define HAVE_CONST_CAST
#define HAVE_SSTREAM
 
/* app features and optional extras */
#define SUPPORT_SSL
#define USE_DOUBLE_PRECISION
Линкуем

После успешной компиляции опенсорса компилируем DLL или EXE использующий этот код. Компиляция статического .lib, если мы клали опенсорс, туда не выявит проблем линковки.

Лишние main()

Обычно бывают файлы с тестами, демо, вспомогательные утилиты и генераторы всяких таблиц и исходников. И естественно главный main() утилиты запускающей данный опенсорс с командной строки. Смело удаляем все файлы где main() найдем, они все нам не нужны. (могут потом понадобится только как примеры использования вызова либа)

Не найденные системные функции

Смотрим нужную стандартную библиотеку и подключаем нужный lib в проект. Например:

 error LNK2019: unresolved external symbol __imp__WSAGetLastError...

выясняем по MSDN что для WSAGetLastError нужен ws2_32.lib:

#pragma comment(linker, "/defaultlib:ws2_32.lib")
Не найденные функции самой библиотеки

Префикс __imp__ означает, что функция была декларирована на экспорт а мы ее хотим вызывать просто как extern. Находим какой префикс используется перед декларациями функций:

    LIBEXPORTPREFIX void SomeFunction();

Смотрим как декларируется LIBEXPORTPREFIX и выясняем какие -D макросы надо добавить в опции компилятора чтобы там не было экспортных/импортных директив. То есть нам нужно просто декларация:

    void SomeFunction();

или

    extern void SomeFunction();

или

    extern "C" void SomeFunction();

что обычно одно и тоже (extern "C" { } мы для верности прописываем всегда вокруг С-инклуда). Если захотим экспортировать что то из нашего DLL то для себя потом сделаем удобные нам инкапсуляторы.

Другие проблемы линковки естественно пойдут от забытых от ламерности extern "C". Иногда стандартные инклуды нужно вынести за пределы extern "C":

#include <winsock2.h>
#include <ws2tcpip.h>
 
extern "C"
{
#include "netlib.h"
}

Не согласованность __stdcall, __cdecl, __fastcall обычно не мешает т.к. компилируем мы весь исходник полностью, все с одними общими опциями, и никаких закрытых или предкомпилированных модулей тут не участвует.

Ограничения

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

Эта категория в данный момент пуста.