跳到主要內容

[Coding] Compiler

Something about compiling. #compiler #link #gcc

Reference

  • PTT LinuxDev, 作者: cole945 (躂躂..) 看板: LinuxDev, 標題: [心得] 用gcc 自製Library, 時間: Sun Nov 5 04:15:45 2006

Static Link

Compile 時將 library 加入程式碼,執行快但佔空間,code size 和 mem 使用都比較多
  1. Compile source codes to generate object files
    $ gcc -c file1.c file2.c file3.c
    • -c 編出 object 檔
  2. Create a static library named libmylib.a
    $ ar rcs libmylib.a file1.o file2.o file3.o
    • 把一堆 object 檔用 ar(archiver) 包裝集合起來,檔名以`.a’ 結尾
  3. Using a Static Library to generate a executable files
    $ gcc -o main main.c -L. -lmylib
    • -L: the directory of the library. 可以指定多次 -LDIR
    • -l: the name of the library (注意藍色部分是 match 的)

Dynamic Link

Compile 時不將 library 加入程式碼,執行程式的時後再將 library 載入程式碼,若有多個程式共用同一個 library,只需載一個 library 進 memory
  1. Compile source code
    $ gcc -c -fPIC file1.c file2.c file3.c
    • -fPIC 表示要編成 position-independent code,這樣不同 process 載入 shared library 時,library 的程式和資料才能放到記憶體不同位置。-fPIC 較通用於不同平台,但產生的 code 較大,而且編譯速度較慢
  2. Create a shared library named libmylib.so
    $ gcc -o libmylib.so.1.0.0 -shared -Wl,-soname,libmylib.so.1 file1.o file2.o file3.o
    • so name:用來表示是一個特定library 的名稱,像是 libmylib.so.1 。以 lib 開頭,接著是該 library 的名稱,然後是 .so,接著是版號,用來表名他的介面;如果介面改變時,就會增加版號來維護相容度
      在 mac 上我遇到 "ld: unknown option: -soname",須以 "-install_name" 取代 "-soname"
      可以用 objdump 檢查 $ objdump -p libmylib.so | grep SONAME
    • real name:是實際放有 library 程式的檔案名稱,即是 soname 後面再加上 minor 版號與 release 版號,像是libmylib.so.1.0.0。一般來說版號的改變規則是,最尾碼的 release 版號用於程式內容的修正,介面完全沒有改變。中間的minor用於有新增加介面,但相舊介面沒改變,所以與舊版本相容。最前面的version版號用於原介面有移除或改變,與舊版不相容時
    • linker name:是用於連結時的名稱,是不含版號的 so name ,如 libmylib.so。通常 linker name 與 real name 是用 ln 指到對應的 real name ,用來提供彈性與維護性
  3. Create link
    $ ln -s libmylib.so.1.0.0 libmylib.so
    $ ln -s libmylib.so.1.0.0 libmylib.so.1
  4. Using a Shared Library
    $ gcc -o main main.c -L. -lmylib
    • linker 會搜尋 libmylib.so 來進行連結,如果目錄下同時有 static 與 shared library 的話,會以 shared 為主。使用 -static 參數可以避免使用 shared 連結
    • 可以用 ldd 看編譯出的執行檔與 shared 程式庫的相依性 (mac 上改用 otool -L)
      bash-3.2$ otool -L a.out
      a.out:
              libmylib.so.1 (compatibility version 0.0.0, current version 0.0.0)
              /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)
  5. Execute
    $ ./main
    • libmylib.so.1 可以被建在其他 path,但為了能 dynamic load,該 path 即需要加入 LD_LIBRARY_PATH
      $ LD_LIBRARY_PATH=/another_path ./main
    • mac 上須改變的是 DYLD_LIBRARY_PATH
Remember to put libmylib.so into PATH, ex. /usr/lib

Dynamic Load

Compile 時不將 library 加入程式碼,執行程式時遇到函式才將 library 載入,用完後再 free 出空間,執行效果最慢。像 Windows 所用的 DLL ,在使用到時才載入,編譯連結時不需要相關的 library。動態載入庫常被用於像 plug-ins 的應用
  1. Compile source code
    $ gcc -c file1.c file2.c file3.c
  2. Create a shared library named libmylib.so
    $ gcc -o libmylib.so.1.0.0 -shared -Wl,-soname,libmylib.so.1 file1.o file2.o file3.o
    $ ln -s libmylib.so.1.0.0 libmylib.so
    $ ln -s libmylib.so.1.0.0 libmylib.so.1
  3. Using a Shared Library- Use the "dlopen" to access the shared library
    #include <dlfcn.h>
    void *dlopen(const char *filename, int flag)
    char *dlerror(void)
    void *dlsym(void *handle, const char *symbol)  取得 symbol 指定的 symbol name 在 library 被載入的記憶體位址
    int dlclose(void *handle)
  4. #include "dlfcn.h"
    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
        void *handle;
        void (*f)();
        char *error;
    
        /* open the needed object */
        handle = dlopen("./libmylib.so", RTLD_LAZY);
        if (!handle) {
            /* get diagnostic information */
            fputs(dlerror(), stderr);
            exit(1);
        }
    
        /* find the address of function and data objects */
        f = dlsym(handle, "function1");
        if ((error = dlerror())!=NULL) {
            fprintf(stderr, "%s\n", error);
            exit(1);
        }
    
        /* excute function1 */
        f();
    
        /* close a dlopen object */
        dlclose(handle);
    }
  5. Compile Since above function are implemented in the library libdl.a, we need to load this library
    $ gcc dltest.c -ldl
    • -ldl: load the library libdl.a
    • 與 dynamic link 差別就在 compile 的時候不需要去 link so

留言

這個網誌中的熱門文章

[Development] git

本篇介紹幾個 git 會用到的基本 command line 指令 安裝 on Mac OS [tested on macOS Catalina 10.15.1] (可以用 Brew 安裝,若尚未安裝 Brew:  https://brew.sh/index_zh-tw ) $ brew install git $ git --version git version 2.21.0 (Apple Git-122.2)   github 官網就有提供 GUI 的應用 ,想用 GUI 的直接去下載安裝就行了,也有簡單明瞭的教學,非常容易。另外也有好幾個第三方的好用 GUI 介面,Google 一下比較一下選自己喜歡的也行。   但以下還是用 command line 的方法來操作,因為這還是最 general 到哪都可以用的基本方法。因為實務上,比如 code 都放在公司的 server,你可能也是都要 ssh 到 sever 上去改 code,改完之後要上傳到 github。而公司的 server 就是一台 Linux 環境,很可能是沒有提供 GUI 讓你使用的,所以你就只能用 command line 的方式完成 git 的上傳。 Create Repo   去本地一個你想要放置 git 專案的地方,比如我想把我之後的 git code 都放在我 Mac local 的 /Users/chungchris/git $ cd /Users/chungchris/git $ git init   就會看到在此 git 目錄下產生一個隱藏的 .git 資料夾,這樣就完成了: (base) Chris-MBP:git chungchris$ ls -al total 0 drwxr-xr-x   3 chungchris   staff     96 11 21 11:01 . drwxr-xr-x+ 53 chungchris   staff   1696 11 21 10:45 .. drwxr-xr-x   9 chungchris   staff  ...

Let's Move On

今天決定要建個部落格 身為資工系的學生, 又那麼愛做筆記 XD 卻到今天才想做這件事似乎有點落漆 還沒明確知道想用來記錄些什麼, 有可能只是與程式相關的東西, 也有可能會很雜 但也很有可能過了一年什麼屁都沒有, 到時候也可以拿出來嘲笑自己一下自我檢討一番 Decide creating the blog today. It seems abnormal for a computer science student to do this so late. After all, I like taking note a lots... Still not sure about what am gonna write here. Maybe all about programming. Maybe it will be really mixed. Nevertheless... very likely that it will still be empty after a year... Then I can open it and piss myself. 迅速 Google 了一下該用哪個平台, 只想找個簡單好用的 外貌先決下 wordpress 和 blogger 脫穎而出, 進一步看了一下覺得並沒有複雜架站的需求所以最後選了 blogger