【學習筆記】linux
vi 文件名 #進入文件編輯模式
yy #複製當前行 y數字y #複製多少行內容 p #箭頭移動到目的行粘貼 u #撤銷上一步 dd #刪除當前行 d數字d #刪除光標後多少行 x #刪除一個字母(至關於delete) X #刪除一個字母(至關於backspace) yw #複製一個詞 dw #刪除一個詞 shift+^ #移動到行頭 shift+4 #移動到行尾 1+shift+g #移動到頁頭 shift+g #移動到頁尾 N+shift+g #移動到目標行
i #當前光標前 a #當前光標後 o #當前光標行的下一行 delete #刪除 esc #退出編輯模式
:w #保存 :q #退出 ! #強制執行 :wq! #強制保存退出
GCC 是一個交叉平臺編譯器,可以在當前CPU 平臺上爲多種不一樣體系結構的硬件平臺開發軟件,所以尤爲適合在嵌入式領域的開發編譯。編程
.c,C 語言源代碼
.h,程序所包含的頭文件
.i,已經預處理過的C 源代碼文件
.s,彙編語言源代碼文件
.o,編譯後的目標文件編輯器
寫個hello.c源代碼函數
gcc hello.c
#include<stdio.h> int main() { printf(「Hello world!\n」); return 0; }
保存、退出學習
該階段,編譯器將上述代碼中的stdio.h編譯起來,可用「-E」選項查看spa
gcc格式爲操作系統
gcc [選項] 要編譯的文件 [選項] [目標文件] #目標文件可缺省,默認生成.out文件
gcc -E hello.c -o hello.i #-o:指目標文件;-i:指 已經預處理過的源程序
預編譯階段將「stdio.h」中的內容插入到hello.i文件中命令行
該階段,gcc首先檢查代碼的規範性、語法錯誤;檢查無誤後,gcc把代碼翻譯成彙編語言。可用「-S」選項查看翻譯
gcc -S hello.i -o hello.s
彙編階段是把編譯階段生成的「.s」文件轉成目標文件。讀者在此可以使用選項「-C」看到彙編代碼已轉化爲「.o」的二進制目標代碼。debug
gcc –c file.s –o file.o
在預編譯中包含進的「stdio.h」中也只有該函數的聲明,而沒有定義函數的實現。那麼,是在哪裏實現「printf」函數的呢?答案是:系統把這些函數實現都作到名爲libc.so.6 的庫文件中去了。
在沒有特別指定時,gcc 會到系統默認的搜索路徑「/usr/lib」下進行查找,從而連接到libc.so.6 庫函數,這樣就能實現函數printf 了,這也就是連接的做用。
gcc file.o –o file
gcc [選項] [文件]
-E:使用此選項表示僅做預處理,不進行編譯、彙編和連接。 -S:編譯到彙編語言不進行彙編和連接。 -c:編譯到目標代碼。 -o:文件輸出到文件。 -static:此選項將禁止使用動態庫,因此,編譯出來的東西通常都很大,也不須要什麼動態 連接庫便可運行。 -share:此選項將盡可能使用動態庫,因此生成文件比較小,可是須要系統有動態庫。 -I dir:在頭文件的搜索路徑列表中添加dir 目錄。 -L dir:在庫文件的搜索路徑列表中添加dir 目錄。 -llibrary:連接名爲library 的庫文件。
Linux 的大部分特點源自於Shell 的GNU(GNU symbolic debugger)調試器,也稱做gdb
以一段代碼爲例
gcc gdb_sample.c
#冒泡排序 void bubble_sort(int arr[], int len) { int temp; for (int i = 0; i < len; i++) { for (int j = 0; j < len-1-i; j++) {//從第一個數開始,依次和後一個數比較 if (arr[j] > arr[j + 1]) { #把較大的數交換到後邊 temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } #內層循環結束後,最大一個數排到最後,保持不動 #每結束一次內層循環,比較次數少一次,所以有-i } } } int main(){ int arr[] = { 22, 45, 67, 36, 93, 444, 26, 84, 3, 7 }; int len = (int)sizeof(arr) / sizeof(arr[0]); bubble_sort(arr, len); for (int i = 0; i < len; i++) { printf("%d ", arr[i]); } }
退出保存後使用gcc對代碼進行編譯,注意必定要加上選項「-g」,這樣編譯出的可
執行代碼中才包含調試信息,不然以後gdb 沒法載入該可執行文件。
啓動gdb進行調試:
gcc -g gdb_sample.c -o gdb_sample
在gdb輸入命令時,可用不用打全命令,在Linux下,可用敲擊兩次Tab鍵來補全命令。
輸入l(list),查看所載入的文件(輸入l便可,系統會自動識別)
break <function> #在進入指定函數時停住 break <linenum> #在指定行號停住 break +offset,break -offset #在當前行號的前面或後面的offset 行停住 break filename:linenum #在源文件filename 的linenum 行處停住 break filename:function #在源文件filename 的function 函數的入口處停住 break *address #在程序運行的內存地址處停住 break #break 命令沒有參數時,表示在下一條指令處停住 break…if <condition> #…能夠是上述的參數,condition 表示條件,在條件成立時停住
info breakpoints [n] info break [n]
輸入r(run)便可,gdb 默認從首行開始運行代碼,若想從
程序中指定行開始運行,可在r 後面加上行號:
r 10 #第十行開始執行
p [變量]
step <count> #單步跟蹤,若是有函數調用,它會進入該函數 next <count> #一樣單步跟蹤,但若是有函數調用,不會進入該函數 set step-mode,set step-mode on #打開step-mode 模式 set step-mod off #關閉step-mode 模式 finish #運行程序,直到當前函數完成返回 until 或u #當你厭倦了在一個循環體內單步跟蹤時,這個命令能夠運行程序直到退出循環體
一個簡單的Makefile:結構組成
all: #目標名字放在":"前面,名字由字母和下劃線組成 #":"後面是須要連接的文件 echo "Hello World" #注意echo前必須有一個Tab鍵位,不能是空格 #echo 後面是生成目標的命令 test: echo "Test Target" #一個makefile能夠定義多個目標
vi max.h
int max (int a, int b);
vi max.c
int max(int a,int b){ if(a>=b){ return a; } else{ return b; } }
vi min.h
int min(int a,int b);
vi min.c
int min(int a,int b){ if(a<b){ return a; } else{ return b; } }
vi main.c
#include <stdio.h> #include "max.h" #include "min.h" int main(int argc, char* argv[]){ int a = 5; int b = 3; int maxNum= max(a,b); int minNum = min(a,b); printf("the max value is %d\nthe min value is %d\n",maxNum,minNum); return 0; }
首先編譯依賴庫文件,而後編譯main函數
編譯max.c
gcc -c max.c -o max.o
編譯min.c
gcc -c min.c -o min.o
編譯main.c
gcc max.o min.o main.c -o main
./main
the max value is 5 the min value is 3
若是依賴函數過多,或者調用o庫文件多,這樣編譯將很是麻煩
因而採用makefile方式來進行簡化
vi Makefile #建立Makefile
#編輯Makefile(模板) simple:main.o max.o min.o gcc -o simple main.o max.o min.o #Tab間隔 main.o:main.c gcc -c main.c -o main.o max.o:max.c gcc -c max.c -o max.o min.o:min.c gcc -c min.c -o min.c
方法一:在Makefile所在的目錄下運行命令
make
方法二:運行命令make all
make [目標名]
gcc -c max.c -o max.o gcc -c min.c -o min.o gcc max.o min.o main.c -o simple
./simple
the max value is 5 the min value is 3
在前面的simple 項目中,如今假設在程序所在的目錄下面有一個clean 文件,這個文件也能夠用過touch命令來建立。
假目標能夠採用.PHONY關鍵字來定義,須要注意的是其必須是大寫字母
.PHONY:clean #假目標 simple:main.o max.o min.o gcc -o simple main.o max.o min.o #Tab間隔 main.o:main.c gcc -c main.c -o main.o max.o:max.c gcc -c max.c -o max.o min.o:min.c gcc -c min.c -o min.c clean: rm main.o min.o max.o simple
採用.PHONY 關鍵字聲明一個目標後,make 並不會將其看成一個文件來處理,而只是看成一個概念上的目標。對於假目標,咱們能夠想像的是因爲並不與文件關聯,因此每一次make 這個假目標時,其所在的規則中的命令都會被執行
在Makefile 中經過使用變量來使得它更簡潔、更具可維護性
$@ #表示一個規則中的目標。當咱們的一個規則中有多個目標時,$@所指的是其中任何形成命令被運行的目標。(表示的是目標的集合) $^ #表示的是規則中的全部先擇條件。(表示的是依賴的集合) $< #表示的是規則中的第一個先決條件。(表示目標列表裏最後一個依賴)
【注意】因爲在Makefile 中「$」具備特殊含義,所以,若是想採用echo 輸出「$」,則必需用兩個連着的「$」。還有就是,「$@」對於Shell 也有特殊的意思,咱們須要
在「$$@」以前再加一個脫字符「\」。
其餘一些字符的表示:
%.o 表示全部的.o文件 %.c 表示全部的.c文件
.PHONY:clean CC = gcc #定義變量 RM = rm OBJ = simple OBJS = main.o max.o min.o $(OBJ):$(OBJS) $(CC) -o $@ $^ main.o:main.c $(CC) -c $^ -o $@ max.o:max.c $(CC) -c $^ -o $@ min.o:min.c $(CC) -c $^ -o $@ clean: @$(RM) $(OBJS) $(OBJ)
addprefix 函數是用來給字符串中的每一個子串前加上一個前綴,其形式是:$(addprefix prefix, names…)
.PHONY:all SOURCE = main.c max.c min.c OBJS = /home/pyma/Makefile add source = $(addprefix $(OBJS)/. $(SOURCE)) all: @echo $(add_source)
filter 函數用於從一個字符串中,根據模式獲得知足模式的字符串,其形式是:$(filter pattern..., text)
.PHONY:all SOURCE = main.c max.c min.c OBJS = /home/pyma/Makefile add source = $(addprefix $(OBJS)/. $(SOURCE)) sources = $(filter %.c %.s,$(add_source) all: @echo $(add_source)
從結果來看,通過filter 函數的調用之後,sources 變量中只存在.c 文件和.s 文件,而.h 文件則被過濾掉了
filter-out 函數用於從一個字符串中根據模式濾除一部分字符串,其形式是:$(filter-out pattern..., text)
.PHONY:all SOURCE = main.c max.c min.c OBJS = /home/pyma/Makefile add source = $(addprefix $(OBJS)/. $(SOURCE)) sources = $(filter-out %.h,$(add_source) all: @echo $(add_source)
從結果來看,filter-out 函數將以「.h」爲後綴的文件從add_source 變量中給濾除了。能夠看出,filter 與filter-out 是互補的
wildcard 是通配符函數,經過它能夠獲得咱們所需的文件,這個函數至關於咱們在Windows或是Linux 命令行中的「*」。其形式是:$(wildcard pattern)
.PHONY:all SOURCE = $(wildcard *.c) OBJS = /home/pyma/Makefile add source = $(addprefix $(OBJS)/. $(SOURCE)) all: @echo $(add_source)
運行結果:從當前Makefile 所在的目錄下經過wildcard 函數獲得全部的C 程序源文件
patsubst 函數是用來進行字符串替換的,其形式是:$(patsubst pattern, replacement, text)
.PHONY:clean CC = gcc #定義變量 RM = rm OBJ = simple SRCS = $(wildcard *.c) OBJS = $(patsubst %.c,%.o,$(SRCS)) $(OBJ):$(OBJS) $(CC) -O $@ $^ main.o:main.c $(CC) -c $^ -o $@ max.o:max.c $(CC) -c $^ -o $@ min.o:min.c $(CC) -c $^ -o $@ clean: @$(RM) $(OBJS) $(OBJ)
OBJS 變量中採用patsubst 函數進行字符串替換,將全部的.c 文件都替換成.o 文件。patsubst 函數可使用模式,因此其也能夠用於替換前綴等,功能更增強大
選自華清遠見《嵌入式操做系統》