Я хочу изменить rpath исполняемого файла с помощью install_name_tool
, но сейчас не могу понять, что такое rpath. install_name_tool
требует, чтобы в командной строке были указаны как старый, так и новый rpath. Какую команду я могу использовать для печати rpath исполняемого файла в macOS?
Распечатать rpath исполняемого файла в macOS
Ответы (5)
Прежде всего, поймите, что исполняемый файл содержит не одну запись rpath
, а массив из одной или нескольких записей.
Во-вторых, вы можете использовать otool
для вывода списка rpath
элементов изображения. Используя otool -l
, вы получите следующий вывод, в самом конце которого находятся записи rpath
:
Load command 34
cmd LC_LOAD_DYLIB
cmdsize 88
name /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (offset 24)
time stamp 2 Wed Dec 31 19:00:02 1969
current version 1038.32.0
compatibility version 45.0.0
Load command 35
cmd LC_RPATH
cmdsize 40
path @loader_path/../Frameworks (offset 12)
Найдите команды LC_RPATH
и обратите внимание на путь под записью path
.
РЕДАКТИРОВАТЬ: относительно того, что такое @loader_path
: это общий и динамический способ обращения к объекту Mach-O, который хочет выполнить загрузку фреймворка.
Хотя это довольно надуманный пример, я думаю, что он должен донести суть. Допустим, у нас есть приложение MyApp.app
, использующее фреймворк MyFramework.framework
. Мы также скажем, что для правильной работы мне нужно, чтобы мое приложение было установлено в /Applications и нигде больше. Таким образом, структура указанного приложения и фреймворка будет следующей:
/Applications/MyApp.app/Contents/MacOS/MyApp
(исполняемый файл) /Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/MyFramework
(Mach-O dylib)
Если бы мы запустили otool -L
(обратите внимание на заглавную букву L) в исполняемом файле, это показало бы следующее относительно MyFramework:
@rpath/MyFramework.framework/Versions/A/MyFramework
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
/usr/lib/libobjc.A.dylib
/usr/lib/libSystem.B.dylib
....
Обратите внимание: поскольку MyFramework.framework использует имя/путь установки @rpath
, нам потребуются записи пути поиска во время выполнения, которые будут заменены вместо @rpath
во время выполнения. Теперь у меня может быть одна запись rpath:
/Applications/MyApp.app/Contents/Frameworks
Это будет работать, и во время выполнения две части будут объединены:
/Applications/MyApp.app/Contents/Frameworks
+ /MyFramework.framework/Versions/A/MyFramework
==
/Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/Versions/A/MyFramework
Очевидно, что жесткое кодирование такого пути не идеально, так как простое перемещение приложения в другую папку или переименование самого приложения приведет к сбою связывания.
@loader_path
— это просто динамический способ ссылки на исполняемый файл приложения, где бы он ни находился в файловой системе. В этом конкретном случае во время выполнения он будет заполнен путем к работающему исполняемому файлу: /Applications/MyApp.app/Contents/MacOS/MyApp
. Тогда мы можем сказать, что для того, чтобы найти MyFramework.framework, вы просто идете вверх по каталогу и переходите к Frameworks
.
@loader_path
?
- person nn0p; 26.11.2016
Вы можете использовать otool -l myexecutable
, но это выводит много ненужной информации, если вас интересует только список rpath.
Вы можете отфильтровать вывод otool -l
по соответствующим записям rpath с помощью
otool -l myexecutable | grep RPATH -A2
Я обнаружил, что могу распечатать имя установки общей библиотеки в macOS, используя
otool -D mylib
Более того, я могу установить имя установки напрямую, без ссылки на старое имя установки, передав флаг -id
в install_name_tool
:
install_name_tool -id @rpath/my/path mylib
В настоящее время я пишу несколько сценариев Bash-3 для обработки DYLD, и этот отвечает на вопрос, поэтому я публикую его для справки:
#! /bin/bash
# ######################################################################### #
if [ ${#} -eq 0 ]
then
echo "
Usage: ${0##*/} FILE...
List rpaths in FILEs
"
exit 0
fi
# ######################################################################### #
shopt -s extglob
# ######################################################################### #
for file in "${@}"
do
if [ ! -r "${file}" ]
then
echo "${file}: no such file" 1>&2
continue
fi
if ! [[ "$(/usr/bin/file "${file}")" =~ ^${file}:\ *Mach-O\ .*$ ]]
then
echo "${file}: is not an object file" 1>&2
continue
fi
if [ ${#} -gt 1 ]
then
echo "${file}:"
fi
IFS_save="${IFS}"
IFS=$'\n'
_next_path_is_rpath=
while read line
do
case "${line}" in
*(\ )cmd\ LC_RPATH)
_next_path_is_rpath=yes
;;
*(\ )path\ *\ \(offset\ +([0-9])\))
if [ -z "${_next_path_is_rpath}" ]
then
continue
fi
line="${line#* path }"
line="${line% (offset *}"
if [ ${#} -gt 1 ]
then
line=$'\t'"${line}"
fi
echo "${line}"
_next_path_is_rpath=
;;
esac
done < <(/usr/bin/otool -l "${file}")
IFS="${IFS_save}"
done
# ######################################################################### #
'Надеюсь, поможет ;-)
NB: Кто-нибудь знает некоторые приемы Bash-3, которые могут быть полезны для этого скрипта?
Я просто использую команду otool
otool -l <my executable>
Он распечатывает поле rpath. Нет необходимости в длинных сценариях.