I have been working through the asio ssl examples (linked below). Despite by best efforts I have been unable to link openssl into the boost example. The output from ld is that ld is missing symbols from libssl.a. The thing that I can not figure out is that I found all the symbols in libssl.a with nm that ld says are missing. I suspect I am doing something dumb but I am not familiar enough with c++ to fix it. I have also included my makefile. The source of ssl-client.cpp is verbatim from the link.
http://www.boost.org/doc/libs/1_41_0/doc/html/boost_asio/example/ssl/client.cpp
INCLUDES = -I /usr/local/boost_1_41_0/ -I /opt/local/include/
LIBS = -L/usr/local/boost_1_41_0/lib/libboost_system.a \
-L/opt/local/lib/libcrypto.a \
-L/opt/local/lib/libssl.a
CPP = g++
build: ssl-client
ssl-client: ssl-client.cpp
$(CPP) $(LIBS) $(INCLUDES) ssl-client.cpp
I think you've misunderstood how the -L option works. -L specifies a path in which to search for libraries. To specify an individual library to link to, use the -l option and omit the "lib" prefix, as follows:
LIBS = -L/usr/local/boost_1_41_0/lib -L/opt/local/lib \
-lboost_system -lcrypto -lssl
Also, there is usually no space between the -I include path option and the actual path. I'm not sure if a space in there causes problems, but you might try this to be on the safe side:
INCLUDES = -I/usr/local/boost_1_41_0/ -I/opt/local/include/
Also, as noted in my comment, you defined the LIBS variable but then used the LIB variable. The call to g++ should be as follows:
$(CPP) $(LIBS) $(INCLUDES) ssl-client.cpp
Related
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.)
I'm trying to compile C++ project with gcc-make command but program giving this error. I already compiled Crypto++ and added include and lib folder but I dont know how to add this dir to gcc.
What should I do for fixing this "-lcrytopp" error?
I'm using makefile and this is line of 33-34.
$(TARGET): build $(OBJECTS)
$(CC) $(OBJECTS) -o $(TARGET) -lcryptopp
Error:
D:\Osman\CnC RA2\Mix\ccmix-crypto\ccmix-crypto>make
g++ src/mix_db_gamedb.o src/mix_db_gmd.o src/mix_header.o src/mix_db_lmd.o
src/mixid.o src/ccmix.o src/mix_file.o -o build/ccmix -lcryptopp
c:/mingw/bin/../lib/gcc/mingw32/5.3.0/../../../../mingw32
/bin/ld.exe: cannot find -lcryptopp
collect2.exe: error: ld returned 1 exit status
Makefile:34: recipe for target 'build/ccmix' failed
make: *** [build/ccmix] Error 1
Crypto++ directory:
Compile error:
You haven't added the directory containing the library to your link line. It should be something like -Lxxx where xxx is the path to the directory containing the cryptopp library:
$(TARGET): build $(OBJECTS)
$(CC) $(OBJECTS) -o $(TARGET) -Lxxx -lcryptopp
(replace xxx with the directory containing the cryptopp library)
What should I do for fixing this "-lcrytopp" error?
When working from the Crypto++ build directory on Unix compatibles, the project does not use include and lib (as your picture shows). Everything is placed in the root directory (as your picture shows).
If you perform a make install, then the directories are setup, but it appears you did not install. I should also say that MinGW is not usually tested anymore because the project is abandoned, so I'm not sure where make install actually installs to on MinGW.
To fix the compile error, tweak your make recipe:
$(TARGET): build $(OBJECTS)
$(CXX) $(CXXFLAGS) -I. $(OBJECTS) ./libcryptopp.a -o $(TARGET)
The recipe above uses CXX (C++ compiler) rather than CC (C compiler); it uses CXXFLAGS (which should be something like -DNDEBUG -g2 -O2); it calls out the header path (-I.); and it links to the static library (./libcryptopp.a). Linking to the static library will avoid your next set of problems.
You can follow MadScientist's advice and use -LXXX and -lcryptopp. You might even add a runpath with -Wl,-rpath,D:\Osman\CnC RA2\Mix\ccmix-crypto\ccmix-crypto. But at the end of the day, using -L and -l causes a fair amount of trouble. Avoid the future problems by statically linking libcryptopp.a.
Also see GNUmakefile | Compiling and Linking on the Crypto++ wiki.
Your fist picture shows ipch and Win32 directories. That usually means you built the Crypto++ library with Visual Studio. Now you are building a program with GCC. You should not mix and match compilers like that. Nothing good will come of it.
I am attempting to install twitcurl on OS X and have met with some problems.
At first, running make would return the clang error: ld: unknown option: -soname. I looked through the responses from other users with similar problems on OS X and found the following advice:
In the makefile, change:
LDFLAGS += -Wl,-rpath-link=$(STAGING_DIR)/usr/lib
to:
LDFLAGS += -rpath=$(STAGING_DIR)/usr/lib
change:
$(CC) -shared -Wl,-soname,lib$(LIBNAME).so.1 $(LDFLAGS) -o lib$(LIBNAME).so.1.0 .o -L$(LIBRARY_DIR) -lcurl
to:
$(CC) -dynamiclib -shared -Wl,-install_name,lib$(LIBNAME).dylib.1 $(LDFLAGS) -o lib$(LIBNAME).dylib .o -L$(LIBRARY_DIR) -lcurl
I tried this, but the only result was another clang error: clang: error: unknown argument: '-rpath=/usr/lib'
Any advice towards installing twitcurl on an OS X system will be greatly appreciated.
----UPDATE----
I just wanted to put in one place all the steps I took to make this work, in case any OS X users with similar problems come across this in the future. My thanks to Andy Piper for the crucial pieces.
open the makefile and replace:
LDFLAGS += -Wl,-rpath-link=$(STAGING_DIR)/usr/lib
with:
LDFLAGS += -rpath $(STAGING_DIR)/usr/lib
and:
$(CC) -shared -Wl,-soname,lib$(LIBNAME).so.1 $(LDFLAGS) -o lib$(LIBNAME).so.1.0 .o -L$(LIBRARY_DIR) -lcurl
with:
$(CC) -dynamiclib -shared -Wl,-install_name,lib$(LIBNAME).dylib.1 $(LDFLAGS) -o lib$(LIBNAME).dylib *.o -L$(LIBRARY_DIR) -lcurl
(note that this is different by two characters from the advice another OS X user gave above)
after running make, copy libtwitcurl.dylib into /usr/lib/
Downloading the twitterClient (which is also the only code example I could find) will be the same, but for compiling it or your own programs you will need to link -lcurl as well. (g++ appname.cpp -ltwitcurl -lcurl)
Finally, once you compile a program, the path name will likely be incorrect in the executable which is created. Use install_name_tool to correct it. For me this looks like:
install_name_tool -change libtwitcurl.dylib.1 /usr/lib/libtwitcurl.dylib nameofexecutable
but if that doesn't work for you, use otool to find the actual path:
otool -L nameofexecutable
and then the first argument after -change should be the erroneous path for libtwitcurl. You can use otool again after running install_name_tool to be sure the change was successful.
I can get the shared / dynamic library to compile but needed to make a couple of adjustments to your Makefile:
LDFLAGS += -rpath $(STAGING_DIR)/usr/lib
and
$(CC) -dynamiclib -shared -Wl,-install_name,lib$(LIBNAME).dylib.1 $(LDFLAGS) -o lib$(LIBNAME).dylib *.o -L$(LIBRARY_DIR) -lcurl
I've now also built the associated twitterClient utility. To do so, I had to symbolically link libtwitcurl.dylib as libtwitcurl.dylib.1 and also change the consumer key and secret in the code to match a valid one from apps.twitter.com on my account. Works fine.
I assume you want to use the twitcurl library from code? Twitter maintains a Ruby-based utility, twurl, which has a similar function and may also be useful.
g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5
I have the following static library called sdpAPI.a. I am having problems trying to link it with my test application. Just wondering if I am doing something wrong. The static library has been built with g++;
My directory is as follows:
/projects/unit_test/main.c
/projects/unit_test/sdp/inc/sdpAPH.h
/projects/unit_test/sdp/lib/sdpAPI.a
My source code is this:
#include <stdio.h>
#include "sdpAPI.h"
int main(void)
{
printf("----- TEST SDP ------\n");
try {
sdpSessionDescription sdp;
sdp.clear();
}
catch(...) {
printf("----- TEST FAILED --------\n");
return 0;
}
printf("------ TEST SUCCESSFULL ------\n");
return 0;
}
And my Makefile is this:
OBJECT_FILES = main.o
CC = g++
CFLAGS = -Wall -Wextra -Wunreachable-code -ggdb -O0
TARGET = sdp_demo
INC_PATH = -I sdp/inc
LIB_PATH = -L sdp/lib/sdpAPI.a
$(TARGET): $(OBJECT_FILES)
$(CC) $(CFLAGS) $(INC_PATH) $(LIB_PATH) $(OBJECT_FILES) -o $(TARGET)
main.o: main.c
$(CC) $(CFLAGS) $(INC_PATH) $(LIB_PATH) -c main.c
clean:
rm -f $(TARGET) $(OBJECT_FILES) *~
These are the linker errors I am getting:
undefined reference to `sdpSessionDescription::sdpSessionDescription()'
undefined reference to `sdpSessionDescription::clear()'
undefined reference to `sdpSessionDescription::~sdpSessionDescription()'
undefined reference to `sdpSessionDescription::~sdpSessionDescription()'
Many thanks for any suggestions,
-L specifies the library path, not a specific library. You probably want -L sdp/lib -l sdpAPI to specify both the path and the library name.
Although it will try to prefix and postfix your library name with lib and either .a or .sl (or similar).
So you may also need to rename your library to libsdpAPI.a as per the gcc manpage:
-l xyz
The linker searches a standard list of directories for the library, which is actually a file named libxyz.a.
Also keep in mind that the order of things in the command line matters. By doing $(CC) $(CFLAGS) $(INC_PATH) $(LIB_PATH) $(OBJECT_FILES) -o $(TARGET) (libraries before objects), there are no unresolved symbols at the point where you list the library, so nothing will be brought in from that library.
Then, when you finally bring in the objects (with their unresolved symbols), they stay unresolved because there are no libraries listed after that.
You should usually do libraries after objects:
$(CC) $(CFLAGS) $(INC_PATH) $(OBJECT_FILES) $(LIB_PATH) -o $(TARGET)
to ensure all unresolved symbols are known before checking the libraries.
This won't catch all problems (such as co-dependent libraries which can be fixed using other means) but it will ensure all unresolved symbols in the object files are known about before looking at the libraries.
From the same section of the man page quoted above:
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.
-L is used to specify a library path :
-Ldir Add directory dir to the list of directories to be searched for -l.
-l is what you need to specify which library to link against :
-l library Search the library named library when linking.
You probably need -L sdp/lib/ -l sdpAPI
How exactly the different options especially -l and -static worked confused me for a long time. Finally did a man gcc to get more details that I wasn't able to find online. Hope this helps someone else too
-llibrary
-l library
Search the library named library when linking. (The second
alternative with the library as a separate argument is only for
POSIX compliance and is not recommended.)
It makes a difference where in the command you write this option;
the linker searches and processes libraries and object files in the
order they are specified. Thus, foo.o -lz bar.o searches library z
after file foo.o but before bar.o. If bar.o refers to functions in
z, those functions may not be loaded.
The linker searches a standard list of directories for the library,
which is actually a file named liblibrary.a. The linker then uses
this file as if it had been specified precisely by name.
The directories searched include several standard system
directories plus any that you specify with -L.
Normally the files found this way are library files---archive files
whose members are object files. The linker handles an archive file
by scanning through it for members which define symbols that have
so far been referenced but not defined. But if the file that is
found is an ordinary object file, it is linked in the usual
fashion. 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.
-static
On systems that support dynamic linking, this prevents linking with
the shared libraries. On other systems, this option has no effect.
This option will not work on Mac OS X unless all libraries
(including libgcc.a) have also been compiled with -static. Since
neither a static version of libSystem.dylib nor crt0.o are
provided, this option is not useful to most people.
-Ldir
Add directory dir to the list of directories to be searched for -l.
Three flags you need to know:
-Ldir
-lLIB
-static
Since you want to link with static library, you need the third flag. Otherwise, you will end up with linking with a dynamic library.
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.