Подключение динамической библиотеки linux в си
Подскажите, кто может. Не могу использовать собственную динамическую библиотеку.
Пишу на си библиотеку сортировок (курсовой проект), нужно обязательно использовать динамическую библиотеку. Собираю проект с помощью make.
APP_NAME = sortapp
LIB_NAME = libsort
CFLAGS = -Wall -Wextra -Werror
CPPFLAGS = -I src -MP -MMD
BIN_DIR = bin
OBJ_DIR = obj
SRC_DIR = src
APP_PATH = $(BIN_DIR)/$(APP_NAME)
LIB_PATH = $(OBJ_DIR)/$(SRC_DIR)/$(LIB_NAME)/$(LIB_NAME).so
SRC_EXT = c
APP_SOURCES = $(shell find $(SRC_DIR)/$(APP_NAME) -name '*.$(SRC_EXT)')
APP_OBJECTS = $(APP_SOURCES:$(SRC_DIR)/%.$(SRC_EXT)=$(OBJ_DIR)/$(SRC_DIR)/%.o)
LIB_SOURCES = $(shell find $(SRC_DIR)/$(LIB_NAME) -name '*.$(SRC_EXT)')
LIB_OBJECTS = $(LIB_SOURCES:$(SRC_DIR)/%.$(SRC_EXT)=$(OBJ_DIR)/$(SRC_DIR)/%.o)
DEPS = $(APP_OBJECTS:.o=.d) $(LIB_OBJECTS:.o=.d) $(TST_OBJECTS:.o=.d)
.PHONY: all
all: $(BIN_DIR) $(OBJ_DIR) $(SRC_DIR) $(RES_DIR) $(APP_PATH)
-include $(DEPS)
$(APP_PATH): $(APP_OBJECTS) $(LIB_PATH)
$(CC) $(CFLAGS) $(CPPFLAGS) -O0 $^ -L$(OBJ_DIR)/$(SRC_DIR)/$(LIB_NAME) -lsort -o $@
$(LIB_PATH): $(LIB_OBJECTS)
$(CC) -shared -o $(LIB_PATH) -g $^
$(OBJ_DIR)/%.o: %.c
$(CC) -fPIC -c $(CFLAGS) $(CPPFLAGS) $< -g -o $@
всё проходит успешно, но при запуске программы выдаёт сообщение:
./sortapp: error while loading shared libraries: obj/src/libsort/libsort.so: cannot open shared object file: No such file or directory
Пытался изменять файл ect/ld.so.conf.d/libc.conf, добавляя в него расположение своей библиотеки, затем обновляя список видимых библиотек командой ldconfig. При использовании команды ldconfig -p вижу, что конфиг библиотеку видит (нижняя строка), однако проблема не пропадает, по прежнему выдаёт ту же ошибку
Так же пытался настраивать переменную среды LD_LIBRARY_PATH
Что так же не дало результатов.
Ошибка:
Помогите, пожалуйста
Ответы (2 шт):
В итоге программа заработала. Но! Только из "корневой папки".
Так выглядит директория в которой лежит проект. src-исходники, obj-объектные файлы и библиотеки, в папке bin лежит только исполняемый файл.
Если я пытаюсь запустить программу, предварительно зайдя в папку bin, то ошибка повторяется, но если запускаю из корневой папки командой bin/sortapp, то всё работает. То есть одно из действий, которые я описывал в вопросе решили проблему, но не до конца. Объясните почему так происходит и как сделать, что бы программу можно было запускать из любой директории?
Для устранения наблюдаемого вами эффекта оказалось достаточно
убрать LIB_PATH (сам .so файл) из списка аргументов линкера
(да, линкер стал умным и используемых вами флагов ему достаточно (теперь нет необходимости включать -Wl,-soname,libsort.so, рекомендуемых в инструкции)).
Т.е. в ваш Makefile я внес только одно небольшое изменение:
$(APP_PATH): $(APP_OBJECTS) $(LIB_PATH)
# $(CC) $(CFLAGS) $(CPPFLAGS) -O0 $^ -L$(OBJ_DIR)/$(SRC_DIR)/$(LIB_NAME) -lsort -o $@
$(CC) $(CFLAGS) $(CPPFLAGS) -O0 $(APP_OBJECTS) -L$(OBJ_DIR)/$(SRC_DIR)/$(LIB_NAME) -lsort -o $@
а именно, заменил $^ на $(APP_OBJECTS).
После этого все заработало, независимо от расположения исполняемого файла и libsort.so.
avp@avp-desktop:~$ cd avp/hashcode/app_libso/
avp@avp-desktop:~/avp/hashcode/app_libso$ rm obj/src/*/*.o
avp@avp-desktop:~/avp/hashcode/app_libso$
avp@avp-desktop:~/avp/hashcode/app_libso$ make
cc -fPIC -c -Wall -Wextra -Werror -I src -MP -MMD src/sortapp/tlib.c -g -o obj/src/sortapp/tlib.o
cc -fPIC -c -Wall -Wextra -Werror -I src -MP -MMD src/libsort/lib.c -g -o obj/src/libsort/lib.o
cc -shared -o obj/src/libsort/libsort.so -g obj/src/libsort/lib.o
cc -Wall -Wextra -Werror -I src -MP -MMD -O0 obj/src/sortapp/tlib.o -Lobj/src/libsort -lsort -o bin/sortapp
Теперь для чистого эксперимента перебросим исполняемый файл и .so в разные места
avp@avp-desktop:~/avp/hashcode/app_libso$ mv obj/src/libsort/libsort.so /tmp
avp@avp-desktop:~/avp/hashcode/app_libso$ mv bin/sortapp /tmp/tst/
avp@avp-desktop:~/avp/hashcode/app_libso$
и запустим программу
avp@avp-desktop:~/avp/hashcode/app_libso$ LD_LIBRARY_PATH=/tmp/ /tmp/tst/sortapp
try .so lib2_test(/tmp/tst/sortapp)
lib2.so::lib2_test() called from /tmp/tst/sortapp using LD_LIBRARY_PATH=/tmp/
lib2_test() = 78
End
Как видите, работает. Теперь переместимся сами и запустим ее еще раз
avp@avp-desktop:~/avp/hashcode/app_libso$ cd
avp@avp-desktop:~$
avp@avp-desktop:~$ LD_LIBRARY_PATH=/tmp/ /tmp/tst/sortapp
try .so lib2_test(/tmp/tst/sortapp)
lib2.so::lib2_test() called from /tmp/tst/sortapp using LD_LIBRARY_PATH=/tmp/
lib2_test() = 78
End
А вот так ее видит ldd
avp@avp-desktop:~$ LD_LIBRARY_PATH=/tmp/ ldd /tmp/tst/sortapp
linux-vdso.so.1 (0x00007fff045f6000)
libsort.so => /tmp/libsort.so (0x00007f9634385000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9633f94000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9634789000)
avp@avp-desktop:~$
Для тестирования я сделал в вашем проекте пару файлов -- аппликейшн src/sortapp/tlib.c
#include <stdio.h>
#include "lib2.h"
int
main (int ac, char *av[])
{
(void)ac;
printf("try .so lib2_test(%s)\n", av[0]);
printf("lib2_test() = %d\n", lib2_test(av[0]));
return puts("End") == EOF;
}
и библиотеку -- src/libsort/lib.c
#include <stdio.h>
#include <stdlib.h>
#include "lib2.h"
int
lib2_test (const char *p)
{
char *lp = getenv("LD_LIBRARY_PATH");
return printf("lib2.so::lib2_test() called from %s using LD_LIBRARY_PATH=%s\n",
p ? p : "(nil)", lp ? lp : "(nil)");
}
а также src/lib2.h
#ifndef _LIB2_H_
#define _LIB2_H_
int lib2_test (const char *prog_name);
#endif
К сожалению, почему именно так (как вы и наблюдали), т.е. вне зависимости от LD_LIBRARY_PATH, программа видит .so только из "корневой папки", я не смог выяснить.
Видимо это происходит из-за того, что линкер сначала получает на вход сам .so файл, а потом ссылку на него, как на библиотеку. Однако, механизм такого его поведения остается для меня загадкой.