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

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

Related

gprof only showing calls - C program in Ubuntu with WSL1

I am having an issue with "gprof" while using WSL1 and "gcc" in Ubuntu. The only information it displays is the "calls" and anything else is set as 0.00. I do not think that is because the program is running too fast because when typing time ./go it returns:
real = 0.569s; user = 0.547s; sys = 0.000s.
The main program (go.c) is:
#include <stdio.h>
#include "functions.h"
#define maxloop 1e7
int main(int argc, char*argv[]) {
int i;
double x;
double xsum = 0.0;
for (i = 1; i < maxloop; i++) {
x = myFun1(i) + myFun2(i) + myFun3(i);
xsum += x;
}
printf("xsum = %.6f\n", xsum);
return 0;
}
The file with the functions (functions.c) is:
#include <math.h>
double myFun1(double x) {
double a = sin(x);
return a;
}
double myFun2(double x){
double a = pow(x,3);
return a;
}
double myFun3(double x){
double a = sqrt(x);
return a;
}
The header (functions.h) is:
double myFun1(double x);
double myFun2(double x);
double myFun3(double x);
I am compiling in the terminal as:
gcc -pg -o go go.c functions.c -lm
Running the gprof as:
gprof ./go -p -b
Upgrade to WSL2 for support of the profiling features required by gprof.

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.

multifile direct compile ok, direct compile error

There are 3 files(generator.c, generator.h and main.c).
generator.c: There is only 1 function (gen fun) which is used to generate an array to store 10 random-generate numbers in generator.c.
generator.h:Declaration of generator.c.
main.c: There is only 1 function (main fun) in main.c which is used to print the number generated previously.
If generator.c is included in main.c and I compile it directly by execute "gcc main.c". The result is ok.
But while I compile it using " gcc -c generator.h, gcc -c main.c, gcc generator.o main.o ", it reported a warning "warning: assignment makes pointer from integer without a cast" at " p = gen(arr); " sentence in main funciton. And the final result was "Segmentation fault (core dumped)". The debug information showed "Cannot access memory at address" if i try to visit the value of pointer *p(i.e. array[0]) in the while loop of main function.
//////generator.c///////
int * gen( int arr[])
{
int i = 0;
int * p = arr;
int len = 10;
srand( (unsigned)((time)(NULL)));
while (i< len)
{
*p = rand() % ( len +1) + 0;
i ++;
p++;
}
return arr;
}
//////generator.h//////
int * gen( int arr[]);
//////main.c///////
int main(void)
{
int i = 0;
int arr[10]={0};
int * p;
p = gen(arr);
while (i < 10)
{
printf("output is %d\n",*p);// Segmentation fault (core dumped)
i++;
p++;
}
return 0;
}
Based on the addition to your question, it appears you are confused about how to include generator.h and then to compile the code. First your generator.h should be:
//////generator.h//////
#ifndef GENERATOR_H
#define GENERATOR_H 1
int *gen (int arr[]);
#endif
(edit: added appropriate Header Guards to prevent multiple inclusion of generator.h)
Your generator.c would then be:
//////generator.c///////
#include <stdlib.h>
#include "generator.h"
int *gen (int arr[])
{
int i = 0;
int * p = arr;
int len = 10;
while (i< len)
{
*p = rand() % len + 1;
i ++;
p++;
}
return arr;
}
And finally your main.c (I called it gen.c) would be:
//////main.c///////
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "generator.h"
int main(void)
{
int i = 0;
int arr[10]={0};
int *p;
srand( (unsigned)((time)(NULL)));
p = gen(arr);
while (i < 10)
{
printf ("output is %d\n",*p);
i++;
p++;
}
return 0;
}
Compile
$ gcc -Wall -Wextra -pedantic -std=c11 -Ofast generator.c -o bin/gen gen.c
(note: I would also encourage adding -Wshadow as a normal part of your compile string as well to identify any shadowed variables)
Example Use/Output
$ ./bin/gen
output is 8
output is 1
output is 5
output is 4
output is 9
output is 5
output is 4
output is 6
output is 5
output is 6
Look things over and let me know if you have further questions.

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.

Linking C code with Cuda code

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.

Resources