【问题标题】:install_name_tool difference between -change and -idinstall_name_tool -change 和 -id 之间的区别
【发布时间】:2016-02-05 09:07:06
【问题描述】:

我一直在为这个概念苦苦挣扎,我无法真正理解 -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 做什么以及何时使用它?

【问题讨论】:

    标签: xcode macos otool install-name-tool


    【解决方案1】:

    安装名称

    术语安装名称指的是最终用户系统中.dylib文件的确切路径,因此运行时链接器可以找到并加载动态库。

    名称可以是:

    • 绝对,系统库就是这种情况。它们在最终用户和开发人员的系统上都位于同一位置。
    • 相对,即与应用程序捆绑的库的情况。在最终用户的系统上,.dylib 将嵌入到应用程序包中,而在开发人员系统上,它们将预先构建在 /usr/local/opt/local 或其他地方,或者它们将作为一部分从源代码构建应用构建。

    后者是主要问题,因为在构建 .dylib 时,它的 安装名称 被链接器标记到 .dylib 中,并且预计会从那里找到并加载它运行。显然这不适用于最终用户系统,因为该路径仅存在于开发人员的系统上,因此解决方案是使用install_name_tool 修改库的安装名称,以及将应用程序包放在一起时,请参考这些库。

    占位符

    由于可执行文件/应用程序包可以安装在最终用户系统的不同位置,您可以使用占位符系统来抽象 安装名称 位置:

    • @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 文件。

    【讨论】:

    • 您是说我们在 /Contents/MacOS/ 内的主要可执行文件上更改内容时使用 -id 吗?
    • @MistyD 不,你会使用-change
    • 所以我仍然对何时使用 -change 感到困惑?你有任何文章可以解释这一点
    • @MistyD 不,很抱歉我没有。
    • @MistyD 有点晚了,但我决定重做我的答案。
    【解决方案2】:

    install_name_tool -id 用于更改dylibinstall name,您可以使用otool -D 在终端中查看一个dylib install name,它会为您显示默认值,/some/path/another_library.dylibanother_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中的例子

    【讨论】:

      【解决方案3】:

      id 在链接时使用,install name 在运行时使用。它们都是为链接器定位 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。让我们链接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再链接一次,

      $ 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

      让我们再次链接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 的运行时位置在 second 行更改为 foo/liba.dylib

      基本上,它告诉 libb.dylib 从current_dir/foo 找到 liba.dylib

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 2016-11-17
        • 1970-01-01
        • 2014-02-09
        • 2011-06-09
        • 2019-04-27
        • 2013-03-07
        相关资源
        最近更新 更多