Dynamic library dynamic attach - c

EDIT found an issue, but it still needs to be solved it should be below in answers
My task is to write app based on existing files. test.c(main) randapi.c randapi.h(2 functions in here) and initapi.c(one function). "how can You use dynamic library as dynamic loaded library. Using eg9 (where i made a dynamic library and it worked fine) write app where this libraries will be attached dynamic"
here is my try with a makefile but terminal says that :failed to open when i come to run file using ./program
i have tried also version without attaching initapi.c but then it says initRand is unknown besides that make file clearly attached it
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#define ITERATIONS 1000000L
int main(int argc, char** argv)
{
long i;
long isum;
float fsum;
void *lib;
lib=dlopen("librandapi.so", RTLD_LAZY);
if (!lib)
{
printf("failed to open");
exit(1);
}
int (*getRand)(int);
float (*getSRand)();
void (*initRand)();
getRand=dlsym(lib,"getRand");
getSRand=dlsym(lib,"getSRand");
initRand=dlsym(lib,"initRand");
initRand();
isum = 0L;
for (i = 0 ; i < ITERATIONS ; i++) {
isum += ((*getRand)(10));
}
printf( "getRand() Average %d\n", (int)(isum / ITERATIONS) );
fsum = 0.0;
for (i = 0 ; i < ITERATIONS ; i++) {
fsum += ((*getSRand)());
}
printf( "getSRand() Average %f\n", (fsum / (float)ITERATIONS) );
dlclose(lib);
return 0;
}
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
makefile
zad9: test.c
gcc -Wall -o zad9 test.c -ldl
librandapi.so: randapi.o initapi.o
gcc -shared -o librandapi.so randapi.o initapi.o
randapi.o: randapi.c randapi.h
gcc -c -Wall -fPIC randapi.c
initapi.o: initapi.c
gcc -c -Wall -fPIC initapi.c
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
zad9: test.c initapi.c
gcc -Wall -o zad9 test.c initapi.c -ldl
librandapi.so: randapi.o initapi.o
gcc -shared -o librandapi.so randapi.o
randapi.o: randapi.c randapi.h
gcc -c -Wall -fPIC randapi.c

Look at this line in man 3 dlopen:
If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) path‐name. Otherwise, the dynamic linker searches for the object as follows (see ld.so(8) for further details):
(and then a buch of rules that do not include the current directory nor the one where the executable is).
My guess is that you are copying librandapi.so to the current directory and that's why dlopen() cannot find it.
If that's the case, the solution is easy:
lib=dlopen("./librandapi.so", RTLD_LAZY);

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

Linux, C - Is it possible to link against 2 dynamic librraries with equal functions names

I am forced to link two version of the same third party dynamic library (Linux .so, C language) into the same executable to support old and new functionality in the same process. Having two executables or remote services are undesirable.
I made the assumption that this must be a doable task. I tried to experiment with the naive approach of creating 2 proxy dynamic libraries each linked against one of the real libraries and have function renamed.
Unfortunately, this attempt failed – both new functions call the same target function.
I still want to believe that the problem is in the lack of my knowledge as there are plenty of compiler and linker ( gcc and ld) options.
I will appreciate any help. I also look forward to using dlopen/dlsym, but first want to check if the original approach can work.
Here is the sample code
/* ./old/b.c */
#include <stdio.h>
int b (int i)
{
printf("module OLD %d\n",i);
return 0;
}
/* ./old/Makefile */
libold.so: b.c
gcc -c -g b.c
gcc -shared b.o -o $#
/* ./new/b.c */
#include <stdio.h>
int b (int i)
{
printf("module new %d\n",i);
return 0;
}
/* ./new/Makefile */
libnew.so: b.c
gcc -c -g b.c
gcc -shared b.o -o $#
/* ./a1.c */
#include <stdio.h>
int b(int);
void call_new(void)
{
printf("will call new 1\n");
b(1);
printf("called new 1\n");
}
/* ./a2.c */
#include <stdio.h>
int b(int);
void call_old(void)
{
printf("will call old 2\n");
b(2);
printf("called old 2\n");
}
/* ./main.c */
#include <stdio.h>
int call_new(void);
int call_old(void);
int main()
{
call_new();
call_old();
return 0;
}
/* ./Makefile */
.PHONY: DEPSNEW DEPSOLD clean
main: liba1.so liba2.so main.c
gcc -c main.c
gcc -o main main.o -rdynamic -Wl,-rpath=new -Wl,-rpath=old -L . -la1 -la2
DEPSNEW:
make -C new
DEPSOLD:
make -C old
liba1.so: DEPSNEW a1.c
gcc -c -fpic a1.c
gcc -shared a1.o -L new -lnew -o liba1.so
liba2.so: DEPSOLD a2.c
gcc -c -fpic a2.c
gcc -shared a2.o -L old -lold -o liba2.so
clean:
find -name "*.so" -o -name "*.o" -o -name main | xargs -r rm
/* ./run.sh */
#/bin/sh
LD_LIBRARY_PATH=new:old:. main
The result is not that I want - function from "new" library is called twice
will call new 1
module new 1
called new 1
will call old 2
module new 2
called old 2
In this case, you can not control the automatic loading of the dynamic library in order to assure which library will be loaded for the depending libraries. What you can do, is to use one of the libraries (the new one) for the dynamic linker and to link the second library manually as follows:
Add function to dynamically load and link the function from the library.
a2.c
#include <stdio.h>
#include <dlfcn.h>
static int (*old_b)(int);
void init_old(void) {
void* lib=dlopen("./old/libold.so", RTLD_LOCAL | RTLD_LAZY);
old_b=dlsym(lib,"b");
}
void call_old(void)
{
printf("will call old 2\n");
old_b(2);
printf("called old 2\n");
}
call the initialization function
main.c
#include <stdio.h>
void init_old(void);
int call_new(void);
int call_old(void);
int main()
{
init_old();
call_new();
call_old();
return 0;
}
Modify the linker options to add the dynamic loading library -ldl
liba2.so: DEPSOLD a2.c
gcc -c -fpic a2.c
gcc -shared a2.o -L old -lold -ldl -o liba2.so
After this modification
~$ ./run.sh
will call new 1
module new 1
called new 1
will call old 2
module OLD 2
called old 2

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/?

How do I unit-test a dynamic library using gcov?

I am building a dynamically-linked library, and am setting up a simple test suite. I want to use gcov to generate a static code analysis coverage report.
My library is a C file containing function implementations and a header file containing function prototypes. My test suite is simply an application that calls the functions in various ways and confirms the validity of the output.
I am compiling both the library and the test suite with the -fprofile-arcs and -ftest-coverage flags, as described on GNU's guide to GCOV. I am also including the -O0 flag to disable compiler optimization and the -g flag to enable debug symbols. The executable generated from the test suite is linked dynamically to the library.
All files compile cleanly and without warning, but it fails to link the test suite to the library -- citing a "hidden symbol __gcov_merge_add". If I compile without the -fprofile-arcs and -ftest-coverage flags, the linking succeeds and I am able to run the test suite executable.
So I have a few questions which still aren't resolved after reading the GNU guide to GCOV.
Why is the linking failing? How can I resolve this?
Do I need to include the profile and coverage flags when compiling both the library and the test suite?
Here is my inc/mylib.h file:
#ifndef __MYLIB_H__
#define __MYLIB_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int
foo (int a);
int
bar (int a);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __MYLIB_H__ */
Here is my src/mylib.c file:
#include <stdio.h>
#include "mylib.h"
int foo(int a) {
if (a > 5) {
return 5;
}
return a;
}
int bar(int a) {
if (a < 0) {
return 0;
}
return a;
}
Here is my test/unittests.c file:
#include <stdio.h>
#include "mylib.h"
void run_foo_tests() {
int inputs[] = {3, 6};
int expected_results[] = {3, 5};
int i, actual_result;
for ( i = 0; i < sizeof(inputs) / sizeof(int); i++ ) {
actual_result = foo(inputs[i]);
if (actual_result == expected_results[i]) {
printf("Test %d passed!\n", i + 1);
} else {
printf("Test %d failed!\n", i + 1);
printf(" Expected result: %d\n", expected_results[i]);
printf(" Actual result: %d\n", actual_result);
}
}
}
void run_bar_tests() {
int inputs[] = {3, -1};
int expected_results[] = {3, 0};
int i, actual_result;
for ( i = 0; i < sizeof(inputs) / sizeof(int); i++ ) {
actual_result = bar(inputs[i]);
if (actual_result == expected_results[i]) {
printf("Test %d passed!\n", i + 1);
} else {
printf("Test %d failed!\n", i + 1);
printf(" Expected result: %d\n", expected_results[i]);
printf(" Actual result: %d\n", actual_result);
}
}
}
int main(int argc, char *argv[]) {
run_foo_tests();
run_bar_tests();
return 0;
}
Here is my Makefile:
CC=gcc
CFLAGS=-Wall -std=c89 -g -O0 -Iinc -fprofile-arcs -ftest-coverage
all: clean build run_tests
build:
$(CC) $(CFLAGS) -fPIC -c src/*.c -o lib/mylib.o
$(CC) -shared lib/mylib.o -o lib/libmylib.so
$(CC) $(CFLAGS) test/*.c -o bin/unittests -Llib -lmylib
run_tests:
LD_LIBRARY_PATH=lib bin/unittests
gcov src/*.c
clean:
rm -f *.gcda *.gcno *.gcov
rm -rf bin lib ; mkdir bin lib
When I run make, I am presented with this output:
rm -f *.gcda *.gcno *.gcov
rm -rf bin lib ; mkdir bin lib
gcc -Wall -std=c89 -g -O0 -Iinc -fprofile-arcs -ftest-coverage -fPIC -c src/*.c -o lib/mylib.o
gcc -shared lib/mylib.o -o lib/libmylib.so
gcc -Wall -std=c89 -g -O0 -Iinc -fprofile-arcs -ftest-coverage test/*.c -o bin/unittests -Llib -lmylib
/usr/bin/ld: bin/unittests: hidden symbol `__gcov_merge_add' in /usr/lib/gcc/x86_64-redhat-linux/4.8.5/libgcov.a(_gcov_merge_add.o) is referenced by DSO
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
make: *** [build] Error 1
You need to give the command line argument -lgcov for the linker (normally -ftest-coverage implies -lgcov, but you have a separate linking step where -ftest-coverage is not given as a command line argument). Alternatively, you can just use the --coverage command line argument, which is a shortcut also for -fprofile-arcs and -ftest-coverage, as explained here: http://www.univ-orleans.fr/sciences/info/ressources/webada/doc/gnat/gcc_3.html:
--coverage
This option is used to compile and link code instrumented for
coverage analysis. The option is a synonym for `-fprofile-arcs'
`-ftest-coverage' (when compiling) and `-lgcov' (when linking). See
the documentation for those options for more details.
At the same place, btw., it is also explained that you don't have to compile all files with these options, which hopefully answers your question 2.

Static libraries and headers in another directories with GCC

I was looking here how to do static libraries using GCC, and the explanation is pretty clear (despise the fact I had to rewrite the factorial function): I have a function (fact.c), the header of the function (fact.h), and the main function (main.c), all of them in my home directory.
fact.h
int fact (int);
fact.c
int
fact (int f) {
if ( f == 0 )
return 1;
else
return (f * fact ( f - 1 ));
}
main.c
#include <stdio.h>
#include "fact.h"
int main(int argc, char *argv[])
{
printf("%d\n", fact(3));
return 0;
}
So I had first to generate the object file (phase 1)...
$ gcc -c fact.c -o fact.o
...then to generate the static library (phase 2)...
$ ar rcs libfact.a fact.o
...later to do the static library linking process (phase 3)...
$ gcc -static main.c -L. -lfact -o fact
...and finally run the program (phase 4 and final)
$ ./fact
My question is the following. Let's suppose my program will be so big that I had no alternative than put the headers in a header directory (/include/fact.h) and the static libraries will also be in another directory (/lib/libfact.a). In that case, how the compilation and/or the code of this program will change?
Edit/Problem Solved: First, the main.c was corrected in order to include a header in another directory called include. Remember that, in this case, both of the .c files are in the main directory.
main.c
#include <stdio.h>
#include "include/fact.h"
int main(int argc, char *argv[])
{
printf("%d\n", fact(3));
return 0;
}
Second, to generate the static library in another directory (phase 2), this is what I had done:
$ ar rcs lib/libfact.a fact.o
Here is your answer,
$ gcc -static main.c -L. -lfact -o fact
-L Add directory to the list of directories to be searched for -l
Its in the link that you gave. If you put the seach direction correctly and low search range, it will not be a problem. Otherwise it is not going to compile the code. Because code did not know where is the header.
You can add -I to specify include path(s).
gcc -I/include fact.c
gcc -I/include -static main.c -L/lib -lfact -o fact_main

Resources