gpt4 book ai didi

c - 使用 clang 从命令行链接 .dylib 库

转载 作者:太空狗 更新时间:2023-10-29 16:05:25 25 4
gpt4 key购买 nike

我正在尝试使用库编写 C 程序。图书馆提供了include/lib/带有头文件和 .dylib 的目录文件,分别。

我的文件与 include/ 位于同一目录中和 lib/ .我正在尝试使用以下命令对其进行编译:

clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window test.c

但是,当我运行我的程序时,出现以下错误:
% ./a.out 
dyld: Library not loaded: @rpath/libcsfml-graphics.2.4.dylib
Referenced from: ~/src/CSFML-2.4-osx-clang/./a.out
Reason: image not found
zsh: abort ./a.out

使用这些库进行编译的正确方法是什么?我更喜欢简单地使用命令行,因为我正在编写一个小程序,而不必设置 Xcode 等。
% ls -l lib/
-rwxr-xr-x@ 1 staff 50296 Mar 1 2017 libcsfml-audio.2.4.0.dylib*
lrwxr-xr-x@ 1 staff 26 Mar 1 2017 libcsfml-audio.2.4.dylib@ -> libcsfml-audio.2.4.0.dylib
lrwxr-xr-x@ 1 staff 24 Mar 1 2017 libcsfml-audio.dylib@ -> libcsfml-audio.2.4.dylib
-rwxr-xr-x@ 1 staff 163680 Mar 1 2017 libcsfml-graphics.2.4.0.dylib*
lrwxr-xr-x@ 1 staff 29 Mar 1 2017 libcsfml-graphics.2.4.dylib@ -> libcsfml-graphics.2.4.0.dylib
lrwxr-xr-x@ 1 staff 27 Mar 1 2017 libcsfml-graphics.dylib@ -> libcsfml-graphics.2.4.dylib
-rwxr-xr-x@ 1 staff 67272 Mar 1 2017 libcsfml-network.2.4.0.dylib*
lrwxr-xr-x@ 1 staff 28 Mar 1 2017 libcsfml-network.2.4.dylib@ -> libcsfml-network.2.4.0.dylib
lrwxr-xr-x@ 1 staff 26 Mar 1 2017 libcsfml-network.dylib@ -> libcsfml-network.2.4.dylib

最佳答案

似乎在用 clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window -Wl,-rpath,"@executable_path/lib" test.c 修复了 rpath 之后您仍然缺少 SFML 库。我刚刚检查了 CSFML 依赖于 SFML,并且基于您的 ls -l lib/ list 中, SFML 显然不在 lib/.我的猜测是,在修复 rpath 之后,您可能没有注意到缺少的依赖项已更改为 @rpath/libsfml-graphics.2.4.dylib而不是 @rpath/libcsfml-graphics.2.4.dylib .请下载 SFML 库并将它们放入 lib/.

现在回答您的问题,如何从命令行在 macOS 上构建。您的构建步骤是正确的,所以我认为困难的部分是 dyld 如何搜索依赖项,而不是它们如何与 ld 链接。

一个简短的理论。

二进制文件(可执行文件或动态库)有 4 种方式引用其依赖项:

  • 通过绝对或相对路径(后者相对于您的工作目录);
  • 通过@executable_path,扩展为依赖树根的可执行文件的路径(如果你有递归依赖);
  • 通过@loader_path,扩展为搜索依赖的可执行文件或库的路径,即它是依赖树中直接父级的路径;
  • 由@rpath 依次替换为二进制文件中的每个rpath,这是最灵活的方式,因为您可以通过拥有多个rpath 在多个目录中进行搜索。

  • 现在的问题是如何确保正确引用依赖项。正如@mattmilten 指出的那样,有两种方法:
  • 使您的构建系统/构建脚本/手动构建命令确保引用正确;
  • 使用 install_name_tool 更正损坏的引用。

  • 在构建过程中使其自动化。

    为了使第一种方法起作用,您需要确保依赖库的标识名称是正确的。假设您将二进制文件链接到某个库 libA.dylib . libA.dylib 的标识名称是链接器 (ld) 在构建二进制文件时将使用的默认引用。您可以通过查看 otool -L libA.dylib 的第一行来找到它(或者在 otool -l libA.dylib 的 LC_ID_DYLIB 部分)。如果是 libcsfml-graphics.2.4.dylib它是 @rpath/libcsfml-graphics.2.4.dylib并且它在链接时被传递给 a.out,这就是为什么当 dyld 无法满足它时您在错误消息中看到它的原因。

    设置正确的标识名称是 libA.dylib 作者的责任。它是根据他们对 libA.dylib 可以放置的位置(使用@rpath 是一个不错的选择)以及他们的版本控制方案(如果 CSFML 版本 2.4.0 可以替换为 2.4.x 而不会丢失二进制文件)的期望来设置的兼容性)。如果您自己构建 libA.dylib,您可以使用 -install_name 进行设置参数(例如 clang -Wl,-dylib -Wl,-install_name,@executable_path/libA.dylib -o libA.dylib liba.c )。如果是第 3 方库,您可以使用 install_name_tool -id @rpath/libA.dylib libA.dylib 进行更改.

    据我所知,标识名称仅在链接期间使用,在加载二进制文件时不使用,因此如果您更喜欢使用 install_name_tool 修复错误引用的第二种方法,您可以忽略它。

    手动固定。

    使用 install_name_tool 修复引用很简单但很乏味。当有很多不正确的引用时,您可能需要一个脚本。您只需要以下一组命令( binary 占位符显然应该替换为实际的二进制名称):
  • install_name_tool -change @executable_path/libA.dylib @rpath/libA.dylib binary更改引用 @executable_path/libA.dylib -> @rpath/libA.dylib ;
  • install_name_tool -add_rpath @executable_path/lib binary添加@executable_path/lib到rpaths;
  • install_name_tool -delete_rpath @executable_path/lib binary删除 @executable_path/lib来自 rpaths;
  • otool -l binary检查现有的 rpath(只需查看 LC_RPATH 部分)。
  • 关于c - 使用 clang 从命令行链接 .dylib 库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52981210/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com