使用标准库编译静态库链接(静态)

Adr*_*ana 4 c++ g++ standard-library static-libraries c++11

我正在尝试编译一个静态库(让我们称之为library.a).该库消耗标准库的资源.有一些方法可以使库静态链接标准库.

我证明了这样的事情:

g++ -c library -static-libstdc++ -o library.o
ar rcs library.o library.a
Run Code Online (Sandbox Code Playgroud)

但如果我这样做,就没有标准库的链接.

然后我证明了这一点:

g++ library -static-stdlib -o library.o
ar rcs library.o library.a
Run Code Online (Sandbox Code Playgroud)

但是请我添加一个主要功能.

是否有可能通过静态链接标准库(std :: string,std :: vector,std :: cin等...)来创建静态库.

谢谢 :)

Mik*_*han 16

是否有可能通过静态链接标准库来创建静态库

不,因为您无法将任何内容链接到静态库.您只能将事物链接到链接器生成的文件中.否则,其生产中不涉及链接.

链接器可以生成两种文件:程序和共享库.程序和共享库是相似的:它们都是由程序加载器可以加载到进程中的可执行代码组成的.它们与静态库相似.归档程序生成一个静态库ar ,它只是一个目标文件包 - 一个存档 - 链接器可以从中提取完成程序或共享库链接所需的文件.

像这样的命令:

g++ -c library.cpp -static-libstdc++ -o library.o
Run Code Online (Sandbox Code Playgroud)

只是编译library.cpplibrary.o,而忽略联动选项-static-libstdc++ ,因为-c手段只是编译.不要链接

你的真正问题只会在你后来的一条评论1中曝光:

问题是我在C++中做一个代码包装器能够在C中使用它,在CI中不能使用标准的C++库.唯一的方法是在库中包含我从标准库中使用的函数.

现在,由于共享库是链接器可以生成的东西,因此您可以静态链接libstdc++到共享库.因此,您可以将其作为共享库,而不是使您的C包装器库成为静态库.

您似乎已经知道如何在C API中包装C++代码.因此,让我们编写一个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
Run Code Online (Sandbox Code Playgroud)

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"
Run Code Online (Sandbox Code Playgroud)

然后一个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;
}
Run Code Online (Sandbox Code Playgroud)

现在我们将构建我们的共享包装器库.

编译我们的一个库源文件:

$ g++ -fPIC -Wall -Wextra -std=c++11 -c reverse.cpp
Run Code Online (Sandbox Code Playgroud)

注意事项-fPIC.我们要在共享库中链接的所有目标文件必须是与位置无关的代码.当我们正在编译一个源文件时 - -c reverse.cpp我们可以跳过该-o选项并接受默认值,-o reverse.o

然后链接我们的共享库:

$ g++ -shared -o libreverse.so reverse.o -static-libstdc++
Run Code Online (Sandbox Code Playgroud)

现在共享库是,./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)
Run Code Online (Sandbox Code Playgroud)

接下来编译我们的C程序源文件:

$ gcc -Wall -Wextra -I. -c main.c
Run Code Online (Sandbox Code Playgroud)

最后将程序链接到libreverse:

$ gcc -o prog main.o -L. -lreverse
Run Code Online (Sandbox Code Playgroud)

此程序./prog对共享库具有运行时依赖性libreverse.so.您无法静态链接,libreverse.so因为它不是静态库.但libreverse.so 被静态地链接libstdc++.a,并且有一个C API.

如果libreverse.so是一个严肃的库,我们现在要做的是将它安装到运行时加载程序的标准搜索目录之一,以便程序可以在运行时自动加载它.我们可以这样做:

$ sudo cp libreverse.so /usr/local/lib/
$ sudo ldconfig
Run Code Online (Sandbox Code Playgroud)

但由于libreverse.so它只是一个玩具库,我们不会为它修改我们的系统.相反,我们只会运行./prog:

$ export LD_LIBRARY_PATH=. # For now, tell the loader to look for libraries here
$ ./prog
Hello world
Run Code Online (Sandbox Code Playgroud)

因此libstdc++ ,通过使包装器库成为共享库,您可以使用C API和C++内部构建包装库,并使用静态链接.

但为什么要这么麻烦?

您似乎想要打扰,因为您认为"在CI中不能使用标准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
Run Code Online (Sandbox Code Playgroud)

然后编译你的C源代码:

$ gcc -Wall -Wextra -I. -c main.c
Run Code Online (Sandbox Code Playgroud)

在这一点上,你有一个目标文件main.o,静态库libreverse.a 包含(只)reverse.o,并让prog您只需连接main.olibreverse.a(reverse.o)与标准C库和标准C++库一起.没有C不允许你这样做的问题.编译完成后,你完成了C语言main.c.这些目标文件和库将由您的系统链接器链接,系统链接器将不知道或关心它们是从哪个语言编译而来.

所以你可以通过以下方式调用链接器g++:

$ g++ -o prog main.o -L. -lreverse
Run Code Online (Sandbox Code Playgroud)

再一次你有一个程序来做到这一点:

$ ./prog
Hello world
Run Code Online (Sandbox Code Playgroud)

或者您可以通过以下方式调用链接器gcc:

$ gcc -o prog main.o -L. -lreverse -lstdc++
Run Code Online (Sandbox Code Playgroud)

这只是相同的链接,结果相同:

$ ./prog
Hello world
Run Code Online (Sandbox Code Playgroud)

正如你看到的,通过连接之间的一个区别g++,而不是gccg++自动添加这两种标准C库和标准C++库的链接器的输入,以及gcc不加C++库,所以你必须自己做.

就此而言,如果您的计算机上安装了GNU Fortran,您可以使用它进行相同的链接:

$ $ gfortran -o prog main.o -L. -lreverse -lstdc++
$ ./prog
Hello world 
Run Code Online (Sandbox Code Playgroud)

虽然没有任何内容prog是用Fortran编写的.

C不会阻止你libstdc++与任何东西联系.希望静态链接libstdc++到带有C API 的的可能但不太可能的理性动机是,您希望其他人能够在没有libstdc++或没有的系统上将程序与此库链接起来有一个与你的ABI兼容.如果这是您的动机,那么请将您的库设为共享库,如上所示.否则,只需链接libstdc++ 任何依赖它的程序.


[1]在Stackoverflow上,始终在您的问题中陈述您的真实问题.请参阅XY问题