静态档案中的 C 符号可见性

C symbol visibility in static archives

我有文件 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. 之外的所有内容标记为隐藏
  4. 使用 ld 的 partial-linking 开关创建方便的存档:ld -r foo.o bar.o baz.o myfn.o -o libmyfn.a

  5. 本地化不是 PUBLIC 的所有内容,像这样:objcopy --localize-hidden libmyfn.a

  6. 现在 nmmyfnlibmyfn.a 中唯一的全局符号,随后 linking 到其他程序中工作得很好:gcc -o main main.c -L. -lmyfn(这里,程序调用 myfn();如果它试图调用 foo(),那么编译将失败)。

如果我在第 3 步中使用 ar 而不是 ld -r,那么在第 5 步中编译会失败:我猜 ar 还没有 linked foo 等到 myfn,一旦这些函数被本地化就不再可以,而 ld -r 在它被本地化之前解析 link。

我欢迎任何确认这是 "right" 方式或描述实现相同方式的更巧妙方式的回复。

假设 myfn.c 有函数 myfun(),你想在其他三个文件 foo.c、bar.c & baz.c

中使用它

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

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

参考以下link使用共享库。

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

从这里开始构建静态库

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

编译并link使用其他程序,例如:

gcc -O2 program.c -lmyfunctions -o myprogram

现在你的 libmyfunctions.a 最终会从源代码中获得额外的东西,而 myfn.c 中的代码不需要这些东西但是 link 开发者应该合理地删除它当它创建最终程序时。

不幸的是,全局变量的 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 可让您识别要保留或删除的单个符号。