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

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
$

Related

How to merge two static libraries into single shared library

As part of my learning, I am trying to merge two static libraries into single shared library. Following sequence of commands I am using to prepare static libraries
$gcc -c mathutil.cpp -o mathutil.o
$ar rcs libmathutil.a mathutil.o
$gcc -c dateutil.cpp -o dateutil.o
$ar rcs libdateutil.a dateutil.o
Could somebody please tell me how to merge these two static libraries into single shared library.
I have tried the following command
gcc -Wl,--whole-archive -shared libutil.so libmathutil.a
But it is giving lot of multiple definition errors.
If you have the source files why not compile them into a shared library directly? Add the -fPIC flag to your compile lines (PIC = Position Independant Code), and then link something like:
Compile the files:
gcc -c -fPIC mathutil.cpp -o mathutil.o
gcc -c -fPIC dateutil.cpp -o dateutil.o
Create the shared lib:
gcc -shared dateutil.o mathutil.o -o bin/shared/libutil.so

Compile a static library link with standard library (static)

I'm trying to compile a static library (let's call it library.a). This library consumes resources of standard libraries. There is some way that the library can statically link a standard library.
I have proven something like:
g++ -c library -static-libstdc++ -o library.o
ar rcs library.o library.a
But if I do so there is no link to the standard libraries.
Then I have proved this way:
g++ library -static-stdlib -o library.o
ar rcs library.o library.a
But ask me to add a main function.
Is there any possibility of creating a static library by statically linking also standard libraries (std :: string, std :: vector, std :: cin, etc ...).
Thanks :)
Is there any possibility of creating a static library by statically linking also standard libraries
No, because you cannot link anything to a static library. You can link things only into
a file that is produced by the linker. Otherwise no linking is involved in its production.
The linker can produce two kinds of files: programs and shared libraries.
Programs and shared libraries are similar: they're both composed of executable code
that the program loader can load into a process. They are not similar to a static
library. A static library is produced by the archiving program ar and is just a
bag of object files - an archive - from which the linker can extract the ones it
needs to complete the linkage of a program or shared library.
A command like:
g++ -c library.cpp -static-libstdc++ -o library.o
just compiles library.cpp into library.o and ignores the linkage option -static-libstdc++
because -c means Just compile. Don't link
Your real problem only comes to light in one of your later comments1:
The problem is that I am doing a wrapper of a code in C++ to be able to use it in C,
in C I can not use the standard C++ libraries. The only way is to include inside
the library the functions that I use from the standard library.
Now since a shared library is something that the linker can produce, you can statically
link libstdc++ into a shared library. So, instead of making your C wrapper library
a static library, you could make it a shared libary.
It seems you already know how to wrap C++ code in a C API. So let's write such
a C wrapper that reverses the first N characters from an input buffer to an output buffer,
using the standard C++ library to do all the work:
reverse.h
#ifndef REVERSE_H
#define REVERSE_H
#ifdef __cplusplus
extern "C" {
#endif
void reverse(char const * in, char * out, unsigned len);
#ifdef __cplusplus
} // extern "C"
#endif
reverse.cpp
#include "reverse.h"
#include <string>
#include <algorithm>
extern "C" {
void reverse(char const * in, char * out, unsigned len)
{
std::string s{in,len};
std::reverse(s.begin(),s.end());
std::copy(s.begin(),s.end(),out);
}
} // extern "C"
Then a C program that calls reverse:
main.c
#include <stdio.h>
#include <reverse.h>
int main()
{
char in[] = "dlrow olleH";
reverse(in,in,sizeof(in) - 1);
puts(in);
return 0;
}
Now we'll build our shared wrapper library.
Compile our one library source file:
$ g++ -fPIC -Wall -Wextra -std=c++11 -c reverse.cpp
Notice -fPIC. All object files that we're going to link in a shared library
must be Position Independent Code. And as we're compiling one source file -
-c reverse.cpp - we can skip the -o option and accept the default, -o reverse.o
Then link our shared library:
$ g++ -shared -o libreverse.so reverse.o -static-libstdc++
Now the shared library is ./libreverse.so and it has no runtime dependency
on libstdc++:
$ ldd libreverse.so
linux-vdso.so.1 => (0x00007ffca98c9000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa178862000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa178498000)
/lib64/ld-linux-x86-64.so.2 (0x000055d17658c000)
Next compile our C program source file:
$ gcc -Wall -Wextra -I. -c main.c
And finally link the program with libreverse:
$ gcc -o prog main.o -L. -lreverse
This program ./prog has a runtime dependency on the shared library libreverse.so.
You can't statically link with libreverse.so because it's not a static library.
But libreverse.so has been statically linked with libstdc++.a, and has
a C API.
If libreverse.so was a serious library what we'd do now is is install it
one of the runtime loader's standard
search directories, so that programs could load it automatically at runtime. We
could do that like:
$ sudo cp libreverse.so /usr/local/lib/
$ sudo ldconfig
But since libreverse.so is just a toy library we won't modify our system for
it. Instead we'll just run ./prog like:
$ export LD_LIBRARY_PATH=. # For now, tell the loader to look for libraries here
$ ./prog
Hello world
So you can make a wrapper library with a C API and C++ internals, with libstdc++
statically linked, by making the wrapper library a shared library.
But why bother?
It seems that you want to bother because you believe that "in C I can not use the standard C++ libraries".
That is a misconception. Here's how you can build the same program with a static
wrapper library
First make your static wrapper library
$ rm libreverse.so # Better delete the old shared one just to avoid confusion.
$ g++ -Wall -Wextra -std=c++11 -c reverse.cpp
$ ar rcs libreverse.a reverse.o
Then compile your C source:
$ gcc -Wall -Wextra -I. -c main.c
At this point, you have an object file main.o, a static library libreverse.a
that contains (only) reverse.o, and to make prog you simply need to link main.o
and libreverse.a(reverse.o) together with the standard C library and the standard C++
library. There is no question of C not allowing you to do this. You finished
with C when you compiled main.c. These object files and libraries will be
linked by your system linker, which will not know or care what language any of
them were compiled from.
So you could invoke the linker via g++, like:
$ g++ -o prog main.o -L. -lreverse
and once more you have a program that does this:
$ ./prog
Hello world
Or you could invoke the linker via gcc, like:
$ gcc -o prog main.o -L. -lreverse -lstdc++
which is just the same linkage, with just the same result:
$ ./prog
Hello world
As you see, the one difference between linking via g++ rather than gcc is that
g++ automatically adds both the standard C library and the standard C++ library
to the linker's inputs, and gcc doesn't add the C++ library, so you have to
do it yourself.
For that matter, if you happened to have GNU Fortran installed on your computer
you could do the same linkage with it:
$ $ gfortran -o prog main.o -L. -lreverse -lstdc++
$ ./prog
Hello world
although nothing in prog was written in Fortran.
C doesn't stop you from linking libstdc++ with anything. A possible,
but unlikely, rational motive you might have for wishing to statically
link libstdc++ into a library with a C API is that you want somebody else to
be able to link programs with this library on a system that doesn't have libstdc++ or doesn't
have one that is ABI compatible with yours. If that is your motivation, then
make your library a shared one as shown above. Otherwise, just link libstdc++
with any program that depends on it.
[1] On Stackoverflow, always state your real problem in your question.
See The XY Problem

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

C++ multi-stage linking

Ok, so this might not be a great question, but I'm a bit stuck.
I have 3 programs:
pegio.c/pegio.h - Does hardware initialization and functions for my device
PegIOHandler.cpp/PegIOHandler.h - Handles I/O for device
PegRTU.cpp - Main function
My project implements the opendnp3 (which allows one to transmit data using the DNP3 protocol) library.
Now, to compile it I first compile the pegio.c file
gcc -c pegio.c -o pegio.o
Easy, up to here I understand.
Secondly I compile the IOHandler and reference pegio.c as it uses it.
g++ -c PegIOHandler.cpp pegio.c -o PegIOHandler.o -std=c++0x
Now it gives me the following output.
g++: warning: pegio.o: linker input file unused because linking not done
But, it still creates the object file. HOWEVER, PegIOHandler implements opendnp3 header files, which is included in PegIOHandler.cpp and PegIOHandler.h. When I attempt to compile these files without using the '-c', it tells me that there are undefined references to the opendnp3 files. I know I have to link them to my project, but how do I do that?
Then compililing my third and final file:
g++ PegRTU.cpp pegio.o PegIOHandler.o -o pegrtu -std=c++0x
This now tells me that there are undefined references to the opendnp3 files.
So: How do I link the opendnp3 library to my project / code files???
Thanks!
Ouch. So many misunderstandings. You don't need the previously compiled object files to compile further source files to object code. However, you do need to link them together at the end of the compilation process, including any libraries required. All in all:
gcc -c pegio.c -o pegio.o
g++ -c PegIOHandler.cpp -o PegIOHandler.o -std=c++0x
g++ -c PegRTU.cpp -o PegRTU.o -std=c++0x
g++ -o executable_name *.o -lopendnp3 # or whatever linker flag is needed for OpenDNP3
And pretty please, read this.

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

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() )