Problems using CUDA with Fortran

Hi everybody,

I need some help with CUDA and Fortran. I am writing 2 programs : one in Fortran and the other in CUDA.

testF.f :

program test

	  parameter(n = 3)

	  integer a(n)

	  a = (/ 1, 2, 3 /)

	  call doubleTAB(a, n)

	  do i = 1, 3

		 write(*,*) i, a(i)

	  enddo

	  stop

	  end

testCU.cu

#include <stdio.h>

__global__

void cudaDoubletab(int * tab, int n) {

  int idx = blockIdx.x * blockDim.x + threadIdx.x;

  if (idx < n) tab[idx] *= 2;

}

int doubletab_(int * h_tab, int * n) 

{ 

int * d_tab;

  size_t memSize = *n * sizeof(int);

  cudaMalloc((void **) &d_tab, memSize);

  cudaMemcpy(d_tab, h_tab, memSize, cudaMemcpyHostToDevice);

dim3 dimGrid(1);

  dim3 dimBlock(3);

  cudaDoubletab<<< 1, 3 >>>(d_tab, 3);

cudaMemcpy(h_tab, d_tab, memSize, cudaMemcpyDeviceToHost);

return (1);

}

But when I try to compil and to link, I have a lot of errors :

testF.o(.text+0x2c6): In function `MAIN__':

: undefined reference to `doubleijk_'

testF.o(.text+0x3f8): In function `MAIN__':

: undefined reference to `doublem_'

testF.o(.text+0x480): In function `MAIN__':

: undefined reference to `doubletab_'

testCU.o(.text+0x1d): In function `doubletab_(int*, int*)':

: undefined reference to `cudaMalloc'

testCU.o(.text+0x30): In function `doubletab_(int*, int*)':

: undefined reference to `cudaMemcpy'

testCU.o(.text+0x90): In function `doubletab_(int*, int*)':

: undefined reference to `cudaConfigureCall'

testCU.o(.text+0xb7): In function `doubletab_(int*, int*)':

: undefined reference to `cudaMemcpy'

testCU.o(.text+0xd8): In function `__cudaUnregisterBinaryUtil':

: undefined reference to `__cudaUnregisterFatBinary'

testCU.o(.text+0x4b34): In function `__iAtomicAdd':

: undefined reference to `__cudaMutexOperation'

testCU.o(.text+0x4b54): In function `__iAtomicAdd':

: undefined reference to `__cudaMutexOperation'

testCU.o(.text+0x4b6c): In function `__uAtomicAdd':

: undefined reference to `__cudaMutexOperation'

testCU.o(.text+0x4b8c): In function `__uAtomicAdd':

: undefined reference to `__cudaMutexOperation'

testCU.o(.text+0x4ba4): In function `__iAtomicExch':

: undefined reference to `__cudaMutexOperation'

testCU.o(.text+0x4bc1): more undefined references to `__cudaMutexOperation' follow

testCU.o(.text+0x70c9): In function `__itexfetchi':

: undefined reference to `__cudaTextureFetch'

testCU.o(.text+0x70ef): In function `__utexfetchi':

: undefined reference to `__cudaTextureFetch'

testCU.o(.text+0x7115): In function `__ftexfetchi':

: undefined reference to `__cudaTextureFetch'

testCU.o(.text+0x713b): In function `__itexfetch':

: undefined reference to `__cudaTextureFetch'

testCU.o(.text+0x7161): In function `__utexfetch':

: undefined reference to `__cudaTextureFetch'

testCU.o(.text+0x7187): more undefined references to `__cudaTextureFetch' follow

testCU.o(.text+0xc526): In function `__device_stub__Z13cudaDoubletabPii':

: undefined reference to `cudaSetupArgument'

testCU.o(.text+0xc53f): In function `__device_stub__Z13cudaDoubletabPii':

: undefined reference to `cudaSetupArgument'

testCU.o(.text+0xc591): In function `__sti____cudaRegisterAll_41_tmpxft_00000163_00000000_4_t

estCU_cpp1_ii_95e70681':

: undefined reference to `__cudaRegisterFatBinary'

testCU.o(.text+0xc5d2): In function `__sti____cudaRegisterAll_41_tmpxft_00000163_00000000_4_t

estCU_cpp1_ii_95e70681':

: undefined reference to `__cudaRegisterFunction'

testCU.o(.gnu.linkonce.t._Z10cudaLaunchIcE9cudaErrorPT_+0xd): In function `cudaError cudaLaunch<char>(char*)':

: undefined reference to `cudaLaunch'

testCU.o(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'

collect2: ld a retourné 1 code d'état d'exécution

PS : I use :

gfortran -c testF.f

nvcc -c testCU.cu

gfortran -o test testF.o testCU.o

You must specifies cuda lib when linkink

gfortran -o test testF.o testCU.o -lcuda -lcudart -L $CUDA_LIBDIR

You need to link the cudart library and the stdc++ one.

gfortran -o test testF.o testCU.o -L/usr/local/cuda/lib64 -lcudart -lstdc++

If you call your executable test, be careful to launch the right executable and not the one coming with Linux.

doubletab should be a void.

Thanks for the quick reply.

I don’t understand why i need to add the stdc++ one. So i use the following command :

gfortran -o test testF.o testCU.o -L/usr/include/cuda/lib -lcudart -lcuda

But i still have errors :

testF.o(.text+0xae): In function `MAIN__':

: undefined reference to `doubletab_'

collect2: ld a retourné 1 code d'état d'exécution

run objdump on testCU.o. I am guessing C++ function name mangling is occurring. Either declare doubletab_ using extern “C”, or pass --host-compilation C to nvcc to force it to use the host C rather than C++ compiler. You need libstdc++ because the CUDA runtime requires it and gfortran won’t automagically link it in, unlike if you used g++ as a linker.

huuuuum… I don’t understand the extern keyword : I thought it was used to precised that a C function is defined in an other compilation unit. Do I need to do something like that??

extern "C" 

void doubletab_(int * h_tab, int * n) 

{ 

int * d_tab;

  size_t memSize = *n * sizeof(int);

  cudaMalloc((void **) &d_tab, memSize);

  cudaMemcpy(d_tab, h_tab, memSize, cudaMemcpyHostToDevice);

dim3 dimGrid(1);

  dim3 dimBlock(3);

  cudaDoubletab<<< 1, 3 >>>(d_tab, 3);

cudaMemcpy(h_tab, d_tab, memSize, cudaMemcpyDeviceToHost);

}

If yes I have same the same error as before :

testF.o(.text+0xae): In function `MAIN__':

: undefined reference to `doubletab_'

collect2: ld a retourné 1 code d'état d'exécution

I fix my problem! I forget to put extern “C” in my header file. But I still want to know why I need to use these keyword… please

I already explained it. C++ uses function name mangling, and CUDA compiles host code using C++ by default. The extern “C” declaration tells the C++ compiler to use C function naming and argument passing conventions rather than C++ when compiling a function defined that way. The result is that function name mangling is turned off and your function has a nice, predictable name in the object code that “dumb” linkers (like C and fortran) can understand.

Thank you very much!!