2016-09-28 161 views
6

我正在阅读一本名为“GCC简介”的书,希望有所澄清。该书表明,下面的代码会导致错误但是当我编译,它构建并运行完美:与静态库链接的gcc

#include <math.h> 
#include <stdio.h> 
int main (void) { 
    double x = sqrt (2.0); 
    printf ("The square root of 2.0 is %f\n", x); 
    return 0; 
} 

我引用这本书的“试图创建单独从这个源文件的可执行使编译器在链接阶段给出错误信息:

$ gcc -Wall calc.c -o calc 
/tmp/ccbR6Ojm.o: In function `main': 
/tmp/ccbR6Ojm.o(.text+0x19): undefined reference 
    to `sqrt' 

的这本书给出的解决方案是,你应该包括路径数学库”libm.a”如下:

$ gcc -Wall calc.c /usr/lib/libm.a -o calc 

这将是非常不方便,必须指定要建立在我们在我们的程序中使用的库的路径。我可以理解将路径添加到我自己的自定义库的原因,但libm.a已内置到gcc中。虽然这本书是相当古老的(2004年出版),与更现代版本的gcc有什么不同,因此我们不需要包含路径为libm.a

* UPDATE *

我注意到,通过taskinoor给出的答案应符合更新的要求,我用的是-lm标志,如果()传递给开方值在编译时已知代码。

我学会了使用VS的C/C++,但我现在的目标是学习和使用gcc。我有Visual Studio 2013和VS编译器/链接器似乎不太挑剔。例如,我可以编译几乎任何简单的程序,而不必指定神秘的编译器标志。

我对gcc版本5.4随KUBUNTU 16.04.1

+4

首先,尝试一本不同的书籍,因为几十年来,链接数学库的标准方法是使用-lm而不是库的完整路径。其次,https://gcc.gnu.org/releases.html包含发布更改。 –

+1

@JohnGriffin:来自同一本书:*“为了避免在命令行中指定长路径,编译器提供了一个快捷选项'-l'来链接库。例如,下面的命令: ' $ gcc -Wall calc.c -lm -o calc'等价于原始命令...“* –

+0

请注意,这些日子的默认值是链接动态库,而不是静态库。也许你想问的是与*标准库链接? – Barmar

回答

6

sqrt (2.0);

现代GCC是完全能够确定你正在努力寻找一个不变的平方根,因此它是能够在编译时计算出来。您的目标代码不包含对sqrt的实际调用。

如果您在运行时使用通过scanf输入的变量,那么在没有libm时它将不会链接。

int main() { 
    double x; 

    scanf("%lf", &x); 
    printf("%lf\n", sqrt(x)); 

    return 0; 
} 

没有libm Ubuntu 14上的gcc 4.8.4。04这个结果:

/tmp/ccVO2fRY.o: In function `main': 
sqrt.c:(.text+0x2c): undefined reference to `sqrt' 
collect2: error: ld returned 1 exit status 

但如果我把而非x喜欢你的例子恒定则没有libm链接罚款。

P.S:我不知道GCC能做到这一点的确切版本。希望别人能指出这一点。

+0

有趣...我必须检查出它... –

+0

我在Linux上也得到这个错误,但在OS X上没有错误。 – Barmar

+0

@Barmar no在OS X上的链接器错误与编译时无法解析的变量?对不起,我不知道有关OS X的信息。可能还有其他事情正在发生。 – taskinoor

2

学习我已经注意到,在某些操作系统中,常见的库可没有明确的链接。特别是,我经常使用最初在我的Mac上开发的C项目,并且在我直接与我使用的库(如libm)进行链接之前,该项目不会在Linux上编译。

当然,这通常是动态的而不是静态链接...