ubuntu下面幾種編譯器


本文檔主要總結了集中編譯器的使用方法:主要包括bazel,gcc,g++

1.gcc

編譯語言:C/C++/FORTRAN/JAVA/OBJC/ADA

  • 語法:gcc(選項) (參數)
  • 選項:  
-o:指定生成的輸出文件;
-E:僅執行編譯預處理;
-S:將C代碼轉換為匯編代碼;
-wall:顯示警告信息;
-c:僅執行編譯操作,不進行連接操作。
  • 參數:

    C源文件:指定C語言源代碼文件。

  • 實例
#假設源程序文件名為test.c

#無選項編譯鏈接
gcc test.c
#將test.c預處理,匯編,編譯並鏈接形成可執行文件,這里未指定輸出文件,默認輸出為a.out。

#選項 -o
gcc test.c -o test
#將test.c預處理,匯編,編譯並鏈接形成可執行文件test。
#-o選項用來指定輸出的文件名。

#選項 -E
gcc -E test.c -o test.i
#將test.c預處理輸出test.i文件。

#選項-S
gcc -S test.i
#將預處理輸出文件test.i匯編成test.s文件。

#選項-c
gcc -c test.s
#將匯編輸出文件test.s鏈接成最終可執行文件test。

#無選項鏈接
gcc test.o -o test
#將編譯出文件test.o鏈接成最終可執行文件test。

#選項 -O
gcc -O1 test.c -o test
#使用編譯優化級別1編譯程序。級別為1~3,級別越大優化效果越好,但是編譯時間越長。
  •  多源文件的編譯方法

   如果有多個源文件,有兩種編譯方法:

#方法一:多個文件一起編譯
gcc testfun.c test.c -o test
#將testfun.c和test.c分別編譯后鏈接成test可執行文件。

#方法二:分別編譯各個源文件,之后對編譯后輸出的目標文件鏈接。
gcc -c testfun.c #將testfun.c編譯成testfun.o
gcc -c test.c     #將test.c編譯成test.o
gcc -o testfun.o test.o -o test  #將testfun.c和test.c鏈接成test

注:第一種方法編譯時需要所有文件重新編譯

     第二種方法可以重新編譯修改的文件,未修改的文件不要重新編譯。

GCC可以用來編譯C/C++、FORTRAN、JAVA、OBJC、ADA等語言的程序

來自: http://man.linuxde.net/gcc

2.g++

  • g++是linux下c++的編譯器,在執行編譯工作的時候,總共需要4步:

(1)預處理,生成*.i的文件;

(2)將預處理后的文件不轉換成匯編語言,生成文件*.s;

(3)由匯編變為目標代碼(機器代碼)生成*.o的文件;

(4)連接目標代碼,生成可執行程序。

  • g++編譯c++經常使用的參數
#-c:只編譯,不連接
g++ -c helloworld.cpp
#只生成helloworld.o不連接

#-o:指定輸出文件名
g++ -c helloworld -o abc.o
#默認是生成helloworld.o,用-o abc.o以后,就生成就是abc.o

#-I:附加一個包含頭文件的路徑。
g++ helloworld.cpp -I"/usr/helloworld/include"

#-l(小L):附一個庫
g++ helloworld.cpp -labc
#使用libabc.so

# -L:添加一個庫的路徑
g++ hello.cpp -L"/usr/hello/lib" -labc

#-shared:生成動態庫文件
g++ -shared hello.cpp -o libhello.so
  • 調用動態庫的時候有幾個問題會經常用到,有時候,明明已經庫的頭文件所在目錄通過include進來了,庫所在文件通過“-L”參數引導,並指定了“-l”的庫名,但通過ldd命令查看時,就是死活找不到你指定鏈接的

so文件。其實編譯鏈接上了共享庫不代表執行時可以找到。所以“-L“什么的對執行沒有用,你需要指明共享庫的路徑。方法有三個:

(1)修改LD_LIBRARY_PATH,指明共享庫的路徑。LD_LIBRARY_PATH:這個環境變量指示動態連接器可以裝載動態庫的路徑。在終端下使用如下命令:

export LD_LIBRARY_PATH = your lib dir export

(2)通過/etc/ld.so.conf文件來指定動態庫的目錄。然后運行ldconfig命令更新搜索共享庫的路徑。通常這個做法就可以解決庫無法鏈接的問題並且一勞永逸。

(3)把庫文件拷貝到/lib下,然后ldconfig就ok了。這個方法有的取巧,且破壞原庫文件的純潔性,不推薦。

  • linux下文件的類型是不依賴於其后綴名的,但是一般講來:

*.o:是目標文件,相當於windows中的*.obj文件

*.so為共享庫,是shared object,用於動態連接的,和dll差不多

*.a為靜態庫,是好多個*.o合在一起,用於靜態連接

*.la為libtool自動生成的一些共享庫,主要是記錄了一些配置信息

3.bazel

參考:http://blog.163.com/wujiaxing009@126/blog/static/71988399201751110532137/

  •  特點:

(1)多語言支持

  JAVA/Objective-C和C++

(2)高級構建描述語言

  項目是使用一種叫BUILD的語言來描述的,它是一種簡簡潔的文本語言,它把一個項目是為一個集合,這個集合由一些互相關聯的庫,二進制文件和測試用例組成。相反,像Make這樣的工具,需要去描述每一個文件如何調用編譯器。

(3)多平台支持

  同一套工具和相同的BUILD文件可以用來為不同的體系結構構建軟件,甚至是不同的平台。在google,bazel被同時用在數據中心系統中的服務器應用和手機端的移動應用上。

(4)可重復性

  在BUILD文件中,每個庫,測試用例和二進制文件都需要明確指定它們的依賴關系。當一個源文件被修改時,bazel憑這些依賴關系來判斷哪些部分需要重新構建,以及那些任務可以並行進行。這就是意味着所有構建都是增量的,並且相同構建總是產生一樣的結果。

(5)可伸縮性

  bazel可以處理大型項目,在google,一個服務器軟件由十幾萬行代碼是很常見的,在什么都不改的前提下重新構建這樣一個項目,大概需要200毫秒。

  • bazel構建C++項目

(1)使用工作區

bazel builds應該在一個工作區內運行,這個工作區應該包括源代碼和build輸出目錄的符號鏈接(如:bazel-bin、bazel-out)。工作區目錄的位置是可以隨意的,但是工作區的根目錄必須包含一個名為WORKSPACE的工作區配置問價,工作區配置文件可以是一個空文件,也可以包含引用外表不構建輸出所需的依賴關系,在一個工作區內,可根據需求共享多個項目。

(2)創建Build文件

bazel通過檢查BUILD文件可以知道哪些目標文件被創建在項目中,這些BUILD文件采用與Python相似的語法所寫,這種語言通常是一系列規則的聲明,每個規則制定相應的輸入、輸出以及實現輸入到輸出的方法。

(3)通過一個例子學習

1)建立工作區

假設有個項目,對應於~/gitroot/my-project/目錄,先創建一個空的~/gitroot/my-project/WORKSPACE工作區配置文件,用於表示這是Bazel項目對應的根目錄。創立一個hello world工程。

└── my-project
    ├── lib
    │   ├── BUILD
    │   ├── hello-greet.cc
    │   └── hello-greet.h
    ├── main
    │   ├── BUILD
    │   ├── hello-time.cc
    │   ├── hello-time.h
    │   └── hello-world.cc
    └── WORKSPACE

 

2)創建源文件

 1 $ # If you're not already there, move to your workspace directory.
 2 $ cd ~/gitroot/my-project #進入項目根目錄
 3 $ mkdir ./main    #創建一個main 的文件夾
 4 $ cat > main/hello-world.cc <<'EOF' #在main文件夾中創建一個名為hello-world.cc的文件,並以EOF作為Linux創建文件結束的標志
 5 #include "lib/hello-greet.h" #include lib中的hello-greet.h
 6 #include "main/hello-time.h" #include main文件夾中的hello-time.h,而hello-time.cc則為hello-time.h的實現
 7 #include <iostream> #標准庫
 8 #include <string>
 9 
10 int main(int argc, char** argv) {
11   std::string who = "world";
12   if (argc > 1) {
13     who = argv[1];
14   }
15   std::cout << get_greet(who) <<std::endl;
16   print_localtime();
17   return 0;
18 }
19 EOF
20 $ cat > main/hello-time.h <<'EOF' #聲明hello-time.cc是干什么事情的
21 #ifndef MAIN_HELLO_TIME_H_
22 #define MAIN_HELLO_TIME_H_
23 
24 void print_localtime();
25 
26 #endif
27 EOF
28 $ cat > main/hello-time.cc <<'EOF'#具體hello-time.cc是怎么實現的
29 #include "main/hello-time.h"
30 #include <ctime>
31 #include <iostream>
32 
33 void print_localtime() {
34   std::time_t result = std::time(nullptr);
35   std::cout << std::asctime(std::localtime(&result));
36 }
37 EOF
38 $ mkdir ./lib
39 $ cat > lib/hello-greet.h <<'EOF'
40 #ifndef LIB_HELLO_GREET_H_
41 #define LIB_HELLO_GREET_H_
42 
43 #include <string>
44 
45 std::string get_greet(const std::string &thing);
46 
47 #endif
48 EOF
49 $ cat > lib/hello-greet.cc <<'EOF'
50 #include "lib/hello-greet.h"
51 #include <string>
52 
53 std::string get_greet(const std::string& who) {
54   return "Hello " + who;
55 }
56 EOF

 

3)添加BUILD文件

從上面的源代碼可知,main/hello-world.cc要用到lib/hello-greet.h和main/hello-time.h。首先在lib目錄下為hello-greet.cc創建BUILD.

1 cc_library(
2     name = "hello-greet", #要BUILD的文件的名字
3     srcs = ["hello-greet.cc"],#腳本
4     hdrs = ["hello-greet.h"],#頭文件
5     visibility = ["//main:__pkg__"],
6 )

 

注意:visibility = ["//main:__pkg__"]表示hello-greet對於main/BUILD是可見的。

接下來在main目錄下創建BUILD文件:

 1 cc_library(
 2     name = "hello-time",
 3     srcs = ["hello-time.cc"],
 4     hdrs = ["hello-time.h"],
 5 )
 6 
 7 cc_binary(
 8     name = "hello-world",
 9     srcs = ["hello-world.cc"],
10     deps = [
11         ":hello-time",
12         "//lib:hello-greet",
13     ],
14 )

 

注意:當依賴的包在同一個目錄下,只需要用:hello-time,當依賴的包在不同的目錄下,需要用全路徑://lib:hello-greet

現在可以建立hello world的c++二進制程序了:

 1 $ bazel build main:hello-world
 2 INFO: Found 1 target...
 3 Target //main:hello-world up-to-date:
 4   bazel-bin/main/hello-world
 5 INFO: Elapsed time: 2.869s, Critical Path: 1.00s
 6 $ ./bazel-bin/main/hello-world
 7 Hello world
 8 Thu Jun 23 18:51:46 2016
 9 $ ./bazel-bin/main/hello-world Bazel
10 Hello Bazel
11 Thu Jun 23 18:52:10 2016

 

ok!成功建立了第一個bazel項目!

4)傳遞依賴(Transitive includes)

如果一個文件包含一個頭文件,那么這個文件的規則也應該依賴與頭文件的庫,相反的,只有直接依賴需要被指定為依賴。例如,假設sandwich.h包括bread.h,而且bread.h包括flour.h,sandwich.h不包括flour.h,因此這個BUILD文件應該是這樣:

 

 1 cc_library(
 2     name = "sandwich",
 3     srcs = ["sandwich.cc"],
 4     hdrs = ["sandwich.h"],
 5     deps = [":bread"],
 6 )
 7 
 8 cc_library(
 9     name = "bread",
10     srcs = ["bread.cc"],
11     hdrs = ["bread.h"],
12     deps = [":flour"],
13 )
14 
15 cc_library(
16     name = "flour",
17     srcs = ["flour.cc"],
18     hdrs = ["flour.h"],
19 )

 

在這里,sandwich庫依賴於bread庫,而bread庫依賴於flour庫。

5)添加包含路徑(adding include paths)

有時候不能(或者不願意)讓依賴的文件包含咋工作區根目錄的路徑,現有的庫可能已經擁有了包括與工作空間不匹配路徑的目錄。例如,假設有如下的目錄結構:

1 └── my-project
2     ├── third_party
3     │   └── some_lib
4     │       ├── BUILD
5     │       ├── include
6     │       │   └── some_lib.h
7     │       └── some_lib.cc
8     └── WORKSPACE

 

bazel希望some_lib.h被包含在third_party/some_lib/include/some_lib.h中,但假定some_lib.cc要依賴於include/some_lib.h。為了使包含路徑有效, third_party/some_lib/BUILD需要指定some_lib是一個包含目錄:

1 cc_library(
2     name = "some_lib",
3     srcs = ["some_lib.cc"],
4     hdrs = ["some_lib.h"],
5     copts = ["-Ithird_party/some_lib"],
6 )

 

這對外部的依賴尤其有用,因為它們的頭文件,否則必須被包含於外部/ [庫名稱]/前綴。

 6)包含外部庫

 

7)編譯並運行c++測試程序

8)在預編譯上添加依賴

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM