我正在尝试编译静态库(让我们称之为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等等)来创建静态库。
谢谢:)
答案 0 :(得分:16)
是否有可能通过静态链接标准库来创建静态库
不,因为您无法将任何内容链接到静态库。您只能将事物链接到 链接器生成的文件。否则,其生产不涉及任何联系。
链接器可以生成两种文件:程序和共享库。
程序和共享库是相似的:它们都由可执行代码组成
程序加载器可以加载到进程中。它们不类似于静态
图书馆。归档程序ar
生成一个静态库,它只是一个
目标文件包 - 存档 - 链接器可以从中提取它
需要完成程序或共享库的链接。
命令如:
g++ -c library.cpp -static-libstdc++ -o library.o
只需将library.cpp
编译为library.o
并忽略链接选项-static-libstdc++
因为-c
表示只是编译。不要链接
你的真正问题只会在你后来的一篇评论 1 :
中曝光问题是我在C ++中做一个代码包装,能够在C中使用它, 在C中我不能使用标准的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
<强> 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"
然后是一个调用reverse
的C程序:
<强>的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
因此,您可以使用libstdc++
创建一个包含C API和C ++内部的包装器库
静态链接,使包装器库成为共享库。
但为什么要这么麻烦?
您似乎想要打扰,因为您认为C中我不能使用标准C ++库&#34;。
这是一种误解。以下是如何使用 static 构建相同程序的方法 包装库
首先制作静态包装库
$ 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
时使用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
中没有任何内容是用Fortran编写的。
C不会阻止您将libstdc++
与任何内容相关联。可能的,
但是你可能想要静态的理性动机
使用C API将libstdc++
链接到库是您希望其他人使用的
能够在没有libstdc++
或没有libstdc++
的系统上将程序与此库链接起来
和你的ABI compatible一个。如果那是你的动力那么
如上所示,使您的库成为共享库。否则,只需链接{{1}}
任何依赖它的程序。
<小时/> [1]在Stackoverflow上,始终在您的问题中陈述真正的问题 。 请参阅The XY Problem