C++ program gets undefined reference to a dynamic C library during linking - c++

I've created a dynamic networking library in C. When I try to link it in my C++ program I get an undefined reference the first time I call one of my functions in the library. What I can't understand is that I created a little test program in C that uses the library and it links just fine.
Could someone help with my problem? Here are the steps I've taken to create my library and link it.
Library creation:
Code my library
Compile with the line: gcc -c -fPIC -g -Wall ./libnet.c
Link my library object file and create the shared object file with the line: gcc -shared -o libnet.so -g -Wall ./libnet.o
Move my library to the appropriate folders and set LD_LIBRARY_PATH:
I copy my library to two directories. One directory is the test C program that links properly and one is the C++ program that doesn't link properly.
I set the environment variable LD_LIBRARY_PATH to both the directories that use the library
Compile and link my program:
Code my program
Compile all my .cpp files with the line: g++ -c -g -Wall ./
Link together all my object files and the shared library to create my program with the line: g++ -o -g -Wall -L./ -lnet
Here is the make file that I use. Maybe I have something wrong in here?
PPFLAGS = -g -Wall
TARGET = msgfrwdserver
OBJS = msgfrwdserver.o
msgfrwdhelper.o msgfrwd.o climsgfrwd.o
LIBS = libnet.so
CPPLP =
-L/usr/home/chris/development/legends/servers/monitor
-L/usr/home/chris/development/legends/servers/msgfrwd
CPPFILES = ./msgfrwdserver.cpp
./msgfrwdhelper.cpp
./classes/msgfrwd.cpp
./classes/climsgfrwd.cpp
CPPIP = -I./classes
-I/usr/home/chris/development/legends/libnet
all: ${OBJS} ${TARGET}
${TARGET}: ${OBJS} ${LIBS}
g++ -o
${TARGET} ${PPFLAGS} -L./ -lnet
${CPPIP} ${OBJS}
msgfrwdserver.o: ./msgfrwdserver.cpp
g++ -c ${PPFLAGS} ${CPPIP}
./msgfrwdserver.cpp
msgfrwdhelper.o:
./msgfrwdhelper.cpp
g++ -c ${PPFLAGS}
./msgfrwdhelper.cpp
msgfrwd.o:
./classes/msgfrwd.cpp
g++ -c
${PPFLAGS} ./classes/msgfrwd.cpp
climsgfrwd.o: ./classes/climsgfrwd.cpp
g++ -c ${PPFLAGS} ${CPPIP}
./classes/climsgfrwd.cpp
clean: rm
-rf ${TARGET} *.o *~ .core ./classes/~
I really have no idea what the problem could be. Any help would be much appreciated. Do I have to do something differently to get a C library to work with a C++ program?
Sorry that the make file is messy. I didn't exactly translate well when I tried to block quote it or say it was a code sample.

C library functions must have en extern "C" definition in order to call them from C++ to turn of name-mangeling.
extern "C"
{
int test();
}
With the extern , the the Microsoft C++ compiler will look for the symbol "_test", otherwise it will look for "?test##YAHXZ" (The C++ name-mangeled version of int test() )

Related

Shared library using a different version of another shared library to the main executable?

Problem
Say I've got a Linux executable MAIN that uses an old version of some shared library LIB.so (which it locates using LD_LIBRARY_PATH).
I'd like MAIN to also use my library MYLIB.so, except this uses a newer version of LIB.so.
MAIN and MYLIB.so both use functions that appear in both versions of LIB.so with the same name (but different implementations).
How do I get the application to also load the new version of LIB.so when it loads MYLIB.so?
What doesn't seem to work
I've tried compiling MYLIB.so with an RPATH option pointing to the new version of the library. However, while this correctly identifies the newer library when I run ldd MYLIB.so, when the application runs it only uses the old library implementation.
My compilation (using single file toy implementations for clarity) is as follows:
# compile old library implementation
g++ -c -Wall -Werror -fpic library_old.cpp
g++ -shared -o liblib.so library_old.o
# compile new library implementation
g++ -c -Wall -Werror -fpic library_new.cpp
g++ -shared -o new/liblib.so library_new.o
# compile my library against new liblib
g++ -c -Wall -Werror -fpic my_library.cpp
g++ -L`pwd`/new -shared -Wl,-rpath,`pwd`/new -o libmine.so my_library.o -llib
# compile application against old liblib
g++ -L`pwd` -Wall -Werror -o main main.cpp -llib -lmine
export LD_LIBRARY_PATH=`pwd`

Link To Library with C and C++ Bindings

I am trying to determine if it is possible to link against a linux library with c and c++ bindings. I have an existing c++ project which is broken down into several libraries. I would like to extend these libraries with C bindings so that I can use them with cgo.
I am aware of how to mix c/c++ with extern "c" syntax. The problem that I have is in daisy chaining libraries. I've created a sample project which demonstrates my question:
https://github.com/Shelnutt2/c_cpp_linker_test
In this project we have hello.c, world.cpp both of which are built into a library called libwords . I can link libwords to libhelloworld without an issue. The problem occurs when trying to build main.cpp, which wants to call a c and c++ functions from libhelloworld (and thus the linked libwords)
Due to the linking differences of C++ vs C the main executable can not find the hello function
main.cpp:15: undefined reference to `hello'
Is it possible to link against the same library in this manner or do I need to break c-bindings into their own wrapper library?
In this example project I used shared libraries, but I'm open to static linking if that is possible.
You should link your application with both libraries. The exports are not transitive.
main: main.o libhelloworld.so
$(CXX) $< -L'$(CURDIR)' -lwords -lhelloworld -o $#
> gmake
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -c -o helloworld.o helloworld.cpp
cc -Wall -g -O -fPIC -DC_LINK_TEST=1 -c -o hello.o hello.c
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -c -o world.o world.cpp
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -shared hello.o world.o -o libwords.so
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -L'/usr/home/me/c_cpp_linker_test' -lwords -shared helloworld.o libwords.so -o libhelloworld.so
c++ -Wall -g -O -fPIC -DC_LINK_TEST=1 -c -o main.o main.cpp
#c++ main.o libhelloworld.so -o main
c++ main.o -L'/usr/home/me/c_cpp_linker_test' -lwords -lhelloworld -o main
> LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd` ./main
c gives us: hello
cpp gives us: hello world
>
Otherwise there is no problem with linking both C and C++ calling conventions, as the name mangling is different.
(never mind the change g++ to c++ - I use clang)

Creating a static CUDA library to be linked with a C++ program

I am attempting to link a CUDA kernel with a C++ autotools project however cannot seem to pass the linking stage.
I have a file GPUFloydWarshall.cu that contains the kernel and a wrapper C function that I would like place into a library libgpu.a. This will be consistent with the remainder of the project. Is this at all possible?
Secondly, the library would then need to be linked to around ten other libraries for the main executable which at the moment using mpicxx.
Currently I am using/generating the below commands to compile and create the libgpu.a library
nvcc -rdc=true -c -o temp.o GPUFloydWarshall.cu
nvcc -dlink -o GPUFloydWarshall.o temp.o -L/usr/local/cuda/lib64 -lcuda -lcudart
rm -f libgpu.a
ar cru libgpu.a GPUFloydWarshall.o
ranlib libgpu.a
When this is all linked into the main executable I get the following error
problem/libproblem.a(libproblem_a-UTRP.o): In function `UTRP::evaluate(Solution&)':
UTRP.cpp:(.text+0x1220): undefined reference to `gpu_fw(double*, int)'
Th gpu_fw function is my wrapper function.
Is this at all possible?
Yes, it's possible. And creating a (non-CUDA) wrapper function around it makes it even easier. You can make your life easier still if you rely on C++ linking throughout (you mention a wrapper C function). mpicxx is a C++ compiler/linker alias, and cuda files (.cu) follow C++ compiler/linker behavior by default. Here's a very simple question that discusses building cuda code (encapsulated in a wrapper function) into a static library.
Secondly, the library would then need to be linked to around ten other libraries for the main executable which at the moment using mpicxx.
Once you have a C/C++ (non-CUDA) wrapper exposed in your library, linking should be no different than ordinary linking of ordinary libraries. You may still need to pass the cuda runtime libraries and any other cuda libraries you may be using in the link step, but this is the same conceptually as any other libraries your project may depend on.
EDIT:
It's not clear you need to use device linking for what you want to do. (But it's acceptable, it just complicates things a bit.) Anyway, your construction of the library is not quite correct, now that you have shown the command sequence. The device link command produces a device-linkable object, that does not include all necessary host pieces. To get everything in one place, we want to add both GPUFloydWarshall.o (which has the device-linked pieces) AND temp.o (which has the host code pieces) to the library.
Here's a fully worked example:
$ cat GPUFloydWarshall.cu
#include <stdio.h>
__global__ void mykernel(){
printf("hello\n");
}
void gpu_fw(){
mykernel<<<1,1>>>();
cudaDeviceSynchronize();
}
$ cat main.cpp
#include <stdio.h>
void gpu_fw();
int main(){
gpu_fw();
}
$ nvcc -rdc=true -c -o temp.o GPUFloydWarshall.cu
$ nvcc -dlink -o GPUFloydWarshall.o temp.o -lcudart
$ rm -f libgpu.a
$ ar cru libgpu.a GPUFloydWarshall.o temp.o
$ ranlib libgpu.a
$ g++ main.cpp -L. -lgpu -o main -L/usr/local/cuda/lib64 -lcudart
$ ./main
hello
$

Linux executable file as shared library

I'm trying to compile an executable file which i want also to use as shared library. When i'm clearly compile and linking it as "executable" - everything fine - file could start and work correctly. At this phase i cant correctly linking other libraries with it (tons of redefinitions in log). When i'm trying to add options -Fpic -shared - program copiles successfully, but starting with segmentation fault. How can i make it executable and "sharedlibrary" at the same time?
A single file cannot be a shared library and an executable at the same time. But you can link your object files twice to make both. It'd go something like this:
g++ -c -o module.o module.cpp # create an object that has no main()
g++ -shared -fPIC -o libmodule.so module.o # build shared library
g++ -o program module.o main.cpp # build executable
Or instead, the last line could link the shared library (in which case you'll need the library present when you run the executable):
g++ -o program -l module main.cpp

Link error with my own C++ library

This is my first time trying to make a simple library. I worked in Ubuntu 12.04 with g++ 4.6.3. Here is the problem:
[[mylib.cpp]]
#include<sqlite3.h>
void Mylib::blahblah() {...}
void Mylib::evenmoreblah() {...}
...
[[mylib.h]]
#include <...>
class Mylib {
...
};
Then I made the lib by:
gcc -c -Wall -fpic mylib.cpp
gcc -shared -o libmylib.so mylib.o
I used the library in a single test.cpp which contains only the main(). I put libmylib.so in ./libdir, and compiled by using:
g++ -g test.cpp -o test -lpthread -L/usr/local/lib -lsqlite3 -L./libdir -lmylib
The error I got:
./libdir/libmylib.so: undefined reference to `sqlite3_close'
./libdir/libmylib.so: undefined reference to `sqlite3_exec'
./libdir/libmylib.so: undefined reference to `sqlite3_free'
./libdir/libmylib.so: undefined reference to `sqlite3_open'
You could link -lsqlite3 into your shared library with
gcc -shared mylib.o -o libmylib.so -lsqlite3
If you do that, you don't need to explicitly link -lsqlite3 to your program, but that won't harm.
and the order of linking arguments for your program is important:
g++ -Wall -g test.cpp -o mytest \
-L./libdir -lmylib -L/usr/local/lib -lsqlite3 -lpthread
it should go from higher-level libraries to lower-level (i.e. system) ones. And don't forget -Wall to get almost all warnings from the compiler, which is very useful.
Read the Program Library HowTo.
PS. Don't call your program test which is a shell builtin (and the standard /usr/bin/test). Use some other name.
If your library make references to sqlite3, you should link sqlite after linking your library :
g++ -g test.cpp -o test -lpthread -L/usr/local/lib -L./libdir -lmylib -lsqlite3
Otherwise ld won't find anything useful in libsqlite3 before linking your library and won't be able to find the requested symbols after that.
Since your library uses sqlite3, you need to add that AFTER your own library in the linker command. I think you could add it to the linking of your shared library too, but not certain.
The linker resolves libraries and their references in the order you list them, so the order is important.