一、靜態庫和動態庫,Makefile專案管理

weixin_34019929發表於2018-07-11

函式庫:本質:一組函式。具有相近的功能或操作同一資料結構。strcpy/strcmp/strcat/strlen/strstr/strchr/strtok... <string.h>

bubble_sort / select_sort / quick_sort / insert_sort <mysort.h>

作用:

  1. 程式碼複用:軟體開發的大部分時間用在應用程式設計上。而不是花在處理底層的細節上。(物件導向程式設計也體現了程式碼複用)

硬體——系統呼叫——標準庫——使用者庫——應用程式 (層層複用)

  1. 程式積累

釋出形式:

  • 原始碼形式釋出

缺點:1. 保密性差 2. 編譯程式耗時、平臺、編譯器版本
優點:方便使用者學習和研究

  • 二進位制形式
    優缺點 與上相反 標準C庫libc.so.6

一、靜態庫:

機制:複製靜態庫作為程式程式碼段的一部分。

優點:將函式庫中的函式本地化。定址方便,速度快。(庫函式呼叫效率 == 自定義函式使用效率)

缺點:消耗系統資源較大。每個程式使用靜態庫都要複製一份。無端浪費記憶體

使用場景:多應用於核心程式,保證時效性,可以忽視空間。

製作:

1. gcc add.c sub.c mul.c -c         ——>得到*.o

2. ar rs libmymath.a add.o sub.o mul.o  ——>得到靜態庫
(libmymath.a命名規範必須是lib開頭 .a結尾)
   ar工具不包含在gcc中
   r更新、c建立、s建立索引
   file libmymath.a         ——>檢視庫資訊
    
3. gcc main.c  -o app -L ./ -l mymath -I ./     ——>使用靜態庫(./ 表示當前資料夾 )

使用:L:指定靜態庫所在目錄位置;l:指定靜態庫名字 I:指定標頭檔案所在目錄位置


二、動態庫(共享庫):

機制:共享程式碼(不共享資料)

優點:節省記憶體(共享)、易於更新(動態連結) ./a.out 《--- libc.so

缺點:相較於靜態庫函式呼叫速度略慢(延遲繫結機制)

使用場景:

  1. 對程式執行速度要求不是很強烈,而相對於系統資源有一定要求的場景
  2. 對於更新比較頻繁的程式
    1)停止執行程式
    2)使用新庫覆蓋舊庫(保證新舊庫名稱一致,介面一致) “介面”
    3)重新啟動程式。

重點強調:

  • 動態庫是否載入到記憶體,取決於程式是否執行
  • 動態庫載入到記憶體的位置不固定----動態連結器

製作:

1. gcc -fPIC add.c mul.c sub.c -c (-fPIC:生成“與位置無關”的目標檔案*.o)
    
2. gcc -shared -o libmymath.so add.o mul.o sub.o
    
3. gcc main.c -L庫路徑 -l庫名 -I標頭檔案名  -o app
    
4. ./app --> 出錯     
    
原因:動態聯結器 ld-linux.so.2 搜尋動態庫的路徑未指定,

執行ldd app發現動態連結器找不到 libmymath 庫。
    
指定方法:

1. 環境變數法:export LD_LIBRARY_PATH=./ 將當前目錄加入環境變數,但是終端退出了就無效了。

2. 配置檔案法:將上條寫入家目錄下.bashrc檔案中    (永久生效,設定到~/.bashrc)

3. 拷貝法:直接將libmymath.so檔案拷貝到/usr/lib/目錄下。(受libc庫的啟發)

4. 快取檔案法:將libmymath.so所在絕對路徑加入到/etc/ld.so.conf檔案,

使用sudo ldconfig -v 動態更新/etc/ld.so.cache檔案(2進位制檔案)
    
*5. 指定動態庫的soname
    
        gcc -shared -Wl,-soname,libmymath.so.1 -o libmymath.so.1.10 add.o mul.o sub.o
    
*6. 建立動態庫的LinkerName
    
        ln -s libmymath.so.1.10 libmymath.so

動-靜態庫共存時:

編譯器預設使用.so的動態庫,找不到才使用靜態庫。

-static可以直接指定使用靜態庫。

objdump -dS app > out

注意比較加了static和沒有加static的可執行檔案大小,及內部printf的地址。


gdb:

使用場景:程式編譯無誤,但是有邏輯錯誤。

加-g 編譯 ---> gdb xxx  (gcc gcbtest.c -o app -g)

list l ---> b 行號 (設定斷點 b 22 if i = 5 條件斷點)
    
info b  檢視斷點資訊。
    
disable/enable  斷點號——設定斷點非使能/使能。
    
delete 斷點號——刪除斷點
    
b 行號 if i=5  設定條件斷點,只有i=3時斷點生效。
    
run  ----  start
    
p 變數名——檢視變數值
display——跟蹤變數
undisplay——取消跟蹤
ptype 變數名——檢視變數型別
    
bt  檢視當前程式函式棧幀使用基本情況

函式的棧幀儲存區域性變數和臨時值,形參,與區域性變數等價。
    
info locals 檢視當前棧幀上變數的儲存值。
    
frame 棧幀編號檢視變數的值
    
s——step
n——next

finish 終止當前函式

continue 結束當前斷點除錯
    
p *陣列名@10 列出陣列前10個元素值

p 陣列名[n]@m 從下標n開始向後列印m個元素。

三、makefile專案管理

3.1用途
  • 專案程式碼編譯管理
  • 節省編譯專案時間
  • 一次編寫終身受益
  • 操作示例檔案:add.c sub.c mul.c dive.c main.c
3.2基本規則

Makefile由一組規則組成,規則如下:

目標:依賴
(tab)命令
如:add.o:add.c
(一個tab縮排)gcc –Wall –g –c add.c –o add.o
目標:要生成的目標檔案
依賴(條件):目標檔案由哪些檔案生成
命令:通過執行該命令由依賴檔案生成目標
3.3Makefile工作原理

基本原則:
1.若想生成目標,檢查規則中的依賴條件是否存在,如不存在,則尋找是否有規則用來生成該依賴檔案
2.檢查規則中的目標是否需要更新,必須先檢查它的所有依賴,依賴中有任一個被更新,則目標必須更新

  • 分析各個目標和依賴之間的關係
  • 根據依賴關係自底向上執行命令
  • 根據修改時間比目標新,確定更新
  • 如果目標不依賴任何條件,則執行對應命令,以示更新
3.5Makefile變數

在Makefile中使用變數有點類似於C語言中的巨集定義,使用該變數相當於內容替換,使用變數可以使Makefile易於維護,修改內容變得簡單
變數定義及使用:

foo = abc
bar = $(foo)

定義了兩個變數:foo、bar,其中bar的值是foo變數值的引用。

1、變數定義直接用'='
2、使用變數值用$(變數名)

通常我們在Makefile中會定義一些變數,方便Makefile的修改維護

src = main.c func1.c func2.c
CC = gcc #arm-linux-gcc
CPPFLAGS : C預處理的選項如:-I
CFLAGS:C編譯器的選項–Wall –g -c
LDFLAGS :連結器選項–L -l

自動變數:

$@:表示規則中的目標
$<:表示規則中的第一個條件
$^:表示規則中的所有條件,組成一個列表,以空格隔開,如果這個列表中有重複的項則消除重複項。

模式規則:
至少在規則的目標定義中要包含'%','%'表示一個或多個,在依賴條件中同樣可以使用'%',依賴條件中的'%'的取值,取決於其目標.

模式規則示例:

%.o:%.c
$(CC) –c $(CFLAGS) $(CPPFLAGS) $< -o $@
其中,“$@”表示依次取出目標值,$<表示依次取出依賴條件。

注意:只有寫成模式規則的時候,$<才表示了所有依賴條件的依次取值
      否則只是取依賴條件中的第一個。
3.5Makefile 函式

src = $(wildcard *.c)
找到當前目錄下所有字尾為.c的檔案,賦值給src

obj = $(patsubst %.c,%.o, $(src))
把src變數裡所有字尾為.c的檔案替換成.o

3.6clean
  • 用途:清除編譯生成的中間.o檔案和最終目標檔案
  • make clean 如果當前目錄下有同名clean檔案,則不執行clean對應的命令
  • 偽目標宣告:.PHONY:clean
  • clean命令中的特殊符號
    – “-”此條命令出錯,make也會繼續執行後續的命令。如:“-rm main.o”
    – “@”不顯示命令本身,只顯示結果。如:“@echo”clean done“”
  • 其它
    – make 預設執行第一個出現的目標,可通過make dest指定要執行的目標
    – distclean目標
    – install目標
    – make -C 指定目錄進入指定目錄,呼叫裡面的Makefile
    – make -n:只列印要執行的命令,不會真正執行命令
    – make -p:顯示隱含規則資料庫中的資訊
    – make -C:切換到另一個目錄中執行該目錄下的Makefile
    – make -f:-f執行一個makefile檔名稱,使用make執行指定的makefile
3.7例子
3483777-689c578f4dcfdc3a.png
image.png
#src = add.c sub.c mul.c main.c 
src = $(wildcard *.c)    #wildcard *.c 在當前資料夾找到所有.c字尾的檔案
#obj = add.o sub.o mul.o main.o 
obj = $(patsubst %.c,%.o,$(src)) 

CC = gcc
target = app
ALL:$(target) 

$(obj):%.o:%.c                          
        $(CC) -c $< -o $@ 

$(target):$(obj) 
        $(CC) $^ -o $@ 

clean:
        -rm -rf app $(obj) 

.PHONY:clean ALL

3.8例題

1.完成該專案圖的makefile

3483777-52e0e88aa7c80681.png
例題1

#src = add.c sub.c mul.c main.c
src = $(wildcard ./src/*.c)    #wildcard:get all file which name end in .c in this file
obj = $(patsubst ./src/%.c,./obj/%.o,$(src))  #obj = add.o sub.o mul.o main.o

inc_path = ./inc/
CC = gcc
target = app
CFLAGES = -I
ALL:$(target)
      
$(obj):./obj/%.o:./src/%.c    #./obj/add.o ./obj/sub.o ./obj/mul.o  : ./src/*.c
        $(CC) -c $< -o $@ $(CFLAGES) $(inc_path)
    
$(target):$(obj)
        $(CC) $^ -o $@
    
clean: 
        -rm -rf app $(obj)
    
.PHONY:clean ALL

2.make生成三個不同的app

src = $(wildcard *.c)              #a.c b.c c.c gdbtest.c
target = $(patsubst %.c,%,$(src))  #a b c gdbtest

ALL:$(target)
CFLAGES = -Wall

$(target):%:%.c
        gcc $< -o $@ $(CFLAGES)

clean:
        -rm -rf $(target)

.PHONY:clean ALL

相關文章