用标准库编译静态库链接(静态) [英] Compile a static library link with standard library (static)

查看:109
本文介绍了用标准库编译静态库链接(静态)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编译静态库(我们称其为库。a)。该库消耗标准库的资源。库可以通过某种方式静态链接标准库。



我已经证明了类似的东西:

  g ++ -c库-static-libstdc ++ -o library.o 
ar rcs library.o library.a

但是,如果这样做,则没有指向标准库的链接。



然后,我证明了这种方式:

  g ++库-static-stdlib -o library.o 
ar rcs library.o library.a

但是请我添加一个主要函数。



是有可能通过静态链接标准库(std ::字符串,std ::向量,std :: cin等)来创建静态库。



谢谢:)

解决方案


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


不,因为您不能将任何内容链接到静态库。您只能将内容链接到链接器生成的
文件中。否则,它的生产中将不涉及任何链接。



链接器可以生成两种文件:程序和共享库。
程序和共享库相似:它们都由可执行代码
组成,程序加载器可以将其加载到进程中。它们 not 与静态
库相似。静态库是由归档程序 ar 生成的,只是一个
包的目标文件-存档-链接器可以从中提取其$ b的文件$ b需要完成程序或共享库的链接。



命令如下:

  g ++ -c library.cpp -static-libstdc ++ -o library.o 

仅将 library.cpp 编译为 library.o 并忽略链接选项 -static- libstdc ++
,因为 -c 表示只需编译。不要链接



您的真正问题仅在您以后的评论之一中暴露出来 1


问题是我正在用C ++对代码进行包装,以便能够在C中使用它,CI中的
无法使用标准C ++库。唯一的方法是将
包含在我的标准库中。


现在,由于 shared 库是链接器可以生成的东西,您可以将
静态链接 libstdc ++ 到共享库中。因此,您可以使它成为共享库,而不是使C包装器库
a成为静态库。



似乎您已经知道如何包装C ++代码了C API。因此,让我们编写这样的
a C包装器,使用标准C ++库将前N个字符从输入缓冲区反转为输出缓冲区



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

然后一个调用反向的C程序:



main.c

  #include< stdio.h> 
#include< reverse.h>

int main()
{
char in [] = dlrow olleH;
reverse(in,in,sizeof(in)-1);
推(入);
返回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 静态链接,并具有
a C API。



如果 libreverse.so 是一个严肃的库,我们会怎么做现在是安装它
,这是运行时加载程序的标准
搜索目录之一,以便程序可以在运行时自动加载它。我们
可以这样:

  $ sudo cp libreverse.so / usr / local / lib / 
$ sudo ldconfig

但是由于 libreverse.so 只是一个玩具库,我们不会为
修改我们的系统。相反,我们只运行 ./ prog ,例如:

  $ export LD_LIBRARY_PATH =。 #现在,告诉加载程序在这里寻找库
$ ./prog
Hello world

因此,您可以通过将包装库设为 libstdc ++
静态链接来创建包装库。 >共享的库。



但是为什么要打扰?



它似乎您想打扰,因为您认为在CI中不能使用标准C ++库。



这是一个误解。这是使用 static
包装器库



首先创建静态包装器库

  $ rm libreverse.so#最好删除旧的共享文件,以免造成混淆。 
$ g ++ -Wall -Wextra -std = c ++ 11 -c reverse.cpp
$ ar rcs libreverse.a reverse.o

然后编译您的C源代码:

  $ gcc -Wall -Wextra -一世。 -c main.c 

此时,您有一个目标文件 main .o ,一个静态库 libreverse.a
,其中包含(仅) reverse.o ,并制作 prog ,您只需链接 main.o
libreverse.a(reverse.o)以及标准C库和标准C ++
库。毫无疑问, C不允许您这样做。编译 main.c 时,您用C完成了
。这些目标文件和库将由
由您的系统链接器链接,该系统链接器将不知道或不在乎它们是用什么语言编译的。$ p
$ b

因此您可以通过 g ++ 调用链接器,例如:

  $ g ++ -o prog main.o -L。 -lreverse 

再一次,您有一个执行此操作的程序:

  $ ./程序
Hello world

或者您可以通过 gcc 调用链接器,例如:

  $ gcc -o prog main.o -L。 -lreverse -lstdc ++ 

这是相同的链接,但结果相同:

  $ ./程序
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 ++ 或没有$ b $的系统上将程序与此库链接b拥有与您的 ABI兼容的一个。如果这是您的动力,则
使您的图书馆成为共享图书馆,如上所示。否则,只需将 libstdc ++
与依赖它的任何程序链接。





[1]在Stackoverflow上,始终在问题中陈述您的 real 问题
请参见 XY问题


I'm trying to compile a static library (let's call it library.a). This library consumes resources of standard libraries. There is some way that the library can statically link a standard library.

I have proven something like:

g++ -c library -static-libstdc++ -o library.o
ar rcs library.o library.a

But if I do so there is no link to the standard libraries.

Then I have proved this way:

g++ library -static-stdlib -o library.o
ar rcs library.o library.a

But ask me to add a main function.

Is there any possibility of creating a static library by statically linking also standard libraries (std :: string, std :: vector, std :: cin, etc ...).

Thanks :)

解决方案

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

No, because you cannot link anything to a static library. You can link things only into a file that is produced by the linker. Otherwise no linking is involved in its production.

The linker can produce two kinds of files: programs and shared libraries. Programs and shared libraries are similar: they're both composed of executable code that the program loader can load into a process. They are not similar to a static library. A static library is produced by the archiving program ar and is just a bag of object files - an archive - from which the linker can extract the ones it needs to complete the linkage of a program or shared library.

A command like:

g++ -c library.cpp -static-libstdc++ -o library.o

just compiles library.cpp into library.o and ignores the linkage option -static-libstdc++ because -c means Just compile. Don't link

Your real problem only comes to light in one of your later comments1:

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.

Now since a shared library is something that the linker can produce, you can statically link libstdc++ into a shared library. So, instead of making your C wrapper library a static library, you could make it a shared libary.

It seems you already know how to wrap C++ code in a C API. So let's write such a C wrapper that reverses the first N characters from an input buffer to an output buffer, using the standard C++ library to do all the work:

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"

Then a C program that calls reverse:

main.c

#include <stdio.h>
#include <reverse.h>

int main()
{
    char in[] = "dlrow olleH";
    reverse(in,in,sizeof(in) - 1);
    puts(in);
    return 0;
}

Now we'll build our shared wrapper library.

Compile our one library source file:

$ g++ -fPIC -Wall -Wextra -std=c++11 -c reverse.cpp

Notice -fPIC. All object files that we're going to link in a shared library must be Position Independent Code. And as we're compiling one source file - -c reverse.cpp - we can skip the -o option and accept the default, -o reverse.o

Then link our shared library:

$ g++ -shared -o libreverse.so reverse.o -static-libstdc++

Now the shared library is ./libreverse.so and it has no runtime dependency on 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)

Next compile our C program source file:

$ gcc -Wall -Wextra -I. -c main.c

And finally link the program with libreverse:

$ gcc -o prog main.o -L. -lreverse

This program ./prog has a runtime dependency on the shared library libreverse.so. You can't statically link with libreverse.so because it's not a static library. But libreverse.so has been statically linked with libstdc++.a, and has a C API.

If libreverse.so was a serious library what we'd do now is is install it one of the runtime loader's standard search directories, so that programs could load it automatically at runtime. We could do that like:

$ sudo cp libreverse.so /usr/local/lib/
$ sudo ldconfig

But since libreverse.so is just a toy library we won't modify our system for it. Instead we'll just run ./prog like:

$ export LD_LIBRARY_PATH=. # For now, tell the loader to look for libraries here
$ ./prog
Hello world

So you can make a wrapper library with a C API and C++ internals, with libstdc++ statically linked, by making the wrapper library a shared library.

But why bother?

It seems that you want to bother because you believe that "in C I can not use the standard C++ libraries".

That is a misconception. Here's how you can build the same program with a static wrapper library

First make your static wrapper library

$ 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

Then compile your C source:

$ gcc -Wall -Wextra -I. -c main.c

At this point, you have an object file main.o, a static library libreverse.a that contains (only) reverse.o, and to make prog you simply need to link main.o and libreverse.a(reverse.o) together with the standard C library and the standard C++ library. There is no question of C not allowing you to do this. You finished with C when you compiled main.c. These object files and libraries will be linked by your system linker, which will not know or care what language any of them were compiled from.

So you could invoke the linker via g++, like:

$ g++ -o prog main.o -L. -lreverse

and once more you have a program that does this:

$ ./prog
Hello world

Or you could invoke the linker via gcc, like:

$ gcc -o prog main.o -L. -lreverse -lstdc++

which is just the same linkage, with just the same result:

$ ./prog
Hello world

As you see, the one difference between linking via g++ rather than gcc is that g++ automatically adds both the standard C library and the standard C++ library to the linker's inputs, and gcc doesn't add the C++ library, so you have to do it yourself.

For that matter, if you happened to have GNU Fortran installed on your computer you could do the same linkage with it:

$ $ gfortran -o prog main.o -L. -lreverse -lstdc++
$ ./prog
Hello world 

although nothing in prog was written in Fortran.

C doesn't stop you from linking libstdc++ with anything. A possible, but unlikely, rational motive you might have for wishing to statically link libstdc++ into a library with a C API is that you want somebody else to be able to link programs with this library on a system that doesn't have libstdc++ or doesn't have one that is ABI compatible with yours. If that is your motivation, then make your library a shared one as shown above. Otherwise, just link libstdc++ with any program that depends on it.


[1] On Stackoverflow, always state your real problem in your question. See The XY Problem

这篇关于用标准库编译静态库链接(静态)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆