Compiling CUDA code while linking a static library - c

I have C code main_code.c and helper_code.c. The former depends on some CUDA code cuda_code.cu and the latter on an external library mylib. For my external library mylib to work, I need to link it to my code with the -static flag:
g++ main_code.c helper_code.c -o main_code -static -L/usr/local/mylib/lib -lmylib -lmylib2
But main_code.c also depends on CUDA code- cuda_code.cu. I can link it with:
nvcc cuda_code.cu -c
g++ main_code.c -o main_code cuda_code.o -L/usr/local/cuda-10.0/lib64 -lcudart -lpthread
I want to compile my code together with the CUDA code and the external library mylib. However, linking mylib works only with the -static flag. A naive attempt would be the following but it does not work:
nvcc cuda_code.cu -c
g++ main_code.c helper_code.c -o main_code cuda_code.o -static -L/usr/local/mylib/lib -lmylib -lmylib2 -L/usr/local/cuda-10.0/lib64 -lcudart -lpthread
This gives the error:
/usr/bin/ld: cannot find -lcudart
which I'm assuming is because you cannot use the static flag while linking with CUDA (because it goes away when I remove the -static flag (in addition to also removing the mylib library linking)).
I then tried compiling helper_code.c separately and then linking it to main_code.c since it's just helper_code.c that needs mylib:
helper.o:
g++ helper_code.c -c -static -L/usr/local/mylib/lib -lmylib -lmylib2
cuda-code.o:
nvcc cuda_code.cu -c
main-code: helper.o cuda-code.o
g++ main_code.c -o main_code helper_code.o cuda_code.o -L/usr/local/cuda-10.0/lib64 -lcudart -lpthread
But this also does not work. I get an undefined reference error that's referring to a function defined in mylib, meaning the linking to mylib isn't working. I can resolve that error by including the mylib library and using the -static flag but that then breaks the CUDA linking.
I can separately get the CUDA linking (to cuda_code.cu) to work or mylib linking to work but not both at the same time.
So is there a workaround to link mylib (which needs -static) while at the same time also linking my CUDA code (which does not allow -static)?

Following the answer linked in talonmies's comment, the following did the trick:
g++ main_code.c -o main_code helper_code.o cuda_code.o -L/usr/local/mylib/lib -L/usr/local/cuda-10.0/lib64 -Wl,-Bstatic -lmylib -lmylib2 -Wl,-Bdynamic -lcudart

Related

compile multiple cuda files (that have dynamic parallelism) and MPI code

I have a bunch of .cu files that use dynamic parallelism (a.cu, b.cu, c.cu.., e.cu, f.cu), and a main.c file that uses MPI to call functions from a.cu on multiple nodes. I'm trying to write a make file to compile the executable, but I keep facing the following errors:
cudafiles.o: In function `__cudaRegisterLinkedBinary_66_tmpxft_00001a84_00000000_17_cuda_device_runtime_compute_61_cpp1_ii_8b1a5d37':
link.stub:(.text+0x1fb): undefined reference to `__fatbinwrap_66_tmpxft_00001a84_00000000_17_cuda_device_runtime_compute_61_cpp1_ii_8b1a5d37'
Here is my makefile:
INCFILES=-I/usr/local/cuda-8.0/include -I/opt/mpi/mvapich2-gnu/2.2/include -I./
LIBFILES=-L/usr/local/cuda-8.0/lib64 -L/opt/mpi/mvapich2-gnu/2.2/lib
LIBS=-lcudart -lcudadevrt -lcublas_device -lmpi
ARCH=-gencode arch=compute_60,code=sm_60
NVCC=nvcc -ccbin g++
default: all
all: clean final.o
io.o: io.cpp
g++ -c -std=c++11 io.cpp
final.o: io.o a.cu b.cu c.cu d.cu e.cu f.cu main.cpp
$(NVCC) -std=c++11 $(INCFILES) $(LIBFILES) $(LIBS) -g -G -Xptxas -v -dc $(ARCH) a.cu b.cu c.cu d.cu e.cu f.cu
$(NVCC) -std=c++11 $(ARCH) $(INCFILES) $(LIBFILES) $(LIBS) -rdc=true -dlink a.o b.o c.o d.o e.o f.o io.o -o cudafiles.o
mpicxx -O3 $(INCFILES) $(LIBFILES) -c main.cpp -o main.o
mpicxx $(INCFILES) $(LIBFILES) $(LIBS) cudafiles.o a.o b.o c.o d.o e.o f.o io.o main.o -o exec
clean:
rm -rf *.o exec
The original problem reported was an undefined reference to main. This was arising from this line in the Makefile:
$(NVCC) -std=c++11 $(ARCH) $(INCFILES) $(LIBFILES) $(LIBS) -rdc=true a.o b.o c.o d.o e.o f.o io.o -o cudafiles.o
As constructed, this actually instructs nvcc to perform full/final linking. However the intent of this line was to perform the device-link step only, required when compiling with -rdc=true or -dc, and when not performing the final link with nvcc. In this case, the final link was being performed by mpicc/mpicxx. To perform the device-link step only, we need to specify -dlink. Without that switch, nvcc expects to do final linking, but fails because none of the supplied objects contain a main function. The correct solution, since we have no intent to do final link at this point, is to use the -dlink switch.
I also suggested converting everything to C++ style linking, since nvcc links that way. It might be possible to sort out a C-style link with a C++-style link, but this just seems troublesome to me. Therefore I suggested converting the only .c file (main.c) to a .cpp file, and convert from mpicc to mpicxx
The next problem that arose was undefined references to e.g. cudaSetDevice() and cudaFree(). These are part of the CUDA runtime API library ("libcudart"). When performing final link with nvcc, these are linked automatically. But since final link is being performed by mpicxx (basically a wrapper on g++), it's necessary to call out the link against that library specifically with -lcudart.
Finally, the remaining problem was a link-order problem. In a nutshell, link dependencies need to be satisfied from left to right in the linker command line. Different compilers are more or less picky about this. The final reordering changes were to specify the libraries to link against in the correct order, and also to specify these libraries at the end of the link command line, so that any dependencies on these libraries, to their left in the link command line, are satisfied.

GNU g++ -G option to create a shared library available on Solaris not on Linux

I am using GNU g++ 4.9.2 compiler both on Solaris and Linux.
On Solaris platform, to create a shared library from a source file (a.c), I use the following command:
g++ -G a.c -o a
a becomes a shared library
a.c contains the following code:
void libfn1()
{
}
If I try not to use -G option i.e. compile as:
g++ a.c -o a
It gets a linker error: Undefined Symbol main
But, on Linux, if I do the same thing: it says:
g++: error: unrecognized command line option -G
How to create a shared library on Linux? What is the g++ option for that?
The g++ documentation says this:
These additional options are available on System V Release 4 for
compatibility with other compilers on those systems:
-G Create a shared object. It is recommended that -symbolic or -shared be
used instead.
Normally you want to generate position independent code too, for a shared library, with the -fPIC flag.
So you'd want to run:
g++ -fPIC -shared a.c -o liba.so
The process to create a shared library on a Linux system is a bit different.
Shared libraries on Linux are .so (for "shared object") files, not .g.
You do it like this:
First, you need to generate position-independent code from your C++ source. That is so your library works from wherever it is called. To do that, you should use g++'s -fPIC flag.
So, for each source file you want to be included in your library, you should only compile it to position-independent code. We'll handle linking later.
For each source file:
g++ -c -fPIC file.cpp
(The -c flag tells g++ "compile, don't link").
for each file.cpp, g++ will generate file.o, an object file containing position-independent code.
To then build the object files into a shared library, you should use
g++ -o -shared myLibrary.so {all_object_files}
So if you have file1.o, file2.o and file3.o, the command would be:
g++ -shared -o myLibrary.so file1.o file2.o file3.o
Of course, if you have a lot of files this can get pretty tedious, so you should write a Makefile to automate this process for you! Here's an example:
myLibrary.so: file1.o file2.o file3.o
$(CXX) -shared $^ -o $#
file1.o file2.o file3.o : CXXFLAGS+=-fPIC

Contiki port will not override printf

I am trying to create a port of contiki for my custom platform using an stm32l1 processor. However when i am trying to override the default printf function from arm-none-eabi-gcc newlib it will not let me.
I have tried creating hedaer and source files, adding them to be built and then either creating the function 'printf' and 'sprintf' in them or naming them something different and then trying to use
#define printf my_printf.
I have also followed other tips i found online that tells me to create a newlib stub file providing the various functions _sbrk , _write , _read... and so on.
However everytime i try to build my program with any printf command, the linker complains on all the newlib stub files with undefinded references.
undefined reference to _sbrk
How can i get the contiki build system to override the standard printf function?
On ubuntu14:10 with gcc 4.93.
CC targets/r1501/printf/printf-stdarg.c
CC contiki/../arm/stm32l152/./syscalls.c
CC ....
CC contiki/core/net/mac/cxmac/cxmac.c
AR contiki-r1501.a
CC project.c
LD project.r1501
/usr/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/thumb/libg.a(lib_a-sbrkr.o): In function_sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to _sbrk'
/usr/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/thumb/libg.a(lib_a-writer.o): In function_write_r':
writer.c:(.text._write_r+0x10): undefined reference to _write'
/usr/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/thumb/libg.a(lib_a-closer.o): In function_close_r':
....More errors from libg.a `
In the syscalls.c file all of theese undefined references are specified.
and printf and sprintf are defined in printf-sdarg.c
arm-none-eabi-gcc -DCONTIKI=1 -DCONTIKI_TARGET_R1501=1
-DNETSTACK_CONF_WITH_IPV6=1 -DUIP_CONF_IPV6_RPL=1 -DAUTOSTART_ENABLE -DHSE_VALUE=8000000 -DF_CPU=32000000 -DPLL_SOURCE_HSE -D'GIT_DESC="v0.1-23-g0c3a4d8-dirty"' -specs=nosys.specs -I. -Icontiki/core -Icontiki/../arm/stm32l152 -Icontiki/../arm/stm32l152/loader -Icontiki/../arm/stm32l152/lib/STM32L1xx_StdPeriph_Driver/inc -Icontiki/../arm/stm32l152/lib/CMSIS/Include -Icontiki/../arm/stm32l152 -Icontiki/platform/r1501 -DWITH_ASCII -DMCK=32000000 -mlittle-endian -mthumb -mcpu=cortex-m3 -msoft-float -Wno-strict-aliasing -DRUN_AS_SYSTEM -DROM_RUN -std=c99 -g -lc -larchive -Lcontiki/../arm/stm32l152 -fdiagnostics-color=always -O0 -I. -Itargets/r1501/. -Itargets/r1501/dev -Itargets/r1501/rf230bb -Itargets/r1501/printf -Icontiki/../arm/stm32l152/. -Icontiki/../arm/stm32l152/lib/STM32L1xx_StdPeriph_Driver/src -Icontiki/core/dev -Icontiki/core/lib -Icontiki/core/net -Icontiki/core/net/llsec -Icontiki/core/net/mac -Icontiki/core/net/rime -Icontiki/core/net/rpl -Icontiki/core/sys -Icontiki/core/cfs -Icontiki/core/ctk -Icontiki/core/lib/ctk -Icontiki/core/loader -Icontiki/core/. -Icontiki/apps/ping6 -Icontiki/core/sys -Icontiki/core/dev -Icontiki/core/lib -Icontiki/core/net/ipv6 -Icontiki/core/net/ip -Icontiki/core/net/rpl -Icontiki/core/net/mac -Icontiki/core/net/llsec -Icontiki/core/net/mac/sicslowmac -Icontiki/core/net/rime -Icontiki/core/net -Icontiki/core/net/mac/contikimac -Icontiki/core/net/mac/cxmac -Itargets/r1501/ -Icontiki -DCONTIKI_VERSION_STRING=\"Contiki-2.6-2077-ga79edc6\" -DAUTOSTART_ENABLE -c project.c -o project.co arm-none-eabi-gcc -L contiki/../arm/stm32l152 -T contiki/../arm/stm32l152/stm32l1xx.ld -g
-nostartfiles -mthumb -fdiagnostics-color=always project.co obj_r1501/contiki-main.o \
contiki-r1501.a -o project.r1501 /usr/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/thumb/libg.a(lib_a-sbrkr.o): In function `_sbrk_r':

How can I compile with shared library if I use Autotools

I have two C programs named drive.c and mylib.c.
drive.c is main module mylib.c is sub modulle that I want work as shared library .
I can compile them with following step and run.
gcc –fPIC –g –c –Wall mylib.c
gcc -shared -Wl,-soname,libmylib.so.1 -o /c/opt/lib/libmylib.so.1.0.1 mylib.o -lc
gcc -g -Wall -Wextra -pedantic -I./ -L/c/opt/lib -o drive.exe drive.c –l:libmylib.so.1
Now I want know is How can I compile them by autotools as same effect of above way ?
What and how do I have to edit configure.ac and Makefile.am for compile them?

linking pthread library issue

Am facing a problem that may be slightly complicated to explain and understand as giving the entire picture would be too big and difficult.
Please excuse me for it.
Consider the following Makefile:
all: clients.so simulator backup
LD_PRELOAD=/home/Juggler/client/clients.so ./simulator
backup: backup.c libclient.a
gcc backup.c -o backup -L /home/Juggler/client -L. -lclient -ldl
simulator: simulator.c libclient.a
gcc -g simulator.c -o simulator -L /home/Juggler/client -L. -lclient -ldl -pthread
libclient.a: libclient.o client.o
ar rcs libclient.a libclient.o client.o
libclient.o:libclient.c
gcc -c libclient.c -o libclient.o -pthread
clients.so: client.o client_invoke.o
ld -shared -o clients.so client_invoke.o client.o -ldl
client_invoke.o: client_invoke.c
gcc -Wall -fPIC -DPIC -c -g client_invoke.c
client.o: client.c
gcc -Wall -fPIC -DPIC -c -g client.c -ldl -pthread
We call function written in client.c from libclient.c and these functions in client.c make call to pthread_key_create(), pthread_setspecific..etc.
Threads are created by simulator.c and theses threads access functions written in he other files.
On doing make...Errors like the following appear.
/home/Juggler/client/libclient.a(client.o):In function 'setup_connection':
/home/Juggler/client/client.c:35: undefined reference to 'pthread_setspecific'
pthread.h has been included in both client.c and libclient.c
Would be grateful for anypointers . I understand information is very less...
Thanks
On linux, pthread functions live in the libpthread library. So you have to link to that.
The proper way, when using pthreads, is to compile and link using the -pthread , which, among other things, will link in the pthread library. You have the -pthread flag for some of your executables, but not for others, and not for your clients.so library, so add the flag where required.
Also, remember, when you are creating a shared library, you should compile the source files with the -fPIC flag.
(And, seems you are calling ld directly to produce the client.so library, you really should use gcc to do the linking.)

Resources