Je souhaite modifier le chemin de ronde d'un exécutable à l'aide de install_name_tool
mais je n'arrive pas à comprendre ce que le chemin de ronde est en ce moment même. install_name_tool
nécessite à la fois l'ancien et le nouveau chemin de ronde à indiquer sur la ligne de commande. Quelle commande puis-je utiliser pour imprimer le chemin de ronde d'un exécutable sous macOS ?
Réponses
Trop de publicités?Tout d'abord, il faut comprendre qu'un exécutable ne contient pas un seul rpath
mais un tableau d'une ou plusieurs entrées.
Deuxièmement, vous pouvez utiliser otool
pour répertorier les rpath
entrées. L'utilisation de otool -l
vous obtiendrez un résultat comme celui qui suit, à la toute fin duquel se trouvent les éléments suivants rpath
entrées :
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)
Recherchez le LC_RPATH
et notez le chemin d'accès sous la commande path
entrée.
EDIT : à propos de quoi @loader_path
est un moyen générique et dynamique de se référer à l'objet Mach-O qui veut charger le cadre.
Bien qu'il s'agisse d'un exemple plutôt artificiel, je pense qu'il devrait faire passer le message. Supposons que nous ayons une application MyApp.app
qui utilise un cadre MyFramework.framework
. Nous dirons également que pour fonctionner correctement, j'ai besoin que mon application soit installée dans le répertoire /Applications et nulle part ailleurs. La structure de cette application et de ce framework serait donc la suivante :
/Applications/MyApp.app/Contents/MacOS/MyApp
(exécutable) /Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/MyFramework
(Mach-O dylib)
Si nous devions exécuter otool -L
(notez le L majuscule) sur l'exécutable, il afficherait ce qui suit concernant 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
....
Il convient de noter que, comme MyFramework.framework utilise un fichier @rpath
nous aurons besoin d'entrées de chemin de recherche au moment de l'exécution qui seront substituées à la place de @rpath
au moment de l'exécution. Maintenant, je pourrais avoir une seule entrée rpath de :
/Applications/MyApp.app/Contents/Frameworks
Cela fonctionnerait et, au moment de l'exécution, les deux parties seraient réunies :
/Applications/MyApp.app/Contents/Frameworks
+ /MyFramework.framework/Versions/A/MyFramework
==
/Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/Versions/A/MyFramework
Il est évident que le codage en dur d'un tel chemin n'est pas idéal, car il suffit de déplacer l'application dans un autre dossier ou de renommer l'application elle-même pour que la liaison échoue.
@loader_path
est simplement un moyen dynamique de faire référence à l'exécutable de l'application, quel que soit l'endroit où il se trouve dans le système de fichiers. Dans ce cas particulier, au moment de l'exécution, il sera rempli avec le chemin de l'exécutable en cours d'exécution : /Applications/MyApp.app/Contents/MacOS/MyApp
. Nous pouvons donc dire que pour trouver MyFramework.framework, il suffit de monter d'un répertoire et d'aller jusqu'à Frameworks
.
J'ai découvert que je pouvais imprimer le nom d'installation d'une bibliothèque partagée sur macOS en utilisant
otool -D mylib
De plus, je peux définir le nom d'installation directement sans référence à l'ancien nom d'installation en passant le paramètre -id
à install_name_tool
:
install_name_tool -id @rpath/my/path mylib
Je suis en train d'écrire plusieurs scripts pour traiter DYLD et celui-ci répond à la question, je le poste donc pour référence :
#!/usr/bin/env ruby
require 'open3'
stdout, stderr, status = Open3.capture3('/usr/bin/otool', '-l', *ARGV)
stdout.scan(/^ +cmd LC_RPATH$.*?^ +path (.*?) \(offset \d+\)$/m) {|(p)| puts p}
Exemple :
lsrpath /usr/local/microsoft/powershell/7/{pwsh,createdump,unknown.xyz}
@loader_path
J'espère que cela vous aidera ;-)