1. 程式人生 > >Linux下開發環境(gcc/g++/makefile/gdb)

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
舉例:
[
[email protected]
testGCC]$ cat hello.c

Cpp程式碼 
#include<stdio.h> 
int main(){ 
printf("in C"); 
return 0; 
}





(0)一步到位的編譯:

[[email protected] testGCC]$ ls
hello.c
[[email protected] testGCC]$ gcc hello.c -o hello
[[email protected] testGCC]$ ./hello

可以使用-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。只啟用預處理,不生成檔案,需要把它重定向到一個輸出檔案(前處理器的輸出預設被送到標準輸出,而非檔案中)。
[[email protected] testGCC]$ ls
hello.c
[[email protected] 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。啟用預處理,編譯,把檔案編譯成彙編程式碼。

[
[email protected]
testGCC]$ ls hello.c hello.i [[email protected] 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檔案。

[[email protected] testGCC]$ ls
hello.c hello.i hello.s
[[email protected] 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。
[[email protected] testGCC]$ ls
hello.c hello.i hello.o hello.s
[[email protected] testGCC]$ gcc hello.o -o hello
[[email protected] 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程式碼 
[[email protected] testGCC]$ ls 
main.cpp printf1.cpp printf1.h printf2.cpp printf2.h 
[[email protected] testGCC]$ g++ -c printf1.cpp ==> 截止到生成(未連結的)目標檔案printf1.o 
[[email protected] testGCC]$ g++ -c printf2.cpp ==> 截止到生成(未連結的)目標檔案printf2.o 
[[email protected] testGCC]$ g++ -c main.cpp ==> 截止到生成(未連結的)目標檔案main.o 
[[email protected] testGCC]$ ls 
main.cpp printf1.cpp printf1.o printf2.h 
main.o printf1.h printf2.cpp printf2.o 
[[email protected] testGCC]$ g++ printf1.o printf2.o main.o -o out ==>將3個obj檔案連結到一個可執行檔案上
[[email protected] testGCC]$ ./out 
printf1 
printf2 


makefile編譯:

Shell程式碼 
[[email protected] testGCC]$ ls 
main.cpp printf1.cpp printf1.h printf2.cpp printf2.h 
[[email protected] testGCC]$ vim makefile 
==>見下面makefile檔案內容 
[[email protected] 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 
[[email protected] testGCC]$ ls 
main.cpp makefile printf1.cpp printf1.o printf2.h 
main.o out printf1.h printf2.cpp printf2.o 
[[email protected] testGCC]$ ./out 
printf1 
printf2 
[[email protected] testGCC]$ make clean 
rm -rf *.o out 
[[email protected] 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 
.PHONY: clean
clean: 
rm -rf *.o out 

二、Makefile檔案的格式(具體參見http://www.ruanyifeng.com/blog/2015/02/make.html)
構建規則都寫在Makefile檔案裡面,要學會如何Make命令,就必須學會如何編寫Makefile檔案。
2.1 概述
Makefile檔案由一系列規則(rules)構成。每條規則的形式如下。

<target> : <prerequisites>
[tab] <commands>
上面第一行冒號前面的部分,叫做"目標"(target),冒號後面的部分叫做"前置條件"(prerequisites);第二行必須由一個tab鍵起首,後面跟著"命令"(commands)。
"目標"是必需的,不可省略;"前置條件"和"命令"都是可選的,但是兩者之中必須至少存在一個。
每條規則就明確兩件事:構建目標的前置條件是什麼,以及如何構建。下面就詳細講解,每條規則的這三個組成部分。
2.2 目標(target)
一個目標(target)就構成一條規則。目標通常是檔名,指明Make命令所要構建的物件,比如上文的 a.txt 。目標可以是一個檔名,也可以是多個檔名,之間用空格分隔。
除了檔名,目標還可以是某個操作的名字,這稱為"偽目標"(phony target)。

clean:
rm *.o
上面程式碼的目標是clean,它不是檔名,而是一個操作的名字,屬於"偽目標 ",作用是刪除物件檔案。

$ make clean
但是,如果當前目錄中,正好有一個檔案叫做clean,那麼這個命令不會執行。因為Make發現clean檔案已經存在,就認為沒有必要重新構建了,就不會執行指定的rm命令。
為了避免這種情況,可以明確宣告clean是"偽目標",寫法如下。

.PHONY: clean
clean:
rm *.o temp
宣告clean是"偽目標"之後,make就不會去檢查是否存在一個叫做clean的檔案,而是每次執行都執行對應的命令。像.PHONY這樣的內建目標名還有不少,可以檢視手冊。
如果Make命令執行時沒有指定目標,預設會執行Makefile檔案的第一個目標。

$ make
上面程式碼執行Makefile檔案的第一個目標。

三、用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

相關推薦

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

先決條件 gcc 這是c語言的編譯器 從前,我寫了一個Linux多執行緒到程式Main.c,使用gcc -g Main.c -lpthread -o Main編譯,就出現來未安裝gcc的提示,我按照提示輸入來幾個y,然後就把gcc裝好了。但是,其實,在Red Hat En

Linux開發stm32一) | 使用gcc-arm-none-eabi工具鏈編譯

1.為什麼不是gcc 之前我們花了三篇文章介紹Linux下如何進行C語言程式設計: Linux C語言程式設計(上篇) | gcc的使用 Linux C語言程式設計(中篇) | make的使用 Linux C語言程式設計(下篇) | gdb的使用 這是為

Linux開發環境的安裝和配置

一:     1.先下載映象檔案     2.源配置   阿里雲源配置官網:http://mirrors.aliyun.com/        源配置:(1) 備份   sudo mv /etc/yu

Linux開發stm32四) | 韌體庫工程開發

st官方韌體庫是在暫存器操作之上的,但是使用暫存器操作的話,需要注意的地方很多,需要對照參考手冊一個一個賦值,稍有不慎便會出錯,所以韌體庫將外設的初始化封裝成初始化結構體,將外設的操作封裝在函式中,將暫存器賦值的操作都封裝起來,我們只需要呼叫API就可以,這樣一來既提高了開發效率,也減少了程

Linux開發stm32三) | 暫存器工程開發

先來回顧一下,前兩篇Linux下開發stm32(一) | 使用gcc-arm-none-eabi工具鏈編譯和Linux下開發stm32(二) | 使用openocd下載與除錯中,我們介紹瞭如何建立一個空的裸機工程(只有啟動檔案和main檔案),並編譯工程生成elf檔案,然後將其轉為bin格式

Linux開發stm32二) | 使用openocd下載程式

1.openocd介紹 openocd全名叫做Open On-Chip Debugger,是一個自由開放的片上除錯工具和程式設計工具,目前已經發布到0.10.0版本,目前主流偵錯程式幾乎都支援,具體可以檢視Open On-Chip Debugger:OpenOCD User’s Guid

【Julia】Linux配置Julia互動開發環境Julia notebook)

0x00 前言 近期Julia這門語言突然被拉入了大眾視野,我也是被一句 “Walk as Python,Run as C” 深深的吸引住了, 如果它沒有在吹牛,那麼這門語言說不定確實是我所想要的,那麼,學學看吧? 本篇文章主要用於介紹如何搭建便於學習與測

Linux搭建PHP開發環境Apache2.4.12+PHP5.6.7+MySQL5.6)

      樓主畢業近幾年都是從事Java開發,但前陣子公司外別的公司合作,並接了個專案,該專案的前期是PHP開發的,後期將逐漸轉為Java來開發,但期間的維護,介面的修改都得繼續用PHP,沒辦法啊,由於一下子找不到PHP開發人員,只能我來頂上了。       寫程式碼到不

Linux中使用VS Code編譯除錯C++專案gcc/g++、Makefile入門、vs code)

最近專案需求,需要在Linux下開發C++相關專案,經過一番摸索,簡單總結了一下如何通過VS Code進行編譯除錯的一些注意事項。 關於VS Code在Linux下的安裝這裡就不提了,不管是CentOS還是Ubuntu,如果不懂且搜Q足夠的情況下,你會解決的。 一. 前置知識——gcc/g++的編譯連結過程

ESP32搭建3.ubuntu14.04搭建esp32開發環境 最新版)

終端 pat 權限 技術 實例 為我 tro component 直接 硬件為樂鑫出品的ESP32一款集成了wifi和藍牙的集成模塊。 1.首先ctrl+alt+t打開終端,sudo -s選擇用root權限登陸 。 2. 輸入指令:sudo apt-get install

java入門---windows和Linux,UNIX,Solaris,FreeBSD開發環境配置

java應用程序 target details 感覺 開發工具 org chm files java ide 首先來看Windows下的操作。我們需要下載java開發工具包JDK。下載地址:http://www.oracle.com/technetwork/java

windows環境搭建Java開發環境一):jdk安裝和配置

變量 win jns jdk安裝 分享 tool 直接 www. 技術 一、資源下載   官網:http://www.oracle.com/technetwork/java/javase/downloads/index.html   本人安裝的是jdk1.8,百度雲資源:鏈

Docker for Windows安裝與Linux+PHP開發環境搭建二)

Docker for Windows安裝與Linux+PHP開發環境搭建(二) 上一篇講了docker安裝與環境搭建的步驟,這一次主要是介紹過程中遇到的錯誤情形及其錯誤處理方法: 1).執行docker pull local.registry.com:5000/php 或其他連線本地

Docker for Windows安裝與Linux+PHP開發環境搭建一)

Docker是什麼? 簡單得來說,Docker是一個由GO語言寫的程式執行的“容器”(Linux containers, LXCs); 目前雲服務的基石是作業系統級別的隔離,在同一臺物理伺服器上虛擬出多個主機。Docker則實現了一種應用程式級別的隔離; 它改變我們基本的開發、操作單元,

ubuntu18.04.1配置前端開發環境nvm),nvm安裝不成功的解決辦法

# Proxy alias setproxy="export ALL_PROXY=socks5://60.205.84.96:10086" alias unsetproxy="unset ALL_PROXY" 寫到 ~/.bashrc 最後面 然後,退出當前的 terminator 再開

Deepin開發環境配置個人備用)

文章目錄 Python相關 安裝pip和pip3 虛擬環境管理 Pycharm 安裝Git 前端相關 VSCo

ubuntu 18.04greenplum安裝筆記一)Linux基礎環境的搭建

背景 需要構建一個用於資料倉庫的分散式資料庫叢集。 每一個節點暫時不需要進行備份,同時也不考慮壞掉的情況。 每一個數據節點最好都不用進行過多的配置,安裝起來方便。 Greenplum的Shared-Nothing的設計思路很適合我目前的業務場景。 物理環境 4檯安裝了Linux的主機,安裝的作業系統的版本均為

Windows,在IDEA中搭建MapReduce開發環境需基礎,非詳盡篇)

hadoop在官網下載,jdk在官網下載,自行解壓下載的hadoop包,安裝下載的jdk。 開啟IDEA,新建專案: File->Project Structure: 選擇之前解壓的hadoop資料夾中的share/hadoop目錄下的common

ubntu單機配置fastdfs作為開發環境4)---將 fastdfs客戶端整合到現有java專案中

前言 話說,起初還覺得fastdfs的配置及整合會很簡單。。結果不是的。單單篇幅已經有四篇文章了。 正題: 請參考: 關於FastDFS蛋疼的叢集和負載均衡(九)之建立FastDFS的Maven專案 這一系列文章有意思。 FastDFS java client SDK

ubntu單機配置fastdfs作為開發環境3)--- nginx如何啟用fastdfs擴充套件以及相關配置

前言 參考: FastDFS+Nginx(單點部署)事例 FastDFS搭建單機圖片伺服器(二) 配置過程簡介 1.配置mod-fastdfs.conf,並拷貝到/etc/fdfs檔案目錄下。 建立nginx存放日誌和資料的目錄 mkdir /home/fastdfs