Merge c++ obj files for C linking - c++

I have a huge C/Pro*C project that I want to improve. I copied a piece of it, rewrote it in C++, and it compiles and works fine.
I now want to include it to my C project. In order to do that, I'd like to merge all my little obj files into one, then add it with the others obj files during the final linking.
However, I got errors, and I need help.
I tried ld -Ur file1.o file2.o -llib1 -llib2 -o feature.o but ld complains that it cannot find my libraries (none of them)
I tried ld -Ur file1.o file2.o -o feature.o but then ld complains that there is a huge ton of undefined references to various STL elements.
I tried g++ file1.o file2.o -llib1 -llib2 -o feature.o but it complains that it cannot find main() which is perfectly normal cause I did not want him to make an executable
I tried g++ file1.o file2.o main.o -llib1 -llib2 -o feature and it compiles perfectly good but that's not what I want...
I tried g++ -Xlinker -Ur file1.o file2.o -o feature.o so that g++ would give automagically the stl links to ld, but again, ld could not find the STL...
What should I do, please ?
EDIT:
The main makefile that I wish to change as little as possible contains a list of binaries and their associated obj files. I wish to add my obj file to one of these lists so that the final linking would be transparent.
EDIT2: I don't want to make a library. My new piece of code will replace the old one, and I'd like to use the same kind of process, module by module.

To merge object files into a static library you should use ar

Related

Getting Cplex example to run: Undefined references

I am trying to get the Cplex basic LP example to work. The code can be found here. I am completely new with c++, but hope to be able to get this running.
I am trying to compile it on linux. I am using the following command to run it
g++ -D IL_STD -I /opt/ibm/ILOG/CPLEX_Studio1271/opl/include ilolpex1.cpp
The -D IL_STD was put there to solve an error as found here. The -I ... was put there to specify the location of the header files. I came up with this myself after a lot of trying and googling, so i am in no way sure this is correct.
Anyway, i when i run it i get errors of undefined references:
/tmp/ccl9O1YF.o: In function `populatebyrow(IloModel, IloNumVarArray, IloRangeArray)':
ilolpex1.cpp:(.text+0x18f): undefined reference to `IloNumVar::IloNumVar(IloEnv, double, double, IloNumVar::Type, char const*)'
I did not make any changes in the file, so i assume the only thing which can be wrong is how the files are linked. I have the feeling it probably just is a simple setting, but after hours of looking i still have no idea how to fix it.
The easiest way to compile the ilolpex1.cpp example is to use the Makefile that is included with the installation. For example, you should do the following:
$ cd /opt/ibm/ILOG/CPLEX_Studio1271/cplex/examples/x86-64_linux/static_pic
$ make ilolpex1
This will produce output, like the following:
g++ -O0 -c -m64 -O -fPIC -fno-strict-aliasing -fexceptions -DNDEBUG -DIL_STD -I../../../include -I../../../../concert/include ../../../examples/src/cpp/ilolpex1.cpp -o ilolpex1.o
g++ -O0 -m64 -O -fPIC -fno-strict-aliasing -fexceptions -DNDEBUG -DIL_STD -I../../../include -I../../../../concert/include -L../../../lib/x86-64_linux/static_pic -L../../../../concert/lib/x86-64_linux/static_pic -o ilolpex1 ilolpex1.o -lconcert -lilocplex -lcplex -lm -lpthread
This will tell you everything you'll need to know if you choose to compile your own application by hand in the future. The details about this are described in the documentation (e.g., here).
Obviously, the iloplex1.cpp file is just a demo how to use IloCplex.
What you yet need is IloCplex itself. This should come either as (a) further source file(s) you have to compile with the demo or as a library you link against.
Have a look at your cplex directories, you might find a lib[...].a file somewhere there, possibly in /opt/ibm/ILOG/CPLEX_Studio1271/opl/lib.
You can link against using GCC's (clang's) -l and -L options. Be aware that when using -l, you leave out lib and .a (-l [...] with above (invalid) sample name).

Create static library with no (OpenSSL) dependencies

I am having a piece of code (test.cpp) which depends on OpenSSL. I would like to create a static library with my piece of code, but it should really include already all dependencies. So that in the end I really only need to link against libtest.a file (also on other distros).
I have tried this
g++-7 -c -std=c++17 -static -L/usr/local/lib -lssl -lcrypto test.cpp -o test.o
ar crf libtest.a test.o
g++-5 main.cpp -std=c++11 libtest.a
but it still gives undefined references to OpenSSL stuff.
Don't judge me, my knowledge about compiling is equal 0, usually I let Qt handle this.
I would appreciate it if somebody could sketch how to accomplish it.
A .a file is a collection of .o files and no more. There is no possibility of linking.
Perhaps you could make a .so file (shared library) which does allow things to be statically linked to it.
Note: If you statically link OpenSSL and the person using your library also uses OpenSSL then it means their binary will be bloated by having two copies of it (linkers are not smart enough to optimize this), so it may be a good idea to also publish a version of your library that doesn't statically link OpenSSL.

Order of libraries in static and dynamic linking

I'm trying to build some example c++ code that use boost library. I use this as reference example of static linking.
And everything is fine when I build with dynamic libs.
g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/main.o src/main.cpp
g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/ThreadExample.o src/ThreadExample.cpp
g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/Utils.o src/Utils.cpp
g++ src/main.o src/ThreadExample.o src/Utils.o -lboost_thread -lboost_filesystem -lboost_system -lboost_timer -o ThreadExampleBinary
But when I use static libs I get lots of undefined reference errors:
g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/main.o src/main.cpp
g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/ThreadExample.o src/ThreadExample.cpp
g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/Utils.o src/Utils.cpp
g++ -static src/main.o src/ThreadExample.o src/Utils.o -lboost_thread -lboost_filesystem -lboost_system -lboost_timer -o ThreadExampleBinary
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::start()':
(.text+0x7fd): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::stop()':
(.text+0x94c): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::elapsed() const':
(.text+0xa59): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::resume()':
(.text+0xb60): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::auto_cpu_timer::auto_cpu_timer(std::ostream&, short)':
(.text+0xca5): undefined reference to `boost::chrono::steady_clock::now()'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o):(.text+0xd4e): more undefined references to `boost::chrono::steady_clock::now()' follow
collect2: error: ld returned 1 exit status
make: *** [ThreadExampleBinary] Error 1
Seems this can be fixed adding additional -lboost_chrono library.
But why it works in dinamic setting?
With static linking, you have to also statically link to any libraries depended on by the libraries you are linking to.
The difference is that shared libraries have an entry in the ELF header, called NEEDED that lists other shared libraries that are to be included when you link in this one.
You can see them with this command:
$ objdump -p /usr/lib/libboost_timer.so | grep NEEDED
NEEDED libboost_chrono.so.1.60.0
NEEDED libboost_system.so.1.60.0
NEEDED librt.so.1
NEEDED libstdc++.so.6
NEEDED libgcc_s.so.1
NEEDED libc.so.6
But for static libraries there is no such system, as they are simply collection of object files.
It is worth noting that the NEEDED entry in the shared objects are entirely optional, and if they are not available, then they will behave exactly like the static ones. But most shared libraries include them.
Many libraries use the pkg-config infrastructure to provide the full command line needed, but AFAIK boost is not one of them.
How to automate this process? Well, you do not. You just include what is needed and follow the linker errors to discover further needs.
You can find which static library includes a symbol with something like:
$ nm --print-file-name --defined-only --demangle /usr/lib/*.a 2> /dev/null | \
grep -q 'boost::chrono::steady_clock::now()'
/usr/lib/libboost_chrono.a:chrono.o:0000000000000090 T boost::chrono::steady_clock::now()
But why it works in dinamic setting?
Most of my make files have the following notes (from when I found the answer back when I needed it ... sorry, I don't know where I found it.)
Note - when a build using '-l' finds the .so version of that library (so - shared object) and the same .a archive is also there, g++ prefers the .so over the .a.
However, you can still achieve static link by fully specifying the path to .a.
Example:
$(CC) $(CC_FLAGS) $< /usr/local/lib/libboost_chrono.a -o $# ...
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sometimes, archive code refers to symbols in yet another archive.
i.e. -lyyy_i686 uses some function from -lxxx_i686, and xxx was listed first in the build command. It is possible that a symbol might remain unresolved and the linker fails.
When this happens, try adding xxx a second time to the end of the archive list
from: -lxxx_i686 -lyyy_i686 -lrt -pthread
becomes -lxxx_i686 -lyyy_i686 -lrt -pthread -lxxx_i686
^^^^^^^^^_____________________________^^^^^^^^^^
The preceeding presumes only .a libraries are findable (no xxx.so)
Another alternative, you can command the linker to search an archive multiple times
-lyyy_i686 -lrt -pthread -(-lxxx_i686-)
tell gcc to link this library as many times as needed __^^__________^^
Again, only .a is findable
Finally, if you choose to link with the .so, note that this does not pull in the entire lib into the current build target. Instead, at runtime, the .so is loaded into memory, if it is not already there. This happens after the program starts. For most applications, this is considered a 'small' start-up performance hit as the program adjusts its memory map (automagically behind the scenes). I believe I once found that the app itself can control when to load the .so.
The use of .so pulls in the entire library to memory (if not already installed). Thus, there would not be any missing symbols, in my xxx vs yyy scenario above, the .so pulls all the symbols, whether used or not.
And once again, when trying to load xxx using "-lxxx_i686", the linker prefers to pull in libxxx_i686.so even when the libxxx_i686.a is in the same directory.

Linking libraries in GCC

there are some files that I am trying to compile in ubuntu using makefile.
I have added the following lines in my makefile after several searches on web.
run: hellocode.cpp
g++ -c hellocode.cpp -lssl -lcrypto
Still while compiling it creates the object files and then throws this error:
undefined reference to 'SSL_write'....
on the contrary if remove the '-c' and use it like this
run: hellocode.cpp
g++ hellocode.cpp -lssl -lcrypto
Then I dont see the previous errors of linking but it shows different errors not related to openssl linking but related to other files in the code. I have already browsed through many questions on this forum related to this none seem to have helped me in this.
Kindly tell me whether my makefile is wrong or is there some problem with my machine that its not able to link to my library.
Here's a simple Makefile that you could adopt. Note that compilation and linking are 2 steps. If needed you can use -I for additional include paths and -L for additional link paths.
.PHONY : all
all : hellocode
hellocode : hellocode.o
g++ -o hellocode hellocode.o -lssl -lcrypto
hellocode.o : hellocode.cpp
g++ -c hellocode.cpp -o hellocode.o
Here are some basics of makefiles if it helps.
library linking should be done at final stage - linking :)
-c means "compile only" - it just builds .o object file, without any reference resolution (so -lXXX is just ignored there).
-lXXX options should be added to last call to gcc (without -c) which produces executable, where all .o files are gathered to link together with libraries to resolve all references.

Linking and using netCDF with gcc

Im trying to use netCDF library in my C++ project, but i cannot, for some reason, use it.
Here is my make file
NETCDF = -L/usr/lib -lnetcdf_c++
WILXAPP = -Lsrc src/wilxtest.cpp -o bin/Debug/WilxAstakTest
Debug:
g++ -Wall -ggdb $(NETCDF) $(WILXAPP)
In my cpp file i basically have (removed bloat)
#include <iostream>
#include <netcdfcpp.h>
int main(int argc, char* argv[])
{
NcFile dataFile("simple_xy.nc", NcFile::Replace);
}
And I get this:
undefined reference to `NcFile::NcFile(char const*, NcFile::FileMode, unsigned long*, unsigned long, NcFile::FileFormat)'|
I'm not sure that the errors you're providing match the source you're showing, since the undefined reference for the constructor signature has no relationship to the way you've invoked the constructor in your example.
Anyway, I suspect your problem is that order matters on the link line. The linker only walks through its libraries etc. one time, so if something that comes LATER on the link line needs something that comes EARLIER on the link line, you fail. You must order your link line such that things that require other things come first, and things that are required come later.
A few other tips: the -L option only gives search paths for libraries, so you don't need -Lsrc here as there's no library you're linking from the src directory. Also you don't need to add -L/usr/lib (in fact, it's a very bad idea) as the compiler already searches the system directories in the proper order, and on many systems (that support multiple architectures for example) /usr/lib won't be the right place.
Finally, when writing makefiles always remember that the recipe should create the exact filename of the target: for GNU make you can use $# for that in all cases. And you need to use the source file as a prerequisite, otherwise you might as well not bother using make and just write a shell script. Try this:
NETCDF = -lnetcdf_c++
WILXAPP = src/wilxtest.cpp
CXX = g++
CXXFLAGS = -Wall -ggdb
bin/Debug/WilxAstakTest: $(WILXAPP)
$(CXX) $(CXXFLAGS) -o $# $^ $(NETCDF)
Solved the very same problem by combining MadScientist's answer (almost complete) with a solution by "Russ" I found in an archived email in the UniData support pages (http://www.unidata.ucar.edu/support/help/MailArchives/netcdf/msg04846.html):
You need to add "-lnetcdf" to the end of your g++ invocation. If you
run "make test" in the src/cxx directory, you will see this is how
the test program is linked. So use something like:
g++ -o example -I<PATH>netcdf-3.5.1-beta13/include example.cpp -L<PATH>netcdf-3.5.1-beta13/lib -lnetcdf_c++ -lnetcdf
if you want to do the compile and link all in one step.
The default installation stores the C++ library in a different library
file than the C library, but I think you could use ld to combine them
into a single library for convenience. There were portability
problems with trying to do this on all platforms, so the interfaces
are distributed to use separate libraries.
--Russ
The point is: you need to link BOTH -lnetcdf_c++ AND -lnetcdf ... in this order.
My 'makefile' looks like this:
NETCDF = -lnetcdf_c++ -lnetcdf
APP = main.cpp
CXX = g++
CXXFLAGS = -Wall -ggdb
Example: $(APP)
$(CXX) $(CXXFLAGS) -o $# $^ $(NETCDF)
m. (MyselfAnotherMadScientist)