Shared library creation?
Hi guys,

I have just learn how to create shared libraries in linux through the 'Program Libraries HOWTO'.

For now, I've been messing around with CUDA's template project to turn it into a shared library.

So far what I've done:

1. Change main() in template.cu to cudamain().
2. I managed to turn it into a static library (a.a) with 'nvcc -lib template.cu -I ../../common/lib.
3. Can't get another program to compile with it. It errors: missing symbol 'cudamain' even though it recognises a.a.

However, what I really want to know is how do I make nvcc create a shared library. Thanks :mellow:
Hi guys,



I have just learn how to create shared libraries in linux through the 'Program Libraries HOWTO'.



For now, I've been messing around with CUDA's template project to turn it into a shared library.



So far what I've done:



1. Change main() in template.cu to cudamain().

2. I managed to turn it into a static library (a.a) with 'nvcc -lib template.cu -I ../../common/lib.

3. Can't get another program to compile with it. It errors: missing symbol 'cudamain' even though it recognises a.a.



However, what I really want to know is how do I make nvcc create a shared library. Thanks :mellow:

#1
Posted 07/28/2008 07:49 AM   
nvcc --help says that --shared will produce a shared library. I've never tried it as I use CMake + FindCUDA.cmake for compiling which handles all the internal compile commands needed to create the shared library.

You may need to declare cudamain as
[code]
extern "C" cudamain() { ... }
[/code]
in your libs header file if the program you are linking your library to is C++.
nvcc --help says that --shared will produce a shared library. I've never tried it as I use CMake + FindCUDA.cmake for compiling which handles all the internal compile commands needed to create the shared library.



You may need to declare cudamain as



extern "C" cudamain() { ... }


in your libs header file if the program you are linking your library to is C++.

#2
Posted 07/28/2008 11:20 AM   
If you are on a 64-bit Linux system, you may also need to pass the -fPIC option through to the host compiler:

[code]
       nvcc --ptxas-options=-v --compiler-options '-fPIC' -o mylib.so --shared mykernel.cu
[/code]
If you are on a 64-bit Linux system, you may also need to pass the -fPIC option through to the host compiler:





       nvcc --ptxas-options=-v --compiler-options '-fPIC' -o mylib.so --shared mykernel.cu

#3
Posted 07/28/2008 12:38 PM   
Thanks guys. However, it still doesn't answer my question on how do I generate the shared library. Is there anyone I can ask regarding this matter?

[color=red]EDIT:[/color] Found this but have not tried it out.

[url="http://www.gpgpu.org/forums/viewtopic.php?p=16723"]http://www.gpgpu.org/forums/viewtopic.php?p=16723[/url]
Thanks guys. However, it still doesn't answer my question on how do I generate the shared library. Is there anyone I can ask regarding this matter?



EDIT: Found this but have not tried it out.



http://www.gpgpu.org/forums/viewtopic.php?p=16723

#4
Posted 07/29/2008 12:45 AM   
[quote name='zakim' date='Jul 28 2008, 06:45 PM']Thanks guys. However, it still doesn't answer my question on how do I generate the shared library. Is there anyone I can ask regarding this matter?

[color=red]EDIT:[/color] Found this but have not tried it out.

[url="http://www.gpgpu.org/forums/viewtopic.php?p=16723"]http://www.gpgpu.org/forums/viewtopic.php?p=16723[/url]
[right][snapback]417396[/snapback][/right]
[/quote]
Did you read my suggestion to use --shared? Did you read seibert's post where a full command line was given?

To reiterate:
[code]
$ nvcc --shared -o libtest.so test.cu --compiler-options '-fPIC'
$ file libtest.so
libtest.so: ELF 64-bit LSB shared object, AMD x86-64, version 1 (SYSV), not stripped
$ ldd libtest.so
       libcudart.so => /opt/cuda/lib/libcudart.so (0x00002ae61beda000)
       libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00002ae61c117000)
       libm.so.6 => /lib64/libm.so.6 (0x00002ae61c417000)
       libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00002ae61c69b000)
       libc.so.6 => /lib64/libc.so.6 (0x00002ae61c8a9000)
       libdl.so.2 => /lib64/libdl.so.2 (0x00002ae61cbfc000)
       libpthread.so.0 => /lib64/libpthread.so.0 (0x00002ae61ce01000)
       librt.so.1 => /lib64/librt.so.1 (0x00002ae61d01b000)
       /lib64/ld-linux-x86-64.so.2 (0x0000003a9ea00000)
[/code]

If this is not what you are asking for, then please clarify what you mean by "how do I generate the shared library"
[quote name='zakim' date='Jul 28 2008, 06:45 PM']Thanks guys. However, it still doesn't answer my question on how do I generate the shared library. Is there anyone I can ask regarding this matter?



EDIT: Found this but have not tried it out.



http://www.gpgpu.org/forums/viewtopic.php?p=16723

[snapback]417396[/snapback]




Did you read my suggestion to use --shared? Did you read seibert's post where a full command line was given?



To reiterate:



$ nvcc --shared -o libtest.so test.cu --compiler-options '-fPIC'

$ file libtest.so

libtest.so: ELF 64-bit LSB shared object, AMD x86-64, version 1 (SYSV), not stripped

$ ldd libtest.so

       libcudart.so => /opt/cuda/lib/libcudart.so (0x00002ae61beda000)

       libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00002ae61c117000)

       libm.so.6 => /lib64/libm.so.6 (0x00002ae61c417000)

       libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00002ae61c69b000)

       libc.so.6 => /lib64/libc.so.6 (0x00002ae61c8a9000)

       libdl.so.2 => /lib64/libdl.so.2 (0x00002ae61cbfc000)

       libpthread.so.0 => /lib64/libpthread.so.0 (0x00002ae61ce01000)

       librt.so.1 => /lib64/librt.so.1 (0x00002ae61d01b000)

       /lib64/ld-linux-x86-64.so.2 (0x0000003a9ea00000)




If this is not what you are asking for, then please clarify what you mean by "how do I generate the shared library"

#5
Posted 07/29/2008 02:37 AM   
Hey guys, this is my attempt at it. Errorrreed. Thanks for the help.

[code]hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects$ cp -rf template/ templatelib
hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects$ cd templatelib/
hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects/templatelib$ vim template.cu
----------- I changed main() to cudamain()
hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects/templatelib$ nvcc --shared -o libtest.so template.cu template_kernel.cu template_gold.cpp --compiler-options '-fPIC' -I ../../common/inc/ -I /usr/local/cuda/include/
template_kernel.cu(68): error: identifier "CUT_BANK_CHECKER" is undefined

1 error detected in the compilation of "/tmp/tmpxft_00002803_00000000-15_template_kernel.cpp1.ii".
hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects/templatelib$ [/code]
Hey guys, this is my attempt at it. Errorrreed. Thanks for the help.



hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects$ cp -rf template/ templatelib

hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects$ cd templatelib/

hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects/templatelib$ vim template.cu

----------- I changed main() to cudamain()

hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects/templatelib$ nvcc --shared -o libtest.so template.cu template_kernel.cu template_gold.cpp --compiler-options '-fPIC' -I ../../common/inc/ -I /usr/local/cuda/include/

template_kernel.cu(68): error: identifier "CUT_BANK_CHECKER" is undefined



1 error detected in the compilation of "/tmp/tmpxft_00002803_00000000-15_template_kernel.cpp1.ii".

hpr@hpr-xps:~/NVIDIA_CUDA_SDK/projects/templatelib$

#6
Posted 07/29/2008 10:28 AM   
Since you are using CUT_BANK_CHECKER, you need to specify the include (-I) and library directories (-L) for CUT. The makefile sets these so you can open it as an example.
Since you are using CUT_BANK_CHECKER, you need to specify the include (-I) and library directories (-L) for CUT. The makefile sets these so you can open it as an example.

#7
Posted 07/29/2008 12:26 PM   
This is from Evan Lezar with final bits from me to make it work

[quote]Hi Zaki

I have read your post ... and had a look at the commands that CMake generate for the k3d project and I have come up with this.

What I have is two files cuda_functions.h and cuda_functions.cu

cuda_functions.h contains the function declarations that I want to be visible to other apps using the shared library - these must be declared as extern "C" ... for example



extern "C" my_function ( int my_parameter );


cuda_functions.cu includes cuda_functions.h and contains the defintion of these functions - for example, the function declared above might be something like


#include "cuda_functions.h"

extern "C" my_function ( int my_parameter )
{
    dim3 threads ( 8, 8 );
    dim3 blocks ( 8, 1, 1);

    my_cuda_kernel <<< blocks, threads >>> ( my_param );

}


now you can build a shared library as follows:

nvcc --shared -o libname_of_shared_library.so cuda_functions.cu -I/usr/local/cuda/include -L/usr/local/cuda/lib -lcudart

assuming that you have installed the cuda api to /usr/local/cuda
Any other dependencies such as cutil.h can be added to the above command.

-o specifies the output filename and by convention it starts with lib and shared libraries (in Linux) have a .so extension
-I tells the compiler where to look for the included header files
-L tells the linker where to look for the libraries that are linked and
-l tells the linker to link the libraries - in this case libcudart (note that the lib is left off the name)

Ok - so now you have a shared cuda library :)

The question remains as to how to use it ...

Let's say you have a file main.c from which you wish to call the cuda function my_function

main.c would look something like:

#include "cuda_functions.h"

int main()
{
  my_function( 5 );
  return 0;
}


This program can now be compiled using gcc and linking in the cuda shared library.  For example


gcc -o out_file main.c -lname_of_shared_library


where name_of_shared_library is the name as in the preceding section.  If the library is not in the same folder as the file you are compiling you may need to specify the location using the -L flag.


Hope this help - please feel free to contact me again if you have any more questions - and perhaps post this on the forum if you get it working so that others with similar problems can be helped :)

Evan[/quote]


Zaki: This is what I had to do to make it work.

The gcc command above would error out with
gcc -o main main.c -lname_of_shared_library
In file included from main.c:2:
../cuda_functions.h:2: error: expected identifier or ‘(’ before string constant
make: *** [main] Error 1


What I had to do was to create another cuda_functions.h for gcc, say name it cuda_functions_wo_extern_C.h

with the contents

my_function ( int my_parameter );
This is from Evan Lezar with final bits from me to make it work



Hi Zaki



I have read your post ... and had a look at the commands that CMake generate for the k3d project and I have come up with this.



What I have is two files cuda_functions.h and cuda_functions.cu



cuda_functions.h contains the function declarations that I want to be visible to other apps using the shared library - these must be declared as extern "C" ... for example







extern "C" my_function ( int my_parameter );





cuda_functions.cu includes cuda_functions.h and contains the defintion of these functions - for example, the function declared above might be something like





#include "cuda_functions.h"



extern "C" my_function ( int my_parameter )

{

    dim3 threads ( 8, 8 );

    dim3 blocks ( 8, 1, 1);



    my_cuda_kernel <<< blocks, threads >>> ( my_param );



}





now you can build a shared library as follows:



nvcc --shared -o libname_of_shared_library.so cuda_functions.cu -I/usr/local/cuda/include -L/usr/local/cuda/lib -lcudart



assuming that you have installed the cuda api to /usr/local/cuda

Any other dependencies such as cutil.h can be added to the above command.



-o specifies the output filename and by convention it starts with lib and shared libraries (in Linux) have a .so extension

-I tells the compiler where to look for the included header files

-L tells the linker where to look for the libraries that are linked and

-l tells the linker to link the libraries - in this case libcudart (note that the lib is left off the name)



Ok - so now you have a shared cuda library :)



The question remains as to how to use it ...



Let's say you have a file main.c from which you wish to call the cuda function my_function



main.c would look something like:



#include "cuda_functions.h"



int main()

{

  my_function( 5 );

  return 0;

}





This program can now be compiled using gcc and linking in the cuda shared library.  For example





gcc -o out_file main.c -lname_of_shared_library





where name_of_shared_library is the name as in the preceding section.  If the library is not in the same folder as the file you are compiling you may need to specify the location using the -L flag.





Hope this help - please feel free to contact me again if you have any more questions - and perhaps post this on the forum if you get it working so that others with similar problems can be helped :)



Evan






Zaki: This is what I had to do to make it work.



The gcc command above would error out with

gcc -o main main.c -lname_of_shared_library

In file included from main.c:2:

../cuda_functions.h:2: error: expected identifier or ‘(’ before string constant

make: *** [main] Error 1





What I had to do was to create another cuda_functions.h for gcc, say name it cuda_functions_wo_extern_C.h



with the contents



my_function ( int my_parameter );

#8
Posted 07/29/2008 10:43 PM   
I have a very similar issue, but the fix I see posted above doesn't seem to work.

Here is the command I am using:

nvcc -Xcompiler '-fPIC' --shared -v myFile.cu -o output.so

However, when I use it, I get the following error:
[b] error: relocation R_X86_64_32S against `a local symbol' can not be used when making a shared object; recompile with -fPIC[/b]

The thread above says I need to create a .h file with a declaration of the external C function and include it in my .cu file. I have done this as follows:.

[i]below is the code of myFile.h[/i]
#ifndef CUDA_IMAGELOADER_H
#define CUDA_IMAGELOADER_H
extern "C" void launch_cudaCalculations(dim3 grid, dim3 block, int sbytes, float* g_data, float* g_odata, int imgw, int imgh, int tilew, int radius, float threshold, float highlight);
#endif


[i]below is the code snippet from myFile.cu:[/i]
#include "myFile.h"
extern "C" void launch_cudaCalculations(dim3 grid, dim3 block, int sbytes, float* in_dev_ptr, float* out_dev_ptr, int cols, int rows)
{ ... do stuff ... }

Now when I compile I get:
[b]myFile.cu(61): error: more than one instance of overloaded function "launch_cudaCalculations" has "C" linkage[/b]


Any ideas?
I have a very similar issue, but the fix I see posted above doesn't seem to work.



Here is the command I am using:



nvcc -Xcompiler '-fPIC' --shared -v myFile.cu -o output.so



However, when I use it, I get the following error:

error: relocation R_X86_64_32S against `a local symbol' can not be used when making a shared object; recompile with -fPIC



The thread above says I need to create a .h file with a declaration of the external C function and include it in my .cu file. I have done this as follows:.



below is the code of myFile.h

#ifndef CUDA_IMAGELOADER_H

#define CUDA_IMAGELOADER_H

extern "C" void launch_cudaCalculations(dim3 grid, dim3 block, int sbytes, float* g_data, float* g_odata, int imgw, int imgh, int tilew, int radius, float threshold, float highlight);

#endif





below is the code snippet from myFile.cu:

#include "myFile.h"

extern "C" void launch_cudaCalculations(dim3 grid, dim3 block, int sbytes, float* in_dev_ptr, float* out_dev_ptr, int cols, int rows)

{ ... do stuff ... }



Now when I compile I get:

myFile.cu(61): error: more than one instance of overloaded function "launch_cudaCalculations" has "C" linkage





Any ideas?

#9
Posted 10/06/2009 09:57 PM   
[quote name='zakim' post='417854' date='Jul 30 2008, 12:43 AM']This is from Evan Lezar with final bits from me to make it work




Zaki: This is what I had to do to make it work.

The gcc command above would error out with
gcc -o main main.c -lname_of_shared_library
In file included from main.c:2:
../cuda_functions.h:2: error: expected identifier or ‘(’ before string constant
make: *** [main] Error 1


What I had to do was to create another cuda_functions.h for gcc, say name it cuda_functions_wo_extern_C.h

with the contents

my_function ( int my_parameter );[/quote]

Regarding the extern issue with gcc (zakim). I have since found that following definition in the .h file allows one to use a single file:

[codebox]// the following is needed to allow for the compilation with nvcc as well as gcc
#ifdef __cplusplus
#define CHECK_EXT extern "C"
#else
#define CHECK_EXT
#endif

CHECK_EXT void function_def ();[/codebox]

Thus, I have defined a macro, CHECK_EXT that is blank if a C compiler is used (as opposed to a C++ compiler). This macro is then prefixed to any function definitions.

As far as I can tell this is due to nvcc and gcc defaulting to either C or C++ compilation. If someone has a better explanations, it would be much appreciated.

@muffinman104: In order to compile with the -fPIC switch using nvcc , one needs to use the --compiler-options -fPIC -shared nvcc options.

For example, the following line is what I use to compile a shared library that is to be built using cublas:

[b]nvcc --shared --compiler-options -fPIC -shared lib_cuda_blas_backend.cu -o libcuda_blas_backend.so -L/usr/local/cuda/lib -lcublas[/b]

The shared library [b]libcuda_blas_backend.so[/b] can then be linked to another C program as normal.

Please let me know if anything is unclear or you have more questions.

Evan
[quote name='zakim' post='417854' date='Jul 30 2008, 12:43 AM']This is from Evan Lezar with final bits from me to make it work









Zaki: This is what I had to do to make it work.



The gcc command above would error out with

gcc -o main main.c -lname_of_shared_library

In file included from main.c:2:

../cuda_functions.h:2: error: expected identifier or ‘(’ before string constant

make: *** [main] Error 1





What I had to do was to create another cuda_functions.h for gcc, say name it cuda_functions_wo_extern_C.h



with the contents



my_function ( int my_parameter );



Regarding the extern issue with gcc (zakim). I have since found that following definition in the .h file allows one to use a single file:



[codebox]// the following is needed to allow for the compilation with nvcc as well as gcc

#ifdef __cplusplus

#define CHECK_EXT extern "C"

#else

#define CHECK_EXT

#endif



CHECK_EXT void function_def ();[/codebox]



Thus, I have defined a macro, CHECK_EXT that is blank if a C compiler is used (as opposed to a C++ compiler). This macro is then prefixed to any function definitions.



As far as I can tell this is due to nvcc and gcc defaulting to either C or C++ compilation. If someone has a better explanations, it would be much appreciated.



@muffinman104: In order to compile with the -fPIC switch using nvcc , one needs to use the --compiler-options -fPIC -shared nvcc options.



For example, the following line is what I use to compile a shared library that is to be built using cublas:



nvcc --shared --compiler-options -fPIC -shared lib_cuda_blas_backend.cu -o libcuda_blas_backend.so -L/usr/local/cuda/lib -lcublas



The shared library libcuda_blas_backend.so can then be linked to another C program as normal.



Please let me know if anything is unclear or you have more questions.



Evan

#10
Posted 11/07/2009 11:46 PM   
Thank You for your suggestion. I have used your this following command to create .so file. [b]nvcc --shared --compiler-options -fPIC -shared lib_cuda_blas_backend.cu -o libcuda_blas_backend.so -L/usr/local/cuda/lib -lcublas [/b] replaced command - [b]/usr/local/cuda-7.0/bin/nvcc --shared -Xcompiler -fPIC -shared add.cu -o libcuda_add.so [/b] While linking this file with c file i.e. main.c it showing error Command- [b]gcc -o main main.c -llibadd.so [/b] error- /usr/bin/ld: cannot find -llibadd.so collect2: ld returned 1 exit status Please let me know where i am getting wrong.
Thank You for your suggestion.
I have used your this following command to create .so file.
nvcc --shared --compiler-options -fPIC -shared lib_cuda_blas_backend.cu -o libcuda_blas_backend.so -L/usr/local/cuda/lib -lcublas

replaced command -
/usr/local/cuda-7.0/bin/nvcc --shared -Xcompiler -fPIC -shared add.cu -o libcuda_add.so


While linking this file with c file i.e. main.c it showing error

Command-
gcc -o main main.c -llibadd.so

error-
/usr/bin/ld: cannot find -llibadd.so
collect2: ld returned 1 exit status

Please let me know where i am getting wrong.

#11
Posted 03/31/2016 10:36 AM   
usually with the -l option you don't pass the "lib" prefix and the ".so" suffix of libary names. It would be -ladd or -lcuda_add Christian
usually with the -l option you don't pass the "lib" prefix and the ".so" suffix of libary names. It would be

-ladd or -lcuda_add

Christian

#12
Posted 03/31/2016 10:44 AM   
Thank You. I have resolved the issue.
Thank You. I have resolved the issue.

#13
Posted 04/05/2016 02:52 PM   
Scroll To Top

Add Reply