compile with gcc

GCC

GCC short name of GNU Compiler Collection, has grown over times to support many languages such as C, C++, Objective-C, Java, Fortran and Ada

GNU toolchain

  • GNU Compiler Collection (GCC): a compiler suit that supports many languages, such as C/C++, Objective-C and Java.
  • GNU Make: an automation tool for compiling and building applications.
  • GNU Binutils: a suit of binary utility tools, including linker and assembler.
  • GNU Debugger (GDB).
  • GNU Autotools: A build system including Autoconf, Autoheader, Automake and Libtool.
  • GNU Bison: a parser generator (similar to lex and yacc).

check out gcc version

 ~  gcc --version                                                                                                      Sat 26 Nov 2016 11:25:47 PM CST
gcc (GCC) 6.2.1 20160830
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

or more detail

~  gcc -v                                                                                                             Sat 26 Nov 2016 11:24:47 PM CST
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/6.2.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc-multilib/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release
Thread model: posix
gcc version 6.2.1 20160830 (GCC)

flag

  • -o: specifies the output executable filename.
  • -Wall: prints “all” warning messages.
  • -g: generates additional symbolic debuggging information for use with gdb debugger.
  • -pg: Profiling gprof your_program > profile
  • O0: 不做最佳化
  • O1: 對BB內做最佳化
  • O2: 對跨BB來做最佳化
  • O3: 改變code的順序來做最佳化
  • Os: 真對code size來做最佳化

Is optimisation level -O3 dangerous in g++

tool

valgrind to detect your programming memory

compile flow

  1. Preprocessor include Header
  2. Compiler(gcc)
  3. Assembler(as) M
  4. Linker(ld)

Static Library vs. Shared Library

A library is a collection of pre-compiled object files that can be linked into your programs via the linker. Examples are the system functions such as printf() and sqrt().

There are two types of external libraries: static library and shared library.

A static library has file extension of “.a” (archive file) in Unixes or “.lib” (library) in Windows. When your program is linked against a static library, the machine code of external functions used in your program is copied into the executable. A static library can be created via the archive program “ar.exe”. A shared library has file extension of “.so” (shared objects) in Unixes or “.dll” (dynamic link library) in Windows. When your program is linked against a shared library, only a small table is created in the executable. Before the executable starts running, the operating system loads the machine code needed for the external functions - a process known as dynamic linking. Dynamic linking makes executable files smaller and saves disk space, because one copy of a library can be shared between multiple programs. Furthermore, most operating systems allows one copy of a shared library in memory to be used by all running programs, thus, saving memory. The shared library codes can be upgraded without the need to recompile your program.

args

refer

GCC and Make Compiling, Linking and Building C/C++ Applications

Static, Shared Dynamic and Loadable Linux Libraries

Options for Linking

用gcc 自製 Library

用gcc 自製 Library

Library可分成三種

  1. static

  2. shared

  3. dynamically loaded

  4. Static libraries Static 程式庫用於靜態連結

簡單講是把一堆 object檔用ar(archiver) 包裝集合起來``,檔名以 .a 結尾。優點是執行效能通常會比後兩者快, 而且因為是靜態連結``,所以不易發生執行時找不到library或版本錯置而 無法執行的問題。缺點則是檔案較大,維護度較低;例如library如果發 現bug需要更新,那麼就必須重新連結執行檔。

1.1 編譯 編譯方式很簡單,先例用 -c 編出 object 檔,再用 ar 包起來即可

hello.c

#include <stdio.h>
void hello(){ printf("Hello "); }

world.c

#include <stdio.h> void world(){ printf("world."); }

mylib.h

void hello(); void world();
$ gcc -c hello.c world.c /* 編出 hello.o 與 world.o */
$ ar rcs libmylib.a hello.o world.o /* 包成 limylib.a */

這樣就可以建出一個檔名為 libmylib.a 的檔。輸出的檔名其實沒有硬性規定, 但如果想要配合 gcc-l 參數來連結,一定要以 lib 開頭, 中間是你要的 library名稱,然後緊接著 .a 結尾

1.2. 使用

main.c

#include "mylib.h"
int main(){
    hello();
    world();
}

使用上就像與一般的 object 檔連結沒有差別。

$ gcc main.c libmylib.a

也可以配合 gcc-l 參數使用

$ gcc main.c -L. -lmylib

-Ldir 參數用來指定要搜尋程式庫的目錄,. 表示搜尋現在所在的目錄。 通常預設會搜 /usr/lib/lib 等目錄。

-llibrary 參數用來指定要連結的程式庫 ,mylib 表示要與 mylib 進行連結 ,他會搜尋 library 名稱前加 lib 後接 .a 的檔案來連結。

 $ ./a.out
Hello world.
  1. Shared libraries Shared library

會在程式執行起始時才被自動載入。因為程式庫與執行檔 是分離的,所以維護彈性較好。有兩點要注意,shared library是在程式起始 時就要被載入, 而不是執行中用到才載入,而且在連結階段需要有該程式庫 才能進行連結。 首先有一些名詞要弄懂,

  • soname

    soname 用來表示是一個特定 library 的名稱,像是 libmylib.so.1 。 前面以 lib 開頭,接著是該 library 的名稱,然後是 .so ,接著 是版號,用來表名他的介面;如果介面改變時,就會增加版號來維護相容度

  • real name

    是實際放有 library 程式的檔案名稱,後面會再加上 minor 版號release 版號,像是 libmylib.so.1.0.0

  • linker name

一般來說,版號的改變規則是(印象中在 APress-Difinitive Guide to GCC中有 提到,但目前手邊沒這本書),

最尾碼的 release 版號``用於程式內容的修正, 介面完全沒有改變 中間的 minor用於有新增加介面,但相舊介面沒改變,所以 與舊版本相容。 最前面的version版號用於原介面有移除或改變,與舊版不相容 時。linker name是用於連結時的名稱,是不含版號的 soname,如:libmylib.so。 通常 linker name與 real name是用 ln指到對應的real name` ,用來提供 彈性與維護性。

2.1. 編譯

shared library的製作過程較複雜。

$ gcc -c -fPIC hello.c world.c

編譯時要加上 -fPIC 用來產生 position-independent code。也可以用 -fpic 參數。 (不太清楚差異,只知道 -fPIC 較通用於不同平台,但產生的code較大 ,而且編譯速度較慢)。

$ gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0.0 \ hello.o world.o

  • -shared 表示要編譯成 shared library
  • -Wl 用於參遞參數給 linker 因此 -sonamelibmylib.so.1 會被傳給 linker 處理。
  • -soname用來指名 sonamelimylib.so.1 library 會被輸出成 libmylib.so.1.0.0 (也就是real name)

若不指定 soname 的話,在編譯結連後的執行檔會以連時的 library 檔名為 soname,並載入他。否則是載入 soname指定的library檔案

可以利用 objdump 來看 librarysoname

$ objdump -p libmylib.so | grep SONAME
SONAME libmylib.so.1

若不指名 -soname 參數的話,則 library 不會有這個欄位資料。 在編譯後再用 ln 來建立 sonamelinker name 兩個檔案。

$ ln -s libmylib.so.1.0.0 libmylib.so
$ ln -s libmylib.so.1.0.0 libmylib.so.1

2.2 使用

與使用 static library 同。

$ gcc main.c libmylib.so

以上直接指定與 libmylib.so 連結。 或用

$ gcc main.c -L. -lmylib

linker 會搜尋 libmylib.so 來進行連結。

如果目錄下同時有 staticshared library 的話,會以 shared 為主

使用 -static 參數可以避免使用 shared 連結。

$ gcc main.c -static -L. -lmylib

此時可以用 ldd 看編譯出的執行檔與 shared 程式庫的相依性

$ldd a.out linux-gate.so.1 => (0xffffe000)
libmylib.so.1 => not found
libc.so.6 => /lib/libc.so.6 (0xb7dd6000)
/lib/ld-linux.so.2 (0xb7f07000)

輸出結果顯示出該執行檔需要 libmylib.so.1 這個 shared library 會顯示 not found 因為沒指定該 library 所在的目錄,所找不到該 library 因為編譯時有指定-soname參數為 libmylib.so.1 的關係,所以該執行檔會 載入libmylib.so.1。否則以libmylib.so連結,執行檔則會變成要求載入 libmylib.so

$ ./a.out
./a.out: error while loading shared libraries: libmylib.so.1: cannot open shared object file: No such file or directory

因為找不到 libmylib.so.1 所以無法執行程式。 有幾個方式可以處理。

a. 把 libmylib.so.1 安裝到系統的library目錄,如/usr/lib下 b. 設定 /etc/ld.so.conf ,加入一個新的library搜尋目錄,並執行ldconfig 更新快取 c. 設定 LD_LIBRARY_PATH 環境變數來搜尋 library 這個例子是加入目前的目錄來搜尋要載作的library

$ LD_LIBRARY_PATH=. ./a.out Hello world.
  1. Dynamically loaded libraries

Dynamicaaly loaded libraries 才是像 windows 所用的 DLL ,在使用到 時才載入,編譯連結時不需要相關的library。動態載入庫常被用於像plug-ins 的應用。

3.1 使用方式 動態載入是透過一套 dl function來處理。

#include <dlfcn.h>
void *dlopen(const char *filename, int flag);  //開啟載入 filename 指定的 library。
void *dlsym(void *handle, const char *symbol);  //取得 symbol 指定的symbol name在library被載入的記憶體位址。
int dlclose(void *handle);  //關閉dlopen開啟的handle。
char *dlerror(void);        //傳回最近所發生的錯誤訊息
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
    void *handle;
    void (*f)();
    char *error; /* 開啟之前所撰寫的 libmylib.so 程式庫 */
    handle = dlopen("./libmylib.so", RTLD_LAZY);
    if (!handle) {
        fputs(dlerror(), stderr);
        exit(1);
    } /* 取得 hello function 的 address */
    f = dlsym(handle, "hello");
    if ((error = dlerror()) != NULL) {
        fputs(error, stderr);
        exit(1);
    } /* 呼叫該 function */
    f();
    dlclose(handle);
}

編譯時要加上 -ldl 參數來與 dl library 連結

$ gcc dltest.c -ldl

結果會印出 Hello 字串 $ ./a.out Hello 關於dl的詳細內容請參閱 man dlopen

參考資料