【问题标题】:Is there a way to know which compiler generated a static library?有没有办法知道哪个编译器生成了静态库?
【发布时间】:2015-09-10 10:13:14
【问题描述】:

第三方为我提供了一个静态库 (.a) 以在 solaris 站上链接。 我尝试用 sunpro 编译,但在链接步骤失败。

我想问题出在我使用的编译器(而不是 gcc?)或只是它的版本(因为编译器提供的 std lib 可能会从库 AFAIK 预期的版本发生变化,这可能会导致链接步骤出错)。

我怎么知道是哪个编译器用来生成这个库的?有没有一些工具可以做到这一点? sunpro/gcc 中的一些选项或其他什么?

作为提示:我前段时间读到编译器在生成目标文件时使用不同的修饰约定(真的吗?)。尽管如此,"nm --demangle" 命令行仍然可以很好地打印出此静态库中调试符号中的所有函数名称。它是如何工作的 ?如果我的假设没问题,nm 确实有办法解决静态库中使用的约定,不是吗?还是仅仅意味着 lib 是由 GNU gcc 生成的,因为 nm 是 GNU binutils 的一部分?

我离我的工作站不近,所以我不能从链接器复制和粘贴错误输出(暂时不能,但我可以在进一步的编辑中复制它们)

【问题讨论】:

  • 你为什么不向提供库的“第三方”询问如何使用它?
  • 我问他们。但是他们的支持团队没有回答,不愿意问开发团队,似乎......:/

标签: linker build-process solaris


【解决方案1】:

从存档中提取目标文件,然后在其中一些文件上运行strings 命令(首先在较小的文件上,因为筛选的噪音较小)。许多编译器在目标文件中插入 ASCII 签名。

比如下面这个无意义的源文件,foo.c

extern void blah();

当在我的 Fedora 10 机器上通过 gcc -c -o foo.o foo.c 编译成 foo.o 时,会产生一个 647 字节的 foo.o 目标文件。在foo.o 上运行strings 会导致

GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)
.symtab
.strtab
.shstrtab
。文本
。数据
.bss
。评论
.note.GNU 堆栈
foo.c

这清楚地表明编译器是 GCC。即使我用-fno-ident 编译它,.GNU-stack note ELF 部分仍然存在。

您可以使用ar 实用程序或使用 Midnight Commander(集成了 ar)来提取目标文件,或者您可以简单地在存档上运行 strings(这可能会给您带来更多噪音并且不太相关,但是仍然会有所帮助。)

【讨论】:

  • 或者直接在库上运行'strings' - 无需先提取目标文件。
  • 就像我提到的,有更多的输出,尤其是在 C++ 目标文件的情况下,而且更容易错过编译器签名。此外,没有要求存档中的所有对象都来自同一个编译器...
【解决方案2】:

我倾向于使用strings 程序(带有'-a' 选项,或者我自己的变体,其中'-a' 行为是标准的)并寻找明显的迹象。例如,在我自己的一个库中,我发现:

/work1/gcc/v4.2.3/bin/../lib/gcc/sparc-sun-solaris2.10/4.2.3/include
/work1/gcc/v4.3.0/bin/../lib/gcc/sparc-sun-solaris2.10/4.3.0/include
/work1/gcc/v4.3.1/bin/../lib/gcc/sparc-sun-solaris2.10/4.3.1/include
/work1/gcc/v4.3.3/bin/../lib/gcc/sparc-sun-solaris2.10/4.3.3/include

这表明该库中的代码多年来已使用各种版本的 GCC 编译(实际上,在一个库中发现这么多版本,我感到非常震惊)。

另一个库包含:

cg: Sun Compiler Common 11 Patch 120760-06 2006/05/26
acomp: Sun C 5.8 Patch 121015-02 2006/03/29
iropt: Sun Compiler Common 11 Patch 120760-06 2006/05/26
/compilers/v11/SUNWspro/prod/bin/cc -O -v -Xa -xarch=v9 ...

因此,目标文件中通常有指纹指示使用了哪个编译器。但你必须知道如何寻找它们。

【讨论】:

  • 我正在尝试从 clang 编译的 mac 目标文件和静态库中提取编译器版本的方法。我能够从库中 40 个目标文件中的 4 个中提取编译器版本,方法是使用字符串命令进行字符串转储,并对显示“Apple LLVM 版本 9.0.0 (clang-900.0.39.2)”但其他文件的“clang”进行 grepping没有这个字符串。在使用 mach-o-view 工具查看这些部分时,从中提取编译器版本的目标文件有一个 Section64(__DWARF,__debug_str) ,其中包含字符串“Apple LLVM 版本 9.0.0 (clang-900.0.39.2) "
  • 您使用的是strings -a 还是只使用strings-a 通常很重要。我倾向于在我的 MacBook Pro 上使用自制的 GCC(目前为 9.2.0)——一个运行 macOS Mojave 10.14.6(工作;抱怨!),另一个运行 macOS Catalina 10.15.3。我刚刚用clang 11.0.0(Xcode 11.3.1)重新编译了一个小库(9个源文件),系统strings报告了9次Apple(/usr/bin/strings libdiag.a | grep -i apple | sort | uniq -c产生9 Apple clang version 11.0.0 (clang-1100.0.33.17)。我不确定是否这样帮助你。
  • 感谢您的评论,乔纳森。我尝试使用字符串和字符串 -a。两人都没有找到。我能够在几个文件中重现相同的内容。但在少数目标文件中,缺少该字符串。你知道任何编译器标志或其他东西会去掉它吗?
  • 我不知道从目标文件中删除此元数据的选项 - 我从不打扰。 otool 命令可以列出各种信息——根据man otool 似乎是llvm-otool,是llvm-objdump 的封面。经典地,strip 命令从目标文件中删除不必要的材料——它在 macOS 上有很多选项。我不确定还有哪些其他命令可能相关。
  • Jonathan,在这里我发布了一个简单的 hello world cpp,我使用 clang++ -c 将其转换为目标文件。但是,strings -a 不显示“clang-”。为什么? stackoverflow.com/questions/59676912/…
【解决方案3】:

该库应该是 C 还是 C++ 库?

如果它是一个 C 库,那么名称修改不会是问题,因为 C 中没有。但是它可能是错误的格式。 Unices 曾经有 a.out 格式的库,但几乎所有较新的版本都切换到更强大的格式,例如 ELF

如果它是一个 C++ 库,那么名称修改可能是一个问题。大多数编译器会在代码中嵌入一些特定于编译器的符号,因此,如果您有像 nm 这样的工具来列出符号,您可以希望从它来自的编译器中推断出来。

例如g++创建一个符号

__gxx_personality_v0

在它的图书馆里

【讨论】:

    【解决方案4】:

    你可以试试unix实用工具file

    file foo.a
    

    【讨论】:

    • 我试过了,但我记得它只告诉我这个文件使用了 SPARC 平台的 ELF 格式。 sunpro 是否像 GCC 那样生成 ELF 格式?
    • file 工具几乎不会返回有关所用编译器的信息!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 2011-12-10
    • 1970-01-01
    • 2021-04-30
    • 1970-01-01
    相关资源
    最近更新 更多