Linux常用工具


軟件開發工具——GCC


GCC(GNU Compiler Collection,GNU編譯套裝)能夠編譯C、C++等語言。原本只能處理C語言,但是隨着眾多開發者的加入和GCC自身的發展,如今的GCC已成為可編譯多種語言的編譯器,如C/C++,Java,Fortran,Pascal等,GCC也由原來的GNU C Compiler變為GNU Compiler Collection,能夠在當前CPU計算機平台上,為眾多不同體系的硬件平台開發軟件服務,尤其應用於嵌入式開發領域。

目前Linux默認使用的C編譯器是GCC,具有如下優點:

  • 方便進行編譯控制

  通過GCC能夠完美地控制整個編譯過程,用戶可以根據需要,在任何階段讓編譯終止或暫停,以檢查或使用編譯器在該階段的輸出信息,並最終生成二進制文件。

  • 提供靈活強大的代碼優化功能

  通常使用"-On"控制優化配置,n越大,代碼優化越明顯。

  • 與GDB調試工具完美結合

  GDB調試工具具有查看程序運行狀態、設置斷點、查看表達式、顯示變量等眾多功能。GCC和GDB的結合使用是開發者進行C語言編程的利劍。

  • 人性化編譯選項

  提供眾多的編譯選項可以定制人性化的編譯過程。例如可以產生調試信息、優化代碼執行過程、選取需要的頭文件等。

  • 充足的提示信息

  提供很多警告信息,增強了程序的穩定性和可移植性。

GCC編譯過程分為四個階段:預處理、編譯、匯編、鏈接。如下圖所示:

提供幫助:

gcc --heip

GCC常用選項:

選項  含義
-V 查看gcc編譯器的版本,顯示gcc執行時的詳細過程
 -O file 把輸出文件制定到file中,該選項可以輸出匯編文件、目標文件以及可執行文件。
 -E 只對源文件進行預處理,不做編譯、匯編及鏈接,GCC會忽略任何不需要預處理的輸入文件。 
 -S 只進行編譯,不做匯編及鏈接,對於每個輸入的非匯編語言文件,輸出文件都是匯編語言文件。 
 -c 只進行匯編,不做鏈接,匯編成源文件的目標文件,默認狀態下生成.o文件,GCC忽略-c選項后面任何無法識別的輸入文件。 

例如新建文件hello.c如下:

#include <stdio.h>

int main()
{
  printf("hello, world\n");
}

 

第一步 預處理階段

執行命令: gcc -o hello.i -E hello.c

預處理器cpp根據以字符開頭#開頭的命令,修改原始C程序。比如hello.c中的第一行為 #include <stdio.h>,預處理器便將stdio.h的內容直接插入到程序中。預處理之后得到文本文件hello.i,打開如下:

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4
# 33 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 424 "/usr/include/features.h" 3 4
.........

extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 868 "/usr/include/stdio.h" 3 4

 
         

# 2 "hello.c" 2

 
         


# 3 "hello.c"
int main()
{
printf("hello, world\n");
}

預處理就是將要包含(include)的文件插入原文件中、將宏定義展開、根據條件編譯命令選擇要使用的代碼,最后將這些代碼輸出到一個“.i”文件中等待進一步處理。

第二步 編譯階段

執行命令: gcc -o hello.s -S hello.i

編譯器ccl將文本文件hello.i 翻譯為hello.s,這個文件里面包含一個匯編程序,就是把C/C++代碼(比如上面的".i"文件)“翻譯”成匯編代碼。匯編語言是非常有用的,因為它將不同高級語言的不同編譯器提供了通用的輸出語言。如下所示:

    .file    "hello.c"
    .text
    .section    .rodata
.LC0:
    .string    "hello, world"
    .text
    .globl    main
    .type    main, @function
main:
.LFB0:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    leaq    .LC0(%rip), %rdi
    call    puts@PLT
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size    main, .-main
    .ident    "GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0"
    .section    .note.GNU-stack,"",@progbits

 

第三步 匯編階段

執行命令:gcc -c -o hello.o hello.s

匯編器as將hello.s翻譯成機器語言保存在hello.o中。匯編就是將第二步輸出的匯編代碼翻譯成符合一定格式的機器代碼,在Linux系統上一般表現位ELF目標文件(OBJ文件)。

第四步 鏈接階段

執行命令: gcc -o hello hello.o

鏈接就是將匯編生成的OBJ文件、系統庫的OBJ文件、庫文件鏈接起來,最終生成可以在特定平台運行的可執行程序。鏈接分為靜態鏈接和動態鏈接兩種。

動態鏈接:動態鏈接使用動態鏈接庫進行鏈接,生成的程序在執行的時候需要加載所需的動態庫才能運行。 動態鏈接生成的程序體積較小,但是必須依賴所需的動態庫,否則無法執行。

靜態鏈接:靜態鏈接使用靜態庫進行鏈接,生成的程序包含程序運行所需要的全部庫,可以直接運行,不過靜態鏈接生成的程序體積較大。

結果得到hello 可執行文件,可以被加載到內存中由系統執行。

./hello

完整的執行過程為:

keegen@keegensCP:~/test$ touch hello.c
keegen@keegensCP:~/test$ vim hello.c
keegen@keegensCP:~/test$ gcc -o hello.i -E hello.c
keegen@keegensCP:~/test$ ls -a
.  ..  hello.c  hello.i
keegen@keegensCP:~/test$ gcc -o hello.s -S hello.i
keegen@keegensCP:~/test$ ls -a
.  ..  hello.c  hello.i  hello.s
keegen@keegensCP:~/test$ gcc -c -o hello.o hello.s
keegen@keegensCP:~/test$ ls
hello.c  hello.i  hello.o  hello.s
keegen@keegensCP:~/test$ gcc -o hello hello.o
keegen@keegensCP:~/test$ ls
hello  hello.c  hello.i  hello.o  hello.s
keegen@keegensCP:~/test$ ./hello
hello, world

總結編譯器的編譯過程:

源文件-->預處理-->編譯/優化-->匯編-->鏈接 -->可執行文件

在編譯過程中。除非使用了"-c",“-S”,或"-E"選項(或者編譯錯誤阻止了完整的過程),否則統一完整鏈接步驟。如運行

gcc hello.c 或 gcc -o hello hello.c
keegen@keegensCP:~/test$ rm -rf hello hello.i hello.o hello.s
keegen@keegensCP:~/test$ ls
hello.c
keegen@keegensCP:~/test$ gcc hello.c
keegen@keegensCP:~/test$ ls
a.out  hello.c
keegen@keegensCP:~/test$ ./a.out
hello, world
keegen@keegensCP:~/test$ gcc -o hello hello.c
keegen@keegensCP:~/test$ ls
a.out  hello  hello.c
keegen@keegensCP:~/test$ ./hello
hello, world

 


免責聲明!

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



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