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

时间:2017-09-27 19:11:40

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

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

谢谢:)

1 个答案:

答案 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.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++或没有libstdc++的系统上将程序与此库链接起来 和你的ABI compatible一个。如果那是你的动力那么 如上所示,使您的库成为共享库。否则,只需链接{{1}} 任何依赖它的程序。

<小时/> [1]在Stackoverflow上,始终在您的问题中陈述真正的问题 。 请参阅The XY Problem