Ответ 1
Скажите, что у вас есть класс Unuseful
, который определяется следующим образом:
Файл Unuseful.h
:
class Unuseful {
public:
void printUnusefulStatement();
};
Файл Unuseful.cpp
:
#include "unuseful.h"
#include <iostream>
void Unuseful::printUnusefulStatement()
{
std::cout << "Hello world!" << std::endl;
}
Теперь у вас есть еще один класс, который нуждается в печати неиспользуемых операторов:
Unuseful u;
u.printUnusefulStatement();
Это означает, что вы хотите использовать внешнюю библиотеку, содержащую конкретную реализацию (printUnusefulStatement
), которую вы хотите включить в свой код.
Вы можете использовать эту библиотеку двумя способами:
- Предоставляя исходный код компилятору
- Предоставив двоичный файл (который ранее был скомпилирован для вашей архитектуры), в компоновщик
Случай 1: использование библиотеки во время компиляции
Это простейший случай.
У вас есть исходный код библиотеки, которую вы должны использовать, и вам просто нужно скомпилировать ее вместе с существующим кодом (скажем, main.cpp
file).
Обычно вы являетесь автором и пользователем библиотеки (класс, который выполняет требуемую задачу).
Компиляция с помощью этой команды:
g++ main.cpp unuseful.cpp
позволяет использовать нужную реализацию в вашем файле main.cpp
.
Случай 2: связывание библиотеки
Чаще, чем в случае 1, у вас нет исходного кода библиотеки, которую вы хотите использовать. У вас есть только заголовочный файл (Unuseful.h
, чтобы продолжить этот пример) и статическая или общая библиотека (возможно, [*] libunuseful.a
и libunuseful.so
файлы, соответственно).
Статическая библиотека представляет собой архив объектных файлов (*.o
), которые связаны внутри ваших окончательных исполняемых файлов, вместо этого динамические файлы загружаются динамически - во время выполнения (смотрите эта страница, чтобы лучше понять разницу).
Статические библиотеки создаются путем простого архивирования файлов *.o
с помощью программы ar
:
# Create the object files (only one here)
g++ -c unuseful.cpp
# Create the archive (insert the lib prefix)
ar rcs libunuseful.a unuseful.o
Общие библиотеки создаются с помощью опции g++
-shared
:
# Create the object file with Position Independent Code[**]
g++ -fPIC -c unuseful.cpp
# Crate the shared library (insert the lib prefix)
g++ -shared -o libunuseful.so unuseful.o
Предположим теперь, что у вас есть файл Unuseful.h
и общая библиотека (libunuseful.so
file), и у вас есть файл main.cpp
, который создает объект Unuseful
и вызывает метод printUnusefulStatement
.
Если вы попытаетесь скомпилировать этот файл (g++ main.cpp
), компоновщик будет жаловаться, потому что он не может найти символ printUnusefulStatement
.
Пришло время использовать библиотеку:
g++ main.cpp -L. -lunuseful
Опция -L
указывает компоновщику, где искать файлы библиотеки, а флаг -L
указывает компоновщику имя используемых библиотек (без префикса lib
).
Теперь создается исполняемый файл (a.out
, потому что я не указывал другое имя), и вы использовали библиотеку для реализации необходимой вам функции (printUnusefulStatement
).
Поскольку общая библиотека загружается во время выполнения, выполнение исполняемого файла a.out
может завершиться неудачно, потому что система не может найти библиотеку.
Обычно это можно решить, установив соответствующую переменную среды, указывающую, какие пути использовать для поиска динамических библиотек:
# Set the LD_LIBRARY_PATH [*]
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
Готово, теперь ваш исполняемый файл скомпилирован, и он сможет запускать и загружать нужную библиотеку.
Заключение
Это быстрый обзор библиотек, которые, я надеюсь, помогут вам понять, как они используются и предоставляются другим.
Есть много аспектов, которые необходимо изучить более подробно, если вам интересно: g++
параметры при создании разделяемых библиотек, ar
параметры, переменные среды, формат разделяемых библиотек и т.д.
[*]: в среде Unix
[**]: если поддерживается для целевой машины, испускайте независимый от положения код, подходящий для динамической компоновки и избегая любого ограничения на размер глобальной таблицы смещения. Этот параметр имеет значение для m68k, PowerPC и SPARC. Независимый от позиции код требует специальной поддержки и поэтому работает только на определенных машинах. [Из справочной страницы g++]