next up previous contents
Next: 撰寫使用者手冊 Up: 開發工具 - make 與 Previous: Makefile 其他法則   Contents

函式庫管理

  • 函式庫:目標檔庫
    1. 靜態函式庫:
      1. 附檔名:通常為 libxxx.a 的類型;
      2. 編譯行為:整個函式庫的資料被整合到執行檔中,所以利用編譯成的檔案會比較大。
      3. 獨立執行的狀態:編譯成功的可執行檔可以獨立執行,而不需要再向外部要求讀取函式庫的內容。
      4. 升級難易度:函式庫升級後,連執行檔也需要重新編譯過一次,將新的函式庫整合到執行檔當中。
    2. 動態函式庫:
      1. 附檔名:通常為 libxxx.so 的類型;
      2. 編譯行為:編譯時執行檔中僅具有指向動態函式庫所在的指標而已,並不包含函式庫的內容,所以檔案會比較小。
      3. 獨立執行的狀態:不能被獨立執行,程式讀取函式庫時,函式庫『必須要存在』,且函式庫的『所在目錄也不能改變』。
      4. 升級難易度:函式庫升級後,執行檔不需要進行重新編譯,故目前的 Linux distribution 比較傾向使用動態函式庫。
  • Linux 放置函式庫之目錄:
    /usr/lib
    /lib
    #%* kernel 的函式庫放在 /lib/modules*)
    
  • 如何判斷某個可執行的 binary 檔案含有什麼動態函式庫?
    1. ldd 指令
      [root@linux ~]# ldd [-vdr] [filename]
      選項:
      --version :列印 ldd 的版本序號
      -v :列出所有內容資訊;
      --help :指令用法資訊
      
    2. 找出檔案 /usr/bin/passwd 的函式庫資料。
      [root@linux ~]# ldd /usr/bin/passwd
              linux-gate.so.1 =>  (0x00d19000)
              .......中間省略......
              libpam_misc.so.0 => /lib/libpam_misc.so.0 (0x00bd6000)
              .......中間省略......
      
    3. 找出函式 /lib/libc.so.6 的相關其他函式庫。
      [root@linux ~]# ldd /lib/libc.so.6
              /lib/ld-linux.so.2 (0x00bf1000)
              linux-gate.so.1 =>  (0x00632000)
      
      [root@linux ~]# ldd -v /lib/libc.so.6
              /lib/ld-linux.so.2 (0x00bf1000)
              linux-gate.so.1 =>  (0x00111000)
      
              Version information:
              /lib/libc.so.6:
                      ld-linux.so.2 (GLIBC_2.1) => /lib/ld-linux.so.2
                      ld-linux.so.2 (GLIBC_2.3) => /lib/ld-linux.so.2
                      ld-linux.so.2 (GLIBC_PRIVATE) => /lib/ld-linux.so.2
      
  • 如何將動態函式庫載入快取記憶體( cache ),以增進動態函式庫的讀取速度?
    1. 在 /etc/ld.so.conf 寫入想要讀入快取記憶體的動態函式庫所在的目錄;
    2. 利用執行檔 ldconfig 將 /etc/ld.so.conf 的資料讀入快取中;
    3. 同時也將資料記錄一份在檔案 /etc/ld.so.cache 中。
      [root@test root]# ldconfig [-f conf] [-C cache] [-p] 
      參數說明: 
      -f conf :conf 預設為 /etc/ld.so.conf  
      -C cache:cache 預設為 /etc/ld.so.cache 
      -p   :列出目前在 cache 內的資料
      
    4. 例題:將 xorg 相關函式庫加到快取記憶體中:
      [root@dywHome2 ~]# cat /etc/ld.so.conf
      include ld.so.conf.d/*.conf
      /usr/X11R6/lib
      /usr/lib/qt3/lib
      [root@dywHome2 ~]# ldconfig -p | grep "libafb"
      [root@dywHome2 ~]# vi /etc/ld.so.conf
      [root@dywHome2 ~]# cat /etc/ld.so.conf
      include ld.so.conf.d/*.conf
      /usr/X11R6/lib
      /usr/lib/qt3/lib
      /usr/lib/xorg/modules # 加入此行
      [root@dywHome2 ~]# ldconfig
      [root@dywHome2 ~]# ldconfig -p | grep "libafb"
              libafb.so (libc6) => /usr/lib/xorg/modules/libafb.so
      
  • 建立函式庫:將多個目標檔案組合成一個函式庫檔案
    1. 函式庫建立指令 ar。例如:
      $ cc -c f1.c               # 產生 f1.o
      $ cc -c f2.c               # 產生 f2.o
      $ ar rv mlib.a f1.o f2.o   # 將目標檔 f1.o 及 f2.o 插入到函式庫 mlib.a
      
      #%* 選項 r :在函式庫中插入目標檔。當插入的目標檔名已在庫中存在,則替換。*)
      #%* 選項 v :顯示執行操作選項的附加信息。*)
      
    2. nm:查看目標檔庫檔案 mlib.a 的內容。
      $ nm mlib.a
      
    3. make 內建函式庫管理法則,例如:將 .c 檔案變成 .a 函式庫
      .c.a:
         $(CC) -c $(CFLAGS) $<
         $(AR) $(ARFLAGS) $@ $*.o
      
      #%* 變數 $(AR) 和 $(ARFLAGS),一般分別為命令 ar 和選項 rv。*)
      
    4. 若有一函式庫 fud,包含 bas.o 檔案,則上例法則中的變數為
      1. $< 代表目前的相依性項目,就是 bas.c。
      2. $@ 代表目前的目標項目,就是 fud.a 函式庫。
      3. $* 代表目前的相依性項目,不過不含副檔名,就是 bas。

  • 實作-管理一個函式庫
    1. 將 2.o 和 3.o 插入 mylib.a 函式庫中。新的 Makefile5 如下:
      all: myapp
      # Which compiler
      CC = gcc
      # Where to install
      INSTDIR = /usr/local/bin
      # Where are include files kept
      INCLUDE = .
      # Options for development
      CFLAGS = -g -Wall -ansi
      # Options for release
      # CFLAGS = -O -Wall -ansi
      # Local Libraries
      MYLIB = mylib.a
      myapp: main.o $(MYLIB)
         $(CC) -o myapp main.o $(MYLIB)
      $(MYLIB): $(MYLIB)(2.o) $(MYLIB)(3.o)
      main.o: main.c a.h
      2.o: 2.c a.h b.h
      3.o: 3.c b.h c.h
      clean:
         -rm main.o 2.o 3.o $(MYLIB)
      install: myapp
         @if [ -d $(INSTDIR) ]; \
          then \
            cp myapp $(INSTDIR);\
            chmod a+x $(INSTDIR)/myapp;\
            chmod og-w $(INSTDIR)/myapp;\
            echo "Installed in $(INSTDIR)";\
         else \
            echo "Sorry, $(INSTDIR) does not exist";\
         fi
      
    2. 執行
      $ rm -f myapp *.o mylib.a
      $ make -f Makefile5
      gcc -g -Wall -ansi   -c -o main.o main.c
      gcc -g -Wall -ansi   -c -o 2.o 2.c
      ar rv mylib.a 2.o
      a - 2.o
      gcc -g -Wall -ansi   -c -o 3.o 3.c
      ar rv mylib.a 3.o
      a - 3.o
      gcc -o myapp main.o mylib.a
      
    3. 試驗 3.o 的相依性項目
      $ touch c.h
      $ make -f Makefile5
      gcc -g -Wall -ansi   -c -o 3.o 3.c
      ar rv mylib.a 3.o
      r - 3.o
      gcc -o myapp main.o mylib.a
      $
      

  • 以子目錄來管理函式庫
    1. 方法一:由主要的 makefile 呼叫子目錄的 makefile。
      mylib.a:
          (cd mylibdirectory;$(MAKE))
      
      1. 要先製作 mylib.a。
      2. 當 make 依據這個法則建立函式庫時,它會進入子目錄 mylibdirectory;
      3. 隨後再喚起 make 命令來管理函式庫。這會喚起一個新 shell。
      4. 括弧是為了確保,所有的處理動作都是在一個 shell 中。
    2. 方法二:在 makefile 中使用變數,目錄加上 D,檔案加上 F。
      .c.o:
            $(CC) $(CFLAGS) -c $(@D)/$(<F) -o $(@D)/$(@F)
      #%* 在子目錄中編譯檔案,並將編譯完的目的檔留在子目錄中。*)
      
      1. 若目標項目所在目錄為 mydir,程式 2.c,目標項目 2.o 檔案,則上例法則中的變數為
        1. $(@D) 代表目前的目標項目所在目錄,就是 mydir。
        2. $(<F) 代表目前的相依性項目的檔案名稱,就是 2.c。
        3. $(@F) 代表目前的目標項目的檔案名稱,就是 2.o。
      2. 隨後利用相依性項目,更新現在目錄的函式庫,法則如下:
        mylib.a: mydir/2.o mydir/3.o
             ar rv mylib.a $?
        #%* \$? 代表需要重建的相依性項目,就是 mydir/2.o 及(或) mydir/3.o*)
        

練習題

  1. 何謂函式庫?
    Sol. 集合目標檔的目標檔庫
  2. 函式庫分為那兩種?
    Sol. 靜態及動態函式庫
  3. 何謂靜態函式庫?
    Sol. 1.附檔名通常為 libxxx.a 的類型;2.整個函式庫的資料被整合到執行檔中,故可執行檔可以獨立執行,但升級時,連執行檔也需要重新編譯過一次。
  4. 何謂動態函式庫?
    Sol. 1.附檔名通常為 libxxx.so 的類型;2.編譯時執行檔中僅具有指向動態函式庫所在的指標,故可執行檔不能被獨立執行,而函式庫升級後,執行檔不需要進行重新編譯;3.目前的 Linux distribution 比較傾向使用動態函式庫。
  5. 通常 Linux 放置函式庫之目錄為何?
    Sol. /usr/lib 及 /lib
  6. 通常 Linux kernel 的函式庫放置目錄為何?
    Sol. /lib/modules
  7. 如何找出檔案 /usr/bin/passwd 的函式庫資料?
    Sol. ldd /usr/bin/passwd
  8. 如何找出函式 /lib/libc.so.6 的相關其他函式庫?
    Sol. ldd /lib/libc.so.6
  9. 如何找出函式 /lib/libc.so.6 的相關其他函式庫,並列出所有內容資訊?
    Sol. ldd -v /lib/libc.so.6
  10. 要將某目錄下之動態函式庫,載入快取記憶體,必須於那個檔案中加入此目錄?
    Sol. /etc/ld.so.conf
  11. 如何將 /etc/ld.so.conf 的資料讀入快取記憶體中?
    Sol. 執行 ldconfig
  12. 如何將 /etc/my.so.conf 的資料讀入快取記憶體中?
    Sol. 執行 ldconfig -f /etc/my.so.conf
  13. 如何將 /etc/ld.so.conf 的資料讀入快取記憶體 /etc/my.so.cache 中?
    Sol. 執行 ldconfig -C /etc/my.so.cache
  14. 如何列出目前在 cache 內的資料?
    Sol. 執行 ldconfig -p
  15. 如何查看動態函式庫 libafb.so,是否在快取記憶體中?
    Sol. 執行 ldconfig -p | grep "libafb"
  16. 若目錄 /usr/lib/xorg/modules 包含動態函式庫 libafb.so,如何將其載入快取記憶體,以增進動態函式庫的讀取速度?請詳列步驟。
    Sol. 1.以 vi 編輯檔案 /etc/ld.so.conf 加入一行 /usr/lib/xorg/modules,命令為 vi /etc/ld.so.conf; 2. 執行 ldconfig; 3.查看動態函式庫 libafb.so,是否在快取記憶體中,ldconfig -p | grep "libafb"
  17. 如何將目標檔 f1.o 及 f2.o 插入到函式庫 mlib.a?
    Sol. ar r mlib.a f1.o f2.o
  18. 如何將目標檔 f1.o 及 f2.o 插入到函式庫 mlib.a,並顯示訊息?
    Sol. ar rv mlib.a f1.o f2.o
  19. 如何查看目標檔庫檔案 mlib.a 的內容?
    Sol. nm mlib.a
  20. 若有一函式庫 fud,包含 bas.o 檔案,則下列 makefile 法則中的變數 $<, $@, $* 分別為何?
    .c.a:
       $(CC) -c $(CFLAGS) $<
       $(AR) $(ARFLAGS) $@ $*.o
    #%* 變數 $(AR) 和 $(ARFLAGS),一般分別為命令 ar 和選項 rv。*)
    

    Sol. 1.$< 代表目前的相依性項目,就是 bas.c。 2.$@ 代表目前的目標項目,就是 fud.a 函式庫。 3.$* 代表目前的相依性項目,不過不含副檔名,就是 bas。
  21. 請列舉兩種以子目錄來管理函式庫之 makefile 寫法。
    Sol. 1.先進入子目錄,並在子目錄中產生函式庫; 2.在 makefile 中使用變數,目錄加上 D,檔案加上 F。
  22. 請說明 makefile 法則 (cd mydir;$(MAKE))。
    Sol. 1.先進入子目錄 mydir,並在子目錄中執行變數 $(MAKE) 的內容; 2.括弧是為了確保,所有的處理動作都是在一個 shell 中。
  23. 若目標項目所在目錄為 mydir,程式 2.c,目標項目 2.o 檔案,則 makefile 法則 $(CC) $(CFLAGS) -c $(@D)/$(<F) -o $(@D)/$(@F) 中的變數 $(@D), $(<F), $(@F) 分別為何?
    Sol. 1.$(@D) 代表目前的目標項目所在目錄,就是 mydir。 2.$(<F) 代表目前的相依性項目的檔案名稱,就是 2.c。 3.$(@F) 代表目前的目標項目的檔案名稱,就是 2.o。
  24. 若有一 makefile 中,目標項目 mylib.a: 2.o 3.o 的法則為 ar rv mylib.a $?,其中 $? 代表意義為何?
    Sol. 代表需要重建(被修改)的相依性項目,就是 2.o 及(或) 3.o
  25. 若有一 makefile 中,目標項目 mylib.a: mydir/2.o mydir/3.o 的法則為 ar rv mylib.a $?,其中 $? 代表意義為何?
    Sol. 代表需要重建(被修改)的相依性項目,就是 mydir/2.o 及(或) mydir/3.o


next up previous contents
Next: 撰寫使用者手冊 Up: 開發工具 - make 與 Previous: Makefile 其他法則   Contents
2017-06-14