Linux基礎開發工具

編輯器 Vim

前導知識

在Linux系統中,開發工具都是獨立的

  • 寫代碼 : 編輯器 vim
  • 編譯 : gcc / g++
  • 調試 : gdb / cdgb
  • 構建工具 : makefile / make / cmake
  • git

Vim的模式 ( 3 + 2 )

Vim_3+2mode.png

命令模式

vim的默認模式

  • 跳到文本末 : shift + g ; 跳到第n行:n + shift + g
  • 到文本開始 : gg
  • 跳到當前行末:shift + 4 --- $
  • 跳到當前行始:shift + 6 --- ^
  • 按照單詞為單位向右移動:w ; 按照單詞為單位向左移動:b
  • 複製:yy || n + yy
  • 貼上:p || n + p
  • 刪除:dd || n + dd
  • 快切大小寫:shift + ~
  • 替換當前光標位置所在的一個字符: r || n + r --- 替換模式可以批量化替換
  • 刪除光標位置右的n個字符:n + x ; 如果要刪除左的話則是 n + shift + x
  • 撤銷:u ; 對 u 的撤銷進行撤銷:ctrl + r --- 一旦退出了 vim 就無法再做撤銷動作

底行模式

  • 強制保存退出:wq! --- 涉及權限問題 ; 退出也可以用 shift + zz 相當於 wq
  • 匹配搜索:/key + n
  • 不退出vim,直接對代碼編譯執行:!cmd
  • 將 a 字符全部替換成 b:%s/src/dst/g
  • 分屏操作:vs ; 切換分屏:ctrl + w --- 是用多文件代碼 .h .c 之類的
    如果vim打開,突然終端退出 ( 未對目標文件進行儲存 ) 那麼vim會形成一個臨時文件,默認在當前路徑下的一個.swp。
    此外,vim退出在光標若在第n行,則重新開啟時依然在第n行。

編譯器 gcc / g++

  • gcc : 只能用來編譯C語言
  • g++ :可用來編譯C/C++
    兩個其實是一樣的,在Linux中,對於程序編譯的過程是一步到位的

一個程序是如何產生的?

  1. 預處理(.i)

    • 展開標頭檔
    • 進行micro替換
    • 去注釋
    • 條件編譯 (為什麼要有條件編譯?-> 討論免費與收費功能)。

      • 條件編譯本質是對代碼進行裁減!

      如何證明預處理做的事情?gcc -E src -o dst
      預處理1.png
      預處理2.png

  2. 編譯

    • 產生匯編代碼(.s)。
      gcc -S src -o dst
      編譯1.png
      編譯2.png
  3. 匯編(.o)

    • 生成機器可識別代碼 => 把匯編轉成二進制文件(可重定位目標二進制文件)。
      gcc -c code.s -o code.o
      彙編1.png
      彙編2.png
  4. 鏈接

    • 生成.exe或庫文件
      gcc code.o -o code
      鏈接1.png

幾個小問題

  1. 二進制文件可否直接執行?
    關於二進制文件.png
    二進制文件無法直接執行 => 因爲這個二進制文件是可重定位目標二進制文件 => 在我們展開的標頭檔中用到的庫方法都只是聲明!
  2. 動態庫與靜態庫
    Linux中,動態庫是.so檔,而靜態庫是.a檔

    • 動態庫
      在動態鏈接中,程式並不會把庫函數的實現直接拷貝到可執行檔,而是保留「引用關係」。
      標頭檔(.h)只提供函數宣告,真正的實現則存放在動態庫(.so / .dll )中。
      當程式啟動時,作業系統會把所需的動態庫載入記憶體,並建立函數的地址表。當執行到某個函數時,程式就透過這張表 跳轉到動態庫中的對應函數,然後再返回程式繼續執行。這也意味著,如果動態庫缺少目標函數,程式將無法正常運行。這種方式稱為動態鏈接
    • 靜態庫
      在靜態鏈接中,編譯器會在鏈接階段,將所需的庫函數實現直接拷貝到可執行檔中(.a / .lib)。一旦可執行檔生成並成功鏈接,程式執行時就不再依賴靜態庫的存在。這種方式稱為靜態鏈接
      動態庫vs靜態庫.png

make / makefile

前導知識:make 是一條指令 makefile 是一個文件
直接先來瞧一瞧make 與makefile
make_makefile.png
make_makefile2.png

  • 目標文件:藉由make後生成的文件名稱
  • 依賴文件列表:要生成目標文件,依賴於哪些文件?
  • 依賴方法:構建可執行文件的方法

細節部分
(1) 依賴關係必須存在,但是依賴文件列表可以為空
(2) 依賴方法可以是任何shell指令
(3) clean 目標,只是利用make的自動推導能力,使其執行rm指令,在構建工程的視角下,看起來就是清理項目,本質就是刪除不需要的臨時文件!
(4) 當 make 後面跟上某個目標(文件名)時,它只會解析該目標所對應的依賴關係和方法
如果不指定目標,make 預設會從 Makefile 中的第一個目標開始,並且只會沿著這個目標的依賴關係推導出一條完整的構建鏈
make指令其實就是去解析makefile中的內容
about make.png

如何清理?

clean_make1.png
clean_make2.png

  • .PHONY:????? --- 用來修飾的文件是一個偽目標,這個文件的本質是總是被執行的
  • 為什麼.exe不使用.PHONY???? --- 為了提高編譯效率 ( 源文件有被修改時才需要再次編譯 )

    • 如何判斷源文件是否被修改?為什麼未修改的文件不會再次編譯?

      • 判斷源文件是否被修改,通常是通過檢查文件的修改時間(Modify time)。如果源文件的修改時間晚於生成的 .exe 檔案,表示源文件已被更新,make 就會重新編譯。
      • 如果對目標使用 .PHONY,make 每次執行時都會認為目標需要執行,導致每次都重新編譯,這會增加不必要的編譯開銷
    • 為什麼Modify時間會影響Change時間?

      • 當我們修改文件內容時,文件的 Modify 時間會更新。而內容的變動通常會影響文件大小,因此也會連帶改變 Change 時間。此外,Modify 時間本身也是文件的一個屬性
    • 不斷訪問同一份文件,access時間竟然不會一直變?

      • 由於修改文件屬性時需要將變更刷新到硬碟上,如果每次訪問都立即更新,將大幅增加對硬碟的訪問次數。而硬碟屬於外部設備,訪問速度相對較慢,這樣會導致整體效率下降,甚至影響整個作業系統的性能。因此access的時間通常是在訪問特定次數後才會更新一次

多個源文件怎麼辦?

多個源文件難道需要一個一個寫入嗎?
多個源文件.png
構建通用Makefie!

BIN=code.exe
#SRC=${shell ls *.c}
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
CC=gcc
Rm=rm -rf
$(BIN):$(OBJ)
    @$(CC) -o $@ $^
%(.o):%(.c)
    @${CC} -c $<
.PHONY:clean
clean:
    @$(Rm) $(OBJ) $(BIN)