Ошибка загрузки общих библиотек: невозможно открыть файл общих объектов :: на внешнем оборудовании - PullRequest
0 голосов
/ 04 февраля 2019

В настоящее время я занимаюсь разработкой приложения на C ++, которое будет ссылаться на несколько библиотек * .so, каждая из которых содержит код для разных машин - написано на C. У меня также есть один общий объект, содержащий код из пользовательского пространства имен Utilities, который (как имяподразумевает) содержит базовые утилиты, полезные для приложения (написанные на C ++, как и остальная часть приложения).

В настоящее время utilities.so является единственной (настраиваемой) библиотекой, на которую ссылается приложение.Приложение прекрасно компилируется и связывается, однако при его выполнении на целевом оборудовании отображается следующая ошибка: bin/updater_v4test: error while loading shared libraries: ../../../bin/device_modules/utilities.so.1.0.0: cannot open shared object file: No such file or directory

При вызове LDD в указанном приложении отображается следующий вывод: ../../../bin/device_modules/utilities.so.1.0.0 => not found

Я написал скрипт, который (после выхода из make без ошибок) собирает все SO и помещает их в каталог / lib / на целевом оборудовании;Это означает, что при каждой успешной сборке приложения (будь то частично или полностью) обновленные файлы помещаются в правильный каталог на целевом оборудовании.

В попытке воспроизвести другие библиотеки, которые я использовал (например,zlib), я попытался создать символическую ссылку на файл библиотеки, но безуспешно (utilities.so.1.0.0 - символическая ссылка, utilities.so - фактическая SO).utilities.so.1.0.0 --> utilities.so

В данный момент я в растерянности, и я не могу тратить гораздо больше времени, пытаясь понять это сам.


Ниже приведен отрывок из утилиты Makefile:

include ../../common/user.mk

LIB_DIR=../../../libs/lib/powerpc-linux-gnu
CFLAGS=-Wall -ggdb -I../../libs/include -I../../common -lpthread -lddc -std=c++0x -I../../libs/include/zlib
LDFLAGS=../../libs/lib/powerpc-linux-gnu/libcurl.so.4 ../../libs/include/minizip/.libs/libminizip.so.1.0.0 \
-L ../../libs/lib \
-L ../../libs/lib/powerpc-linux-gnu \
-Wl,-rpath-link,../../libs/lib/powerpc-linux-gnu \
-lrt -lddc -lpthread -shared
BIN_DIR=../bin
CANONICAL_BIN_DIR := $(shell readlink -f $(BIN_DIR))
CANONICAL_CUR_DIR := $(shell readlink -f "./")
COMP_OBJECTS := $(wildcard *.cpp)
OBJECTS := $(patsubst %.cpp,%.o,$(wildcard *.cpp))

all: objects utilities.so
    -cp --parents utilities.so $(GLOBAL_BIN_LIB)
    -ln -s utilities.so utilities.so.1.0.0
    -mv utilities.so.1.0.0 $(GLOBAL_BIN_LIB)
#   -cp --parents *.h $(GLOBAL_HEADER_DIR)
    -rm -f utilities.so
    -rm -f *.o
    for header in $(wildcard *.h); do \
        echo $$header; \
        ln -s $(CANONICAL_CUR_DIR)/$$header $(GLOBAL_HEADER_DIR)/$$header; \
    done;
    @printf "########## BUILT $^ ##########\n\n"

utilities.so: $(OBJECTS)
    ${CXX} $^ -o $@ ${LDFLAGS}

objects: $(COMP_OBJECTS)
    ${CXX} -c $^ ${CFLAGS}

А теперь отрывок из приложения Makefile.Здесь я добавил ссылку на библиотеку во флаги компоновщика, все файлы заголовков включены в один каталог.

include ../../../common/user.mk

LIB_DIR=../../../libs/lib/powerpc-linux-gnu
CFLAGS=-Wall -ggdb -I../../../libs/include -I${COMMON_DIR} -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I${HEADER_DIR}
LDFLAGS=../../../libs/lib/powerpc-linux-gnu/libcurl.so.4 ../../../libs/include/minizip/.libs/libminizip.so.1.0.0 ../../../bin/device_modules/utilities.so.1.0.0 \
    -L ../../../libs/lib \
    -L ../../../libs/lib/powerpc-linux-gnu \
    -Wl,-rpath-link,../../../libs/lib/powerpc-linux-gnu \
    -lrt -lddc -lpthread -L ${SO_DIR}
BIN_DIR=../bin
CANONICAL_BIN_DIR := $(shell readlink -f $(BIN_DIR))
CANONICAL_CUR_DIR := $(shell readlink -f "./")

all: test_update.bin
    -cp --parents test_update.bin $(BIN_DIR)
    -ln -s $(CANONICAL_BIN_DIR)/test_update.bin $(GLOBAL_BIN_APP)/test_update.bin
    -rm -f *.bin
    @printf "########## BUILT $^ ##########\n\n"

test_update.bin: main.o updaterdelegate.o commonfunctions.o tinyxml.o
    ${CXX} $^ -o $@ ${LDFLAGS}

####################
#  Required Files  #
####################

main.o: Main.cpp
    ${CXX} -c $^ -o $@ ${CFLAGS}

updaterdelegate.o: UpdaterDelegate.cpp
    ${CXX} -c $^ -o $@ ${CFLAGS}

commonfunctions.o: $(shell python -c "import os.path; print os.path.relpath('${IMPL_CMN_FUNC}'.replace('\"', ''), '${CANONICAL_CUR_DIR}'.replace('\"', ''))")
    ${CXX} -c $^ -o $@ ${CFLAGS}

tinyxml.o: $(shell python -c "import os.path; print os.path.relpath('${IMPL_TXML}'.replace('\"', ''), '${CANONICAL_CUR_DIR}'.replace('\"', ''))")
    ${CXX} -c $^ -o $@ ${CFLAGS}

####################
# /Required Files  #
####################

Я просто добавлю вывод сборки утилит.so и приложения.

utilities.so:

(Очистить опущено)

=============== CLEAN COMPLETE... BUILDING... ===============


make: Entering directory `~/_workspace/upv4/common/utils'
powerpc-linux-gnu-g++  -c ArgumentHandling.cpp Extensions.cpp Logging.cpp -Wall -ggdb -I../../libs/include -I../../common -lpthread -lddc -std=c++0x -I../../libs/include/zlib
ArgumentHandling.cpp: In member function ‘void Utilities::ArgumentHandler::freeMemory()’:
ArgumentHandling.cpp:136: warning: deleting ‘void*’ is undefined
powerpc-linux-gnu-g++  ArgumentHandling.o Extensions.o Logging.o -o utilities.so ../../libs/lib/powerpc-linux-gnu/libcurl.so.4 ../../libs/include/minizip/.libs/libminizip.so.1.0.0 -L ../../libs/lib -L ../../libs/lib/powerpc-linux-gnu -Wl,-rpath-link,../../libs/lib/powerpc-linux-gnu -lrt -lddc -lpthread -shared
cp --parents utilities.so """~/_workspace/upv4""/bin/device_modules"
ln -s utilities.so utilities.so.1.0.0
mv utilities.so.1.0.0 """~/_workspace/upv4""/bin/device_modules"
rm -f utilities.so
rm -f *.o
for header in ArgumentHandling.h Enumerations.h Extensions.h Logging.h; do \
        echo $header; \
        ln -s ~/_workspace/upv4/common/utils/$header """"~/_workspace/upv4""/bin/device_modules"/headers"/$header; \
    done;
ArgumentHandling.h
Enumerations.h
Extensions.h
Logging.h
########## BUILT objects utilities.so ##########

make: Leaving directory `~/_workspace/upv4/common/utils'



=============== BUILD COMPLETE... PARSING... ===============


========== Warnings ==========

Total: 1

ArgumentHandling.cpp:136: warning: deleting ‘void*’ is undefined


========== Errors ==========

Total: 0

test_update.bin:

(Очистить опущено)

=============== CLEAN COMPLETE... BUILDING... ===============


make: Entering directory `~/_workspace/_workspace/upv4/test/app/src'
powerpc-linux-gnu-g++  -c Main.cpp -o main.o -Wall -ggdb -I../../../libs/include -I"""~/_workspace/_workspace/upv4""/common" -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I"""""~/_workspace/_workspace/upv4""/bin/device_modules"/headers""
powerpc-linux-gnu-g++  -c UpdaterDelegate.cpp -o updaterdelegate.o -Wall -ggdb -I../../../libs/include -I"""~/_workspace/_workspace/upv4""/common" -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I"""""~/_workspace/_workspace/upv4""/bin/device_modules"/headers""
powerpc-linux-gnu-g++  -c ../../../common/commonFunctions.cpp -o commonfunctions.o -Wall -ggdb -I../../../libs/include -I"""~/_workspace/_workspace/upv4""/common" -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I"""""~/_workspace/_workspace/upv4""/bin/device_modules"/headers""
powerpc-linux-gnu-g++  -c ../../../common/xmlreader/tinyxml2.cpp -o tinyxml.o -Wall -ggdb -I../../../libs/include -I"""~/_workspace/_workspace/upv4""/common" -lpthread -lddc -std=c++0x -I../../../libs/include/zlib -I"""""~/_workspace/_workspace/upv4""/bin/device_modules"/headers""
powerpc-linux-gnu-g++  main.o updaterdelegate.o commonfunctions.o tinyxml.o -o test_update.bin ../../../libs/lib/powerpc-linux-gnu/libcurl.so.4 ../../../libs/include/minizip/.libs/libminizip.so.1.0.0 ../../../bin/device_modules/utilities.so.1.0.0 -L ../../../libs/lib -L ../../../libs/lib/powerpc-linux-gnu -Wl,-rpath-link,../../../libs/lib/powerpc-linux-gnu -lrt -lddc -lpthread -L """"~/_workspace/_workspace/upv4""/bin/device_modules""
cp --parents test_update.bin ../bin
ln -s ~/_workspace/_workspace/upv4/test/app/bin/test_update.bin """~/_workspace/_workspace/upv4""/bin"/test_update.bin
ln: failed to create symbolic link `~/_workspace/_workspace/upv4/bin/test_update.bin': File exists
make: [all] Error 1 (ignored)
rm -f *.bin
########## BUILT test_update.bin ##########

make: Leaving directory `~/_workspace/_workspace/upv4/test/app/src'



=============== BUILD COMPLETE... PARSING... ===============


========== Warnings ==========

Total: 0




========== Errors ==========

Total: 0

Сценарий сборки является пользовательским, я его собралчтобы избавиться от всего вывода make, когда он мне не нужен, и он анализирует все ошибки и предупреждения.Из-за этой проблемы я снова включил make output.

Я что-то пропустил во время компиляции / компоновки библиотеки или что-то не так во время компоновки приложения?Я склонен сказать, что это происходит во время компиляции / компоновки библиотеки - хотя я не знаю, что именно происходит не так, потому что все компилируется и компоновывается просто отлично.Почему приложение ищет файл .so в пути, который он не может иметь?

Я также убедился, что файлы .so находятся с переменной $ PATH, поэтому приложение должно иметь возможностьнайди их.

1 Ответ

0 голосов
/ 04 февраля 2019

Система обычно ищет общие объекты в фиксированном наборе каталогов.Вы можете справиться с этим, определив переменную среды LD_LIBRARY_PATH и добавив каталог, в который вы устанавливаете общие библиотеки.

Или вы можете добавить эти библиотеки в некоторые из стандартных каталогов библиотек и выполнить ldconfig -a дляобновите кеш общих библиотек.

Подробнее см. ldconfig(8).

edit

Существует два механизма загрузки общего объекта.

  • Первый - это обычный механизм загрузки библиотеки, который определяет, что должно быть загружено во время запуска исполняемого файла, и подразумевает связывание вашего исполняемого файла с общими объектами.Это то, что вы делаете в своем Makefile.Вы указываете общие исполняемые файлы, и общий объект ld.so.xxx (который связан с вашим приложением, когда вы динамически связываете его) загружается и следует за всеми неразрешенными идентификаторами, чтобы найти для них место в виртуальном адресном пространстве.Объект ld.so.xxx использует файл /etc/ld.so.cache, который является просто хеш-таблицей с каталогами и общими исполняемыми файлами, доступными для загрузки таким способом.Этот файл индексируется так называемым soname (что полезно для обеспечения сосуществования разных версий одной и той же библиотеки в одной и той же системе) и обычно сопоставляется с последней версией общего ресурса, найденной в списке каталогов, указанном в файле./etc/ld.so.conf (это статическая информация для ускорения процесса загрузки библиотек, которая генерируется при каждой загрузке системы).Если общий ресурс был найден во время соединения (этот механизм не используется ld, а используется только для загрузки библиотек во время запуска программы), чтобы иметь soname, то в /etc/ld.so.cache выполняется поиск в *1025* длянайти окончательный файл, который должен быть загружен.Этот кэш создается при каждой загрузке системы, поэтому вам не придется с этим справляться, а только если вы не хотите перезагружаться и устанавливаете новую библиотеку для системного использования.Важно отметить, что совместно используемым объектам нужно дать soname s, чтобы это работало, и что список каталогов в файле /etc/ld.so.conf является единственными каталогами, используемыми для поиска файлов.Это означает, что для использования стандартной библиотеки вам необходимо поместить ее в один из этих каталогов (или добавить каталог в список в /etc/ld.so.conf), а затем выполнить ldconfig -a, чтобы перестроить кэш и позволить ему включить ссылкудля файла под этим soname.

    Другой способ добавить его в список поиска - поместить список в форме переменной PATH.Переменная LD_LIBRARY_PATH, поэтому, если у вас есть общие объекты в ${HOME}/libs, вы можете добавить эту строку в .profile:

    export LD_LIBRARY_PATH=${HOME}/libs
    

    или

    setenv LD_LIBRARY_PATH ${HOME}/libs
    

    это позволяет вашей библиотеке жить за пределами стандартных каталогов, но подумайте дважды, так как это гораздо менее эффективный способ загрузки файла (поскольку он включает обработку списка каталогов для поиска окончательных общих объектов, в то время как предыдущий подходdirect вы запрашиваете файл, соответствующий soname, который запрашивает ld.so.xxx, только один поиск, только один шаг)

  • Второй - использовать библиотечную функцию dlopen(3)которые позволяют вам загружать общий объект и выполнять некоторую домашнюю работу, прежде чем вызывать что-либо внутри.Библиотека dl позволяет вам искать символ в общем исполняемом файле и затем решать, интерпретировать ли вы его как данные или как цель перехода.dlopen() просто открывает и загружает в виртуальное адресное пространство общий объект.Он разрешает зависимости (если требуется) и является более гибким способом (но также непрозрачным) загрузки неизвестного кода для выполнения.Так работают плагины.Вы решаете в файле конфигурации или динамически, что загружать, а затем загружаете его.Программа не должна предварительно знать таблицу символов того, с чем вы имеете дело, и вы можете свободно внедрять все, что хотите, в загружаемый модуль.

Все эти методыработать с двоичными файлами ELF, поэтому у вас есть много свободы, но и много сложностей.

подробнее ...

Как я видел из вашей компиляции:

  • вы включаете -l в команды только для компиляции , библиотеки нужны только если вы связываете исполняемый файл, не помещайте библиотеки в фазу компиляции.
  • для библиотеки, которую нужно искать и выбирать компоновщиком, она должна быть названа как lib<name>.so (без информации о версии в конце)так что это означает, что вы обычно находите три имени для стандартной библиотеки (позвольте мне использовать математическую библиотеку -lm в качестве примера):

    / usr / lib / libm.so.3.2.8 # этоELF-файл с содержимым библиотеки./usr/lib/libm.so.3 -> libm.so.3.2.8 # это имя, использованное для создания библиотеки./usr/lib/libm.so -> libm.so.3 # это фактический файл, который программа ld (1) ищет при использовании -lm.

эти ссылки должныбыть создан, как обычно не делает система.Это часть процедуры установки для общей библиотеки.Ссылка soname позволяет вам иметь разные версии библиотеки и определять, какая из них будет использоваться во время выполнения (все должны быть совместимы, чтобы вы могли обмениваться, когда вы делаете несовместимую модификацию, тогда вы должны изменить сонам,чтобы система не запуталась при загрузке)

Очень важно знать, что программа ld(1) выбирает библиотеку, только если она называется lib<name>.so, без информации о версии.Действительно, компилятор сначала ищет lib<name>.so, затем lib<name>.a, затем жалуется.

Очень важно поставить -L мест для поиска библиотек перед any *Опция 1087 *, которая будет использовать эти каталоги в параметрах связывания.

Вам нужно только запустить ldconfig -a и установить библиотеку в системный каталог, если вы не собираетесь использовать механизм LD_LIBRARY_PATH.(этот механизм не работает для учетной записи root по понятным причинам:))

Ожидается, что добавленные комментарии прояснят процесс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...