Скомпилируйте статическую библиотечную ссылку со стандартной библиотекой (статической)

Я пытаюсь скомпилировать статическую библиотеку (назовем ее 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 Проблема

Другие вопросы по тегам