构建一个使用 ld 选项 -rpath 和 $ORIGIN 的简单(hello-world-esque)示例 [英] Building a simple (hello-world-esque) example of using ld's option -rpath with $ORIGIN

查看:12
本文介绍了构建一个使用 ld 选项 -rpath 和 $ORIGIN 的简单(hello-world-esque)示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:下面是完整的工作示例.原始问题如下:

我在使用带有 $ORIGIN 的 ld 的 -rpath 参数时遇到问题.
由于找不到完整的示例,我想我会尝试自己写一个,以便我和其他人以后可以使用它.一旦我得到它的工作,我会整理它.

I'm having problems using ld's -rpath parameter with $ORIGIN.
As I couldn't find a complete example, I thought I'd try to write one myself, so that I and others can use it later. Once I get it working I'll tidy it up.

我之前问过这个问题,但是我觉得我的帖子有点混乱.

I asked about this before, but I think my post was a bit confusing.

示例项目构建了一个共享库和一个链接到该库的可执行文件.
它非常小(3 个文件,22 行,包括构建脚本).
您可以从这里

The example project builds one shared library and one executable that links to said library.
It's very small (3 files, 22 lines incl buildscript).
You can download the project from here

文件结构(构建前):

  • 项目/
    • src/
      • foo.cpp
      • main.cpp

      project/src/foo.cpp

      
      int foo()
        { return 3; }
      

      project/src/main.cpp

      
      int foo();
      
      #include <iostream>
      int main()
        {
          std::cout << foo() << std::endl;
          return 0;
        }
      

      project/make.sh

      
      # Make directories:
      mkdir -p -v obj
      mkdir -p -v lib
      mkdir -p -v run
      
      # Build the library:
      g++ -c -o obj/foo.o src/foo.cpp -fPIC
      g++ -shared -o lib/foo.sh obj/foo.o
      
      # Build the executable:
      g++ -c -o obj/main.o src/main.cpp
      g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../../lib' -Llib -l:foo.sh
      

      <小时>

      project 目录,运行 make.sh(确保它是可执行的).


      From the project directory, run make.sh (make sure it's executable).

      文件结构(构建后):

      • 项目/
        • src/
          • foo.cpp
          • main.cpp
          • foo.o
          • main.o
          • foo.so
          • main.run

          run/main.run 现在应该在执行时从任何地方加载 lib/foo.sh.

          run/main.run should now load lib/foo.sh on execution, from anywhere.

          目前,这仅部分有效.
          文件编译和链接正常,但是当从 project 以外的任何目录运行时链接失败(这是练习的重点).

          Currently, this only partly works.
          The files compile and link OK, but it fails to link when run from any directory except project (which is the point of the exercise).

          readelf -d 检查 main.run 显示:
          0x0000000000000001(需要)共享库:[lib/foo.sh]
          0x000000000000000f (RPATH) 库路径:[$ORIGIN/../../lib]看起来很接近(我宁愿有 [foo.sh] 而不是 [lib/foo.sh] 但我稍后会修复它).

          Inspecting main.run with readelf -d shows:
          0x0000000000000001 (NEEDED) Shared library: [lib/foo.sh]
          0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../../lib] Which looks close (I'd rather have [foo.sh] than [lib/foo.sh] but I'll fix that later).

          AFAICT -Wl,-rpath,'$ORIGIN/../../lib' 中的$ORIGIN 表示project/run/main.运行 所以这个rpath应该变成project/lib.

          AFAICT the $ORIGIN in -Wl,-rpath,'$ORIGIN/../../lib' means project/run/main.run so this rpath should become project/lib.

          我试过$ORIGIN/.., $ORIGIN/../lib, $ORIGIN/../..,$ORIGIN/../../lib 无济于事.

          I have tried $ORIGIN/.., $ORIGIN/../lib, $ORIGIN/../.., $ORIGIN/../../lib to no avail.

          注意:我使用的是 -l:,它需要完整的库文件名(除其他原因外,当所有函数采用相同的名称格式时,使用变量编写脚本更容易).

          Note: I'm using -l: which requires the complete library filename (amongst other reasons, it's easier to script with variables when all functions take the same name format).

          有谁知道为什么这不起作用?
          或者,是否有人拥有或知道完整的工作示例?

          Does anyone know why this isn't working?
          Or alternately, does anyone have or know of a complete working example?

          推荐答案

          (我宁愿使用 [foo.sh] 而不是 [lib/foo.sh] 但我稍后会修复它).

          (I'd rather have [foo.sh] than [lib/foo.sh] but I'll fix that later).

          您的大部分问题是:名称中的 / 阻止了动态链接器执行 rpath 魔术.

          There's most of your problem: the / in the name stops the dynamic linker from doing the rpath magic.

          (你的 rpath 也是错误的.想想看:从 shell 中,如果你当前在你的可执行文件所在的目录中,你将如何到达你的库所在的目录?在这里,你需要 cd ../lib.所以你的 rpath 应该是 $ORIGIN/../lib.)

          (Your rpath is wrong too. Think about it: from the shell, if you were currently in the directory where your executable is, how would you get to the directory where your library is? Here, you'd need to cd ../lib. So your rpath should be $ORIGIN/../lib.)

          如果您将对象构建为 libfoo.so 并与 -Llib -lfoo 链接,则链接器会找出您的意图,并做正确的事.但是,如果您要使用不寻常的命名约定,则必须提供帮助:

          If you built your object as libfoo.so and linked with -Llib -lfoo, the linker would work out what you were intending, and do the right thing. But if you're going to use unusual naming conventions, you'll have to help it out:

          1. 更改库的链接行以将库的 SONAME 显式设置为 foo.sh:

          g++ -shared -Wl,-soname,foo.sh -o lib/foo.sh obj/foo.o

          修复rpath:

          g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib' -Llib -l:foo.sh

          运行 ldd main/main.run 来查看发生了什么很有用.在您最初的失败案例中,您会看到如下内容:

          It's useful to run ldd main/main.run to see what's going on. In your original failing case, you'll see something like:

              lib/foo.sh (0xNNNNNNNN)
          

          (缺少任何 =>/some/resolved/path 表明它没有完成任何路径解析).在固定情况下,您会看到如下内容:

          (the lack of any => /some/resolved/path showing that it's not done any path resolution). In the fixed case, you'll see something like:

              foo.sh => /your/path/to/run/../lib/foo.sh (0xNNNNNNNN)
          

          这篇关于构建一个使用 ld 选项 -rpath 和 $ORIGIN 的简单(hello-world-esque)示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆