dlopen не может использовать неопределенный символ для функции, которая является прототипом

Я пишу общую библиотеку для Linux (64-разрядная версия) с C11.

Я создал 3 файла C и H.

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;
}

Компиляция кода следующим образом

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

Все в порядке до этого момента. dll.so файл создан. Но когда я использую функцию dlopen для загрузки библиотеки как:

тест.д

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

dlerror дает мне: ошибка dlopen: ./dll.so: неопределенный символ: pipeListeningThreadFunc

Я не понимаю, что в этом плохого.

Чтобы понять проблему, я перенес реализацию функции pipeListeningThreadFunc в dllman.h и скомпилировал таким же образом. На этот раз все работает исправно.

Что не так с определением функции как прототипа? Почему он не может найти функцию, если она определена как прототип в файле заголовка и реализована в файле C?


person tcak    schedule 11.11.2014    source источник
comment
Вы никогда не компилируете файл C с реализацией.   -  person unwind    schedule 11.11.2014


Ответы (1)


Я думаю, вам нужно выполнить следующие команды:

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

Ваши команды отсутствуют dllman.c

Linux позволяет создавать библиотеки, в которых отсутствуют некоторые символы (в вашем случае dll.so не содержит функции pipeListeningThreadFunc). Однако, когда библиотека загружена, pipeListeningThreadFunc должен находиться где угодно - будь то в этой библиотеке или в другой библиотеке. Поскольку этой функции не существует, dlopen не работает.

person Alex F    schedule 11.11.2014
comment
Я изменил файл make, как вы предложили. Теперь проблема в 3-й строке gcc, которая связана с -shared. У меня есть некоторые глобальные переменные, определенные в dllman.h, и 3-я строка дает dllman.o:(.data+0x0): множественное определение `commPipeReadDesc' dll.o:(.data+0x0): впервые определено здесь. Я определил переменную в dllman.h и использовал в функции запуска. - person tcak; 11.11.2014
comment
Определите эти переменные в h-файле с ключевым словом extern. Затем определите их без ключевого слова extern в одном из c-файлов. Например, посмотрите этот ответ: stackoverflow.com /вопросы/14855915/ - person Alex F; 11.11.2014
comment
Честно говоря, мне не нравилась идея определять одну и ту же переменную дважды. Я бы хотел, чтобы был лучший способ, но это же C десятилетий, верно?! Во всяком случае, я определил static struct в dllman.h и поместил в него все эти переменные. Затем получили доступ к этим переменным через него из всех других файлов. Это сработало очень хорошо. - person tcak; 11.11.2014
comment
Примечание: вы уже знаете, как определить прототип функции и реализацию: void Function(); (прототип в h-файле) и void Function(){} (реализация в c-файле). Глобальные переменные определяются так же: extern int x; (h-файл, как и вперед объявление для функции) и int x; (c-файл, как реализация для функции) - person Alex F; 12.11.2014
comment
Определив статическую переменную в h-файле, вы получите разную копию этой переменной в каждом c-файле, в который включен этот h-файл. - person Alex F; 12.11.2014
comment
Да, через некоторое время я продолжил работу над проектом и заметил, что значения переменных в статической структуре не совпадают во вновь созданном потоке. Затем я превратил их в структуру typedef, объявил для нее extern в H-файле и определил переменную в C-файле. Это, по крайней мере, помогло мне дублировать переменные только один раз со структурой вместо того, чтобы делать каждую из них. - person tcak; 12.11.2014