1

我正在尝试在 MAC OSX 上编译一个程序,该程序最初是在 Linux 操作系统上编写的。这是一个包含多个 makefile 的大程序。我已经研究了几个星期,现在似乎无法弄清楚为什么会导致未定义的符号错误。有一个总体 Makefile 调用其他 makefile,以便编译顺序正确。

编译时,它会创建静态库以及多个应用程序。因为这家伙太大了,程序首先创建了这些静态库(.a 文件)。然后,当它专门为应用程序编译源代码时,它会链接静态库。(希望这不会太令人困惑)。

我可以很好地完成静态库的构建,但是一旦我到达构建应用程序的地步,我就会收到大量未定义的符号错误告诉我,例如

未定义符号:“_bagUpdateOptSurface”,引用自:libdbdbv6.a(dbv_bag.o) 中的 _dbv_bag

当我用 nm 检查 dbv_bag.o 时,我得到了很多未使用标题 U 定义的函数。

我可以用 nm 追溯这个函数并发现......

bagUpdateOptSurface.c -->bagUpdateOptSurface.o -->libbag.a --->dbv_bag.c --->dbv_bag.o --->libdbdv6.a --->应用程序

该函数是通过带有标题 T 的静态库 libbag.a 定义的,但目标文件 dbb_bag.o 将其与 U 定义为未定义。在那里的某个地方信息丢失了,我似乎无法理解为什么。

如果那里有更多经验将程序移植到mac的人可以帮助了解正在发生的事情,我将非常感激。欢迎任何想法对或错。

提前致谢

4

1 回答 1

0

只是出于好奇,您是否尝试过使用gccg++而不是ld进行链接?通常这些大型项目使用带有定义变量的 makefile,你可以说make LD=gcc target或类似的东西。

只要有“T”版本,很多“U”标志就无关紧要。

您可以尝试制作一个简单的示例。只需几个简短的 1 或 2 行源文件,编译为 .o(使用 -c 标志),放入库(ar -rv),看看能否重现问题。一旦简化,答案通常更容易找到。

如果不是链接器标志问题,则可能是链接行上的排序问题(依赖地狱)。或者你可能只是在某个地方错过了一个图书馆。

我想我还应该询问您使用的是什么版本的 gcc/g++,以及什么版本的 OSX...

另一种可能性是使用 g++ 意外重载函数,以及可能与实现不同的标头签名。

您可以尝试删除所有 .o 和库文件并重新编译世界(一切)。有时 .o 文件(或库)从源文件/头文件中过时,并导致非常多的痛苦和痛苦......



回复评论:

正如上面提到的,虽然被埋没了:通常这样的问题是指命令行上的依赖地狱和链接排序。至少他们曾经如此。我不确定是否仍然如此。

您可以复制目录,尽可能多地删除代码(二进制搜索调试),做一个简单的例子,问题通常会变得更容易识别。

使用 gcc/g++ 链接:您可以通过gcc -c将file.c编译为file.o,然后通过ld将file.o链接到可执行文件中。或者您可以执行gcc file.o -o file调用gcc ,然后使用适当的参数调用ld 。如果您不太确定需要的库或需要传递给ld的标志,有时它会很有用。

Gcc 4.2.1 和 OSX 10.6.8 应该不是问题。我只是好奇你是否使用了一些真正过时的东西,因为旧的编译器有一些有趣的缺点/问题。

虽然,现在我想起来了,你用什么编译器在 Linux 下编译?您可能在 OSX 下使用较新/较旧的 gcc/g++ 编译器,而您的问题源于对编译器的“改进”。

重载函数:gcc/g++ 经常根据文件名后缀来判断 C vs C++ 编译。OSX 通常有一个不区分大小写的文件系统。所以gcc file.c和g++ file.C都可以工作,无论文件是命名为file.c还是file.C。但是,C 和 C++ 语言之间的差异可能会咬你一口。例如,如果您定义了 foo(signed int),则类型信息将被合并(损坏)到 C++ 编译下的编译函数名称中。随后从 C 代码调用它不一定有效(链接正确)。

类似地,如果头文件说foo(short int)而源代码说foo(long int)你可能会遇到有趣的问题。

于 2012-11-04T12:41:05.217 回答