I was trying to follow along with the C++ headers tutorial here, and as the tutorial says I have the files main.cpp, add.cpp, and add.h. The only is that up until now I haven't been using an IDE and compiling straight from the command line.
But I can't seem to figure out how I would compile add.h and and add.cpp into a library.
As of now, if give the command: g++ -o main main.cpp add.h add.cpp, it compiles just fine and gives me a main.exe. But how would I make it so the library (containing add.h and add.cpp) would be precompiled, and saved as a dll? Is this something that's relatively straight forward with the command line?
Thanks for any help guys, cheers.
There are two types of libraries: static and dynamic libraries. Static libraries are linked together with the resulting program, so each program that uses that library will get its own copy of the library code.
A more memory-efficient way is to use shared libraries (on windows called DLL), which are loaded on demand from a location that is specific for each platform, but the advantage is that only one instance of the library code needs to be loaded to memory when different programs that use the library are running simultaneously, and the resulting binary code of those programs do not contain the library code. it resides in a separate file that needs to be shipped together with the application and installed to a proper location.
If you use unix-like build tools (even on a windows system), this could be a typical sequence of commands you would use to produce a library that contains the code in your add.cpp file:
for a static library:
g++ -c add.cpp
ar crf libadd.a add.o
g++ -o main main.cpp -L. -ladd
the first will compile the add.cpp into add.o, the second will create a static library libadd.a from add.o file. If you want to include more object files into your library, add them to the end of that command line. The last command compiles your main.cpp program while linking it with the static library file libadd.a. The -L. option instructs the linker to search for the library file in the current directory. Alternately, you may want to put the library file in some other directory and use the -Lyour_directory option.
for a shared library (a dll):
g++ -shared -o libadd.so add.cpp
g++ -o main main.cpp -L. -ladd
but to run it, the system must be able to locate the shared library. You can help it by adding the directory where your library is located by adding it to the LD_LIBRARY_PATH environment variable, for instance:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
for the Windows platform, you may need to use a few more qualifiers, which are nicely explained in the mingw tutorial: http://www.mingw.org/wiki/sampledll
g++ -c main.cpp
g++ -c add.cpp
g++ - o x.dll main.o add.o
Related
Just for the purpose of learning, I've made a small example of a main program tentatively loeading a shared library via dlopen (and then a symbol from it via dlsym) and using a default one if the former is not avalable.
On my machine, to make the non-default library available to the main program, I need to compile the former via g++ -fPIC -shared MyLib.cpp -o libMyLib.so, whereas both main.cpp and DefaultLib.cpp are compiled simply by g++ -c main.cpp -o main.o and g++ -c DefaultLib.cpp -o DefaultLib.o. How can I provide the options -fPIC -shared to the compilation of MyLib.cpp in Compiler Explorer?
The current attempt is here, where, I believe, MyLib.cpp is compiled just like the other two cpp files, i.e. without providing options -fPIC and -shared, and maybe most importantly without generating a file with the name libMyLib.so, thus resulting dlopen failing to load; indeed, the foo from the other, default library DefaultLib is called.
Can I compile and dlopen a dynamic library in Compiler Explorer?
Yes, it's certainly possible.
In CMakeLists.txt:
add_library(MyLib SHARED MyLib.cpp)
...and remove MyLib.cpp from add_executable.
Then in main.cpp:
void * lib = dlopen("build/libMyLib.so", RTLD_LAZY);
Because the library is placed in the build subdirectory.
Demo
I use g++ 10.2.0 and try to create a static library, but when I create object file for archiving a static library, object file format always shows precompiled header, it makes the final static library cannot work:
//file static_test.cpp
void fn(){
int temp;
++temp;
}
//file static_test.h
void fn();
build them but not link
g++ -c static_test.h static_test.cpp -o static_test.o
use file to show static_test.o format
file static_test.o
static_test.o:GCC precompiled header (version 014) for C++
and I archive it
ar rsv libstatic_test.a static_test.o
use file to show libstatic_test.a format:
current ar archive
use a main.cpp to test this static library
#include "static_test.h"
int main(){
fn();
return 0;
}
compile them and link
g++ main.cpp libstatic_test.a
libstatic_test.a: cannot add symbol: archive has no index;run ranlib to add one
collect2: error:ld return 1
why and how to solve this problem, tks~
-c is only for a single file, the second static_test.cpp is ignored. You should get the compiler warning about multiple files set to -c. g++ -c static_test.h results the precompiled header in static_test.o and static_test.cpp is ignored. The proper command should be
g++ -c static_test.cpp -o static_test.o
Do not pass header files to the compiler when you compile object files. All other commands you are using look ok.
if you would like to create a static library with gcc, you have to say it to the linker/wrapper programm "gcc" like:
gcc -static -o libyourlibname(.lib/.so) obj1.o obj2.o -s
legende:
-static: tells the linker to build a static lib
-o : output file
-s : strip all debug/linking stuff, including debug informations
note:
may be you need the option -fPIC at .c compile time like:
gcc -O2 -fPIC -c file1.c -o file1.o
legende:
-O2 : tells the c compiler to optimize
-fPIC : create program independet code (internal for the output code)
-c : compile C file to object file:
-o : tell the linker how the object file should be named
By the way:
Pre-compiled header files are only created by compiling C/C++ files only.
You have require huge memory, and mostly pre-compiled header files are not needed in small projects of small student homework tasks.
And each time you change the header file, you (the compiler) have to create a new copy of the .pch file.
Of course, .pch files are good for end-products which does not change it in the form for the developer. But they are mostly depend on the compiler.
So, you can't use .pch files from Windows MinGW64 Project under Linux (with the near) same compiler in different versions.
In my use case, I have YAML-CPP, SQLite3, and my 'data.cpp' file that I want to all be combined into the same dynamic library, 'libdata.so'.
I first compiled yaml-cpp (as an archive):
mkdir -p "build"
cd "build"
cmake ..
make -j5
to get 'libyaml-cpp.a'.
I then compile sqlite3:
gcc -c -o libsqlite3.a sqlite3.c -lpthread -ldl
to get 'libsqlite3.a'. I know that this a C-based file, and there are differences between it and C++, but I've read that it shouldn't make too much difference here. I also know that I'm using -lpthread -ldl which is for dynamic loading, but I'm not sure how to get around it.
My question is: Can I compile my 'data.cpp' file with YAMP-CPP and SQLite3 such that they all exist in the same 'libdata.so' output file (where the linker will use the YAML-CPP and SQLite3 functions contained in 'libdata.so' when they're called by 'data.cpp')?
I have tried:
g++ -c -fPIC -o libdata.so \
-Wl,--whole-archive libsqlite3.a \
-Wl,--whole-archive libyaml-cpp.a \
-ldl -lpthread \
data.cpp
(for the sake of the snippet, all files reside in the same directory)
UPDATE
I added the suggestion from botje to the line and it helped in part. After more research, I found a few more pieces that progressed further:
gcc -DSQLITE_OMIT_LOAD_EXTENSION -c -fPIC -lpthread -o libsqlite3.a sqlite3.c
mkdir -p "build"
cd "build"
env CFLAGS='-fPIC' CXXFLAGS='-fPIC' cmake ..
make -j$(CORES)
cd ..
cp "build/libyaml-cpp.a" ./
g++ -shared -fPIC -o libdata.so \
-L./ \
-Wl,-Bdynamic data.cpp \
-Wl,-Bstatic -lsqlite3 -lyaml-cpp \
-Wl,-Bdynamic -lpthread
g++ -L./ -ldata -o tester tester.cpp
The library now compiles, however, when I try to link against it with 'tester.cpp', I get the error:
/usr/bin/ld: libdata.so: undefined reference to YAML::detail...
I'm guessing this may be a flag ordering issue, but I'm not sure what order it should be then. Placing the flags for SQLite3 and YAML-CPP before the data.cpp argument fails to compile the shared library.
After some more research, here's the method that worked for me (with extra verbosity):
# Compile SQLite3:
# - Disable the plugin loader (removes the libdl dependency)
# - Compile only (-c)
# - Use Position Independent Code (-fPIC)
# - Add the PThread library
# - After compilation, archive object (for completeness)
gcc -DSQLITE_OMIT_LOAD_EXTENSION -c -fPIC -pthread -o sqlite3.o sqlite3.c
# Compile YAML-CPP
# - Create (and enter) a build directory
# - Run CMAKE with -fPIC enabled
# - Run MAKE
# - Exit and copy archive from build directory
mkdir -p "build"
cd "build"
env CFLAGS='-fPIC' CXXFLAGS='-fPIC' cmake ..
make -j$(CORES)
cd ..
cp build/libyaml-cpp.a libyaml-cpp.a
# Compile Shared Library
# - Ensure shared (-shared) (also prevents looking for a 'main')
# - Use Position Independent Code (-fPIC)
# - Use current directory for locating libraries
# - Set target CPP file
# - STATICALLY link from SQLite3 and YAML-CPP archives
# - DYNAMICALLY link from PThread library (used by SQLite3 for thread-safe access)
g++ -shared -fPIC -o libdata.so data.cpp \
-L./ \
-Wl,-Bstatic -l:sqlite3.o -lyaml-cpp \
-Wl,-Bdynamic -pthread
# Compile Test Program
# - Specify current directory for includes and libraries
# - Link dynamically to 'libdata.so'
g++ -I./ -L./ -ldata -o tester tester.cpp
The last issue I encountered ended up being a missing include directory for YAML-CPP.
A couple of notes for credit:
#Botje: For pointing out that I need -shared and not -c in the compilation of a shared library. (libdata.so)
#Maxim Egorushkin: For linking to a very useful document on the matter.
One thing to note as well, is that when linking against a C library in a C++ program, you may need to use 'extern "C"' (as elaborated in the linked page). This is especially important when using the SQLite3 library.
Note that linking .a files into .so is rather unusual. People do that, but for wrong reasons.
When you link a .so, provide individual .o files compiled with -fPIC. Don't pack those .o files into .a first, that doesn't make much sense.
Why? Because .a file is merely a bunch of .o files. There is no point in making a .a file from a bunch of .o files just to turn that then into .so file.
To make a static library one builds .o files and packs them into .a. In fact, static library is a wrong name, technically, .a file is an archive (of .o files). Archives cannot link to other libraries they need because .o file cannot carry dependencies, neither can .a files.
To make a shared library one builds .o files with -fPIC option and links them into .so, along with any required libraries (static or shared). This is the .so file that carries dependency information on other .so files, .a archives are linked in.
When you build a .a that means you trade sharing code (in form of .so) for maximum execution efficiency (in the form of linking parts of .a into your executable directly). That means you build .o files without -fPIC option (it introduces extra access overhead) and bundle them into .a. Note, that .a file cannot refer to other libraries it needs (unlike .so), it is just a bunch of .o files. Static library .a is almost just a form to refer to multiple .o file. For local builds you should use thin archives that don't copy .o into .a rather refer to .o.
Also note, that when you link .a archive, only those .o files from the archive get linked into your executable (or shared library) that resolve currently unresolved symbols (unless --whole-archive). That means, if you have a global/namespace scope object with a constructor and link that into .so then it links in everything from the supplied object files and your global object constructor runs as expected. However, if you link in .a, the linker only pulls in those symbols/object-files that resolve currently undefined symbols, so that if your global object isn't referred to (possibly indirectly) from a file with main function, it won't be linked in and its constructor won't run.
For your purpose of building one .so from multiple 3rd-party libraries, you should compile those libraries' object files with -fPIC but not link them into .a. Then you link all those .o files into one .so file with all the libraries required by those comprising .o (either statically or dynamically).
With regards to -lpthread this is sadly a very common misconception perpetuated by POSIX standard wording being out of date.
In the old days there were two implementations of Pthreads API on Linux (and probably other systems): LinuxThreads and NPTL. POSIX standard merely says that if you want POSIX-compliant behaviour then link NPTL, not LinuxThreads and that is what that -lpthread linker option for. They fail to explain this reasoning or remove that sentence because it is woefully out of date.
Nowadays, modern Linux, and probably other systems, provide only the POSIX-compliant version. Hence, that -lpthread flag is obsolete, serves no purpose and isn't sufficient to build correct multi-threaded programs.
When you build multi-threaded programs you need to follow the documentation of your compiler. gcc and clang require using -pthread flag for both compiling and linking.
I am creating a shared library from a class from an example I got here C++ Dynamic Shared Library on Linux. I would like to call another shared library from the shared library created and then use it in the main program. So I have the myclass.so library and I want to call another library say anotherclass.so from the myclass.so library and then use this myclass.so library in the main program. Any idea on how I can do this please.
There is more than one way in which multiple shared libraries may be added to
the linkage of a program, if you are building all the libraries, and the program,
yourself.
The elementary way is simply to explicitly add all of the libraries to the
the linkage of the program, and this is the usual way if you are building only the
program and linking libraries built by some other party.
If an object file foo.o in your linkage depends on a library libA.so, then
foo.o should precede libA.so in the linkage sequence. Likewise if libA.so
depends on libB.so then libA.so should precede libB.so. Here's an illustration.
We'll make a shared library libsquare.so from the files:
square.h
#ifndef SQUARE_H
#define SQUARE_H
double square(double d);
#endif
and
square.cpp
#include <square.h>
#include <cmath>
double square(double d)
{
return pow(d,2);
}
Notice that the function square calls pow, which is declared in the
Standard header <cmath> and defined in the math library, libm.
Compile the source file square.cpp to a position-independent object file
square.o:
$ g++ -Wall -fPIC -I. -c square.cpp
Then link square.o into a shared library libsquare.so:
$ g++ -shared -o libsquare.so square.o
Next we'll make another shared library libcube.so from these files:
cube.h
#ifndef CUBE_H
#define CUBE_H
double cube(double d);
#endif
and
cube.cpp
#include <cube.h>
#include <square.h>
double cube(double d)
{
return square(d) * d;
}
See that the function cube calls square, so libcube.so is going to
depend on libsquare.so. Build the library as before:
$ g++ -Wall -fPIC -I. -c cube.cpp
$ g++ -shared -o libcube.so cube.o
We haven't bothered to link libsquare with libcube, even though libcube
depends on libsquare, and even though we could have, since we're building libcube.
For that matter, we didn't bother to link libm with libsquare. By default the
linker will let us link a shared library containing undefined references, and it
is perfectly normal. It won't let us link a program with undefined references.
Finally let's make a program, using these libraries, from this file:
main.cpp
#include <cube.h>
#include <iostream>
int main()
{
std::cout << cube(3) << std::endl;
return 0;
}
First, compile that source file to main.o:
$ g++ -Wall -I. -c main.cpp
Then link main.o with all three required libraries, making sure to list
the linker inputs in dependency order: main.o, libcube.so, libsquare.so, libm.so:
$ g++ -o prog main.o -L. -lcube -lsquare -lm
libm is a system library so there's no need to tell the linker where to look for
it. But libcube and libsquare aren't, so we need to tell the linker to look for
them in the current directory (.), because that's where they are. -L. does that.
We've successfully linked ./prog, but:
$ ./prog
./prog: error while loading shared libraries: libcube.so: cannot open shared object file: No such file or directory
It doesn't run. That's because the runtime loader doesn't know where to find libcube.so (or libsquare.so, though it didn't get that far).
Normally, when we build shared libraries we then install them in one of the loader's default
search directories (the same ones as the linker's default search directories), where they're available to any program, so this wouldn't happen. But I'm not
going to install these toy libraries on my system, so as a workaround I'll prompt the loader where to look
for them by setting the LD_LIBRARY_PATH in my shell.
$ export LD_LIBRARY_PATH=.
$ ./prog
27
Good. 3 cubed = 27.
Another and better way to link a program with shared libraries that aren't located
in standard system library directories is to link the program using the linker's
-rpath=DIR option. This will write some information into the executable to tell
the loader that it should search for required shared libraries in DIR before it tries
the default places.
Let's relink ./prog that way (first deleting the LD_LIBRARY_PATH from the shell so that it's not effective any more):
$ unset LD_LIBRARY_PATH
$ g++ -o prog main.o -L. -lcube -lsquare -lm -Wl,-rpath=.
And rerun:
$ ./prog
27
To use -rpath with g++, prefix it with -Wl, because it's an option for linker, ld,
that the g++ frontend doesn't recognise: -Wl tells g++ just to pass the
option straight through to ld.
I would like to add some points to the response of #Mike.
As you do not link libcube library with libsquare you are creating a sort of "incomplete library". When I say incomplete, I meant that when you link your application you must link it with both libcube and libsquare even though it does not use any symbol directly from libsquare.
It is better to link libcube directly with libsquare. This link will create the library with a NEEDED entry like:
readelf -d libcube.so
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libsquare.so]
Then when you link your application you can do:
g++ -o prog main.o -L. -lcube
Although, this will not link because the linker tries to locate the NEEDED library libsquare. You must precise its path by adding -Wl,-rpath-link=. to the linking command:
g++ -o prog main.o -L. -lcube -Wl,-rpath-link=.
Note: For runtime, you must still set LD_LIBRARY_PATH or link with rpath as mentioned by #Mike.
In your library if you are using any other shared library so simply your library user is also dependent on that library. While creating library you can use -l so the linker have notion for shared library and it will link when required.
But when you deliver your library as its dependent on some other library you need to export that too along with your and provide some environment variable or linker flag to load it from specified path (Your exported package). That will not lead any discrepancy other wise if its some standard library function user might get definition from his system's some other library and will lead in disastrous situation.
Simply use the library like you'd use it in any other application. You don't have to link to anotherclass.so, just to myclass.so.
However, you will have to make both libraries (myclass.so and anotherclass.so) available for your later application's runtime. If one of them is missing you'll get runtime errors just like it is with any other application.
I apologize that this is redundant, but none of the answers available seem to be able to solve my problem. I am attempting to compile an executable using a shared object library. The shared object library is called libsession.so and is found in the same directory that I am compiling the executable. To compile and link, I use the following command
g++ test_main.cpp -o program -std=c++11 -I ../src/base -L. -lsession
Unforutanely, I get the cannot find -lsession error when linking. If I change the command to directly reference the shared library as follows
g++ test_main.cpp -o program -std=c++11 -I ../src/base libsession.so
then the executable compiles/links and all is well. Does anyone have any thoughts as to what I may be doing wrong?
The only difference between using an '-l' option and specifying a file
name is that '-l' surrounds library with 'lib' and `.a' and searches
several directories.
https://gcc.gnu.org/onlinedocs/gcc-3.0/gcc_3.html#SEC16