Compiling C and C++ with single makefile - c++

I'm trying to create an executable that uses my earlier created shared library, which by the way is now static which includes the openSSL static library. So I used the same Makefile that I was using to create that library, and hacked it to make it work here. This is how it looks
LIBBASE=/home/AB/Documents/APP/APP_2.17.0
OPENSSL1.0.2p_INSTALL_LOC=/home/AB/Documents/APP/OpenSSL-1.0.2p-installation
CC=gcc
CXX=g++
CFLAGS= -Wall -g -pedantic
CPPFLAGS= -Wall -g -pedantic
RM= rm -f
.PHONY: all clean
c_src=$(shell find . -iname "*.c")
$(info source=$(c_src))
cpp_src=$(shell find . -iname "*.cpp")
$(info cppsource=$(cpp_src))
INC=-I$(LIBBASE)/include
$(info includes=$(INC))
# need to link pthread library here as well
LIB = -pthread
# aforementioned library
LIB+=-L$(LIBBASE)/lib
LIB+= -l:libSCA.a
#need to add SSL related libraries
LIB+= -L$(OPENSSL1.0.2p_INSTALL_LOC)/lib
LIB+= -l:libssl.a -l:libcrypto.a -static-libgcc
# As mentioned, we need to link dl and libz libraries as well
LIB+= -ldl -lz
$(info links=$(LIB))
obj=$(c_src:.c=.o) $(cpp_src:.cpp=.o)
all: APP
clean:
$(RM) *.o APP
$(shell find $(APPBASE) -type f -iname "*.o" -exec rm -rf {} \;)
.c.o:
${CXX} -static ${CPPFLAGS} $(INC) -c $< -o $#
#${CC} -static ${CFLAGS} $(INC) -c $< -o $#
.cpp.o:
${CXX} -static ${CPPFLAGS} $(INC) -c $< -o $#
APP: $(obj)
$(LINK.cxx) $^ -o $# $(LIB)
I am, however unable to get this to work. I am getting a whole lot of undefined references to symbols that my library defines. I've taken care of using extern C around those symbols in the cpp files but it doesn't seem to help.
BTW, Is there a more straightforward or easier way than this?
Also, while browsing through the various answers here, I came across the statement that, targets like .c.o are rather obsolete and shouldn't be used anymore. Is there a definitive guide to Makefiles that is recent, exhaustive and practical (is it too much to ask)??
UPDATE 1: So here that I have access to the logs, I've noticed that all the undefined reference errors I am getting are related to symbols defined by the SSL library that I was statically linking to my shared library. A sample of my err log:
/home/AB/Documents/APP/APP_2.17.0_Linux/libAPP.so: undefined reference to `SSL_CTX_free'
/home/AB/Documents/APP/APP_2.17.0_Linux/libAPP.so: undefined reference to `X509_set_issuer_name'
So I thought of making a static library that will internally link against (or rather incorporate) libssl.a. Modified my aforementioned makefile and created a static libAPP.a. But I still kept getting those errors.
I finally added libssl.a and libcrypto.a to this makefile and voila, a lot of those errors got fixed. I still had some errors related to dlopen and pthreads so I added those as well. I also compile everything with the CXX compiler to eliminate issues due to name mangling.
What bugs me now is that the SSL related symbols are supposed to be already present in libAPP.a (although nm reports them as undefined and which might need another question on it's own :D ). But I still need to specify the libSSL.a and libcrypto.a here for the linker to find them! So what good is creating an archive (libAPP.a) instead of a shared library (libAPP.so)?
Finally during the linking phase, my linker cannot find lz
/usr/bin/ld: cannot find -lz
Just for the heck of it, I tried adding the same flag into the makefile that creates that archive and that one has no problem finding it. Any suggestions??

I would do this in these steps:
Collect all commands to build everything "by hand." Only if that works it makes sense to move on if you're a beginner. These commands could be put in a batch file.
Extract the dependencies and rules.
Write that in the Makefile; at the end of the day a Makefile is just that: condensed knowledge how to build.
Try the Makefile.
If I experience errors, I'll use make's options -d, -p and -n to see what it's thinking. There might be more useful options.

Most obvious problem is that you are using $(LINK.c) to link when your program contains C++ components, so you aren't getting any C++ libraries or such. Try using $(LINK.C) or $(LINK.cc) or $(LINK.cpp) or $(LINK.cxx) (which you need for C++ varies on make version, but at least one of them should be predefined.)

Related

Understanding Makefile. make cannot link armadillo library

I am new to C++ and I am having trouble understanding how Makefiles do their thing with the g++ compiler.
I have successfully installed armadillo library (via apt) and have a very simple c++ program test.cpp, like the one below:
#include <iostream>
#include <armadillo>
using namespace std;
int main()
{
arma::mat A;
A << -1 << 2 << arma::endr
<< 3 << 5;
cout << A << endl;
arma::fmat B;
B.randu(4,5);
cout << B;
return 0;
}
This works just fine if I compile manually like this:
g++ src/test.cpp -std=c++11 -Wall -o test -DARMA_DONT_USE_WRAPPER -lopenblas -llapack
I can manually run the program and it delivers the matrices as expected.
On the other hand, I have the Makefile template from the VSCode C/C++ Extension, which I have modifed slightly for including the LAPACK an BLAS Fortran libraries:
########################################################################
####################### Makefile Template ##############################
########################################################################
# Compiler settings - Can be customized.
CC = g++
CXXFLAGS = -std=c++11 -Wall
LDFLAGS = -DARMA_DONT_USE_WRAPPER -lopenblas -llapack
# Makefile settings - Can be customized.
APPNAME = test
EXT = .cpp
SRCDIR = src
OBJDIR = obj
############## Do not change anything from here downwards! #############
SRC = $(wildcard $(SRCDIR)/*$(EXT))
OBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)/%.o)
DEP = $(OBJ:$(OBJDIR)/%.o=%.d)
# UNIX-based OS variables & settings
RM = rm
DELOBJ = $(OBJ)
# Windows OS variables & settings
DEL = del
EXE = .exe
WDELOBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)\\%.o)
########################################################################
####################### Targets beginning here #########################
########################################################################
all: $(APPNAME)
# Builds the app
$(APPNAME): $(OBJ)
$(CC) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
# Creates the dependecy rules
%.d: $(SRCDIR)/%$(EXT)
#$(CPP) $(CFLAGS) $< -MM -MT $(#:%.d=$(OBJDIR)/%.o) >$#
# Includes all .h files
-include $(DEP)
# Building rule for .o files and its .c/.cpp in combination with all .h
$(OBJDIR)/%.o: $(SRCDIR)/%$(EXT)
$(CC) $(CXXFLAGS) -o $# -c $<
################### Cleaning rules for Unix-based OS ###################
# Cleans complete project
.PHONY: clean
clean:
$(RM) $(DELOBJ) $(DEP) $(APPNAME)
# Cleans only all files with the extension .d
.PHONY: cleandep
cleandep:
$(RM) $(DEP)
#################### Cleaning rules for Windows OS #####################
# Cleans complete project
.PHONY: cleanw
cleanw:
$(DEL) $(WDELOBJ) $(DEP) $(APPNAME)$(EXE)
# Cleans only all files with the extension .d
.PHONY: cleandepw
cleandepw:
$(DEL) $(DEP)
I have passed the needed libraries under LDFLAGS = -DARMA_DONT_USE_WRAPPER -lopenblas -llapack. Nevertheless, this solution does not work. It looks to me like the compiler is unable to find the armadillo library, so I must have linked it somehow wrongly. It delivers:
g++ -std=c++11 -Wall -o test obj/test.o -DARMA_DONT_USE_WRAPPER -lopenblas -llapack
/usr/bin/ld: obj/test.o: in function `TLS wrapper function for arma::arma_rng_cxx11_instance':
test.cpp:(.text._ZTWN4arma23arma_rng_cxx11_instanceE[_ZTWN4arma23arma_rng_cxx11_instanceE]+0x25): undefined reference to `arma::arma_rng_cxx11_instance'
collect2: error: ld returned 1 exit status
make: *** [Makefile:36: test] Error 1
So, aside from the obvious question (Why does this not work?), I would as well appreciate if someone could help me clarify as well the following aspects:
On the one hand, rom the message error it seems that the command run g++ -std=c++11 -Wall -o test obj/test.o -DARMA_DONT_USE_WRAPPER -lopenblas -llapack does not include the name of the cpp file I wrote (as opposed to in my manual compilation, in which it works). Nevertheless, if I do not use armadillo, the Makefile recipe above works just fine. I see the Makefile somehow looking for all cpp files in the source code folder SRC = $(wildcard $(SRCDIR)/*$(EXT)), but I cannot see where is this forwarded to the compiler. Can someone help me with that?
The other thing is that, in my manual compilation, it seems to make no difference to pass the LAPACK and BLAS libraries as CXXFLAGS or LDFLAGS, meaning both of the following commands:
g++ src/test.cpp -std=c++11 -Wall -DARMA_DONT_USE_WRAPPER -lopenblas -llapack -o test
and
g++ src/test.cpp -std=c++11 -Wall -o test -DARMA_DONT_USE_WRAPPER -lopenblas -llapack
work just fine. As far as I have been able to read, I understood the flags before -o are meant for the compiler, and those after are meant for the "linker" (whatever that is). Can someone explain me what are the main differences between the CXXFLAGS and LDFLAGS? Why both combinations work? And what is the linker?
Thank you very much for your help.
Best,
D.
The other answer is a good general introduction to compilation but if you want to know what is happening in your situation you need to first understand that answer and the difference between source files, object files, and executable files and the way that they work, then go deeper to figure out what's wrong.
As far as I have been able to read, I understood the flags before -o are meant for the compiler, and those after are meant for the "linker" (whatever that is)
No, that is not right.
Turning source files into an executable involves several steps each managed by a different tool. The compiler front-end (e.g., g++) manages the order of these. Each of these may use different options, and whenever the compiler front-end invokes one of these tools it will pass the appropriate flags from the command line for that tool. It's not the case that "only" flags before or after -o are passed to different tools; it doesn't matter where on the command line they live.
The tools involved with compilation, in the order in which they're invoked, are:
Preprocessor: this handles #include and #ifdef and #define, etc. (the lines that start with # in your source). The preprocessor takes the options -D, -I, and some others.
Compiler: this turns your source code (after preprocessing to handle all the included files etc.) into assembly code which is very low-level: basically machine code but in ASCII form. This does the bulk of the work including optimization etc. Flags like -O2, -g, and many others are used by this tool.
Assembler: this turns the assembly code into a binary format for your CPU and generates an object file (foo.o).
Linker: this takes one or more object files plus libraries and turns them into an executable. This tool uses options like -L and -l to find libraries.
There's a separate tool, the archiver (ar) which is not invoked by the compiler front-end, which is used to turn object files (foo.o) into static libraries (libfoo.a).
Note, the above is a "classical" view of building: newer compilers munge the above steps together sometimes to get either better error messages or better optimization or both.
Most of the time the first three steps are all done by a single invocation of the compiler front-end: it turns a source file into an object file. You do this once for each source file. Then at the end, another invocation of the compiler front-end takes those object files and builds an executable.
If you look at the output make prints you'll see these two steps. First you'll see the compilation step, which is controlled by this make rule:
$(OBJDIR)/%.o: $(SRCDIR)/%$(EXT)
$(CC) $(CXXFLAGS) -o $# -c $<
and runs this command:
g++ -std=c++11 -Wall -o obj/test.o -c src/test.cpp
The -c option here tells the compiler, "do all the steps up to and including the compile step, then stop and don't do the link step".
Then you will see your link command, which is controlled by this make rule:
$(APPNAME): $(OBJ)
$(CC) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
and runs this command:
g++ -std=c++11 -Wall -o test obj/test.o -DARMA_DONT_USE_WRAPPER -lopenblas -llapack
What do you notice about this? The -DARMA_DONT_USE_WRAPPER is a preprocessor option, but you're passing it to the link step and not passing it to the compile step. That means when the source is compiled, that option is not present and so whatever operation it was intended to suppress (using a wrapper apparently) is not being suppressed.
You need to put preprocessor options in a make variable that is sent to the compiler / preprocessor, so it should be this:
CXXFLAGS = -std=c++11 -Wall -DARMA_DONT_USE_WRAPPER
LDFLAGS = -lopenblas -llapack
Be sure to run clean before trying to build again.
One minor thing, but generally you should use CXX for your C++ compiler and CC for your C compiler (these are the usual conventions). If you do end up trying to compile C++ source with a C compiler you are likely to have problems. Less so the other way round.
So what it happening? Roughly speaking, you have two steps:
Compilation
Linking
When you compile a small exe, you can combine these into a single steps. Makefiles generally don't as two steps is more general.
For compilation the input has a .cpp suffix and you are passing the -c flag to tell the compiler to just compile. This will result in an object file (.o suffix).
For linking, there is no -c. The inputs are object files and the output is your application.
Other suffixes are possible (.cxx, .CC etc.).
There are 4 commonly used make variables
CPPFLAGS for preprocessor flags, can be used for C and C++ compilation
CFLAGS for flags specific to C compilation
CXXFLAGS for flags specific to C++ compilation
LDFLAGS for flags specific to linking
Historically, ld was the linker (and hence LDFLAGS), but it isn't smart enough to handle C++ linking well on its own. So now it is usually the C++ compiler that performs the task of "linker driver", that is g++ controls the linking that ld does.
Finally, your specific problem. You should add the armadillo library to LDFLAGS. The best way to do that is to just add -larmadillo. If armadillo is not installed in a 'standard' location like /usr/lib then you may need to additional arguments such as
-L/path//to/armadillo_lib -Wl,-rpath,/path//to/armadillo_lib
(the first one tells the linker where the library is, the second one puts that path into the executable so that is also knows where the library is).

G++ Library Not Found

I am trying to compile a TBB and OpenMp comparison program that I made. It is compiling fine with the default visual studio compiler. So, I know that TBB is installed correctly. However, I would like to use g++ instead. I have created a Makefile, and from what I read the -ltbb flag is needed.
My error is, "c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: cannot find -ltbb".
I am not an expert when it comes to making sure I have everything linked correctly and am still trying to learn.
This is my current Makefile
CPLUSPLUS = g++
OPTFLAGS = -O3
TBB_INCLUDE_PATH = C:\tbb-2020.1-win\tbb\include
TBB_LIBRARY_PATH = C:\tbb\tbb\lib\intel64\vc14
all: pps
pps: avl.o main.o parPlaneSweep.o
$(CPLUSPLUS) -I$(TBB_INCLUDE_PATH) -L$(TBB_LIBRARY_PATH) $(OPTFLAGS) -o $# $^ -ltbb
avl.o: avl.h avl.c
$(CC) -c $(OPTFLAGS) -fPIC avl.c
main.o: main.cpp parPlaneSweep.h
$(CPLUSPLUS) -c $(OPTFLAGS) -fopenmp main.cpp
parPlaneSweep.o: parPlaneSweep.h parPlaneSweep.cpp
$(CPLUSPLUS) -c $(OPTFLAGS) -fPIC -fopenmp parPlaneSweep.cpp
clean:
rm *.o
rm pps
Please update your question rather than pointing people at other websites.
First, you should never use backslashes in makefiles, even on Windows (there are exceptions to this on Windows but they're very rare). Always use forward slashes as directory separators.
Second, you define the variables TBB_INCLUDE_PATH and TBB_LIBRARY_PATH but then you never use them. Just mentioning the name of the variable doesn't use the variable. You have to include it in $(...) to use it, like $(TBB_INCLUDE_PATH).
Finally, all common linkers are single-pass linkers, which means the order in which you put the libraries and object files on the link line is critically important. You should always put the object files first, and the libraries last. If you have multiple libraries the order in which they appear may be important as well. Your link line should be something like this:
pps: avl.o main.o parPlaneSweep.o
$(CPLUSPLUS) -I$(TBB_INCLUDE_PATH) -L$(TBB_LIBRARY_PATH) $(OPTFLAGS) -o $# $^ -ltbb
If you want to know what $# and $^ mean, you can read about automatic variables.

Error loading shared libraries: cannot open shared object file :: on external hardware

I'm currently developing a C++ application which will reference multiple *.so libraries, each containing code for different machines - written in C.
I also have one shared object containing code from a custom namespace Utilities, which (as the name implies) contains basic utilities useful for the application (written in C++, like the rest of the application).
Currently, utilities.so is the only (custom) library referenced by the application.
The application compiles and links just fine, however executing it on the target hardware display the following error: bin/updater_v4test: error while loading shared libraries: ../../../bin/device_modules/utilities.so.1.0.0: cannot open shared object file: No such file or directory
When calling LDD on said application, the following output is shown: ../../../bin/device_modules/utilities.so.1.0.0 => not found
I've written a script which (upon make exiting without errors) collects all SOs and pushes them in to the /lib/ directory on the target hardware; meaning that upon each successful build of the application (whether in part or entirely), the updated files are pushed to the correct directory on the target hardware.
In an attempt to mimic other libraries I've used (e.g. zlib), I've attempted to create a symlink to the library file, with no luck (utilities.so.1.0.0 is the symlink, utilities.so is the actual SO).
utilities.so.1.0.0 --> utilities.so
At the moment I'm at a loss, and I can't waste much more time in trying to figure this out myself.
Below is an excerpt from the utilities Makefile:
include ../../common/user.mk
LIB_DIR=../../../libs/lib/powerpc-linux-gnu
CFLAGS=-Wall -ggdb -I../../libs/include -I../../common -lpthread -lddc -std=c++0x -I../../libs/include/zlib
LDFLAGS=../../libs/lib/powerpc-linux-gnu/libcurl.so.4 ../../libs/include/minizip/.libs/libminizip.so.1.0.0 \
-L ../../libs/lib \
-L ../../libs/lib/powerpc-linux-gnu \
-Wl,-rpath-link,../../libs/lib/powerpc-linux-gnu \
-lrt -lddc -lpthread -shared
BIN_DIR=../bin
CANONICAL_BIN_DIR := $(shell readlink -f $(BIN_DIR))
CANONICAL_CUR_DIR := $(shell readlink -f "./")
COMP_OBJECTS := $(wildcard *.cpp)
OBJECTS := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
all: objects utilities.so
-cp --parents utilities.so $(GLOBAL_BIN_LIB)
-ln -s utilities.so utilities.so.1.0.0
-mv utilities.so.1.0.0 $(GLOBAL_BIN_LIB)
# -cp --parents *.h $(GLOBAL_HEADER_DIR)
-rm -f utilities.so
-rm -f *.o
for header in $(wildcard *.h); do \
echo $$header; \
ln -s $(CANONICAL_CUR_DIR)/$$header $(GLOBAL_HEADER_DIR)/$$header; \
done;
#printf "########## BUILT $^ ##########\n\n"
utilities.so: $(OBJECTS)
${CXX} $^ -o $# ${LDFLAGS}
objects: $(COMP_OBJECTS)
${CXX} -c $^ ${CFLAGS}
And now an excerpt from the application Makefile.
Here I've added a reference to the library in the linker flags, the header files are all included in from one directory.
include ../../../common/user.mk
LIB_DIR=../../../libs/lib/powerpc-linux-gnu
CFLAGS=-Wall -ggdb -I../../../libs/include -I${COMMON_DIR} -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I${HEADER_DIR}
LDFLAGS=../../../libs/lib/powerpc-linux-gnu/libcurl.so.4 ../../../libs/include/minizip/.libs/libminizip.so.1.0.0 ../../../bin/device_modules/utilities.so.1.0.0 \
-L ../../../libs/lib \
-L ../../../libs/lib/powerpc-linux-gnu \
-Wl,-rpath-link,../../../libs/lib/powerpc-linux-gnu \
-lrt -lddc -lpthread -L ${SO_DIR}
BIN_DIR=../bin
CANONICAL_BIN_DIR := $(shell readlink -f $(BIN_DIR))
CANONICAL_CUR_DIR := $(shell readlink -f "./")
all: test_update.bin
-cp --parents test_update.bin $(BIN_DIR)
-ln -s $(CANONICAL_BIN_DIR)/test_update.bin $(GLOBAL_BIN_APP)/test_update.bin
-rm -f *.bin
#printf "########## BUILT $^ ##########\n\n"
test_update.bin: main.o updaterdelegate.o commonfunctions.o tinyxml.o
${CXX} $^ -o $# ${LDFLAGS}
####################
# Required Files #
####################
main.o: Main.cpp
${CXX} -c $^ -o $# ${CFLAGS}
updaterdelegate.o: UpdaterDelegate.cpp
${CXX} -c $^ -o $# ${CFLAGS}
commonfunctions.o: $(shell python -c "import os.path; print os.path.relpath('${IMPL_CMN_FUNC}'.replace('\"', ''), '${CANONICAL_CUR_DIR}'.replace('\"', ''))")
${CXX} -c $^ -o $# ${CFLAGS}
tinyxml.o: $(shell python -c "import os.path; print os.path.relpath('${IMPL_TXML}'.replace('\"', ''), '${CANONICAL_CUR_DIR}'.replace('\"', ''))")
${CXX} -c $^ -o $# ${CFLAGS}
####################
# /Required Files #
####################
Just for gits and shiggles, I'll add the build output of the utilities.so and application.
utilities.so:
(Clean ommitted)
=============== CLEAN COMPLETE... BUILDING... ===============
make: Entering directory `~/_workspace/upv4/common/utils'
powerpc-linux-gnu-g++ -c ArgumentHandling.cpp Extensions.cpp Logging.cpp -Wall -ggdb -I../../libs/include -I../../common -lpthread -lddc -std=c++0x -I../../libs/include/zlib
ArgumentHandling.cpp: In member function ‘void Utilities::ArgumentHandler::freeMemory()’:
ArgumentHandling.cpp:136: warning: deleting ‘void*’ is undefined
powerpc-linux-gnu-g++ ArgumentHandling.o Extensions.o Logging.o -o utilities.so ../../libs/lib/powerpc-linux-gnu/libcurl.so.4 ../../libs/include/minizip/.libs/libminizip.so.1.0.0 -L ../../libs/lib -L ../../libs/lib/powerpc-linux-gnu -Wl,-rpath-link,../../libs/lib/powerpc-linux-gnu -lrt -lddc -lpthread -shared
cp --parents utilities.so """~/_workspace/upv4""/bin/device_modules"
ln -s utilities.so utilities.so.1.0.0
mv utilities.so.1.0.0 """~/_workspace/upv4""/bin/device_modules"
rm -f utilities.so
rm -f *.o
for header in ArgumentHandling.h Enumerations.h Extensions.h Logging.h; do \
echo $header; \
ln -s ~/_workspace/upv4/common/utils/$header """"~/_workspace/upv4""/bin/device_modules"/headers"/$header; \
done;
ArgumentHandling.h
Enumerations.h
Extensions.h
Logging.h
########## BUILT objects utilities.so ##########
make: Leaving directory `~/_workspace/upv4/common/utils'
=============== BUILD COMPLETE... PARSING... ===============
========== Warnings ==========
Total: 1
ArgumentHandling.cpp:136: warning: deleting ‘void*’ is undefined
========== Errors ==========
Total: 0
test_update.bin:
(Clean ommitted)
=============== CLEAN COMPLETE... BUILDING... ===============
make: Entering directory `~/_workspace/_workspace/upv4/test/app/src'
powerpc-linux-gnu-g++ -c Main.cpp -o main.o -Wall -ggdb -I../../../libs/include -I"""~/_workspace/_workspace/upv4""/common" -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I"""""~/_workspace/_workspace/upv4""/bin/device_modules"/headers""
powerpc-linux-gnu-g++ -c UpdaterDelegate.cpp -o updaterdelegate.o -Wall -ggdb -I../../../libs/include -I"""~/_workspace/_workspace/upv4""/common" -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I"""""~/_workspace/_workspace/upv4""/bin/device_modules"/headers""
powerpc-linux-gnu-g++ -c ../../../common/commonFunctions.cpp -o commonfunctions.o -Wall -ggdb -I../../../libs/include -I"""~/_workspace/_workspace/upv4""/common" -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I"""""~/_workspace/_workspace/upv4""/bin/device_modules"/headers""
powerpc-linux-gnu-g++ -c ../../../common/xmlreader/tinyxml2.cpp -o tinyxml.o -Wall -ggdb -I../../../libs/include -I"""~/_workspace/_workspace/upv4""/common" -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I"""""~/_workspace/_workspace/upv4""/bin/device_modules"/headers""
powerpc-linux-gnu-g++ main.o updaterdelegate.o commonfunctions.o tinyxml.o -o test_update.bin ../../../libs/lib/powerpc-linux-gnu/libcurl.so.4 ../../../libs/include/minizip/.libs/libminizip.so.1.0.0 ../../../bin/device_modules/utilities.so.1.0.0 -L ../../../libs/lib -L ../../../libs/lib/powerpc-linux-gnu -Wl,-rpath-link,../../../libs/lib/powerpc-linux-gnu -lrt -lddc -lpthread -L """"~/_workspace/_workspace/upv4""/bin/device_modules""
cp --parents test_update.bin ../bin
ln -s ~/_workspace/_workspace/upv4/test/app/bin/test_update.bin """~/_workspace/_workspace/upv4""/bin"/test_update.bin
ln: failed to create symbolic link `~/_workspace/_workspace/upv4/bin/test_update.bin': File exists
make: [all] Error 1 (ignored)
rm -f *.bin
########## BUILT test_update.bin ##########
make: Leaving directory `~/_workspace/_workspace/upv4/test/app/src'
=============== BUILD COMPLETE... PARSING... ===============
========== Warnings ==========
Total: 0
========== Errors ==========
Total: 0
The build script is custom, I built it myself to rid myself of the entire make output when I don't need it, and it parses out all the errors and warnings.
Due to the issue, I have turned make output back on.
Did I miss something during compilation/linking of the library, or is something going wrong during the linking of the application?
I'm inclined to say it's during compilation/linking of the library - although I don't know what exactly is going wrong, as everything is compiling and linking just fine.
Why is the application looking for the .so file in a path it can't possibly have?
I also made sure that the .so files are found with the $PATH variable, so the application should be able to find them.
The system normally searches for shared objects in a fixed set of directories. You can handle around this by defining the environment variable LD_LIBRARY_PATH and adding the directory where you install the shared libraries into.
Or you can add those libraries to some of the standard libraries directories and execute ldconfig -a to update the cache of shared libraries.
See ldconfig(8), for more info.
edit
There are two mechanisms to load a shared object.
The first is the normal library loading mechanism, that specifies what has to be loaded at start executable time, and implies linking your executable with the shared objects. This is what you do in your Makefile. You specify the shared executables, and the ld.so.xxx shared object (which is linked to your application when you are dynamically linking it) loads and follows all the unresolved identifiers to find a place for them in the virtual address space. The ld.so.xxx object uses the /etc/ld.so.cache file, that is just a hash table with the directories and shared executables available to be loaded this way. That file is indexed by what is called the soname (which is something useful to allow different versions of the same library to coexist in the same system) and normally maps to the last versioned shared found in the list of directories listed in the file /etc/ld.so.conf (this is static information to accelerate the process of loading libraries and is generated at each boot of the system). If the shared was found at link time (this mechanism is not used by ld, but only to load the libraries at program start time) to have a soname, then that soname is searched in the /etc/ld.so.cache to find the final file that has to be loaded. This cache is built on each boot of the system, so you don't have to cope with that, but only if you don't want to reboot and you install a new library for system use. It is important to note that shared objects must be given sonames for this to work, and that the list of directories in the file /etc/ld.so.conf are the only directories used to search for files. This means that for a standard library to be usable, you need to put it in one of this directories (or add the directory to the list in /etc/ld.so.conf) and then execute ldconfig -a to rebuild the cache and let it include a reference for the file under that soname.
The other way it to add to the list of search places a list in the form of a PATH variable. The variable is LD_LIBRARY_PATH so, in case you have your shared objects in ${HOME}/libs, you can add this line to your .profile:
export LD_LIBRARY_PATH=${HOME}/libs
or
setenv LD_LIBRARY_PATH ${HOME}/libs
this allows your library to live outside of the standard directories, but think twice, as this is a far less efficient way to load a file (as it involves processing a list of directories to look for the final shared objects, while the previous approach is direct, you ask for the file matching the soname that ld.so.xxx asks for, only one search, only one step)
The second is to use a library function dlopen(3) that allow you to load a shared object and do some housekeeping before calling anything inside. The dl library allows you to search for a symbol in the shared executable and then decide if you interpret it as data or a jump target. dlopen() just opens and loads into the virtual address space a shared object. It resolves the dependencies (if requested to) and is the more flexible way (but it is also nontransparent) to load unknown code for execution. This is the way plugins normally work. You decide in a config file, or dynamically what to load, and then you load it. The program doesn't have to know previously the symbol table of what you are dealing with and you are free to implement whatever you want in the module you are loading.
All of these methods work with ELF binaries, so you have a lot of freedom, but also a lot of complexity on it.
more...
As i've seen from your compilation:
you are including -l in the compile only commands, the libraries are only needed if you are linking an executable, don't put libraries in the compile phase.
for a library to be searched and selected by the linker, it has to be named as lib<name>.so (without the version info at the end) so this means that you normally find three names for a standard library (let me use the math library -lm as an example):
/usr/lib/libm.so.3.2.8 # this is the ELF file with the library contents.
/usr/lib/libm.so.3 -> libm.so.3.2.8 # this is the soname used to create the library.
/usr/lib/libm.so -> libm.so.3 # this is the actual file the ld(1) program searches for when using -lm.
those links have to be created, as the system normally doesn't. This is part of the installation procedure for a shared library. The soname link allows you to have different versions of a library and detect which one of them will be used at runtime (all must be compatible so you can interchange, when you make an incompatible modification, then you have to change the soname, so the system doesn't get confused on loading)
It is very important to know that the ld(1) program only selects a library if it is called lib<name>.so, with no version info. Indeed, the compiler first searchs for lib<name>.so, then for lib<name>.a, then it complains.
It is very important to put -L places to search for libraries before any -l option that will use those directories in the linking parameters.
You only need to run ldconfig -a and install the library in a system directory if you are not going to use the LD_LIBRARY_PATH mechanism. (this mechanism doesn't work for root account, for obvious reasons :))
Expecting this added comments give some light to the process.

GCC Shared Library Problems

I'm trying to create a shared library on ubuntu using gcc
I just have one simple class(shared.h and shared.cpp) and one client to use it (main.cpp)
This is my makefile and I'm still not able to to get the program to compile.
all:
#compile object(fPIC: creates position independent code)
gcc -fPIC -Wall -g -c shared.cpp
#compile shared library
gcc -shared -Wl,-soname,libshared.so.1 -o libshared.so.1.0.1 shared.o -lc
#link shared library
gcc -g -o main main.cpp -L. -lshared
I'm confident the first line is correct
I am unsure what "-lc" does. I think it passes something to the linker?
I don't want to install the library, I just want to be able to link it from the current directory. I have tried: export LD_LIBRARY_PATH=.
but it does not seem to make a difference. Everything is in the current directory.
ERROR: /usr/bin/ld: cannot find -lshared
how do I get the compiler to check the current directory for my library?
The problem is not that it's not looking in the directory, the problem is that you've named the library "libshared.so.1.0.1". When you use -lshared, it's looking for a file named 'libshared.so' or 'libshared.a' in the library search path.
Most of the time, when using versioned system libraries, you'll provide a link to the latest one as 'libshared.so', even if you have installed 'libshared.so.1' or 'libshared.so.1.0.1'.
In your case, if you continue to leave the file named 'libshared.so.1.0.1', you'll want to create 2 symbolic links:
libshared.so - So that the library can be found using ld
libshared.so.1 - Since you declared the SO name as libshared.so.1 when building it, you need to provide this link, otherwise, the executable will not be able to find the proper shared library at runtime.
You don't write any dependencies, which is the purpose of Makefile-s. And you probably need to force the run path Perhaps something like
.PHONY: all clean
CXX=g++
CXXFLAGS=-g -Wall
all: main
main: main.o libshared.so
$(LINK.cpp) -o $# $< -Wl,-rpath,. -L. -lshared
libshared.so: shared.pic.o
$(LINK.cpp) -shared -o $^ $<
main.o: main.cc shared.hh
%.pic.o: %.cc
$(CXX) $(CXXFLAGS) -fPIC -c -o $# $<
#
clean:
rm -f *.o *.so main *~

LIBPATHS not being used in Makefile, can't find shared object

I'm having trouble getting a sample program to link correctly (in this case against the ICU library). When I do 'make', everything builds fine. But when I run it, it says it can't find one of the .so's. I double checked they're all installed in /usr/local/lib. What I discovered was it was looking in /usr/lib. If I symlink from there to there actual location, it works.
Why is my LIBPATHS being ignored or not used?
Here is the Makefile
CC = g++
INCPATHS = -I/usr/local/include
CFLAGS = -c -Wall $(INCPATHS)
LIBPATHS = -L/usr/local/lib/
LIBS = $(LIBPATHS) -licuio -licui18n -licuuc -licuio -licudata
EXECUTABLE = prog
print_linking = echo -e "\033[32m" "Linking: $<" "\033[39m"
print_compiling = echo -e "\033[33m" "Compiling: $<" "\033[39m"
print_cleaning = echo -e "\033[31m" "Cleaning: `pwd`" "\033[39m"
all: main
# [target]: [dependencies]
# <tab> system command
main: main.o
#$(print_linking)
#$(CC) -o $(EXECUTABLE) main.o $(LIBS) >> /dev/null
main.o: main.cpp
#$(print_compiling)
#$(CC) $(CFLAGS) main.cpp
clean:
#$(print_cleaning)
#rm -rf *.o *~ $(EXECUTABLE)
Your LIBPATHS tells the linker where to find the library when linking to resolve symbols.
At runtime, you need to tell the loader where to find the library. It doesn't know about what happened at compile time. You can use the LD_LIBRARY_PATH variable as mentioned above, or check into /etc/ld.so.conf and it's friends.
The path to the dynamic libraries isn't stored in the executable by default. You can either:
use LD_LIBRARY_PATH at runtime to give a path where to search for dynamic libraries
use -Wl,-Rpath at link time to store a path in the executable
One solution is to add /usr/local/lib to the environment variable LD_LIBRARY_PATH.
You can do this in your .profile or .cshrc
You can also get the linker to store the full path to the library in the executable.
Both solutions have different tradeoffs with respect to using the execultable by different users and/or on different machines.