Linux

嘗試執行 C 程序時 Makefile 失敗

  • October 31, 2018

我在製作 Makefile 文件時有很多任務,我有這些文件:

https://raw.githubusercontent.com/systems-cs-pub-ro/uso/master/tema1/boo.c
https://github.com/systems-cs-pub-ro/uso/raw/master/tema1/light.o
https://raw.githubusercontent.com/systems-cs-pub-ro/uso/master/tema1/sound.c 
https://raw.githubusercontent.com/systems-cs-pub-ro/uso/master/tema1/sound.h

而且我必須創建一個 Makefile :“生成一個執行檔,exec使用light.o並在以前sound.o編譯時創建sound.c。在接收任何命令時make,或者make build它必須生成文件exec。如果有必要,在 Makefilerun中添加一個符合整個程序的規則,然後執行它。另外,添加一條clean刪除您創建的目標文件的規則。還添加一條在編譯後templates創建中間文件(boo.s, )的規則“。boo.o``boo.c

這是我的makefile

build: light.o sound.o
       gcc light.o sound.o -o exec
sound.o: sound.c
       gcc -c sound.c
templates: boo.c
       gcc -c boo.c
       gcc -S boo.c
run: exec
    ./exec
clean:
     rm -f sound.o boo.o boo.s exec

但它告訴我我沒有創建“正確的”執行檔,我做錯了什麼?我認為我應該boo.o在 exec 文件中添加,但是當我嘗試這樣做時,我得到:boo.c multiple definition of main light.o:light.c:first defined here.

(這聞起來像家庭作業。)

一、報錯資訊:

boo.c multiple definition of main
light.o:light.c:first defined here.

它表明您嘗試連結在一起的文件具有名為 的函式的多個副本,main()這顯然是不正確的。

您正在嘗試重用light.o,但只有當它具有除main(). 讓我們稱之為light()。您還需要一個.h文件#included in ,以便編譯器無需查看其原始碼即可boo.c知道函式的屬性(基本上是參數的類型和返回值的類型,如果有的話) 。light()

在我看來,您的文件組合在一起的方式與作業中的預期有些不同。您的教授可能已經創建了一系列關聯在一起的作業:如果您在該系列的先前作業中走捷徑,那麼重用先前程式碼的後續作業將無法正常工作。

你的教授正試圖教你如何安排你的程式碼以便它可以重用,如果你不這樣做會發生什麼。

Makefile 規則的基本形式是:

<name of target>: <names of files the creation process depends on>
       <command(s) to create the target file>

文件的創建.c不僅取決於文件​​本身,還取決於.h它包含的文件。通常,您可以假設任何系統包含文件(您包含的那些文件#include <filename>不會改變您,因此您不需要將它們添加到您的 Makefile 規則中。但是任何.h屬於您項目的文件也應該包含在內。

也可能存在實際上不是文件的“虛擬目標”。他們允許你做類似的事情make clean。您還可以將虛擬目標用作另一個目標的依賴項:由於虛擬目標沒有與之關聯的真實文件,因此每次將虛擬目標列為依賴項時都會執行“創建”虛擬目標的命令對於其他東西,並且需要建造其他東西。

此外,可能存在其中沒有任何命令的 Makefile 規則,但會列出一個或多個 Makefile 目標作為其依賴項。如果只有一個依賴項,那麼沒有命令的目標將作為作為依賴項列出的目標的另一個名稱。如果它有多個依賴項,那麼無命令目標將成為一種使用單個命令建構多個 Makefile 目標的方法。

在我看來,您的教授打算將build:目標變成這樣一個沒有自己命令的目標。它應該只取決於兩個目標:

  • 一個單獨的目標來建構實際的執行檔
  • templates目標_

light.o你可能想知道我怎麼不看原始碼就知道它的內容?很簡單 - 我下載了你的light.o然後使用了這個命令:

$ readelf -s light.o

Symbol table '.symtab' contains 12 entries:
  Num:    Value  Size Type    Bind   Vis      Ndx Name
    0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
    1: 00000000     0 FILE    LOCAL  DEFAULT  ABS light.c
    2: 00000000     0 SECTION LOCAL  DEFAULT    1 
    3: 00000000     0 SECTION LOCAL  DEFAULT    3 
    4: 00000000     0 SECTION LOCAL  DEFAULT    4 
    5: 00000000     0 SECTION LOCAL  DEFAULT    5 
    6: 00000000     0 SECTION LOCAL  DEFAULT    7 
    7: 00000000     0 SECTION LOCAL  DEFAULT    8 
    8: 00000000     0 SECTION LOCAL  DEFAULT    6 
    9: 00000000    51 FUNC    GLOBAL DEFAULT    1 main
   10: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND puts
   11: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND sound

這告訴我light.o來自一個名為 的源文件light.c,定義了一個名為的函式main()並使用了名為puts()and的函式sound(),這裡沒有定義。puts()來自標準庫,但sound()需要在與該文件連結在一起的其他文件中定義以生成完整的執行檔。

引用自:https://unix.stackexchange.com/questions/478836