【问题标题】:Compile a static library link with standard library (static)用标准库编译静态库链接(静态)
【发布时间】:2017-09-27 19:11:39
【问题描述】:

我正在尝试编译一个静态库(我们称之为 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 等)来创建静态库。

谢谢:)

【问题讨论】:

  • 据我所知,标准库是默认链接的。
  • 尽管如此,如果您想静态链接而不是动态链接,请参阅:stackoverflow.com/q/26103966/2104697
  • 问题是我在 C++ 中做一个代码的包装以便能够在 C 中使用它,在 C 中我不能使用标准的 C++ 库。唯一的方法是在库中包含我从标准库中使用的函数。我没有程序。要编译代码,我应该编写一个程序并删除 g++ 参数“-c”,但如果这样做,我必须将 main 函数放入代码中。然后我不能将它用作库。
  • 你正在编译的源代码是library还是library.c。您应该指定带有扩展名的文件名。

标签: c++ c++11 g++ static-libraries standard-library


【解决方案1】:

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

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

链接器可以生成两种文件:程序和共享库。 程序和共享库是相似的:它们都是由可执行代码组成的 程序加载器可以加载到进程中。它们类似于静态 图书馆。一个静态库是由归档程序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程序:

ma​​in.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.olibreverse.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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多