Скомпилируйте статическую библиотечную ссылку со стандартной библиотекой (статической)
Я пытаюсь скомпилировать статическую библиотеку (назовем ее library.a). Эта библиотека потребляет ресурсы стандартных библиотек. Есть некоторый способ, которым библиотека может статически связать стандартную библиотеку.
Я доказал что-то вроде:
g++ -c library -static-libstdc++ -o library.o
ar rcs library.o library.a
Но если я это сделаю, то ссылки на стандартные библиотеки не будет.
Тогда я доказал так:
g++ library -static-stdlib -o library.o
ar rcs library.o library.a
Но попросите меня добавить основную функцию.
Есть ли возможность создания статической библиотеки, статически связывая также стандартные библиотеки (std:: string, std:: vector, std:: cin и т.д...).
Спасибо:)
1 ответ
Есть ли возможность создания статической библиотеки, статически связывая также стандартные библиотеки
Нет, потому что вы ничего не можете связать со статической библиотекой. Вы можете связать вещи только в файл, созданный компоновщиком. В противном случае никакие ссылки не участвуют в его производстве.
Компоновщик может создавать файлы двух типов: программы и общие библиотеки. Программы и разделяемые библиотеки похожи: обе они состоят из исполняемого кода, который загрузчик программы может загрузить в процесс. Они не похожи на статическую библиотеку. Статическая библиотека создается программой архивации ar
и это просто пакет объектных файлов - архив, из которого компоновщик может извлечь те файлы, которые ему необходимы для завершения связывания программы или разделяемой библиотеки.
Команда как:
g++ -c library.cpp -static-libstdc++ -o library.o
просто компилирует library.cpp
в library.o
и игнорирует параметр связи -static-libstdc++
так как -c
значит просто скомпилировать. Не связывать
Ваша настоящая проблема раскрывается только в одном из ваших последующих комментариев 1:
Проблема в том, что я делаю обертку кода в C++, чтобы иметь возможность использовать его в C, в C I нельзя использовать стандартные библиотеки C++. Единственный способ - включить в библиотеку функции, которые я использую из стандартной библиотеки.
Теперь, когда компоновщик может создать общую библиотеку, вы можете статически связать libstdc++
в общую библиотеку. Таким образом, вместо того, чтобы делать вашу библиотеку оболочки C статической, вы можете сделать ее общей библиотекой.
Кажется, вы уже знаете, как обернуть код C++ в C API. Итак, давайте напишем такую оболочку C, которая инвертирует первые N символов из входного буфера в выходной буфер, используя стандартную библиотеку C++ для выполнения всей работы:
reverse.h
#ifndef REVERSE_H
#define REVERSE_H
#ifdef __cplusplus
extern "C" {
#endif
void reverse(char const * in, char * out, unsigned len);
#ifdef __cplusplus
} // extern "C"
#endif
reverse.cpp
#include "reverse.h"
#include <string>
#include <algorithm>
extern "C" {
void reverse(char const * in, char * out, unsigned len)
{
std::string s{in,len};
std::reverse(s.begin(),s.end());
std::copy(s.begin(),s.end(),out);
}
} // extern "C"
Затем программа на C, которая вызывает reverse
:
main.c
#include <stdio.h>
#include <reverse.h>
int main()
{
char in[] = "dlrow olleH";
reverse(in,in,sizeof(in) - 1);
puts(in);
return 0;
}
Теперь мы создадим нашу общую библиотеку оболочки.
Скомпилируйте один исходный файл нашей библиотеки:
$ g++ -fPIC -Wall -Wextra -std=c++11 -c reverse.cpp
уведомление -fPIC
, Все объектные файлы, которые мы собираемся связать в общей библиотеке, должны иметь независимый от позиции код. И как мы собираем один исходный файл - -c reverse.cpp
- мы можем пропустить -o
вариант и принять по умолчанию, -o reverse.o
Затем свяжите нашу общую библиотеку:
$ g++ -shared -o libreverse.so reverse.o -static-libstdc++
Теперь общая библиотека ./libreverse.so
и он не имеет зависимости во время выполнения от libstdc++
:
$ ldd libreverse.so
linux-vdso.so.1 => (0x00007ffca98c9000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa178862000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa178498000)
/lib64/ld-linux-x86-64.so.2 (0x000055d17658c000)
Затем скомпилируйте исходный файл нашей программы на C:
$ gcc -Wall -Wextra -I. -c main.c
И, наконец, связать программу с libreverse
:
$ gcc -o prog main.o -L. -lreverse
Эта программа ./prog
имеет зависимость времени выполнения от общей библиотеки libreverse.so
, Вы не можете статически связать с libreverse.so
потому что это не статическая библиотека. Но libreverse.so
был статически связан с libstdc++.a
и имеет C API.
Если libreverse.so
Это была серьезная библиотека, и сейчас мы должны установить ее в один из стандартных поисковых каталогов загрузчика среды выполнения, чтобы программы могли автоматически загружать ее во время выполнения. Мы могли бы сделать это как:
$ sudo cp libreverse.so /usr/local/lib/
$ sudo ldconfig
Но с тех пор libreverse.so
это просто игрушечная библиотека, мы не будем модифицировать нашу систему для нее. Вместо этого мы просто побежим ./prog
лайк:
$ export LD_LIBRARY_PATH=. # For now, tell the loader to look for libraries here
$ ./prog
Hello world
Таким образом, вы можете создать библиотеку-оболочку с C API и внутренними компонентами C++, с libstdc++
статически связаны, делая библиотеку оболочки общей библиотекой.
Но зачем?
Кажется, что вы хотите беспокоиться, потому что вы считаете, что "в C I не может использовать стандартные библиотеки C++".
Это ошибочное мнение. Вот как вы можете собрать ту же программу со статической библиотекой-оберткой
Сначала сделайте свою статическую библиотеку обертки
$ rm libreverse.so # Better delete the old shared one just to avoid confusion.
$ g++ -Wall -Wextra -std=c++11 -c reverse.cpp
$ ar rcs libreverse.a reverse.o
Затем скомпилируйте ваш источник C:
$ gcc -Wall -Wextra -I. -c main.c
На данный момент у вас есть объектный файл main.o
статическая библиотека libreverse.a
который содержит (только) reverse.o
и сделать prog
вам просто нужно связать main.o
а также libreverse.a(reverse.o)
вместе со стандартной библиотекой C и стандартной библиотекой C++. Нет никаких сомнений в том, что С не позволяет вам сделать это. Вы закончили с C, когда вы скомпилировали main.c
, Эти объектные файлы и библиотеки будут связаны вашим системным компоновщиком, который не будет знать или не заботиться о том, на каком языке был скомпилирован любой из них.
Таким образом, вы можете вызвать компоновщик через g++
, лайк:
$ g++ -o prog main.o -L. -lreverse
и еще раз у вас есть программа, которая делает это:
$ ./prog
Hello world
Или вы можете вызвать компоновщик через gcc
, лайк:
$ gcc -o prog main.o -L. -lreverse -lstdc++
это та же самая связь, с тем же самым результатом:
$ ./prog
Hello world
Как видите, одно отличие между ссылками через g++
скорее, чем gcc
в том, что g++
автоматически добавляет к входам компоновщика как стандартную библиотеку C, так и стандартную библиотеку C++, и gcc
не добавляет библиотеку C++, поэтому вы должны сделать это самостоятельно.
В этом случае, если у вас на компьютере установлен GNU Fortran, вы можете сделать то же самое с ним:
$ $ gfortran -o prog main.o -L. -lreverse -lstdc++
$ ./prog
Hello world
хотя ничего в prog
был написан на фортране.
C не мешает вам ссылаться libstdc++
с чем. Возможный, но маловероятный, рациональный мотив, который вы могли бы иметь для желающих статически связать libstdc++
В библиотеку с C API входит то, что вы хотите, чтобы кто-то еще мог связывать программы с этой библиотекой в системе, которая не имеет libstdc++
или не имеет тот, который совместим с вашим ABI. Если это ваша мотивация, сделайте вашу библиотеку общей, как показано выше. В противном случае просто ссылка libstdc++
с любой программой, которая зависит от этого.
[1] В Stackru всегда указывайте реальную проблему в своем вопросе. Смотрите XY Проблема