Installing and using a shared library - c

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.

Related

Why even though linking is finished correctly, i get undefined reference error?

I'm trying to learn c and I implemented a bubblesort function and i decided It would be better idea if i made a library that will contain various sorting algorithms, so I compiled my code with this:
gcc -shared -fPIC -o bin/bsort.o sort/Bubblesort.c
my bubblesort.c is working (and not related to question at all and there is nothing other than bubblesort function there):
// Licensed under public domain with no warranty
void bubblesort(int* array) {
//implemention goes here
}
my sort.h file:
void bubblesort(int* array);
my nsort.c
#include "sort/sort.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int main() {
int* sortthis = malloc(1000*sizeof(int));
for(int i = 0; i < 1000; i++) {
*(sortthis+i) = random(); //random int is defined somewhere else
}
bubblesort(sortthis);
for(int i = 0; i < 90; i++) {
printf("%d ",*(sortthis+i));
}
free(sortthis);
return 0;
}
my script that i use to compile:
gcc -shared -fPIC -o bin/bsort.o sort/Bubblesort.c
gcc nsort.c sort/sort.h -Lbin/bsort.o -lm -o demo.elf
what could be i'm doing wrong, i tried various things but it didn't work, i kept getting following error:
/usr/bin/ld: /tmp/ccxhd5zd.o: in function `main':
nsort.c:(.text+0x23): undefined reference to `bubblesort'
collect2: error: ld returned 1 exit status
gcc --version (just in case if there is a bug in this version):
gcc (Debian 10.2.1-6) 10.2.1 20210110
You don't put -L before the .o file. -L is for adding directories that -l searches for libraries.
To link with an object file, just add it as an ordinary file argument.
You also don't need to include header files in the compiler arguments. The compiler reads them when it sees #include.
gcc nsort.c bin/bsort.o -lm -o demo.elf

Run C function with CUDA calls in Delphi program

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.

Compiling in gcc dynamically with objects in other folders

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

dynamic link library in c can not find -lmean

The code for the library:
calc_mean.c
//#include <stdio.h>
double mean(double a, double b) {
return (a+b) / 2;
}
The header file:
calc_mean.h
double mean(double, double);
The programm using the library:
main.c
#include <stdio.h>
#include "calc_mean.h"
int main(int argc, char* argv[]) {
double v1, v2, m;
v1 = 5.2;
v2 = 7.9;
m = mean(v1, v2);
printf("The mean of %3.2f and %3.2f is %3.2f\n", v1, v2, m);
return 0;
}
I created static library using following commands:
gcc -c calc_mean.c -o calc_mean.o
ar rcs libmean.a calc_mean.o
Linking against static library:
gcc -static main.c -L. -lmean -o statically_linked
everything works perfectly fine as long as its static library...
Now these are the commands which I used to create shared library:
gcc -c -fPIC calc_mean.c -o calc_mean.o
gcc -shared -Wl,-soname,libmean.so.1 -o libmean.so.1.0.1 calc_mean.o
after these two commands when I enter the linkng command
gcc main.c -o dynamically_linked -L. -lmean
I am getting error message can not find -lmean
ld returned 1 exit status
attaching error message here
can some one give me steps to create DLL in C?
This is because you are creating a file named libmean.so.1.0.1, but you ask the linker to link with libmean.so (this is what -lmean expands to).
You need a symbolic link libmean.so pointing to libmean.so.1.0.1.
When you try to link the lib by giving -lmean, it automatically searches for libmean.so, but you have created the lib as libmean.so.1.0.1. This is the problem. Either change the lib name or create a symbolic link.
Did you copy the libmean.so.1 in /usr/lib/ (or) /opt/lib/?

Cuda mixed C project linking

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

Resources