歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

Linux下開發環境(gcc/g++/makefile/gdb)

先決條件
gcc 這是c語言的編譯器
從前,我寫了一個Linux多線程到程序Main.c,使用gcc -g Main.c -lpthread -o Main編譯,就出現來未安裝gcc的提示,我按照提示輸入來幾個y,然後就把gcc裝好了。但是,其實,在Red Hat Enterprise Linux 6上,默認已經安裝好gcc,可以編譯C語言程序了。
gcc-c++ 擴展為c++編譯器
This package adds C++ support to the GNU C compiler. It includes support for most of the current C++ specification, including templates and exception handling. It does not include the standard C++ library.
libstdc++-v3 The GNU Standard C++ Library v3
libstdc++-v3 is developed and released as part of GCC, separate snapshots are no longer made available. The libstdc++-v3 sources are included with the GCC sources and can be downloaded from the GCC FTP area or from any of the GCC mirror sites.
一、gcc與g++編譯流程
預處理preprocessing --> 編譯compilation --> 匯編assembly --> 鏈接linking
舉例:
[hadoop@sam1 testGCC]$ cat hello.c
Cpp代碼

#include<stdio.h>
int main(){
printf("in C");
return 0;
}
(0)一步到位的編譯:
[hadoop@sam1 testGCC]$ ls
hello.c
[hadoop@sam1 testGCC]$ gcc hello.c -o hello
[hadoop@sam1 testGCC]$ ./hello
in C
可以使用-O選項告訴GCC對源代碼進行基本優化,使程序執行更快,可以替換使用如下命令:
gcc hello.c -o hello -O0 //沒有優化
gcc hello.c -o hello -O1 //缺省,主要進行跳轉和延遲退棧兩種優化
gcc hello.c -o hello -O2 //除了完成-O1 的優化之外,還進行一些額外的指令調整工作
gcc hello.c -o hello -O3 //除了完成-O2 的優化之外,還進行包括循環展開和其他一些與處理特性相關的優化工作
(1)預處理:源文件hello.c --> 預處理文件hello.i。只激活預處理,不生成文件,需要把它重定向到一個輸出文件(預處理器的輸出默認被送到標准輸出,而非文件中)。
[hadoop@sam1 testGCC]$ ls
hello.c
[hadoop@sam1 testGCC]$ gcc -E hello.c -o hello.i
注:
hello.c後綴為c表示:
C source code which must be preprocessed.
-E Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard
output.
Input files which don't require preprocessing are ignored.
(2)編譯:預處理文件hello.i --> 匯編文件hello.s。激活預處理,編譯,把文件編譯成匯編代碼。
[hadoop@sam1 testGCC]$ ls
hello.c hello.i
[hadoop@sam1 testGCC]$ gcc -S hello.i -o hello.s
注:
hello.s:
Assembler code. 經過編譯後產生了匯編代碼
長這個樣子:
匯編代碼

.file "hello.c"
.section .rodata
.LC0:
.string "in C"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, %eax
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"
.section .note.GNU-stack,"",@progbits
-S Stop after the stage of compilation proper; do not assemble. The output is in the form of an assembler code file for each non-assembler input file specified.
By default, the assembler file name for a source file is made by replacing the suffix .c, .i, etc., with .s.
(3)匯編:匯編文件hello.s --> .o的匯編文件。激活預處理,編譯和匯編,把程序做成obj文件。
[hadoop@sam1 testGCC]$ ls
hello.c hello.i hello.s
[hadoop@sam1 testGCC]$ gcc -c hello.s -o hello.o
注:
-c Compile or assemble the source files, but do not link. The linking stage simply is not done. The ultimate output is in the form of an object file for
each source file.
By default, the object file name for a source file is made by replacing the suffix .c, .i, .s, etc., with .o.
Unrecognized input files, not requiring compilation or assembly, are ignored.
(4)鏈接:.o的匯編文件 --> 最終的可執行文件hello。
[hadoop@sam1 testGCC]$ ls
hello.c hello.i hello.o hello.s
[hadoop@sam1 testGCC]$ gcc hello.o -o hello
[hadoop@sam1 testGCC]$ ./hello
in C
注:
以上幾個參數實際上指定編譯在哪個stage退出,不在乎開始指定的文件是什麼形式
-E 截止到預編譯完成。
-S 截止到產生匯編文件。
-c 截止到產生目標文件,不鏈接。
不帶參數 截止到最終產生鏈接好的可執行文件。
另外,gcc -g 這個參數讓編譯器在目標文件中加上了調試信息,具體表現為ELF格式目標文件中多出了很多debug段,通過readelf -S ***.o查看,多出了諸如如下的這些調試段:
[27] .debug_aranges PROGBITS 00000000 0006e4 000020 00 0 0 1
[28] .debug_pubnames PROGBITS 00000000 000704 00004f 00 0 0 1
[29] .debug_info PROGBITS 00000000 000753 0000cb 00 0 0 1
[30] .debug_abbrev PROGBITS 00000000 00081e 00008d 00 0 0 1
[31] .debug_line PROGBITS 00000000 0008ab 000046 00 0 0 1
[32] .debug_frame PROGBITS 00000000 0008f4 000054 00 0 0 4
[33] .debug_str PROGBITS 00000000 000948 000095 01 MS 0 0 1
二、一個簡單工程的編譯——makefile(3 個.cpp 文件,2 個.h 文件)
main.cpp
Cpp代碼

#include<iostream>
#include "printf1.h"
#include "printf2.h"
int main(){
printf1();
printf2();
}
printf1.h
Cpp代碼

void printf1();
printf1.cpp
Cpp代碼

#include <iostream>
#include "printf1.h"
using namespace std;
void printf1(){
cout<<"printf1"<<endl;
}
printf2.h
Cpp代碼

void printf2();
printf2.cpp
Cpp代碼

#include <iostream>
#include "printf2.h"
using namespace std;
void printf2(){
cout<<"printf2"<<endl;
}
常規編譯:
Shell代碼

[hadoop@sam1 testGCC]$ ls
main.cpp printf1.cpp printf1.h printf2.cpp printf2.h
[hadoop@sam1 testGCC]$ g++ -c printf1.cpp ==> 截止到生成(未鏈接的)目標文件printf1.o
[hadoop@sam1 testGCC]$ g++ -c printf2.cpp ==> 截止到生成(未鏈接的)目標文件printf2.o
[hadoop@sam1 testGCC]$ g++ -c main.cpp ==> 截止到生成(未鏈接的)目標文件main.o
[hadoop@sam1 testGCC]$ ls
main.cpp printf1.cpp printf1.o printf2.h
main.o printf1.h printf2.cpp printf2.o
[hadoop@sam1 testGCC]$ g++ printf1.o printf2.o main.o -o out ==>將3個obj文件鏈接到一個可執行文件上
[hadoop@sam1 testGCC]$ ./out
printf1
printf2
makefile編譯:
Shell代碼

[hadoop@sam1 testGCC]$ ls
main.cpp printf1.cpp printf1.h printf2.cpp printf2.h
[hadoop@sam1 testGCC]$ vim makefile
==>見下面makefile文件內容
[hadoop@sam1 testGCC]$ make
g++ -c main.cpp #默認生成main.o
g++ -c printf1.cpp
g++ -c printf2.cpp
g++ main.o printf1.o printf2.o -o out
[hadoop@sam1 testGCC]$ ls
main.cpp makefile printf1.cpp printf1.o printf2.h
main.o out printf1.h printf2.cpp printf2.o
[hadoop@sam1 testGCC]$ ./out
printf1
printf2
[hadoop@sam1 testGCC]$ make clean
rm -rf *.o out
[hadoop@sam1 testGCC]$ ls
main.cpp makefile printf1.cpp printf1.h printf2.cpp printf2.h
makefile文件:
Makefile代碼

out: main.o printf1.o printf2.o #生成out需要依賴的文件
g++ main.o printf1.o printf2.o -o out
main.o: main.cpp printf1.h printf2.h #生成main.o需要依賴的文件
g++ -c main.cpp #默認生成main.o
printf1.o: printf1.h printf1.cpp
g++ -c printf1.cpp
printf2.o: printf2.h printf2.cpp
g++ -c printf2.cpp
clean:
rm -rf *.o out
三、用gdb調試
資料:使用 GDB 調試 Linux 軟件,David SeagerCICS/390 開發部,IBM Hursley:http://www.ibm.com/developerworks/cn/linux/sdk/gdb/
資料:LINUX GDB調試實例:http://blog.csdn.net/wangjiannuaa/article/details/6584750
另見本博客《(第一章 1)通用雙向鏈表》(系統程序員-成長計劃)
下面一個例子說明如何用gdb查看 “緩沖區溢出程序”的運行時堆棧情形——
C代碼

#include<stdio.h>
voidwhy_here(void){
printf("whyuhere?!\n");
_exit(0);
}
intmain(intargc,char*argv[]){
intbuff[1];
buff[2]=(int)why_here;
return0;
}
#gcc -g buf.c -o buf
啟動gdb調試buf

在程序開始處設置斷點(Sam:這裡實際上只設置了一個斷點,因為定義變量不會在指令序列中出現)

程序跑起來(直到遇到斷點 )

查看main函數棧信息

如果遇到函數:
單步跳入是step
單步跳過是next
非常好的文檔:
http://www.seas.upenn.edu/cets/answers/gcc.html http://baike.baidu.com/link?url=uU1zNRtDxA6rGdGQWqsjlM_0q8M_0iGbQD43Z9DbPr9e3dVFE4vSWcebSuwIWpis
Copyright © Linux教程網 All Rights Reserved