Linking C code with Cuda code - c

So I'm writing a very basic CUDA code (vector addition) to teach myself the basics of CUDA programming. I've got it working when I write one .cu file, but now I am trying to make it work with a .c and .cu file linked together. My main.c file is as follows:
#include "Test.h"
#include <stdlib.h>
int main(int argc, char *argv[]) {
int n = 1000;
size_t size = n * sizeof(float);
int i;
float *h_a = malloc(size), *h_b = malloc(size), *h_c = malloc(size);
for(i = 0; i < n; i++) {
h_a[i] = h_b[i] = i;
}
addVec(h_a, h_b, h_c, n);
exit(0);
}
Here, Test.h simply says:
void addVec(float *, float *, float *, int);
My vecAdd.cu file says:
#include "Test.h"
__global__ void vecAdd(float *a, float *b, float *c, int n) {
int i = blockDim.x * blockIdx.x + threadIdx.x;
if(i < n)
c[i] = a[i] + b[i];
}
void addVec(float *a, float *b, float *c, int n) {
float *d_a, *d_b, *d_c;
size_t size = n * sizeof(float);
cudaMalloc(&d_a, size);
cudaMalloc(&d_b, size);
cudaMalloc(&d_c, size);
...
}
I then run the commands:
gcc -c -Wall -O3 main.c -o ../obj/main.o
nvcc -c -O3 vecAdd.cu -o ../obj/vecAdd.o
gcc -L/usr/local/cuda/lib64 -lcudart ../obj/main.o ../obj/vecAdd.o -o ../bin/nvTest
The first two work fine. The last one, when I try to link the two object files, tells me that I have an undefined reference to addVec, though it is defined in vecAdd.cu... what am I doing wrong?

You have a C/C++ linkage problem that is basically identical to that described here. This is because nvcc is using a c++ compiler for host code (creating c++ style linkage references i.e. "mangling") and gcc is interpreting main.c as a c (not c++) file and therefore creating c style linkage references.
There are at least 2 ways to fix it:
convert your main.c into a main.cpp and use g++ where you are using gcc now (for your first and 3rd compile and link steps). Then everything will be consistently c++ style references.
Declare within your C++ module (vecAdd.cu) that the external reference should be C style as described here.

Related

How to link main with made libraries?

I'm trying to link libraries I made to main source code, but it throws this error. I've been searching for last two hours how to fix this but nothing worked for me.
Compiling:
cd "c:\Users\miros\OneDrive\Documents\C codes\labovi"
gcc 01main.c -o 01main
.\01main
d:/programs/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: C:\Users\miros\AppData\Local\Temp\ccGHtHKg.o:01main.c:(.text+0x46): undefined reference to 'faktorijel'
d:/programs/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: C:\Users\miros\AppData\Local\Temp\ccGHtHKg.o:01main.c:(.text+0x72): undefined reference to 'suma'
collect2.exe: error: ld returned 1 exit status
01ucitavanje.h
#ifndef UCITAVANJE_H
#define UCITAVANJE_H
#include <stdio.h>
#include <stdlib.h>
long long *niz;
int n;
void ucitavanje();
#endif
01ucitavanje.c
#include "01ucitavanje.h"
void ucitavanje(){
scanf("%d", &n);
niz = malloc(sizeof(long long) * n);
for (int i = 0; i < n; i++)
scanf("%d", niz + i);
}
01izracunavanje.h
#ifndef IZRACUNAVANJE_H
#define IZRACUNAVANJE_H
#include <stdio.h>
long long faktorijel(int n);
long long suma(long long *niz, int n);
#endif
01izracunavanje.c
#include "01izracunavanje.h"
long long faktorijel(int n){
long long f;
for (int i = 2; i <= n; i++)
f *= i;
return f;
}
long long suma (long long *niz, int n){
long long s = niz[0];
for (int i = 1; i < n; i++)
s += niz[i];
return s;
}
main.c
#include "01izracunavanje.h"
#include "01ucitavanje.h"
int main(){
ucitavanje();
for (int i = 0; i < n; i++)
niz[i] = faktorijel((int)niz[i]);
printf("%d", suma(niz, n));
free(niz);
return 0;
}
You're compiling only main.c into the executable, so the other functions aren't available.
You need to compile each source file into an object file, then link the object files together.
gcc -c main.c
gcc -c 01izracunavanje.c
gcc -c 01ucitavanje.c
gcc -o 01main main.o 01izracunavanje.o 01ucitavanje.o
I'm going to give you a mid-line correction because you put your compilation on one very long line.
In this case, you pass all your .c files to gcc. From
{ gcc 01main.c -o 01main }
We'd rather write
{ gcc -o 01main 01main.c 01izracunavanje.c 01ucitavanje.c }
Since you're not actually building a distribution library but rather a bunch of source files we just compile them all together. It generates better code that way anyway once you start optimizing.
Order of .c files doesn't really matter, but the file containing main is first by tradition. Putting -o before the first .c file used to matter and most people still do it.

Invalid conversion 'void*' to 'struct*' [duplicate]

This question already has answers here:
malloc - invalid conversion from void* to double*
(2 answers)
Closed 4 years ago.
I'm beginner in C. I'm trying to practice with solving some problems. And I'm getting this error when I compile my code.
[Error] invalid conversion from 'void*' to 'triangle*' [-fpermissive]
The code and purpose is explained below.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct triangle
{
int a;
int b;
int c;
};
typedef struct triangle triangle;
//sort_by_area() function is here
int main()
{
int n;
scanf("%d", &n);
triangle *tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}
As you can see I have structure and I tried to allocate memory for it with the quantity of input. And try to use it for sort_by_area function. But the problem is triangle *tr = malloc(n * sizeof(triangle)); line gives me the error mentioned above.
Also this code is working for online compilers. I tried to run this code on DEV C++ with default settings. I don't know about the versions and changing the versions of my compiler. I don't even know whether it is about the compiler version. But I am wondering why I'm getting this error. What is the logic behind.
This looks like C code, but you're compiling with a C++ compiler. As such, it complains on the line you mentioned because malloc returns a void * but you're assigning the result to a triangle *.
In C++ an explicit cast is required for this. In C, a void * may be implicitly converted to or from any object pointer type.
Since this appears to be C code and not C++ code, you should compile with a C compiler.
You compile this program as C++ program and this implicit conversion is not allowed in C++.
As I know dev C++ uses MinGW and you may use -xc option to compile program as C program or Settings -> language standard -> and choose the language standard needed
The code looks like C code but you are compiling it with C++ compiler.
Make sure that the file has proper extension for C++(not .c extension).
malloc() returns a (void *) pointer by default, so you have to explicitly cast the (void *) to (triangle *) in your code.
But if you are writing C++ code then I would recommend not to use malloc and free, instead try to use "new" operator in C++ since while instantiating objects it will call the constructors as well(unlike in malloc).
So to avoid complications go with new and delete in C++.
The code in C should look like (file a.c)
Compile using: gcc a.c -o a.o
Run using : ./a.o
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct triangle {
int a;
int b;
int c;
};
typedef struct triangle triangle;
int main() {
int n;
scanf("%d", &n);
triangle *tr = (triangle *)malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
//sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
free(tr);
return 0;
}
The same code in C++ would look like (file a.cpp)
Compile using: g++ a.cpp -o a.o
Run using : ./a.o
#include <iostream>
using namespace std;
struct triangle {
int a;
int b;
int c;
};
int main() {
int n;
cin >> n;
triangle *tr = new triangle[n];
for (int i = 0; i < n; i++) {
cin >> tr[i].a >> tr[i].b >> tr[i].c;
}
// sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
cout << tr[i].a << " " << tr[i].b << " " << tr[i].c << "\n";
}
delete [] tr;
return 0;
}
triangle *tr = (triangle*)malloc(n * sizeof(triangle));
Change the line as shown above. malloc returns generic pointer, so you need to explicitly typecast it to your desired pointer.
Refer this

Undefined reference to function from linked library

I am trying to use the cblas library for matrix multiplication, but get "undefined reference to `cblas_dgemm'" when I try to compile, even though the library should be linked properly.
Code in test.c looks like this:
...
#include <cblas.h>
void reference_dgemm (int N, double ALPHA, double* A, double* B, double* C)
{
int ORDER = 101; // row major
char TRANSA = 111; // no transpose
char TRANSB = 111;
int M = N;
int K = N;
double BETA = 1.;
int LDA = N;
int LDB = N;
int LDC = N;
cblas_dgemm(ORDER, TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC);
}
is compiled like this:
gcc -lblas test.c
giving this error:
/tmp/cc9fVU41.o: In function `reference_dgemm':
test.c:(.text+0xc7): undefined reference to `cblas_dgemm'
collect2: error: ld returned 1 exit status
I have tried using #include <gsl/gsl_cblas.h> with -lgslcblas instead, as in this example, same problem. Format and name of the referenced function I got from /usr/include/cblas.h

What distinguishes these LAPACK programmes? One compiles, the other does not

I have two programmes using the LAPACK routine dgeev in C. One appears to be working, the other does not compile claiming undefined reference to dgeev. I seek to understand why.
The first code below - called mamapack.c - produces sensible results when compiled and run like this:
ludi#ludi-M17xR4:~/Desktop/tests$ gcc -o mamapack mamapack.c -L/usr/local/lib -llapack -lblas && ./mamapack
#include<stdio.h>
#include<math.h>
#include <stdlib.h>
//...........................................................................
void dgeTranspose( double *Transposed, double *M ,int n) {
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
Transposed[i+n*j] = M[i*n+j];
}
//...........................................................................
// MatrixComplexEigensystem: computes the eigenvectors and eigenValues of input matrix A
// The eigenvectors are stored in columns
//............................................................................
void MatrixComplexEigensystem( double *eigenvectorsVR, double *eigenvaluesW, double *A, int N) {
int i;
double *AT = (double *) malloc( N*N*sizeof(double ) );
dgeTranspose( AT, A , N);
char JOBVL ='N'; // Compute Right eigenvectors
char JOBVR ='V'; // Do not compute Left eigenvectors
double VL[1];
int LDVL = 1;
int LDVR = N;
int LWORK = 4*N;
double *WORK = (double *)malloc( LWORK*sizeof(double));
double *RWORK = (double *)malloc( 2*N*sizeof(double));
int INFO;
double *eigenvaluesWR =eigenvaluesW;
double *eigenvaluesWI = eigenvaluesW + N;
dgeev_( &JOBVL, &JOBVR, &N, AT , &N,
eigenvaluesWR, eigenvaluesWI,
VL, &LDVL,
eigenvectorsVR, &LDVR,
WORK, &LWORK, &INFO );
printf("\nping1\n");
dgeTranspose( AT, eigenvectorsVR , N);
for(i=0;i<N*N;i++) eigenvectorsVR[i]=AT[i];
free(WORK);
free(RWORK);
free(AT);
}
int main() {
int i,j;
const int N = 3;
double A[] = { 1. , 0. , 0. , 0. , 1., 0. , 0., 0., 1.};
double eigenVectors[N*N];
double eigenValues[2*N];
MatrixComplexEigensystem( eigenVectors, eigenValues, A, N);
printf("\nEigenvectors\n");
for(i=0;i<N;i++){
for(j=0;j<N;j++) printf("%e ", eigenVectors[i*N + j]);
printf("\n");
}
printf("\nEigenvalues \n");
for(i=0;i<N;i++) printf("%e ", eigenValues[i] );
printf("\n--------------------------------------------------------\n");
return 0;
}
Then I ran another code that I called lapack1.c, which is just the official "Example program in C" from this documentation: https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/dgeev.htm
(I dare not post it separately due to potential copyright restrictions)
ludi#ludi-M17xR4:~/Desktop/tests$ gcc -o lapack1 lapack1.c
-L/usr/local/lib -llapack -lblas && ./lapack1
produces
tmp/cciRzQru.o: In function main': lapack1.c:(.text+0xf3): undefined
reference todgeev' lapack1.c:(.text+0x1b6): undefined reference to
`dgeev' collect2: error: ld returned 1 exit status
Check your function names carefully. The linker is complaining about an undefined reference to function dgeev(). The working code is calling a different function, named dgeev_().
Compiling with the option -D as follows:
ludi#ludi-M17xR4:~/Desktop/tests$ gcc -Ddgeev=dgeev_ -o lapack1
lapack1.c -L/usr/local/lib -llapack -lblas && ./lapack1
Will indeed work.

Fail to link c code to lapack / blas : undefined reference

i have been trying for hours and it drives me crazy. The last error I get is :
demo_cblas.c:(.text+0x83): undefined reference to `clapack_sgetrf'
demo_cblas.c:(.text+0xa3): undefined reference to `clapack_sgetri'
I am compiling the code using
/usr/bin/gcc -o demo_cblas demo_cblas.c -L /usr/lib64 -l :libgfortran.so.3 -L /usr/lib64 \
-llapack -L /usr/lib64 -lblas
I try with and without libgfortran, with different compilers gcc-33, gcc-47, gcc-48. The test code is not from me but comes from this forum ...
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "clapack.h"
#include "cblas.h"
void invertMatrix(float *a, unsigned int height){
int info, ipiv[height];
info = clapack_sgetrf(CblasColMajor, height, height, a, height, ipiv);
info = clapack_sgetri(CblasColMajor, height, a, height, ipiv);
}
void displayMatrix(float *a, unsigned int height, unsigned int width)
{
int i, j;
for(i = 0; i < height; i++){
for(j = 0; j < width; j++)
{
printf("%1.3f ", a[height*j + i]);
}
printf("\n");
}
printf("\n");
}
int main(int argc, char *argv[])
{
int i;
float a[9], b[9], c[9];
srand(time(NULL));
for(i = 0; i < 9; i++)
{
a[i] = 1.0f*rand()/RAND_MAX;
b[i] = a[i];
}
displayMatrix(a, 3, 3);
return 0;
}
I am on Suse 12.3 64bits. In /usr/lib64 I have liblapack.a liblapack.so, ... and libblas.a libblas.so, ... and libgfortran.so.3
The same code without the function "invertMatrix" (the one using the library) compiles fine.
Any idea or suggestion ?
Thank you all for your help.
Vava
I'm quite positive that you also need to link to libcblas, which is the c wrapper library for libblas. Note that libblas is a FORTRAN library which therefore does not contain the function clapack_* you're calling.
I've just got this working on FreeBSD with:
gcc -o test test.c \
-llapack -lblas -lalapack -lcblas
I'd installed math/atlas (from ports) and the lapack and blas packages.
See my question here

Resources