是否有可能通过静态链接标准库来创建静态库
不,因为您无法将任何内容链接到静态库。您只能将事物链接到
由链接器生成的文件。否则,其生成过程中不涉及任何链接。
链接器可以生成两种文件:程序和共享库。
程序和共享库是相似的:它们都是由可执行代码组成的
程序加载器可以加载到进程中。它们不类似于静态
图书馆。一个静态库是由归档程序ar 生成的,它只是一个
一袋目标文件 - 一个档案 - 链接器可以从中提取它的那些
需要完成程序或共享库的链接。
类似的命令:
g++ -c library.cpp -static-libstdc++ -o library.o
只需将library.cpp 编译成library.o 并忽略链接选项-static-libstdc++
因为-c 表示只需编译。不要链接
你真正的问题只有在你后来的一个 cmets 中才暴露出来1:
问题是我正在用 C++ 封装代码以便能够在 C 中使用它,
在 C 中我不能使用标准的 C++ 库。唯一的方法是包含在里面
我从标准库中使用的函数。
现在,由于 shared 库是链接器可以生成的东西,因此您可以静态地
将libstdc++ 链接到共享库。所以,而不是制作你的 C 包装库
静态库,您可以将其设为共享库。
您似乎已经知道如何在 C API 中封装 C++ 代码。所以让我们写这样的
将前 N 个字符从输入缓冲区反转到输出缓冲区的 C 包装器,
使用标准 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
因此,您可以使用 C API 和 C++ 内部构造一个包装库,使用 libstdc++
静态链接,通过使包装库成为共享库。
但是为什么要麻烦呢?
您似乎想打扰,因为您认为“在 C 中我不能使用标准 C++ 库”。
这是一种误解。以下是使用 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++ 或没有的系统上将程序与此库链接
有一个ABI compatible 和你的。如果那是你的动力,那么
使您的库成为共享库,如上所示。否则,只需链接libstdc++
任何依赖它的程序。
[1] 在 Stackoverflow 上,始终在您的问题中说明您的
真实问题。
见
The XY Problem