Compile a static library link with standard librar

2019-04-10 07:19发布

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 :)

1条回答
你好瞎i
2楼-- · 2019-04-10 08:10

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

查看更多
登录 后发表回答