1

cudaカーネルを含む1つの.cuファイルと、カーネルを呼び出すラッパー関数があります。.cファイルもたくさんあります。そのうちの1つにmain関数が含まれています。これらの.cファイルの1つは、.cuからラッパー関数を呼び出してカーネルを呼び出します。

これらのファイルを次のようにコンパイルします。

LIBS=-lcuda -lcudart
LIBDIR=-L/usr/local/cuda/lib64
CFLAGS = -g -c -Wall -Iinclude -Ioflib
NVCCFLAGS =-g -c -Iinclude -Ioflib
CFLAGSEXE =-g -O2 -Wall -Iinclude -Ioflib

CC=gcc
NVCC=nvcc
objects := $(patsubst oflib/%.c,oflib/%.o,$(wildcard oflib/*.c))

table-hash-gpu.o: table-hash.cu table-hash.h
        $(NVCC) $(NVCCFLAGS) table-hash.cu -o table-hash-gpu.o

main: main.c $(objects) table-hash-gpu.o
    $(CC) $(CFLAGSEXE) $(objects) table-hash-gpu.o -o udatapath udatapath.c $(LIBS) $(LIBDIR)

これまでのところ、すべてが順調です。table-hash-gpu.cuは、.cファイルの1つから関数を呼び出します。mainにリンクすると、関数が存在しないというエラーが表示されます。誰かが何が起こっているのか教えてもらえますか?

4

1 に答える 1

3

nvccは、ホストC ++コンパイラを使用してデバイスコードとホストコードの両方をコンパイルします。これは、名前マングリングを意味します。C ++でCコンパイラを使用してコンパイルされた関数を呼び出す必要がある場合は、C呼び出し規約を使用していることをC++コンパイラに通知する必要があります。私はあなたが見ているエラーはこれに類似していると思います:

$ cat cfunc.c 

float adder(float a, float b, float c)
{
    return a + 2.f*b + 3.f*c;
}

$ cat cumain.cu 

#include <cstdio>
float adder(float, float, float);

int main(void)
{
    float result = adder(1.f, 2.f, 3.f);
    printf("%f\n", result);
    return 0;
}

$ gcc -m32 -c cfunc.c
$ nvcc -o app cumain.cu cfunc.o
Undefined symbols:
  "adder(float, float, float)", referenced from:
      _main in tmpxft_0000b928_00000000-13_cumain.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

ここでは、nvcc(つまりホストC ++コンパイラ)でコンパイルされたコードがC関数を呼び出そうとし、リンクエラーが発生します。これは、C++コードadderが提供されたオブジェクトファイルでの名前が壊れていることを想定しているためです。メインが次のように変更された場合:

$ cat cumain.cu 

#include <cstdio>
extern "C" float adder(float, float, float);

int main(void)
{
    float result = adder(1.f, 2.f, 3.f);
    printf("%f\n", result);
    return 0;
}
$ nvcc -o app cumain.cu cfunc.o
$ ./app
14.000000

できます。extern "C"関数の宣言をC++コンパイラに限定するために使用すると、参照時にC ++のマングリングとリンケージのルールが使用されず、adder結果のコードが正しくリンクされます。

于 2012-09-04T05:25:07.833 に答える