linking library for creating static library - c++

I have written some code in Lib_file.h and Lib_file.cpp. I wish to convert this code to a static library. I am able to compile the code (using the command g++ -I <necessary include files> -o Lib_file.o Lib_file.cpp)to get Lib_file.o. I am also able to add it to an archive using the ar rvs Lib_file.a Lib_file.o command. Now when I try to use this library in some other code using the -L option, I get undefined reference errors. This errors point to the code in my Lib_file.o . So my question is how do I get the code in my Lib_file.cpp to link to the libraries that it uses.
I have tried the following options so far
I. After creating the Lib_file.o, I tried the following command
g++ -L<include path> -l<.a files> Lib_file.o . On executing this command, I get the following error
/usr/lib/../lib64/crt1.o: In function `_start':
init.c:(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status
II. I tried to include all the necessary .a files in a new archive along with my Lib_file.o using the ar command. Still I get the undefined reference error when I try to use the Lib_file.a library with my application
Please help me out here

First of all, all libraries are normally named something like libxyz.a where xyz is the name of the library.
Secondly, you try to create a program using only the object file you used for the library, and also linking it with itself. This will of course not work, since the library have no main function which is needed for normal programs. You have to create another program, and link that one with the library.
Like
gcc myotherprogram.c -o myotherprogram -L/some/path -lxyz
As you can see in my command line above, I placed the library last on the command line. It's needed because the linker look for dependencies in kind of reversed order.
Edit: Linking your static library with other libraries: You don't. A static library is completely standalone, and if it needs other libraries itself to work then they have to be present on the command line when compiling the actual program.
For example, lets say that library xyz depends on the standard math library (i.e. the m library). You can't "link" with it when creating the xyz library as you don't actually link static libraries, you just put a collection of object files together in an archive (ar and the .a extension is for archive). When you build the actual application that needs the xyz library you also needs to link with whatever libraries that xyz needs:
gcc myotherprogram.c -o myotherprogram -L/some/path -lxyz -lm

Related

How gnu linker choose which dynamic library to link

I was using gpgpu-sim, a GPU simulator, to conduct researches. There are several .so files in my own folder:
And there are some alternatives .so in Nvidia's cudart lib folder:
And there are some .o files and need to be linked with libcudart.so, when I type in the command:
g++ -L "Path/to/MyFolder" -l cudart *.o
I hope the generated a.out would link to libcudart.so, but it just linked to a strange so file:
libcudart_gpgpu-sim_git-commit-6443f21d433f1b642003867e56fe1f54efae55e3_modified_0.so => not found
And when I typed this code:
g++ -L "Path/to/NvidiaFolder" -l cudart *.o
The program can sussessfully find libcudart.so.9 in my LD_LIBRARY_PATH folder,but it shows that the version can't match!:
./a.out: /path/to/myFolder/libcudart.so.9.0: version `libcudart.so.9.0'not found (required by ./a.out)
Can anybody tell me how ld works and how to solve those problems?
I finally find out the reason.
if you use this code to link objects to generate a shared library:
g++ -shared -Wl,-soname,libNAME_A.so -o libNAME_B.so
then, if some on is trying to link NAME_B.so using:
g++ <INPUT> -lNAME_B -o <OUTPUT>
the output will finally look for libNAME_A.so.
refer to g++ man page:
-Wl,option
Pass option as an option to the linker. If option contains commas,
it is split into multiple options at the commas. You can use this
syntax to pass an argument to the option. For example,
-Wl,-Map,output.map passes -Map output.map to the linker. When
using the GNU linker, you can also get the same effect with
-Wl,-Map=output.map.
and for ld man page:
-soname=name
When creating an ELF shared object, set the internal DT_SONAME
field to the specified name. When an executable is linked with a
shared object which has a DT_SONAME field, then when the executable
is run the dynamic linker will attempt to load the shared object
specified by the DT_SONAME field rather than the using the file
name given to the linker.
There is nothing to do with CUDA here, it's just a linking and runtime environment setup problem.
The ld linker searches for objects and library archives following the order specified by -L option parameters, and only after into default system directories. The linker will link the object code that first match this search.
At runtime, if you linked against dynamic libraries (.so files) you will need to properly define the LD_LIBRARY_PATH environment variable with a list of paths to look for dynamic libraries, separated by colon (:).
So if you link to your objects using libraries from your local path (assuming you are looking for libcudart.so):
g++ -o myprogram *.o -L "/Path/to/myFolder" -lcudart
you need to set LD_LIBRARY_PATH as follows before running your program:
export LD_LIBRARY_PATH="/Path/to/myFolder:$LD_LIBRARY_PATH"
./myprogram
I hope this help and clarify your understanding. Frankly I don't understand the origin of your libcudart_gpgpu-sim_git-commit match

C++ using functions from shared library

I have the following problem:
I have two separate c++ projects, and want to use certain functions from one of them in the other. I am compiling using g++, on Linux.
I decided to do this by creating a shared library out of the project from which to use the functions. I added -fPIC to the compiler flags in the Makefile and then created a shared library like this:
g++ -shared -Wl,-soname,libmyproject.so.1 -o libmyproject.so a.o b.o c.o -lc
Then I simply copied the .so file and the header files into the (parent) directory of the new project and added the following to its Makefile:
To LIBS:
-L/../external_proj/libmyproject.so
To CXXFLAGS:
-I/../external_proj
Then I #include the appropriate header file in the destination project code and try to call certain functions from the original project. However, when I compile the destination project I get an error "undefined reference" for the imported function.
My question is then: is there something I'm missing in this setup? Is there perhaps something that needs to be added to the headers in the original project in order to export the functions I want to use?
I should note this is the first time I have attempted to use a shared library in this way. Thanks.
The -L option only specifies the directory where the linker will search for libraries to link with. Then you will need to use the -l option to specify the base name of the shared library (without the "lib" prefix and the ".so" suffix).
But even that will unlikely to be enough. The runtime loader needs to find the shared library, when you attempt to try to execute it. -L and -l will be sufficient to successfully link, but the runtime loader only searches /usr/lib(64)?, and a few other places by default. It does NOT search the current directory, and the ELF binary only records the names of the shared libraries that must be loaded, and not their full pathnames. You have to explicitly record any extra directories to search for any shared libraries, which is the -rpath option.
To finish the job you will also need to pass -rpath to the linker, but g++ does not support this option directory, you will have to use -W to do that.
The full set of options you will likely need are:
-L/../external_proj -lmyproject -Wl,-rpath -Wl,`cd ../external_proj && pwd`
See gcc documentation for more information on the -W option.
Absolute pathnames should be used with -rpath, hence the need to obtain the full pathname to the directory where the shared library is.
The -L flag is to add a path to search libraries in. The -l (lower-case L) is for linking with a library in the search path.
Or you can skip the flags and link with the library directly, almost like you do now (but without the -L option).
If you use the -l option, then remember that for a file libname.so you use only name as the library name. As in -lname. The linker will search for the correct files with the added prefix and suffix.
And lastly an important note about the paths used when linking: If you use -L and -l to link with a shared library, it's only the linker which will find the library. The OS runtime-loader will not be able to see the path used and will not find the library, if it's in a non-standard location. For that you must also set the runtime-path using the special linker option -rpath.
Unfortunately the GCC frontend program g++ doesn't recognize that option, you have to use -Wl to tell g++ to pass on an option to the actual linker. As in -Wl,-rpath,/path/to/libraries.
To summarize, here are the different variants you can use:
Link directly with the library: g++ your_source.cpp ../external_proj/libmyproject.so
Use the -L and -l options: g++ your_source.cpp -L../external_proj -lmyproject
To set the runtime linker path: g++ your_source.cpp -L../external_proj -lmyproject -Wl,-rpath,../external_proj

linking a self-registering, abstract factory

I've been working with and testing a self-registering, abstract factory based upon the one described here:
https://stackoverflow.com/a/582456
In all my test cases, it works like a charm, and provides the features and reuse I wanted.
Linking in this factory in my project using cmake has been quite tricky (though it seems to be more of an ar problem).
I have the identical base.hpp, derivedb.hpp/cpp, and an equivalent deriveda.hpp/cpp to the example linked. In main, I simply instantiate the factory and call createInstance() twice, once each with "DerivedA" and "DerivedB".
The executable created by the line:
g++ -o testFactory main.cpp derivedb.o deriveda.o
works as expected. Moving my derived classes into a library (using cmake, but I have tested this with ar alone as well) and then linking fails:
ar cr libbase.a deriveda.o derivedb.o
g++ -o testFactory libbase.a main.cpp
only calls the first static instantiation (from derivedA.cpp) and never the second static instantiation, i.e.
// deriveda.cpp (if listed first in the "ar" line, this gets called)
DerivedRegister<DerivedA> DerivedA::reg("DerivedA");
// derivedb.cpp (if listed second in the "ar" line, this does not get called)
DerivedRegister<DerivedB> DerivedB::reg("DerivedB");
Note that swapping the two in the ar line calls only the derivedb.cpp static instantiation, and not the deriveda.cpp instantiation.
Am I missing something with ar or static libraries that somehow do not play nice with static variables in C++?
Contrary to intuition, including an archive in a link command is not the same as including all of the objects files that are in the archive. Only those object files within the archive necessary to resolve undefined symbols are included. This is a good thing if you consider that once there was no dynamic linking and otherwise the entirety of any libraries (think the C library) would be duplicated into each executable. Here's what the ld(1) manpage (GNU ld on linux) has to say:
The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again.
Unfortunately there's no standard way to include every member of an archive in the linked executable. On linux you can use g++ -Wl,-whole-archive and on Mac OS X you can use g++ -all_load.
So with GNU binutils ld, the link command should be
g++ -o testFactory -Wl,-whole-archive libbase.a -Wl,-no-whole-archive main.cpp
the -Wl,-no-whole-archive ensures that any archive appearing later in the final link command generated by g++ will be linked in the normal way.

g++ trying (failing) to link statically to libstdc++ for shared object

I'm trying to create a shared object using a number of .O files created with the -fPIC command. When I run g++ with the -shared argument it appears to be trying to statically link to the libstdc++.a library, which of course fails. I'm trying to figure out why it's automatically trying to link statically when I'm not using the -static-stdc++ argument.
when I try creating the shared object I get the error ...libstdc++.a(ios) relocate R_x86_64_325 against 'vtable for std::ios_base': cannot be used when making a shared object
I ran G++ with the -V argument and received and can see LD receives the argument -lstdc++.
When linking together a single shared object, you need to do this from existing .o files. You can not do this from existing .so files; this would link those .so files to your .so file, but not into your .so file. So gcc seeks out and finds an archive of .o files (.a) and tries to link them. But since those are not compiled for relocation (no -fPIC), these can not be used to create .so files.
Your options are:
dynamically link your .so to the libstdc++ (and thus make it depending on the .so file that is installed in the system)
build .o files for libstdc++ and compile them with -fPIC then compile from those your .so file (here it does not matter if you use the .o files directly or an ar archive)
For the first (that I would recommend) option the following will suffice (it is from a makefile that I use for creating malloc/free intercepting .so files)
gcc -shared -lstdc++ -o your.so yourfiles.o
I'll bet it's finding the static library first in its library search path, or ONLY finding the static library. Make sure that the appropriate version of the shared version is installed and can be found. You can probably truss your g++ run to hunt down the order in which it's opening libraries.

linking issue - trying to build a library and use another archive with it

Is it possible to build a library that uses another, already compiled library?
I have some make files that are used to normally build an executable. When making the executable, I use -L ../include/lib1.a to include the original library.
Now, I am building a separate program that is calling the classes from the executable, which was never built into a library, just compiled to the executable with a link like
${CPP} -c ${INC} ${CFLAGS} MyFile.cpp ${OBJ} ${LIB2} -lm
Where LIB2 includes the reference to lib1.a
Now I want to access the class MyFile.cpp directly, and when I build it to its own library lib2.a, and try to call it from the new program, I get a bunch of errors that the classes it references are missing. This is in spite of the fact that when building the new program I am linking in both lib1.a and lib2.a
Should:
-L../include/lib1.a
not be:
-L../include -llib1
I.e. -L denotes the library search path and -l the archive name?
Yes, you should be able to do it. It would be helpful to see the exact errors you are getting.
If you compile your sources into a library and supply the libraries they use on the command line, the compiler is liable to put the other library(s) into your new one. If that happens, and then someone tries to build a program against your library and those others, they will get a whole mess of "doubly-defined symbol" errors.
When you build lib2.a it will not contain the objects files contained in lib1.a.
Your final executable has to link in both of them.