I have a large project in C and i'm trying to integrate some Cuda kernels in it. I'm compiling my c-files with "gcc -c main.c" and my .cu files with "nvcc -c cuda_GMRES.cu" and then I try to link the 2 object files with nvcc: "nvcc -o main.o cuda_GMRES.o" and receive the following error:
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function
_start':
(.text+0x20): undefined reference tomain'
collect2: ld returned 1 exit status
It's the first time I'm trying to combine cuda with C files and I might have done something wrong.Can someone help me please. I'm on a GPU Cluster with Rocks OS.
My main.c file:
#include <stdio.h>
#include <math.h>
#include "cuda_wrapper.h" //header containing wrapper function
//cuda_GMRES that calls the kernel cuda_dot
int main (int argc,char* argv[])
{
//content
//bla bla bla
//cuda Function call
cuda_GMRES(50);
return 0;
}
My cuda_wrapper.h file:
#ifndef Cuda_GMRES_cuda_wrapper_h
#define Cuda_GMRES_cuda_wrapper_h
//wrapper function declaration
void cuda_GMRES(double a);
#endif
My cuda_GMRES.cu file that contains the kernel calling function:
#include <stdio.h>
#include "cuda_wrapper.h"
#include "cuda_dot.cu"
//kernel declaration
__global__ void cuda_dot();
//kernel calling function
extern "C"
void cuda_GMRES(double a)
{
double b;
double *dev_a;
double *res;
cudaMemcpy(dev_a, &a, sizeof(double), cudaMemcpyHostToDevice );
cuda_dot<<< 1, 1 >>>(*dev_a, res );
cudaMemcpy(&b, res, sizeof(double), cudaMemcpyDeviceToHost );
}
My cuda_dot.cu file that contains the kernel:
__global__ void cuda_dot(double a, double *help)
{
*help=2*a;
}
Your linking command appears to contain a fatal error. Supposing you first compile two objects like this:
gcc -c main.c
nvcc -c cuda_GMRES.cu
you should have two object files main.o and cuda_GMRES.o. You then do this:
nvcc -o main.o cuda_GMRES.o
This command says "link a program file called main.o using cuda_GMRES.o", ie. overwrite main.o. It is for this reason that the linker is complaining about a missing main subroutine, you are not supplying one (and you are destroying the object file which contains one at the same time).
You want something like this:
nvcc -o executable main.o cuda_GMRES.o
where executable is the name of the final linked program, or
nvcc main.o cuda_GMRES.o
which will emit a default linked program called a.out
Related
I have a project I'm working on that currently has a matrix.c file containing a some functions and has a corresponding header matrix.h. I made a shared library libccalc.so using matrix.c and another file. I am trying to create a directory in /usr/local/lib and a directory in /usr/local/include, both called ccalc to house the respective .so and .h files which can then later be used to compile programs using the functionality of libccalc.so. However, when I do this I am getting an error.
To be precise, matrix.c contains functions:
Matrix *mat_create(int rows, int cols),
void mat_fill(Matrix *mat, double *entries) and
void mat_print(Matrix *mat)
which are declared in matrix.h. I place the files in their respective directories as explained above, I run ldconfig /usr/local/lib/ccalc and I make a new file test.c in some other directory with the following:
// test.c
#include <stdio.h>
#include "matrix.h"
int main() {
Matrix *m = mat_create(2, 2);
double entries[4] = {1, 2, 3 ,4};
mat_fill(m, entries);
mat_print(m);
return 0;
}
matrix.h contains the following:
// matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#define MAX_SIZE 50
typedef struct Matrix Matrix;
struct Matrix {
int rows;
int cols;
double *data;
};
Matrix *mat_create(int n, int p);
void mat_fill(Matrix *mat, double *entries);
void mat_print(Matrix *mat);
#endif
When I enter the command: gcc -I/usr/local/include/ccalc -L/usr/local/lib/ccalc -lccalc test.c -o test, I get the error:
/usr/bin/ld: /tmp/ccesD44J.o: in function `main':
test.c:(.text+0x26): undefined reference to `mat_create'
/usr/bin/ld: test.c:(.text+0x71): undefined reference to `mat_fill'
/usr/bin/ld: test.c:(.text+0x7d): undefined reference to `mat_print'
collect2: error: ld returned 1 exit status
However, when I place libccalc.so and matrix.h in /usr/local/lib and /usr/local/include, enter ldconfig and enter the command gcc -L/usr/local/lib/ccalc -lccalc test.c -o test, and run ./test, it works perfectly
Can someone tell me what I am doing wrong?
The order of program arguments to gcc matters a lot. Please read the documentation about Invoking GCC.
Also, test is often a builtin command. See test(1).
So (on Linux) rename test.c as prog.c then compile your program with
gcc -Wall -Wextra -g prog.c -L/usr/local/lib/ccalc -lccalc -o prog
Then use strace(1) and gdb(1) to understand the behavior of prog, and ldd(1), objdump(1) with readelf(1) to analyze prog. See also elf(5) and ld.so(8).
Regarding building shared libraries, read Drepper's paper How to write shared libraries
You probably want to compile matrix.c into libcalc.so using
gcc -fPIC -Wall -O -shared -g matrix.c -o libcalc.so
but you might need other program arguments.
Regarding matrix operations, this answer could be inspirational.
I have source files written in C programming using notepad++ and I am running them from command lines and later i need to link them inorder to generate the .exe file.
Here are the following commands I want to use while generating .exe file
gcc logc.c -o logc
gcc mainc.c -o mainc
gcc -o output logc.o mainc.o
But when i run the following command my compiler is returning with the following error status.
gcc logc.c -o logc
(x86)/mingw-w64/i686-8.1.0-win32-dwarf-rt_v6-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/lib/../lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x39): undefined reference to `WinMain#16'
when i run the following command to compile my mainc file
C:\Users\user\AppData\Local\Temp\ccskY3nf.o:mainc.c:(.text+0x31): undefined reference to `Log'
collect2.exe: error: ld returned 1 exit status
And here are my mainc.c and logc.c and logc.h files for your reference
logc.c file is here
#include <stdio.h>
#include "logc.h"
void InitLog()
{
Log("Initializing Log");
}
void Log(const char* message)
{
printf(" %s",message);
}
mainc.c file is here
#include <stdio.h>
#include <conio.h>
#include <stdbool.h>
#include "logc.h"
int main()
{
int x = 5;
bool comparisonResult = x == 5;
if(comparisonResult == 1)
Log("Hello World");
return 0;
}
and logc.h file is here
#ifndef _LOG_H
#define _LOG_H
void InitLog();
void Log(const char* message);
#endif
How can i compile individual source files and then link them and generate an executable file.
Thanks in advance.
You don't create object files, for that you need the -c argument:
gcc logc.c -c
gcc mainc.c -c
gcc -o output logc.o mainc.o
By default gcc will generate an executable file, not an object file. So when you compile logc.c, it tries to make an executable but it can't find the main function so it fails. Similarly with main.c, it tries to make an executable but can't find Log
You need to add the -c option to create object files:
gcc logc.c -c -o logc.o
gcc mainc.c -c -o mainc.o
My objective is to have a Delphi( or freepascal) code, that will call the C function func like this one:
The C/Cuda file:
/* 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;
}
The pascal main file:
// this is the "progpas.pas" file
program progpas;
{$mode objfpc}{$H+}
uses unitpas;
var
...
begin
...
func(a, b, c, len);
...
end.
The pascal unit file:
// 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.
I've found this post Programming CUDA using Delphi or FreePascal
, but it shows more a way to program CUDA in delphi.
I don't want to program CUDA in Delphi, I want to program in CUDA in pure C/C++ code and only call that C function in delphi.
What is the problem?
How can I link the .cu code to the delphi one?
I'm using linux ubuntu 16.04 LTS, but I also have CUDA and VS in windows if necessary.
Note: if you guys could explain in detail how to do it, would help ( new to pascal and linking files )
I've already tried to generate the .o object file and link it in free pascal with
$ nvcc progcuda.cu -c -o progcuda.o then $fpc progpas.pas
but it fails at linking.
Note: I've tried once to link a normal .o generated by C code to pascal code, using gcc and freepascal compiler, and it worked, but if I use nvcc instead of gcc and rename the extension to .cu ( still same code), the linking fails.
note: new account in stack overflow, i cannot repply answers yet.
I don't know anything about Delphi and FreePascal, but I do know about CUDA, C and C++, so maybe my solution will also work for you.
I'll be demonstrating it with a simple problem:
Content of f.cu:
int f() { return 42; }
Content of main.c:
extern int f();
int main() {
return f();
}
The following works:
$ gcc -c -xc f.cu # need -xc to tell gcc it's a C file
$ gcc main.c f.o
(no errors emitted)
Now when we try replacing gcc with 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
The problem here is that nvcc adds references to some symbols from the CUDA runtime API when compiling f.cu, and these symbols have to be linked to the final executable. My CUDA installation is in /opt/cuda, so I will use that, but you have to replace it with wherever CUDA is installed on your system. So if we link libcudart.so when compiling the library we get:
$ 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
This looks better, no strange errors, but it's still not finding the function f. That's because nvcc is treating f.cu as a C++ file, so it does name mangling when creating the object file, and we have to specify that we want f to have C, and not C++ linkage (see more here: http://en.cppreference.com/w/cpp/language/language_linkage).
To do that we have to modify f.cu like this:
extern "C" int f() { return 42; }
Now when we do:
$ nvcc -c f.cu
$ gcc main.c f.o -L/opt/cuda/lib64 -lcudart
(no errors emitted)
I hope you manage to modify this to work with your language.
EDIT: I tried a bit more complicated example:
// 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;
}
When compiling it I got:
f.o:(.data.DW.ref.__gxx_personality_v0[DW.ref.__gxx_personality_v0]+0x0): undefined reference to `__gxx_personality_v0'
collect2: error: ld returned 1 exit status
To fix it you also need to add the standard C++ libraries to the linker flags:
$ nvcc -c f.cu
$ gcc main.c f.o -L/opt/cuda/lib64 -lcudart -lstdc++
$ ./a.out
Running kernel
I fixed the files as #Goran Flegar explained:
Add extern "C" int func(...); to the .cu file. And then tried to compile/link the .cu code, but with no device calls (yet with device code), and all worked well.
but when i add a device call ( foo<<<Nb,Nt>>>(...) ) and compile with:
$nvcc progcuda.cu -c
$fpc progpas.pas -ofinal.exe -Fl/usr/local/cuda/lib64
i get:
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
So there's still some missing libs.
Solution:
Found that linking the stdc++ and gcc_s lib to pascal solved the compilation problem.
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.
Run
$nvcc progcuda.cu -c
$fpc progpas.pas -ofinal.exe -Fl/usr/local/cuda/lib64
and everything works.
I am developing a project with an ordeneted use of folders. I want a folder called /bin to store all the binary files and a folder called /src with all the .c and .h files.
The program will solve system of equations and all the functions related to matrix calculations will be compiled dynamically.
I have this folders:
/project/src/matrixlib (it will be the fynamic lybrary with all the matrix calculations)
With files:
matrix.c
#include<stdio.h>
#include"matrix.h"
int matrix_alloc(int n, int m, Matrix *matrix);
{
//do whatever, this is not the problem
}
matrix.h
#ifndef matrix_h__
#define matrix_h__
struct Matrix
{
//definition here
};typedef struct Matrix Matrix;
extern int matrix_alloc(int, int, Matrix*);
#endif //matrix_h__
I compile this folder with:
gcc -c -Wall -Werror -fpic matrix.c
gcc -shared -o libmatrix.so matrix.o
Then I have the folder:
/project/src/main
With files:
main.c (using function "matrix_alloc" and including "matrix.h")
#include<stdio.h>
#include "matrix.h"
int main(void)
{
Matrix matrix;
matrix_alloc(3,3,&matrix);
return 0;
}
and I compile like this:
gcc -I/project/src/matrixlib -L/project/src/matrixlib -Wl,-rpath=/project/src/matrixlib -Wall main.c -o main
But I've got this error:
/tmp/cc8kLMIe.o: In function `main':
main.c:(.text+0x34): undefined reference to `matrix_alloc'
collect2: error: ld returned 1 exit status
But I don't really understand what is going on because matrix_alloc is in matrix.h folder.
Could you help me please?
Thanks
You're not linking libmatrix.so with your program. Add -lmatrix to your compiler invocation
gcc and CUDA question
Hi,
I have compiled a CUDA shared library but can't link it with the main program that uses it. I am compiling the main program with gcc.
The code:
simplemain.c
#include <stdio.h>
#include <stdlib.h>
void fcudadriver();
int main()
{
printf("Main \n");
fcudadriver();
return 0;
}
test.cu
__global__ void fcuda()
{
}
void fcudadriver()
{
fcuda<<<1,1>>>();
}
I compile test.cu as --> It works
nvcc --compiler-options '-fPIC' -o libtest.so --shared test.cu
I compile simplemain.c as ---> It gives error :(
gcc simplemain.c -L. -ltest
/tmp/ccHnB4Vh.o:simplemain.c:function main: error: undefined reference to 'fcudadriver'
collect2: ld returned 1 exit status
try using g++ instead of gcc. nvcc uses c++ style linking conventions. (You don't need to rename any files.)
alternatively, if you must use gcc, preface your void fcudadriver() function definition like this:
extern "C" void fcudadriver()
C and C++ name the functions in different way.
Since nvcc treat the CPU code in .cu file as C++, you could rename your simplemain.c to simplemain.cpp, and compile it with g++
Another solution could be adding extern "C" before the function definition in the .cu file.