2013-04-25 78 views
4
#include <math.h> 
#include <stdio.h> 
int main() 
{ 
    printf("%f", roundf(3.14)); 
} 

我編譯上面的代碼(未使用-lm),添加使用LDD的a.out,結果是爲什麼它不需要鏈接libm?

linux-vdso.so.1 => (0x00007fffab9ff000) 
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd6da0f8000) 
/lib64/ld-linux-x86-64.so.2 (0x00007fd6da4eb000) 

爲什麼a.out的不與的libm鏈接,但可以使用roundf(或類似sqrt)? 我使用nm來測試libc.so.6和ld-linux-x86064.so.2,但所有這些都沒有roundf的象徵。

我想知道roundf定義在哪裏,或者它已經被編譯器內聯了嗎? (試驗用gcc 4.7.3和gcc 4.6.3)


答案是http://fedoraproject.org/w/index.php?title=UnderstandingDSOLinkChange

+0

這些存在於libc IIRC中。 – 2013-04-25 00:26:40

+0

IIRC代表交叉工具嗎? – snyh 2013-04-25 00:32:45

+1

IIRC =「如果我記得正確」 – Tim 2013-04-25 00:41:57

回答

6

作爲一種優化,編譯器會計算在編譯時的值,並使用恆定,所以有是否涉及roundf()涉及。你可以看到生成的代碼進行驗證:

main: 
    pushl %ebp 
    movl %esp, %ebp 
    andl $-16, %esp 
    subl $16, %esp 
    movl $.LC0, %eax 
    fldl .LC1 
    fstpl 4(%esp) 
    movl %eax, (%esp) 
    call printf 
    leave 
    ret 

你可以看到,有在生成組件roundf()沒有呼叫。 (您可以使用gcc -S filename.c生成此文件並讀取生成的filename.s文件)。

+0

哦,我太愚蠢了.- 但是最初的問題是我有一些項目被編譯好用gcc 4.6.3但是當我更新我的系統Deepin,基於Ubuntu的中文發行版)很多項目都無法成功編譯。 gcc報告無法找到roundf並告訴我手動鏈接這些庫。 (有很多未定義的功能) 我不明白爲什麼。 – snyh 2013-04-25 00:42:36

+0

@snyh:我建議你發佈一個關於這個問題的新問題,使用一個不會讓gcc優化調用的演示程序。我很驚訝你*不需要在gcc 4.6.3中使用'-lm'。但是加入'-lm'應該可以解決這個問題(假設它所抱怨的所有功能都是數學函數)。 – 2013-04-25 00:48:48

+0

@KeithThompson對不起,但我不能構造一個簡單的演示代碼。 一個項目是webkitgtk-1.8.2,另一個是DDE(一個新的Linux桌面環境)。 DDE的代碼和cmake文件是我寫的,所以我可以確定我之前沒有鏈接過libm,並且至少可以在三個月內編譯OK。但是現在我必須明確地與libm鏈接.- 我想知道gcc中是否有一些技巧。或者是否有一些默認的鏈接庫? - 它不僅在webkitgtk中報告libm而且報告了libstdC++。 – snyh 2013-04-25 00:57:38

1

您在評論中提到了libstdc++,這讓我懷疑問題是您正在與g++而不是gcc鏈接。

gcc命令調用編譯器和/或連接基。如果您使用它來編譯源文件,它通常會確定語言(並因此決定使用哪個編譯器前端)。

g++命令是類似的,但它專門用於C++;如果它調用鏈接器,它會根據需要傳遞參數來鏈接庫,如C++所需的libstdc++

例如,這兩個命令,這只是編譯不連接:

gcc -c foo.cpp 
g++ -c foo.cpp 

是(據我所知)等效的,但這些命令:

gcc foo.cpp -o foo 
g++ foo.cpp -o foo 

都沒有;前者可能會失敗(取決於foo.cpp使用的功能)。

事實證明,與gcc命令不同,g++命令隱含地鏈接了數學庫,至少在我係統的版本中。所以,如果你的C++代碼同時使用C++ - 特定功能(比如說,<iostream>)和數學函數,然後用gcc命令鏈接很容易產生約兩個libstdc++libm定義函數的抱怨 - 這正是你」重新看。

如果您使用g++命令鏈接,那應該解決問題。你可能不得不修改Makefile或同等學歷,或任何其生成。

(如果是這樣的解決方案,很可能需要添加「C++」來對你的問題的標記列表。)

至於你爲什麼沒有遇到這個問題,我不知道。一些C(和/或C++)編譯器將隱含地鏈接數學庫;其他編譯器需要指定-lm可以說是一個錯誤。

+0

我發現關鍵是「ld的默認行爲允許用戶通過中間對象/庫'間接'鏈接到所需的對象/庫」。 ([鏈接] http://fedoraproject.org/w/index.php?title=UnderstandingDSOLinkChange),但現在它不能:( – snyh 2013-04-25 03:04:29