[英]Makefile Dependencies, What Should Be a Dependency?
我有一個關於Makefile依賴項的概念性問題,這是因為我在網上看到有關此問題的不一致之處。
假設我有以下文件:
main.cpp uses-> my_math.cpp and my_strings.cpp
my_math.cpp uses-> my_math.h
my_strings.cpp uses-> my_strings.h
如果我有一個makefile,則一般費用如下:
program: $(all_objs)
g++ $(all_objs) -o program
main.o: ...
.......
my_math.o: ...
.......
my_strings.o: ...
.......
我不知道每個依賴項應該包含什么內容。 就像math.o #includes my_math.h和my_strings.h一樣,這是否意味着如果我更改my_math.h,main.cpp需要重新編譯嗎? 但為什么? 它像圖書館一樣使用它,對不對? 它不需要重新編譯main.cpp還是對?
像這樣,main.o的結果應該是:
1) main.o: main.cpp
gcc -c main.cpp
2) main.o: main.cpp my_strings.cpp my_strings.h my_math.cpp my_math.h
gcc -c main.cpp
3) main.o: main.cpp my_strings.cpp my_strings.h my_math.cpp my_math.h
gcc -c main.cpp my_strings.cpp my_math.cpp
我對依賴項以及鏈接的工作方式有些迷失。
任何幫助,將不勝感激! 謝謝!
依賴項是需要更改源代碼才能進行更改的所有內容。 這不僅包括您的#include
-d標頭,還包括間接包含的系統標頭,甚至(原則上)還包括編譯器和構建鏈本身(在升級C ++編譯器時,應重新編譯所有軟件)。 如果您的某些C ++代碼是從某些源生成的(例如,通過GNU bison或Qt moc之類的工具或您自己的腳本生成),則源和生成工具都是依賴項。 另請參閱有關程序包管理器的信息 。
實際上, GCC編譯器能夠輸出大多數make
依賴項,尤其是使用-M
和相關的處理器選項 。 閱讀有關自動依賴項生成的信息 。 另請參見本 。
(實際上,您通常不會在Makefile
編寫對編譯器本身的某些顯式依賴關系;但是,在升級編譯器時,請不要忘記make clean
)
除非您的main.cpp
包含my_strings.cpp
(這不是常規的並且味道很差),否則您的make
規則將不會從my_strings.cpp
到main.o
進行依賴。 但是您的main.cpp
可能是#include
-ing(直接或間接) my_strings.h
因此main.o
應依賴於main.cpp
還應依賴於my_strings.h
根據經驗,目標文件my_strings.o
取決於源文件my_strings.cpp
和所有直接或間接包含在其中的#include
-d 頭文件 。 你的主要program
執行依賴於它的所有目標文件和要鏈接到它的庫。 g++
程序參數的順序非常重要。
它像圖書館一樣使用它,對不對?
根據顯示的內容,您沒有任何自己的庫 (但您可能使用標准的C ++庫,也許還使用其他一些系統庫)。 在Linux上,這些文件是lib*.a
文件(靜態庫)或lib*.so
文件(共享庫)。 庫是目標代碼(有時是其他資源)的有組織的集合。
我對依賴項以及鏈接的工作方式有些迷失。
了解源代碼文件, 目標文件 (它們包含重定位信息)和可執行文件 (在Linux上,目標文件和可執行文件以及共享庫使用ELF格式)之間的區別。 另請閱讀有關編譯器 , 鏈接器 ( g++
程序可以同時運行)和構建自動化 (要使用make
的角色)的作用。
閱讀程序庫HowTo以及有關翻譯單元和鏈接器 (及名稱修改 )的更多信息,尤其是Levine的有關鏈接器和加載器的書。
參見這 & 該 & 此 (約實例Makefile
為C ++程序)。
順便說一句,在編譯C ++代碼時,應該使用g++
(不是gcc
)。 有很大的區別(即使gcc
有時能夠編譯C ++或Fortran代碼,您也大多會使用gcc
來編譯C代碼)。 並且(假設您專門使用GNU make)您的Makefile
應該提到$(CXX)
(不是g++
)。 您需要了解make
的內置規則(運行一次make -p
來獲取它們),然后最好利用它們(例如,使用$(COMPILE.cc)
或$(COMPILE.cpp)
等)。 您當然應該將-Wall -Wextra
(以獲取所有警告,甚至更多)和-g
(以獲取調試信息)傳遞給g++
。 實際上,您應該在Makefile
設置CXXFLAGS
變量。
花時間仔細閱讀GNU make文檔和Invoking GCC 。
查看現有自由軟件項目的Makefile
-s。 由於各種原因,一些項目正在使用諸如autoconf
或cmake
類的工具生成其Makefile
-s。 但是大多數簡單的項目不需要這種通用性,因此您應該能夠為C ++項目編寫自己的Makefile
。 當然,可以從現有代碼中汲取靈感。
如果你有
main.cpp uses-> my_math.cpp and my_strings.cpp
my_math.cpp uses-> my_math.h
my_strings.cpp uses-> my_strings.h
Make的目的是通過構建.o文件和鏈接.o文件,以兩種不同方式維護模塊之間的依賴性。
您可以將其描述為main.o是根的依賴關系樹
main.o
/ \
my_math.o my_strings.o
對於每個.o,還有關於源文件的依賴樹,例如
main.o my_math.o my_strings.o
/ \ / \ / \
main.cpp main.h my_math.cpp my_math.h my_strings.cpp my_strings.h
因此,在進行make構建時,它將建立一個依賴樹,其根目錄以main.o為基礎,然后嘗試構建main所需的所有.o文件。 當所有.o文件構建完畢后,它們將被鏈接。
通過遵循依賴關系樹,Make可以確保在更改其中一個依賴模塊時,將鏈接/構建main。
但是,如果您從包含的頭文件之一#define MAXSTRING 32
使用了諸如說常量之類的內容,則您不再僅依賴於.o文件,而是依賴於頭文件的內容,因此需要確保main.o如果因為鏈接不夠而更改了標頭,則會構建此鏈接,因此您需要在依賴項中添加.h
main.o
/ | \
my_math.o my_strings.o my_strings.h
當然,有一些方法可以使報頭更健壯,從而避免這種依賴性,但這是另一個問題。
您的cpp
文件在編譯方面不依賴於其他cpp
文件。 簡單的cpp
文件應僅依賴於h
文件。
在您的問題中,您說main.cpp
取決於my_math.cpp
和my_strings.cpp
,但我認為這是不正確的。 我猜你那里有#include
,這是你的依賴。
一般來說, cpp
文件的依賴項都是#include
d h
文件。
通常, cpp
文件之間沒有依賴關系。 您只需通過編譯即可生成o
文件。 然后,最終的二進制文件取決於所有o
文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.