c文件调用cuda函数
经过无数次的折腾,终于成功在C文件中调用了cu文件里面定义的函数。
*.c
文件可以用 gcc
或者 g++
编译, *.cu
文件需要用 nvcc
编译器编译,所以
.c文件调用.cu文件的函数
有三个文件, b.h
中声明了 kernel_wrapper
函数,在 b.cu
中实现, a.c
需要调用
kernel_wrapper
函数。
b.h
文件 1
2
3
4
5
6
7
8
9
10#ifndef __B_H_
#define __B_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cuda.h>
#include <cuda_runtime.h>
void kernel_wrapper(int *a);
#endif
b.cu
文件
1 | #include "b.h" |
a.c
文件
1 | #include "b.h" |
Makefile
文件: 1
2
3
4
5
6
7
8run: a.o b.o
gcc -L /usr/local/cuda/lib64 -o run a.o b.o -lcudart -lcuda
a.o: a.c b.h
gcc -I /usr/local/cuda/include -c -o a.o a.c
b.o: b.cu b.h
nvcc -c -o b.o b.cu
-I
告诉编译器查找头文件的位置。-L
告诉链接器查找需要链接库的位置。-l
告诉链接器链接的库文件,通常的名字是不加lib
的,比如libcudart.so
这里写cudart
。
现在进行编译,输入 make
,得到报错信息:
1 | undefined reference to `kernel_wrapper' |
解决办法
正如开头所说的, nvcc
使用 C++
编译器
g++
,而 c
文件要链接由 g++
编译的库,因此会报错。
解决办法就是告诉编译器,函数以 c
的方式来编译封装接口,而函数中的 C++
语法还是用
C++
来编译。
1 | // b.cu |
而且需要注意的是 CUDA 共享库需要在目标文件(*.o)后使用。
1
gcc -L /usr/local/cuda/lib64 -o run a.o b.o -lcudart -lcuda
另一方法是使用 g++
或者 nvcc
来链接,还未尝试。
.c文件调用.cu文件生成的.so库
还是上述修改过后的文件。
编译 b.cu
文件为 libcudab.so
动态链接库。
1 | nvcc --shared --compiler-options "-fpic -shared" b.cu -o libcudab.so -I /usr/local/cuda/include -L /usr/local/cuda/lib64 -lcudart -lcublas |
再编译并链接 a.c
。 1
gcc -o main a.c -L. -lcudab -I /usr/local/cuda/include
可能遇到的错误
error while loading shared libraries:XXX.so
- 如果共享库安装到了
/lib
或者/usr/lib
目录下,需要执行一下ldconfig
命令。
ldconfig
命令的用途,主要是在默认搜寻目录(/lib
和
/usr/lib
)以及动态库配置文件
/etc/ld.so.conf
内所列的目录下,搜索出可共享的动态链接库(格式如
lib*.so*
),进而创建出动态装入程序( ld.so
)所需的连接和缓存文件。缓存文件默认为 /etc/ld.so.cache
,此文件保存已排好序的动态链接库名字列表。
- 如果共享库文件安装到了
/usr/local/lib
(很多开源的共享库都会安装到该目录下)或其它 "非/lib或/usr/lib" 目录下, 那么在执行ldconfig
命令前,还要把新共享库目录加入到共享库配置文件/etc/ld.so.conf
中, 如下:
1 | # cat /etc/ld.so.conf |
- 如果共享库文件安装到了其它 "非/lib或/usr/lib" 目录下,但是又不想在
/etc/ld.so.conf
中加路径(或者是没有权限加路径)。那可以export
一个全局变量LD_LIBRARY_PATH
,然后运行程序的时候就会去这个目录中找共享库.。
参考
[1] Cuda C - Linker error - undefined reference [2] 在.c文件中调用c++定义的函数 [3] Linux下c和cuda混合编译,并生成动态链接库.so和使用