在Delphi程序中使用CUDA调用运行C函数

在Delphi程序中使用CUDA调用运行C函数,c,cuda,freepascal,C,Cuda,Freepascal,我的目标是得到一个Delphi(或freepascal)代码,它将调用C函数func,如下所示: C/Cuda文件: /* this is the "progcuda.cu" file */ #include <stdio.h> __global__ void foo(int *a, int *b, int *c, int n){ /* add all the vector's element */ } void func(int *a, int *b,

我的目标是得到一个Delphi(或freepascal)代码,它将调用C函数func,如下所示:

C/Cuda文件:

/* this is the "progcuda.cu" file */
#include <stdio.h>

__global__ void foo(int *a, int *b, int *c, int n){
    /*
    add all the vector's element
    */
}


void func(int *a, int *b, int *c,int n){
    int *da,*db,*dc;
    cudaMalloc(&da, n*sizeof(int));
    cudaMalloc(&db, n*sizeof(int));
    cudaMalloc(&dc, n*sizeof(int));

    cudaMemcpy(da,a,sizeof(int)*n,cudaMemcpyHostToDevice);
    cudaMemcpy(db,b,sizeof(int)*n,cudaMemcpyHostToDevice);
    cudaMemcpy(dc,c,sizeof(int)*n,cudaMemcpyHostToDevice);

    foo<<<1,256>>>(da,db,dc);
    cudaMemcpy(c,dc,sizeof(int),cudaMemcpyDeviceToHost);

    /* do other stuff and call another Host and Device functions*/

    return;
}
pascal单位文件:

// this is the "unitpas.pas" file
unit unitpas;
{$link progcuda.o}
interface

uses ctypes;
procedure func(a, b, c : cpint32 , n:cint32); cdecl; external;
procedure foo(a, b, c : cpint32 , n:cint32);cdecl; external;

implementation

end.
我找到了这篇文章,但它更多地展示了在delphi中编程CUDA的方法

我不想在Delphi中编程CUDA,我想用纯C/C++代码在CUDA中编程,并且只在Delphi中调用该C函数

有什么问题? 如何将.cu代码链接到delphi代码

我使用的是LinuxUbuntu16.04LTS,但如果需要的话,我在windows中也有CUDA和VS

注意:如果你们能详细解释一下怎么做,会有帮助的(pascal和链接文件的新手)


我已经尝试生成.o对象文件,并在免费pascal中将其链接到
$nvcc progcuda.cu-c-o progcuda.o
然后
$fpc progpas.pas

但它在链接方面失败了

注意:我曾经尝试过使用gcc和freepascal编译器将C代码生成的普通.o链接到pascal代码,并且成功了,但是如果我使用nvcc而不是gcc,并将扩展名重命名为.cu(仍然是相同的代码),链接将失败



注释:堆栈溢出中的新帐户,我不能回答。

< P>我对Delphi和FreePascal一无所知,但我知道CUDA、C和C++,所以我的解决方案也会对你有用。 我将用一个简单的问题来演示它:

f.cu的内容

int f() { return 42; }
main.c的内容

extern int f();

int main() {
    return f();
}
以下工作:

$ gcc -c -xc f.cu # need -xc to tell gcc it's a C file
$ gcc main.c f.o
(no errors emitted)
现在,当我们尝试将
gcc
替换为
nvcc

$ nvcc -c f.cu
$ gcc main.c f.o
/tmp/ccI3tBM1.o: In function `main':
main.c:(.text+0xa): undefined reference to `f'
f.o: In function `__cudaUnregisterBinaryUtil()':
tmpxft_0000704e_00000000-5_f.cudafe1.cpp:(.text+0x52): undefined reference to `__cudaUnregisterFatBinary'
f.o: In function `__nv_init_managed_rt_with_module(void**)':
tmpxft_0000704e_00000000-5_f.cudafe1.cpp:(.text+0x6d): undefined reference to `__cudaInitModule'
f.o: In function `__sti____cudaRegisterAll()':
tmpxft_0000704e_00000000-5_f.cudafe1.cpp:(.text+0xa9): undefined reference to `__cudaRegisterFatBinary'
collect2: error: ld returned 1 exit status
这里的问题是,
nvcc
在编译
f.cu
时添加了对CUDA运行时API中某些符号的引用,这些符号必须链接到最终的可执行文件。我的CUDA安装在
/opt/CUDA
中,因此我将使用它,但您必须将其替换为系统上安装CUDA的任何位置。因此,如果我们在编译库时链接
libcudart.So
,我们会得到:

$ nvcc -c f.cu
$ gcc main.c f.o -L/opt/cuda/lib64 -lcudart
/tmp/ccUeDZcb.o: In function `main':
main.c:(.text+0xa): undefined reference to `f'
collect2: error: ld returned 1 exit status
这看起来更好,没有奇怪的错误,但仍然找不到函数
f
。这是因为 NVCC 将代码> F.Cu<代码>作为C++文件,所以在创建对象文件时,它会命名为“MULFIN”,并且我们必须指定“<代码> f>代码>具有C,而不是C++链接(参见这里更多)。 为此,我们必须修改
f.cu
如下:

extern "C" int f() { return 42; }
现在,当我们这样做时:

$ nvcc -c f.cu
$ gcc main.c f.o -L/opt/cuda/lib64 -lcudart
(no errors emitted)
我希望你能设法修改它以适应你的语言

编辑:我尝试了一个更复杂的例子:

// f.cu
#include <stdio.h>

__global__ void kernel() {
    printf("Running kernel\n");
}

extern "C" void f() {
    kernel<<<1, 1>>>();
    // make sure the kernel completes before exiting
    cudaDeviceSynchronize();
}

// main.c
extern void f();

int main() {
    f();
    return 0;
}
为了修复它,还需要向链接标志添加标准C++库:

$ nvcc -c f.cu
$ gcc main.c f.o -L/opt/cuda/lib64 -lcudart -lstdc++
$ ./a.out
Running kernel

我修复了@Goran Flegar解释的文件: 添加
extern“C”int func(…)到.cu文件。然后尝试编译/链接.cu代码,但没有设备调用(但使用设备代码),并且都运行良好

但是当我添加一个设备调用(
foo(…)
)并编译时:

$nvcc progcuda.cu -c
$fpc progpas.pas -ofinal.exe -Fl/usr/local/cuda/lib64
我得到:

Free Pascal Compiler version 3.0.4 [2017/12/13] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling prog1.pas
Linking sum.exe
/usr/bin/ld: aviso: link.res contém seções de saída; você se esqueceu -T?
/usr/bin/ld: sum.o: undefined reference to symbol '_Unwind_Resume@@GCC_3.0'
//lib/x86_64-linux-gnu/libgcc_s.so.1: error adding symbols: DSO missing from command line
prog1.pas(16,1) Error: Error while linking
prog1.pas(16,1) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Error: /usr/bin/ppcx64 returned an error exitcode
所以还缺少一些LIB


解决方案:

发现将stdc++和gcc_库链接到pascal解决了编译问题

unit unitpas;
// file "unitpas.pas"
{$LINK progcuda.o}
{$LINKLIB c}
{$LINKLIB cudart}
{$linklib stdc++}
{$linklib gcc_s}

interface

uses ctypes;
function func(x,y: cint32): cint32; cdecl; external;

implementation

end.


一切都正常。

也许我的答案就足以解决问题。如果您还包括您得到的确切链接错误,我们将能够更好地帮助您。
Free Pascal Compiler version 3.0.4 [2017/12/13] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling prog1.pas
Linking sum.exe
/usr/bin/ld: aviso: link.res contém seções de saída; você se esqueceu -T?
/usr/bin/ld: sum.o: undefined reference to symbol '_Unwind_Resume@@GCC_3.0'
//lib/x86_64-linux-gnu/libgcc_s.so.1: error adding symbols: DSO missing from command line
prog1.pas(16,1) Error: Error while linking
prog1.pas(16,1) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Error: /usr/bin/ppcx64 returned an error exitcode
unit unitpas;
// file "unitpas.pas"
{$LINK progcuda.o}
{$LINKLIB c}
{$LINKLIB cudart}
{$linklib stdc++}
{$linklib gcc_s}

interface

uses ctypes;
function func(x,y: cint32): cint32; cdecl; external;

implementation

end.
$nvcc progcuda.cu -c
$fpc progpas.pas -ofinal.exe -Fl/usr/local/cuda/lib64