1. 程式人生 > >Linux下多個檔案的C++工程編寫、編譯要點

Linux下多個檔案的C++工程編寫、編譯要點

編譯流程:


假定有三個檔案:

main.cpp:

#include <iostream>
#include "include/func1.hpp"

int main(){
	cout<<"this is main"<<endl;
	func1();
	return 0;
}

func1.hpp:
void func1();

func1.cpp:
#include <iostream>
void func1(){
	cout<<"this is func1"<<endl;
}

假定目錄結構為:
./makefile
./func1.cpp
./include/func1.hpp

./main.cpp

其中func1.hpp僅給出了函式定義,
實現位於func1.cpp中。


自底向上地看,
1.預處理+編譯:
g++ -c main.cpp -o main.o
#對main.cpp 進行預處理+編譯,但不連結(選項-c),生成中間檔案main.o(選項-o)

g++ -c func1.cpp -o func1.o
#同理


2.連結
g++ main.o func1.o -o program
#由main.o func1.o連結生成可執行檔案program(選項-o似乎是指定輸出檔名)


備註:
#如果只有一個main.cpp 作為原始檔,g++ main.cpp可以直接預處理+編譯+連結生成可執行檔案a.out。
#g++ -E main.cpp -o main.ii可以只進行預處理,預處理生成的檔案由-o指定,這裡是main.ii。
#在上述的專案結構中,main.cpp中需要include位於./include的func1.hpp。這時,正確的寫法是:
#include "./include/func1.hpp"
而不是
#include <./include/func1.hpp> (提示找不到檔案)
這可能是因為,用<>括起來的一般都是系統的某些庫,比如#include <iostream>,這樣的include可能是要到特殊的目錄下去尋找相關檔案的,所以使用者自己的檔案這樣引用就可能出現“找不到”的情況。


#注意到上述專案中func1的定義和實現是分開的。那麼,其定義和實現是在預處理-編譯-連結的哪個階段才整合在一起的呢?在預處理階段,include 的內容會被整合到一個檔案裡。最初,func1.cpp中有#include "./include/func1.hpp"的語句。然而注意到,去掉這個語句之後,按上述操作仍能得到正確的program。因此推測,上述專案中func1的定義和實現直到編譯階段都還是分開的。分別編譯後,定義位於main.o(因為main.o include 了func1.hpp), 而實現位於func1.o,兩者直到連結完成後才整合到program中。也就是說,直到連結完成之後,main函式才能正確地“呼叫”func1。


上述專案的makefile如下:
all: program


program: main.o func1.o
        g++ main.o func1.o -o program


main.o: main.cpp
        g++ -c main.cpp -o  main.o


func1.o: func1.cpp
        g++ -c func1.cpp -o func1.o


clean: 
        rm *.o




如果專案中有定義和實現分開的情況,可以參考以下規則:
1.在寫程式碼階段,注意:
#呼叫函式的地方一定要正確地include被呼叫函式的定義(hpp),而並不需要關心其實現(cpp)在哪裡。
2.在編譯階段,注意:
#每個.cpp生成一個對應的.o;
#所有的.o連結生成可執行檔案。


如果專案結構變為:
./makefile
./src/func1.cpp
./src/main.cpp
./include/func1.hpp
保持main.cpp中為#include "include/func1.hpp";
makefile修改為:
all: program


program: main.o func1.o
        g++ main.o func1.o -o program


main.o: src/main.cpp
        g++ -c src/main.cpp -o  main.o


func1.o: src/func1.cpp
        g++ -c src/func1.cpp -o func1.o


clean: 
        rm *.o


執行make,發現提示找不到include/func1.hpp。
原先以為,遇到#include "xxx"的寫法,前處理器尋找include檔案的預設目錄是makefile所在的目錄,現在看來不是,推測應該是包含該#include語句的cpp所在的目錄。查資料獲知,可以通過增加如下指令選項來新增包含目錄:
g++ -I. -c src/func1.cpp -o func1.o
這就是把makefile所在的目錄新增到了前處理器的包含目錄中,這樣前處理器就會在.目錄下尋找include/func1.hpp。


正確的makefile如下:
all: program


program: main.o func1.o
g++ main.o func1.o -o program


main.o: src/main.cpp
g++ -I. -c src/main.cpp -o  main.o


func1.o: src/func1.cpp
g++ -I. -c src/func1.cpp -o func1.o


clean: 
rm *.o


如果在編譯時需要的包含檔案存放在多個目錄下,可以使用多個-I來指定各個目錄:
g++ -I./include1 -I./include2 -c xxx.cpp -o xxx.o