Исполняемый файл C ++ не может связаться с общей библиотекой после scp - PullRequest
1 голос
/ 21 ноября 2019

Итак, я работаю над проектом, который предназначен для запуска на удаленном сервере. Я разрабатываю программу на локальном компьютере, компилирую ее, затем загружаю на удаленный сервер. И локальный компьютер, и удаленный сервер работают на CentOS 7.7.

Программа разработана с использованием CLion IDE, настроенной с помощью CMake. Программа зависит от нескольких общих библиотек, которые должны ссылаться на исполняемый файл в соответствии с тем, что я написал в CMake. На моем локальном ПК я могу отлично скомпилировать и запустить программу. Тем не менее, после того, как я scp весь каталог проекта на удаленном сервере, исполняемый файл не запускается. Он не может найти ни один из файлов ".so", в соответствии с тем, что говорит ldd.

Это мой CMakeList.txt, где каждый путь является относительным путем, а не абсолютным.

cmake_minimum_required(VERSION 3.15)
project(YS_Test)

set(CMAKE_CXX_STANDARD 11)

set(SOURCE_PATH_ src)

file(GLOB SOURCE_FILES_ ${SOURCE_PATH_}/*.*)

set(PROJECT_LIBS_ libTapQuoteAPI.so libTapTradeAPI.so libTapDataCollectAPI.so)

include_directories(api/include)
link_directories(api/lib/linux)

add_executable(YS_Test ${SOURCE_FILES_})

target_link_libraries(YS_Test ${PROJECT_LIBS_})

Пожалуйста, не говорите мне установить LD_LIBRARY_PATH, чтобы исправить мою проблему. Программа работала на моем локальном компьютере без LD_LIBRARY_PATH, поэтому я ожидаю, что она будет работать на удаленном сервере без LD_LIBRARY_PATH. Я хотел бы знать, что на самом деле здесь происходит, вместо того, чтобы работать вокруг. Спасибо!

Ответы [ 2 ]

1 голос
/ 21 ноября 2019

Поскольку вы не хотите обходного пути (@Botje уже дал вам два), я попробую объяснение вместо этого. Если на вашей машине разработки используется эта команда:

ldd YS_Test

Вы увидите все общие библиотеки, используемые вашей программой, с соответствующими путями. LibTapQuoteAPI.so libTapTradeAPI.so libTapDataCollectAPI.so находятся в вашем каталоге 'api / lib / linux', но разрешены с полными абсолютными путями. Если вы делаете то же самое на своем сервере, некоторые общие объекты не могут быть разрешены, потому что они не находятся в одном месте.

Если вы используете одну из следующих команд (не уверены, какие из них доступны в Centos):

chrpath --list YS_Test

или

patchelf --print-rpath YS_Test

Вы увидите RPATH илиRUNPATH теги, встроенные в вашу программу. Этот путь используется компоновщиком Linux для поиска зависимостей, которые находятся за пределами стандартных ld местоположений. Вы можете найти расширенные объяснения в Интернете по этому поводу, например этот или статья в Википедии .

Нарушая свое обещание, я даю вам третий обходной путь: используйте patchelf или chrpath на вашем сервере после scp для изменения встроенного тега RPATH, указывая его относительно $ORIGIN (который представляет местоположение программы).

1 голос
/ 21 ноября 2019

Если я правильно понимаю вашу проблему, вы хотите отправить скомпилированную программу YS_Test вместе с некоторыми зависимостями и запустить ее на удаленном сервере. По умолчанию исполняемый файл будет искать только в каталогах, настроенных в /etc/ld.so, в которые не будет включен путь развертывания.

Примечание. Обычно вы развертываете не весь каталог сборки , а толькоскомпилированные артефакты и зависимости. В этом ответе я предполагаю, что вы развертываете двоичный файл и его зависимости в том же каталоге.

У вас есть два варианта:

  • Требовать от пользователей вашей программыустановить LD_LIBRARY_PATH, либо самостоятельно, либо с помощью скрипта-обёртки. Эта переменная будет инструктировать динамический компоновщик также искать в указанных каталогах. Даже если вам не нравится это решение, оно является наиболее распространенным подходом.
  • Добавьте -Wl,-rpath='$ORIGIN' к параметрам компоновщика. Это добавит атрибут DT_RUNPATH в динамический раздел исполняемого файла. Поскольку вы используете CMake, вы также можете установить его, используя целевые свойства BUILD_RPATH и / или INSTALL_RPATH. Страница man ld.so описывает этот атрибут следующим образом:

    Если зависимость общего объекта не содержит косую черту, то она ищется в следующем порядке:

    • ...
    • Использование каталогов, указанных в атрибуте динамического раздела DT_RUNPATH двоичного файла, если таковой имеется.

    Часть $ORIGIN расширяется до каталога, содержащего программу илиобщий объект.

Если вы действительно настаиваете на отправке вашего каталога сборки (например, во время разработки), вы можете взглянуть на CMake BUILD_RPATH_USE_ORIGINСвойство (и его обычный глобальный аналог CMAKE_BUILD_RPATH_USE_ORIGIN) позволяет вставлять относительных путей в двоичные файлы вместо абсолютных.

...