【问题标题】:C symbol visibility in static archives静态档案中的 C 符号可见性
【发布时间】:2017-02-20 05:53:32
【问题描述】:

我有文件 foo.c bar.c 和 baz.c,加上包装代码 myfn.c 定义了一个函数 myfn(),该函数使用来自其他文件的代码和数据。

我想创建一个目标文件或存档文件,myfn.o 或 libmyfn.a,以便 myfn() 可以用于其他项目,而无需同时从 {foo,bar,baz 导出大量符号}.o 也是如此。

在 Linux/gcc 中正确的做法是什么?谢谢。


更新:我找到了一种方法。我最初应该强调这是关于静态档案,而不是 DSO。无论如何,食谱:

  1. #define PUBLIC __attribute__ ((visibility("default"))) 然后在myfn.c 中将myfn() 标记为PUBLIC。不要标记其他任何内容PUBLIC

  2. 使用gcc -c foo.c bar.c baz.c myfn.c -fvisibility=hidden 编译对象,这会将除myfn() 之外的所有内容都标记为隐藏。

  3. 使用ld 的部分链接开关创建便捷存档:ld -r foo.o bar.o baz.o myfn.o -o libmyfn.a

  4. 将所有不是 PUBLIC 的内容本地化,如下所示:objcopy --localize-hidden libmyfn.a

  5. 现在nmmyfnlibmyfn.a 中唯一的全局符号,随后链接到其他程序就可以正常工作:gcc -o main main.c -L. -lmyfn(这里,程序调用myfn();如果它试图调用foo()然后编译会失败)。

如果我在第 3 步中使用 ar 而不是 ld -r,则在第 5 步中编译失败:我猜 ar 尚未将 foo 等链接到 myfn,并且一旦这些函数被链接,则不再可以本地化,而 ld -r 在链接被本地化之前解析链接。

我欢迎任何确认这是“正确”方式或描述实现相同目标的更巧妙方式的回复。

【问题讨论】:

  • 正确的方法是查找有关图书馆创建的文献或教程。
  • 请帮我张贴这个答案,尤金,这样我就可以否决它。谢谢。

标签: c gcc linker visibility symbols


【解决方案1】:

假设 myfn.c 有函数 myfun() 你想在其他三个文件 foo.c、bar.c 和 baz.c 中使用它

现在从 myfn.c 中的代码创建一个共享库,即 libmyf.a

在其他三个文件中使用此函数调用 myfun()。在这些文件中将函数声明为 extern。现在您可以创建这些文件的目标代码并在链接阶段链接 libmyf.a。

使用共享库请参考以下链接。

http://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html

【讨论】:

  • 感谢Pankaj,但我基本上知道如何构建库;我不知道如何控制符号的可见性。我想我现在明白了。
  • gcc.gnu.org/wiki/Visibility 以上页面确认了您的解决方案,并提供了另一种使用#pragmas 的方法。
【解决方案2】:

不幸的是,全局变量的 C 链接是全有或全无的,因为所有模块的全局变量将在 libmyfn.a 的最终外部符号列表中可用。

gcc 工具链提供了一个扩展,可让您对外部用户隐藏符号,同时使它们可用于您库中的其他翻译单元:

foo.h:

void foo();

foo.c:

void foo() __attribute__ ((visibility ("hidden")));

myfn.h:

void myfn();

myfn.c:

#include <stdio.h>
#include "foo.h"

void myfn() {
    printf("calling foo...\n");
    foo();
    printf("calling foo again...\n");
    foo();
}

为了可移植性,您可能会受益于为__attribute__ ((visibility ("hidden"))) 制作宏,并将其放置在以gcc 为条件的条件编译块中。

此外,Linux 提供了utility called strip,它允许您从编译的目标文件中删除一些符号。选项 -N-K 可让您识别要保留或删除的单个符号。

【讨论】:

  • 这似乎是最接近我最初的、措辞不是很好的问题的回答。也许您现在可以再看一下我已经编辑过的问题,让我知道您对提议的解决方案有何看法?
  • @PythonAteMyHamster 您将一些函数标记为公开并剥离其他所有函数的新方法看起来不错。
  • 我给它一个小时,但如果没有人发布更好的东西,那么你会得到正确答案。
【解决方案3】:

从这里开始构建静态库

gcc -c -O2 foo.c bar.c baz.c myfn.c
ar av libmyfunctions.a foo.o bar.o baz.o myfn.o

编译并与其他程序链接,例如:

gcc -O2 program.c -lmyfunctions -o myprogram

现在您的libmyfunctions.a 最终会从源代码中获得 myfn.c 中的代码不需要的额外内容,但是链接器应该在创建最终程序时合理地删除这些内容。

【讨论】:

  • 谢谢 selbie,但是当我问这个问题时,“额外的东西”正是我试图消除的问题!
  • 链接器将为您删除未使用的目标代码。但是,如果您试图最小化 .lib 文件的大小,那么您将需要自定义构建。 (例如#define LIBRARY_BUILD 1,然后不用于构建的代码位于#ifndef LIBRARY_BUILD 部分下。
  • 这不是关于控制链接器引入什么目标代码,selbie,它是关于将 libmyfn.a 中符号的可见性限制为仅代表 API 的那些(而不是所有其他实现的函数API)。我更新的帖子现在显示了实现我想要的一种方法。还是谢谢你。
猜你喜欢
  • 2020-10-02
  • 2010-12-31
  • 2015-10-18
  • 2012-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-13
  • 2011-12-23
相关资源
最近更新 更多