2011-12-08 68 views
2

假設你的程序由兩個源文件(main.c和auxiliary.c)和兩個頭文件(declarations.h和auxiliary.h)組成。關於GCC編譯器和鏈接器的問題

然後你運行編譯如下:

$gcc main.c auxiliary.c -o myprogram 

問題1:請問編譯器創建一個單一的目標文件爲我的計劃(即,只是庫丟失),還是會創建兩個對象文件,每個源文件一個(然後將所有內容鏈接在一起)?

問題2:有沒有必要單獨調用鏈接器?因爲如果你使用上面的命令,編譯器會爲你處理這個問題,對吧?

問題3爲什麼一些庫自動鏈接(例如,stdio)以及爲什麼一些庫需要額外的工作(例如,math.h需要在編譯時添加-lm)。 -lm代表什麼?

問題4:假設你有一個源文件,並且你的程序不需要任何外部庫。這是否意味着您將從編譯器獲得的對象代碼已經可執行了? (即,編譯它像$ gcc -c main.c)。

+0

這東西是特定於每個實現。像使用「C」和「編譯器」這樣的通用標籤來標記它並不合適,就像引用「the」C編譯器一樣。 –

+0

同意。我重新命名爲「有關GCC編譯器的問題」 –

回答

3
  1. gcc創建每個源文件的目標文件,然後鏈接它們生成可執行文件。

  2. 你舉的例子證明了gcc能鏈的所有所需的步驟

  3. 那就會自動鏈接是標準C庫的庫。其他需要指定。當你不需要atan2()時,這允許構建一個更小的可執行文件。
    -lm向編譯器指示應找到數學庫,其編號爲m。在Unix上,其文件名爲libm.solibm.a,具體取決於鏈接是動態的(在運行時執行並導致較小的可執行文件)還是靜態的(在鏈接時執行並導致獨立的可執行文件)。

  4. 不管怎樣,它必須鏈接到標準C庫。而且,目標代碼的文件格式與可執行文件不同。

+0

4.技術上來說,它們都是ELF文件,但具有一些不同的屬性。 –

+0

謝謝。還有一個問題:維基百科和其他資源如何說math.h是標準庫的一部分? - > http://en.wikipedia.org/wiki/C_standard_library –

+0

在維基百科文章中有關於它的章節。而且,並非每種C的風味都符合最新的標準。 – mouviciel

1

問題1:與「-save-臨時工」執行你的GCC的語句,你會看到,編譯器會創建兩個目標文件。

問題2:對鏈接器的調用是隱式的。 'gcc'命令實際上不是一個編譯器,而是根據需要通過調用預處理器,編譯器,彙編器和鏈接器來驅動編譯過程。 在小程序中,讓'gcc'處理所有內容可能是一個好主意,但對於大型程序和許多源文件,這意味着即使沒有更改也會重新編譯所有源文件。

問題3:這是一個慣例。 (m庫是數學庫。)

問題4:不,事實並非如此。總是有一些額外的代碼必須鏈接來處理流程啓動/拆卸需求。在Linux上,這些是crt1.o,crti.o,crtbegin.o和crtn.o文件。

+0

感謝您的回答。我猜測,當我在gcc中使用-c選項時,編譯器會輸出彙編代碼,彙編器會將其轉換爲對象文件並停在那裏,對吧?在這種情況下,是否可以停止在彙編代碼步驟? (即,使gcc輸出程序集而不是目標文件?) –

+1

@DanielS是的,這是可能的。看到這個:http://stackoverflow.com/questions/137038/how-do-you-get-assembler-output-from-c-c-source-in-gcc –

4
  1. GCC將通常使每個源文件中的一個對象。但有一個-combine選項可以告訴你,否則你想要的。當你有幾十個源文件時重新編譯所有東西並不是一個好主意(當你有更多的東西時,你將它們分割成庫)。

  2. 歷史。曾經有一段時間 - 共享庫之前 - 數學庫相對較大,並將其放入每個可執行文件中,即使那些不需要的可執行文件也被認爲是浪費的(使用數學庫涉及printf等功能的替代版本)你有沒有用,即使成本)

  3. 我等着看一個程序,它不使用甚至標準庫的任何部分(邏輯調用主要爲exit(main(argc, argv))所以至少exit被稱爲完成)然後是啓動和結束代碼。