gee*_*del 9 c macos linker ld unix-ar
将C库从Linux(Ubuntu)移植到OS X时,我遇到链接器问题.C代码是从Matlab自动生成的,所以理想情况下我不想更改代码本身.
问题似乎是在一个C文件中,它只包含未初始化的变量声明,然后被其他C文件EXTERN实现Matlab算法.OS X链接器显然无法识别此文件中的符号.相同的源代码在Linux上运行良好,所以我想了解OS X链接器的行为方式不同,以及是否有一个标志我可以传递给它来改变行为.
静态库构建时没有错误/警告.但是在构建引用静态库的应用程序时,会抛出以下错误消息(在OS X上):
Undefined symbols for architecture x86_64:
"_my_var", referenced from:
_algorithm in libtestlibrary.a(algorithm.o)
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
'nm'表示libtestlibrary.a确实包含符号_my_var.
下面是Matlab代码的简化版本.
图书馆代码:
// DATA.C : declaration of data
#include "data.h"
int my_var;
// DATA.H - extern declaration of data
#ifndef H_DATA
#define H_DATA
extern int my_var;
#endif
// ALGORITHM.C - performs the calculation
#include "data.h"
int algorithm(int x) {
my_var += x;
return my_var;
}
//ALGORITHM.H - declaration of library API
#ifndef H_ALGORITHM
#define H_ALGORITHM
int algorithm(int x);
#endif
Run Code Online (Sandbox Code Playgroud)
库构建命令:
gcc -c algorithm.c
gcc -c data.c
ar rcs libtestlibrary.a data.o algorithm.o
Run Code Online (Sandbox Code Playgroud)
申请代码:
// MAIN.C : Code which calls into the static library
#include "algorithm.h"
int main() {
int x = 1;
x = algorithm(x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
应用程序构建命令
gcc -c main.c
gcc -o testapp main.o -ltestlibrary
Run Code Online (Sandbox Code Playgroud)
如果我将data.c中的定义更改为'int my_var = 0',那么初始化变量,那么库和应用程序在Linux和OS X上都能正确构建.但是,正如我上面所说,我不想要更改代码,因为它是从Matlab自动生成的.
在此先感谢您的帮助!
你的问题是你没有初始化may_var
.
如果不初始化数据符号并将其放入静态库,则会将其创建为公共符号.链接静态库时,我的OS X链接器无法识别.
如果你初始化它(data.c):
#include "data.h"
int my_var = 0;
Run Code Online (Sandbox Code Playgroud)
然后编译器将把它放到一个不同的部分,它将正确链接到静态库中.
编辑:
或者,您可以将-fno-common
选项传递给gcc
gcc -c data.c -fno-common
Run Code Online (Sandbox Code Playgroud)
然后,这将指示gcc
不为未初始化的变量生成公共符号,然后您可以在库中链接它们.
这是OS X上Mach-O可执行格式的问题,在此处进行了描述.
@Sergey L. 的回答非常好,可以解决问题。然而,它并没有捕捉到正在发生的事情的本质。该行为实际上是在 OS X 存档器中ar
,它没有在存档的目录 (TOC) 中列出常用符号。我创建了如上的文件,这是与存档器(OS X 10.9.4,Xcode 5.1.1)的会话:
$ gcc -c algorithm.c
$ gcc -c data.c
$ ar rcs libtestlibrary.a data.o algorithm.o
$ ar x libtestlibrary.a '__.SYMDEF SORTED'
$ od -c __.SYMDEF\ SORTED
0000000 \b \0 \0 \0 \0 \0 \0 \0 \0 002 \0 \0 020 \0 \0 \0
0000020 _ a l g o r i t h m \0 \0 \0 \0 \0 240
0000040
Run Code Online (Sandbox Code Playgroud)
TOC 在存档中显示为名为 的条目__.SYMDEF SORTED
。如您所见,TOC 不包含my_var
. 这是问题的本质。
您可以使用 将常用符号添加到 TOC ranlib -c
。这是它的工作原理:
$ ranlib -c libtestlibrary.a
$ ar x libtestlibrary.a '__.SYMDEF SORTED'
$ od -c __.SYMDEF\ SORTED
0000000 020 \0 \0 \0 \b \0 \0 \0 020 002 \0 \0 \0 \0 \0 \0
0000020 210 \0 \0 \0 030 \0 \0 \0 _ m y _ v a r \0
0000040 _ a l g o r i t h m \0 ? ** 177 \0 \0
0000060
Run Code Online (Sandbox Code Playgroud)
如您所见,已ranlib -c
添加my_var
到 TOC。
现在链接步骤将起作用:
$ gcc -L . -o testapp main.o -ltestlibrary
$
Run Code Online (Sandbox Code Playgroud)
因此,重新编译代码以使链接正常工作并不是绝对必要的。
ranlib 的手册页是这样说的:
-c Include common symbols as definitions with respect to the table
of contents. This is seldom the intended behavior for linking
from a library, as it forces the linking of a library member
just because it uses an uninitialized global that is undefined
at that point in the linking. This option is included only
because this was the original behavior of ranlib. This option
is not the default.
Run Code Online (Sandbox Code Playgroud)
因此,这是对传统行为的有意偏离,以避免将不需要的模块链接到输出中。我可能会-fno-common
在我自己的开发中使用。
归档时间: |
|
查看次数: |
1285 次 |
最近记录: |