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.cpp成library.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.o
并libreverse.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++,而不是gcc是
g++自动添加这两种标准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++
任何依赖它的程序.