install_name_tool -change 和 -id 的区别
install_name_tool difference between -change and -id
我一直在为这个概念苦苦挣扎一段时间,我无法真正理解 -change
和 -id
之间的区别。手册页指出
-id name
Changes the shared library identification name of a dynamic shared library to name. If the Mach-O binary is not a dynamic
shared library and the -id option is specified it is ignored.
-change old new
Changes the dependent shared library install name old to new in the specified Mach-O binary. More than one of these options
can be specified. If the Mach-O binary does not contain the old install name in a specified -change option the option is
ignored.
到目前为止,我已经尝试了 -change
。假设我有以下结构
Test.App
|_Contents
|_MacOS
| |_test -----> item A
|_Library
|_test_library.dylib --->item B
|_another_library.dylib --->item C
现在假设我 运行 itemB
上的以下内容
$ otool -L test_library.dylib
test_library.dylib
/some/path/another_library.dylib -->item D
以上结果表明 test_library.dylib
依赖于 another_library.dylib
现在如果我需要更改 another_library.dylib
的位置我会这样做
install_name_tool -change /some/path/another_library.dylib some/new/path/another_library.dylib test_library.dylib
这会改变项目 D 的位置。我的问题是 install-name_tool -id
有什么作用以及我什么时候使用它?
安装名称
术语安装名称指的是最终用户系统中.dylib
文件的确切路径,因此运行time链接器可以找到并加载动态库。
名称可以是:
- 绝对,系统库就是这样。它们在最终用户和开发人员的系统中位于同一位置。
- 相对,这是与应用程序捆绑在一起的库的情况。在最终用户的系统上,
.dylib
将嵌入到应用程序包中,而在开发人员系统上,它们将预先构建在 /usr/local
、/opt/local
或其他地方,或者它们将作为应用构建的一部分从源构建。
后者是主要问题,因为在构建 .dylib
时,它的 安装名称 被链接器标记到 .dylib
中,这就是预计会在 运行 时间找到并加载它。显然这不会在最终用户系统上工作,因为该路径只存在于开发人员的系统上,所以解决方案是使用 install_name_tool
修改 install name库和引用这些库的可执行文件,将应用程序包放在一起时。
占位符
由于 executables/app 捆绑包可以安装在最终用户系统的不同位置,您可以使用占位符系统来抽象 安装名称 位置:
@executable_path
:主要可执行文件的完整路径。
@loader_path
:引用可执行文件的完整路径或.dylib
。
@rpath
:主要可执行文件中设置的 RPATH。这也可以使用 install_name_tool
. 更改
因此,例如在 macOS 应用程序包中,可执行文件将位于 TheApp.app/Contents/MacOS/TheApp
中,库将位于 TheApp.app/Contents/Frameworks
中,因此您需要使用路径 @executable_path/../Frameworks/Library.dylib
引用库。
然而,最好将主要可执行文件的 RPATH 设置为 @executable_path/../Frameworks
,并使用 @rpath/Library.dylib
.
引用库
install_name_tool
install_name_tool
有两个主要选项:
-id
:设置 .dylib
文件本身的 安装名称 并将用作原型 安装名称 从那时起,当某些东西与 .dylib
链接时。您可以在构建 .dylib
后立即“更正” 安装名称,但这是一个不寻常的工作流程,因为图书馆如何知道使用它的环境?
-change
:这会更改引用可执行文件(或 dylib)中 .dylib
的 安装名称 。
当 -id
名称与 -change
名称不匹配时会发生什么?没有什么。 -change
选项是正确的重要选项,因为一旦 运行 时间链接器找到 .dylib
,任务就完成了。
xcodedevtools
您显然会使用脚本编写所有修复程序,但这有点乏味,所以我开发了 copy_dylibs.py
脚本来为您完成所有工作。在链接您的应用程序可执行文件后将其配置为 运行,它会查看您的可执行文件以递归查找 .dylib
文件以复制到应用程序包中。然后它修复了它们的 安装名称 ,留下原始的 .dylib
文件。
install_name_tool -id
用于改变dylib
的install name
,你可以使用otool -D
在终端中看到一个dylib install name
,它会为你显示默认值,/some/path/another_library.dylib
是another_library.dylib
的默认install name
,当然你可以在终端中使用install_name_tool -id
更改它,就像这样使用终端
install_name_tool -id /some/path/another_library_newname.dylib /some/path/another_library.dylib
现在,你使用otool -D /some/path/another_library.dylib
,你会发现install name
是/some/path/another_library_newname.dylib
这是我在 picture
中的示例
id
在link时使用,install name
在运行时使用。它们都是为linker 定位 dylib 提供的信息。我关注了这个 tutorial.
让我举个例子,
$ cat a.cc
#include <iostream>
void a() { std::cout << "a()" << std::endl; }
$ clang++ -c a.cc
$ clang++ -o liba.dylib -dynamiclib a.o
$ otool -L liba.dylib
liba.dylib:
liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
如您所见,第一行是 id
。让我们 link 和 libb.dylib,
$ cat b.cc
#include <iostream>
void a();
void b() { std::cout << "b()" << std::endl; a(); }
$ clang++ -c b.cc
$ clang++ -o libb.dylib -dynamiclib b.o -L. -la
$ otool -L libb.dylib
libb.dylib:
libb.dylib (compatibility version 0.0.0, current version 0.0.0)
liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
请注意第二行,这里使用了 liba.dylib 的 id
。让我们再次将 id 更改为 foo/liba.dylib
和 link,
$ install_name_tool -id foo/liba.dylib liba.dylib
$ otool -D liba.dylib
liba.dylib:
foo/liba.dylib
liba.dylib:
foo/liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
所以你看到 -D
和 -L
都将当前 id
输出为 foo/liba.dylib
。
让我们再次 link 和 liba.dylib,
$ clang++ -o libb.dylib -dynamiclib b.o -L. -la
$ otool -L libb.dylib
libb.dylib:
libb.dylib (compatibility version 0.0.0, current version 0.0.0)
foo/liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
看出区别了吗? 运行 查找 liba.dylib 的时间位置更改为 第二 行的 foo/liba.dylib
。
基本上,它告诉 libb.dylib 从 current_dir/foo
中找到 liba.dylib
我一直在为这个概念苦苦挣扎一段时间,我无法真正理解 -change
和 -id
之间的区别。手册页指出
-id name
Changes the shared library identification name of a dynamic shared library to name. If the Mach-O binary is not a dynamic
shared library and the -id option is specified it is ignored.
-change old new
Changes the dependent shared library install name old to new in the specified Mach-O binary. More than one of these options
can be specified. If the Mach-O binary does not contain the old install name in a specified -change option the option is
ignored.
到目前为止,我已经尝试了 -change
。假设我有以下结构
Test.App
|_Contents
|_MacOS
| |_test -----> item A
|_Library
|_test_library.dylib --->item B
|_another_library.dylib --->item C
现在假设我 运行 itemB
上的以下内容$ otool -L test_library.dylib
test_library.dylib
/some/path/another_library.dylib -->item D
以上结果表明 test_library.dylib
依赖于 another_library.dylib
现在如果我需要更改 another_library.dylib
的位置我会这样做
install_name_tool -change /some/path/another_library.dylib some/new/path/another_library.dylib test_library.dylib
这会改变项目 D 的位置。我的问题是 install-name_tool -id
有什么作用以及我什么时候使用它?
安装名称
术语安装名称指的是最终用户系统中.dylib
文件的确切路径,因此运行time链接器可以找到并加载动态库。
名称可以是:
- 绝对,系统库就是这样。它们在最终用户和开发人员的系统中位于同一位置。
- 相对,这是与应用程序捆绑在一起的库的情况。在最终用户的系统上,
.dylib
将嵌入到应用程序包中,而在开发人员系统上,它们将预先构建在/usr/local
、/opt/local
或其他地方,或者它们将作为应用构建的一部分从源构建。
后者是主要问题,因为在构建 .dylib
时,它的 安装名称 被链接器标记到 .dylib
中,这就是预计会在 运行 时间找到并加载它。显然这不会在最终用户系统上工作,因为该路径只存在于开发人员的系统上,所以解决方案是使用 install_name_tool
修改 install name库和引用这些库的可执行文件,将应用程序包放在一起时。
占位符
由于 executables/app 捆绑包可以安装在最终用户系统的不同位置,您可以使用占位符系统来抽象 安装名称 位置:
@executable_path
:主要可执行文件的完整路径。@loader_path
:引用可执行文件的完整路径或.dylib
。@rpath
:主要可执行文件中设置的 RPATH。这也可以使用install_name_tool
. 更改
因此,例如在 macOS 应用程序包中,可执行文件将位于 TheApp.app/Contents/MacOS/TheApp
中,库将位于 TheApp.app/Contents/Frameworks
中,因此您需要使用路径 @executable_path/../Frameworks/Library.dylib
引用库。
然而,最好将主要可执行文件的 RPATH 设置为 @executable_path/../Frameworks
,并使用 @rpath/Library.dylib
.
install_name_tool
install_name_tool
有两个主要选项:
-id
:设置 .dylib
文件本身的 安装名称 并将用作原型 安装名称 从那时起,当某些东西与 .dylib
链接时。您可以在构建 .dylib
后立即“更正” 安装名称,但这是一个不寻常的工作流程,因为图书馆如何知道使用它的环境?
-change
:这会更改引用可执行文件(或 dylib)中 .dylib
的 安装名称 。
当 -id
名称与 -change
名称不匹配时会发生什么?没有什么。 -change
选项是正确的重要选项,因为一旦 运行 时间链接器找到 .dylib
,任务就完成了。
xcodedevtools
您显然会使用脚本编写所有修复程序,但这有点乏味,所以我开发了 copy_dylibs.py
脚本来为您完成所有工作。在链接您的应用程序可执行文件后将其配置为 运行,它会查看您的可执行文件以递归查找 .dylib
文件以复制到应用程序包中。然后它修复了它们的 安装名称 ,留下原始的 .dylib
文件。
install_name_tool -id
用于改变dylib
的install name
,你可以使用otool -D
在终端中看到一个dylib install name
,它会为你显示默认值,/some/path/another_library.dylib
是another_library.dylib
的默认install name
,当然你可以在终端中使用install_name_tool -id
更改它,就像这样使用终端
install_name_tool -id /some/path/another_library_newname.dylib /some/path/another_library.dylib
现在,你使用otool -D /some/path/another_library.dylib
,你会发现install name
是/some/path/another_library_newname.dylib
这是我在 picture
中的示例id
在link时使用,install name
在运行时使用。它们都是为linker 定位 dylib 提供的信息。我关注了这个 tutorial.
让我举个例子,
$ cat a.cc
#include <iostream>
void a() { std::cout << "a()" << std::endl; }
$ clang++ -c a.cc
$ clang++ -o liba.dylib -dynamiclib a.o
$ otool -L liba.dylib
liba.dylib:
liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
如您所见,第一行是 id
。让我们 link 和 libb.dylib,
$ cat b.cc
#include <iostream>
void a();
void b() { std::cout << "b()" << std::endl; a(); }
$ clang++ -c b.cc
$ clang++ -o libb.dylib -dynamiclib b.o -L. -la
$ otool -L libb.dylib
libb.dylib:
libb.dylib (compatibility version 0.0.0, current version 0.0.0)
liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
请注意第二行,这里使用了 liba.dylib 的 id
。让我们再次将 id 更改为 foo/liba.dylib
和 link,
$ install_name_tool -id foo/liba.dylib liba.dylib
$ otool -D liba.dylib
liba.dylib:
foo/liba.dylib
liba.dylib:
foo/liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
所以你看到 -D
和 -L
都将当前 id
输出为 foo/liba.dylib
。
让我们再次 link 和 liba.dylib,
$ clang++ -o libb.dylib -dynamiclib b.o -L. -la
$ otool -L libb.dylib
libb.dylib:
libb.dylib (compatibility version 0.0.0, current version 0.0.0)
foo/liba.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1)
看出区别了吗? 运行 查找 liba.dylib 的时间位置更改为 第二 行的 foo/liba.dylib
。
基本上,它告诉 libb.dylib 从 current_dir/foo