1. 程式人生 > 實用技巧 >【轉】在linux下使用gcc/g++編譯多個.h檔案

【轉】在linux下使用gcc/g++編譯多個.h檔案

轉自:https://www.jianshu.com/p/e5c6a255076b

博主寫得很好

多個檔案編譯在linux下編譯,下面有三個檔案,分別是1.cpp 和 2.cpp 和myhead.h 檔案。

1.cpp

#include <iostream>
#include "myhead.h"
using namespace std;

int main(){
    print();
    cout<<"yes !"<<endl;
    return 0;
}

2.cpp

#include <iostream>
#include "myhead.h"
using namespace std;

void print(){
    std::cout<<" print "<<std::endl;
    cout<<
}

myhead.h

#ifndef __myhead_h
#define __myhead_h
void  print();
#endif

假如他們都在一個目錄下面,那麼編譯流程:

g++ -c 2.cpp             #將2.cpp 編譯成2.o 檔案
g++ 1.cpp -o a.out 2.o   #多個檔案一起連結

or

g++ -c 2.cpp 
g++ -c 1.cpp 
g++ 1.o 2.o -o test

當然,沒有標頭檔案,兩個.c檔案也是可以編譯的。如下:

1.cpp檔案

#include <iostream>
using namespace std;
void fn();
int main(){
    cout<<"123"<<endl;
    fn();
    return 0;
}

2.cpp檔案

#include <iostream>
void fn(){
    std::cout<<"fn"<<std::endl;
}

編譯:

g++ -c 1.cpp 
g++ -c 2.cpp 
g++ -o test 1.o 2.o

在稍微大一點的專案裡面,一般都會包含多個檔案。尤其是包含多個頭檔案,各自標頭檔案的實現,和包含main函式的檔案。這樣的好處就是更容易開發和維護。

舉一個簡單的例子,main.cpp 檔案是包含main函式的檔案,在myinclude的檔案下,包含了myhead.h 和 myhead.cpp 檔案。分別是標頭檔案的定義和實現。


檔案樹

main.cpp :

#include <iostream>
#include <myhead.h>
using namespace std;
int main(){
    //fun_head();
    cout<<"in main"<<endl;
    int x=100;
    int y=200;
    cout<<"sum : "<<sum(x,y);
    return 0;
}

myhead.h

#ifndef __myhead_h
#define __muhead_h
void  print();
int sum(int a,int b);
#endif

myhead.cpp

#include "myhead.h"
#include <iostream>
using namespace std;
void  print(){
    cout<<"in fun head"<<endl;
}
int sum(int a,int b){
    return a+b;
}

下面開始編譯:
假如在當前目錄直接編譯的話:

zhaozheng@ubuntu:~/code/c++/test_compile/src$ g++ main.cpp -o main
main.cpp:2:20: fatal error: myhead.h: No such file or directory
compilation terminated.

直接編譯的結果就是報錯了,錯誤的原因是 預設的include目錄下面沒有 myhead.h 標頭檔案。

如果不知道include的預設的標頭檔案,請看:
http://www.jianshu.com/p/3eb25114576e

那麼通過 -I 選項 連結上去。重新編譯

zhaozheng@ubuntu:~/code/c++/test_compile/src$ g++ main.cpp -o main -I ../myinclude/
/tmp/ccH3BlLo.o: In function `main':
main.cpp:(.text+0x3e): undefined reference to `sum(int, int)'
collect2: error: ld returned 1 exit status

有報錯,錯誤的原因是標頭檔案雖然找到了,但是沒有提示錯誤,沒有定義sum函式。sum函式是在myhead.cpp檔案上面定義的。也就是需要把myhead.cpp檔案編譯一下。

zhaozheng@ubuntu:~/code/c++/test_compile/myinclude$ g++ -c myhead.cpp -o myhead.o

編譯通過:


image.png

最後,再一次的編譯:

zhaozheng@ubuntu:~/code/c++/test_compile/src$ g++ main.cpp -o main -I ../myinclude/    ../myinclude/myhead.o
zhaozheng@ubuntu:~/code/c++/test_compile/src$ 
image.png

執行結果:


image.png

PS : 上面寫得是,如果編譯,連結多個檔案,如果好奇編譯和連結的具體過程,請看 :
http://www.jianshu.com/writer#/notebooks/10152412/notes/9498296

PS:
gcc/g++ 裡面的-c選項指的是,比如

gcc -c myhead.cpp -o myhead.o

將一個檔案編譯,但是不連結。將程式碼變成機器碼。

比如,

gcc -c main.cpp -o main.o

將main.cpp檔案編譯為main.o 檔案

那麼連結器的作用是什麼?

gcc -o main  main.o  ../myinclude/myhead.o 

這樣將兩個.o檔案和依賴庫的檔案連結起來,程式設計可執行的檔案。

<br />
PPS:

  1. 以後再來寫,什麼是編譯,什麼是連結。
  2. 動態庫和靜態庫的區別

多個檔案編譯的時候,可以順便理解一下static,extern兩個關鍵字的意思。

  • extern
    如下所示的程式碼:

如果在2.cpp檔案裡面定義了一個變數,在1.cpp這個檔案裡面去訪問這個變數。在連結的時候,2.cpp裡面的變數對1.cpp是可以的。1.cpp裡面是可以訪問這個變數的,但是,需要使用extern宣告這個變數是賴在其他檔案的。

編譯

g++ -c 1.cpp 
g++ -c 2.cpp
g++ 1.o 2.o -o test

但是,如果去掉extern的話,那麼連結的時候,就會報一個錯誤


錯誤提示,連線的時候 兩個檔案裡面的value都是彼此可以的,所以,提示變數被定義了多次。

2.o:(.data+0x0): multiple definition of `value'
1.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status

改正這個錯誤,除了可以加上extern 之外,還可以加上static,改變變數的可見範圍。(加上static之後,變數只能在當前檔案裡面可見。)

  • static

static 宣告一個變數的時候,除了可以將變數的空間開闢在全域性區。第二個就是改變變數的可見範圍,這個變數只能在檔案內部可以。



作者:zhaozhengcoder
連結:https://www.jianshu.com/p/e5c6a255076b
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。