0

I am writing a shared library on Linux (64-bit) with C11.

I created 3 C and H files.

dll.c

#include "dllman.h"

void start(){
    pipeListeningThreadFunc( NULL );
}

dllman.h

#include <stdio.h>

void* pipeListeningThreadFunc( void* args );

dllman.c

#include "dllman.h"

void* pipeListeningThreadFunc( void* args ){
    printf("Blah");
    return NULL;
}

Compiling code as follows

gcc -std=gnu11 -c -Wall -Werror -fpic -lpthread dll.c
gcc -std=gnu11 -shared -fpic -o dll.so dll.o

Everything is okay until this point. dll.so file is created. But when I use dlopen function to load the library with as:

test.d

...
void* lh = dlopen("./dll.so", RTLD_NOW | RTLD_GLOBAL);
...

dlerror gives me: dlopen error: ./dll.so: undefined symbol: pipeListeningThreadFunc

I don't understand what is wrong with this.

To be able to understand the problem, I moved the implementation of function pipeListeningThreadFunc to dllman.h, and compiled in same way. This time everything works properly.

What is wrong with defining function as prototype? Why can't it find the function when it is defined as prototype in header file and implemented in C file?

tcak
  • 2,142
  • 1
  • 16
  • 23

1 Answers1

2

I think you meed to execute the following commands:

gcc -std=gnu11 -c -Wall -Werror -fpic -lpthread dll.c
gcc -std=gnu11 -c -Wall -Werror -fpic -lpthread dllman.c
gcc -std=gnu11 -shared -fpic -o dll.so dll.o dllman.o

Your commands are missing dllman.c

Linux allows to build libraries that are missing some symbols (in your case, dll.so doesn't contain pipeListeningThreadFunc function). However, when library is loaded, pipeListeningThreadFunc must be found anywhere - whether in this library or another library. Since this function doesn't exist, dlopen fails.

Alex F
  • 42,307
  • 41
  • 144
  • 212
  • I changed the make file as you suggested. Now the problem is on 3rd gcc line that is with "-shared". I have some global variables those are defined in "dllman.h", and 3rd line gives "dllman.o:(.data+0x0): multiple definition of `commPipeReadDesc' dll.o:(.data+0x0): first defined here". I defined the variable in dllman.h and **used** in "start" function. – tcak Nov 11 '14 at 15:33
  • Define these variables in h-file with `extern` keyword. Then define them without `extern` keyword in one of c-files. For example, look this answer: http://stackoverflow.com/questions/14855915/creating-global-variables-causes-linker-error – Alex F Nov 11 '14 at 15:37
  • To be honest, I didn't like the idea of defining same variable twice. I wish there was a better way, but it is same C of decades, right?! Anyway, I defined a `static struct` in dllman.h and put all those variables into it. Then accessed those variables through it from all other files. It worked very well. – tcak Nov 11 '14 at 16:22
  • Just a note: you already know how to define a function prototype and implementation: `void Function();` (prototype in h-file) and `void Function(){}` (implementation in c-file) Global variables are defined by the same way: `extern int x;` (h-file, like forward declaration for function) and `int x;` (c-file, like implementation for function) – Alex F Nov 12 '14 at 09:41
  • By defining static variable in h-file, you get different copy of this variable in every c-file, where this h-file included. – Alex F Nov 12 '14 at 09:45
  • Yes, after a while, I continued working on the project, and noticed that the values of variables in static struct weren't same in the newly created thread. Then I turned them into typedef struct, declared an extern for it in H file, and defined a variable in C file. This at least helped me to duplicate variables only once with struct instead of doing each of them. – tcak Nov 12 '14 at 20:19