草庐IT

c++ - 用标准库(静态)编译静态库链接

coder 2024-02-12 原文

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

谢谢 :)

最佳答案

Is there any possibility of creating a static library by statically linking also standard libraries



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

链接器可以生成两种文件:程序和共享库。
程序和共享库很相似:它们都由可执行代码组成
程序加载器可以加载到进程中。它们与静态不相似
图书馆。静态库由归档程序ar生成并且只是一个
目标文件包 - 一个存档 - 链接器可以从中提取它
需要完成一个程序或共享库的联动。

像这样的命令:
g++ -c library.cpp -static-libstdc++ -o library.o

只是编译 library.cpp进入 library.o并忽略链接选项 -static-libstdc++因为 -c意味着只需编译。不要链接

你真正的问题只在你后来的评论之一中暴露出来:

The problem is that I am doing a wrapper of a code in C++ to be able to use it in C, in C I can not use the standard C++ libraries. The only way is to include inside the library the functions that I use from the standard library.



现在,由于共享库是链接器可以生成的东西,因此您可以静态地
链接 libstdc++进入共享库。所以,而不是让你的 C 包装库
静态库,您可以将其设为共享库。

您似乎已经知道如何在 C API 中包装 C++ 代码。所以让我们写这样的
将前 N 个字符从输入缓冲区反转到输出缓冲区的 C 包装器,
使用标准 C++ 库来完成所有工作:

反向.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++ 库”。

那是一种误解。以下是如何使用静态构建相同的程序
包装库

首先制作你的静态包装库
$ 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 不允许你这样做的问题。你完成了
编译时使用 C main.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++与任何东西。一种可能,
但不太可能,你可能有想要静态地的理性动机
链接 libstdc++进入带有 C API 的库是您希望其他人
能够在没有 libstdc++ 的系统上将程序与这个库链接起来或者没有
有一个是 ABI compatible和你的。如果那是你的动机,那么
使您的图书馆成为共享图书馆,如上所示。否则,只需链接 libstdc++任何依赖于它的程序。

[1] 在 Stackoverflow 上,始终在您的问题中说明您的真正问题。
The XY Problem

关于c++ - 用标准库(静态)编译静态库链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46455558/

有关c++ - 用标准库(静态)编译静态库链接的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  3. ruby - Sinatra set cache_control to static files in public folder编译错误 - 2

    我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.

  4. ruby - 将 spawn() 的标准输出/标准错误重定向到 Ruby 中的字符串 - 2

    我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])

  5. ruby-on-rails - Prawn - 表格单元格内的链接 - 2

    我正在尝试用Prawn生成PDF。在我的PDF模板中,我有带单元格的表格。在其中一个单元格中,我有一个电子邮件地址:cell_email=pdf.make_cell(:content=>booking.user_email,:border_width=>0)我想让电子邮件链接到“mailto”链接。我知道我可以这样链接:pdf.formatted_text([{:text=>booking.user_email,:link=>"mailto:#{booking.user_email}"}])但是将这两行组合起来(将格式化文本作为内容)不起作用:cell_email=pdf.make_c

  6. ruby-on-rails - 标准化文件名的字符串,删除重音和特殊字符 - 2

    我正在尝试找到一种方法来规范化字符串以将其作为文件名传递。到目前为止我有这个:my_string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^a-z]/,'_')但第一个问题:-字符。我猜这个方法还有更多问题。我不控制名称,名称字符串可以有重音符、空格和特殊字符。我想删除所有这些,用相应的字母('é'=>'e')替换重音符号,并将其余的替换为'_'字符。名字是这样的:“Prélèvements-常规”“健康证”...我希望它们像一个没有空格/特殊字符的文件名:“prelevements_routin

  7. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  8. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

随机推荐