重學C語言:你真的會用這些工具嗎,pkg-config

c語言歷史

1978年前後,K&R發明了C語言,並編寫了UNIX操作系統。

1989年,ANSI出版了C語言標準,被稱為ANSI C89。

1999年,C標準經歷了一次主要的改版。為數值和科學計算增添了一些附加功能,單行註釋,for循環中聲明變量等等。

2011年,C11標準發佈,有了可以編寫泛型函數的方法。

POSIX標準

Portable Operating System Interface of UNIX,縮寫為 POSIX。實際上1978年C和UNIX都問世了,到了1988年POSIX標準建立,隨後1989年C語言標準建立。當前最新的POSIX標準應該是2008年的標準。C語言標準和POSIX標準之間是存在一定聯繫的。例如POSIX標準定義了shell腳本如何工作,以及C程序原希望用到的一些C庫。例如C語言的popen(打開管道)就是POSIX標準,而不是C語言定義的內容。POSIX標準的操作系統必須通過支持C99的編譯器編譯。幾乎所有的操作系統都建立在POSIX兼容的基礎上,甚至windows server也是基於POSIX的。

BSD和GNU是兩個有著較高流行度和影響力的POSIX的實現版本,BSD許可證的要求弱於GNU,它要求使用者維持BSD授權源碼原有的版權聲明和免責聲明,但不要求同時提供你的源碼。如果你要商用GNU聲明過的源碼,GNU有權要求你公開源碼。

編譯環境

編譯器,首選gcc

gdb調試器,可以單步執行C代碼

Valgrind,用於測試C內存使用錯誤

Gprof,用於運行效率評測

Make,使你不用直接調用編譯器,優化編譯過程

pkg-config,用於查找庫

doxygen,用於生成程序文檔

text editor,這個就不多說了,每個人都有自己喜歡的編輯器。

開始編寫代碼了

#include <math.h> //erf,sqrt/<math.h>

#include <stdio.h> //printf/<stdio.h>

int main(){

printf("the integral of a Normal(0,1) distribution"

"between -1.96 and 1.96 is :%g\\n",ert(1.96*sqrt(1/2.)));

}

這段代碼沒啥好解釋的,和helloworld差不多。我們來看看如何編譯的。

gcc erf.c -o erf -lm -g -Wall -O3 -std=gnull

-o用來給出輸出的文件名

-lm表示math庫需要被鏈接進來,實際上gcc編譯時有一個隱含的-lc選項,把libc庫鏈接進來了,否則printf是找不到的。

-g表示加入調試符號,這些符號不會把程序拖慢,但是會增大程序的大小(佔用硬盤的大小)。

-std=gnull,允許你使用符合C11和POSIX標準的代碼。如果你的代碼是C11標準發佈之前的,可以使用-std=gnu99

-O3是指優化等級為3級,

-Wall添加編譯器告警,你也可以加上-Werror,那麼所有告警都當作錯誤處理,你必須解決所有的編譯告警才能得到編譯結果。

鏈接庫文件

如果你的代碼用到了個庫,並且這個庫放在某個特定位置,那麼你的gcc語句應該如下所示:

gcc -I/usr/local/include erf.c -o erf -L/usr/local/lib -luserful

-I選項指定編譯器的搜索範圍,這裡可以找到這個lib的供外部使用的頭文件

-L選項指定鏈接時庫的搜索路徑

假如你需要用到兩個庫,而且著兩個庫又存在依賴關係,那麼在gcc中需要按順序給定庫的搜索路徑。假設libgel依賴libboard,gcc語句如下:

gcc erf.o -lborad -lgel

一般來說,如果你找到一個庫文件在/some/path/lib中,那麼對應的頭文件會在/some/path/include中。

在硬盤中查找庫文件是很煩人的事情,實際上pkg-config維護了一個包含配置信息和位置信息的資料庫,如果你的機器中沒有,建議安裝。

sudo apt-get install pkg-config

然後安裝libxml

sudo apt-get install libxml2

安裝完成之後,我們就可以看看pkg-config的功能了

ubuntu$ pkg-config --libs libxml-2.0

-lxml2 //這裡得到的剛好是鏈接是所需要的

ubuntu$ pkg-config --cflags libxml-2.0

-I/usr/include/libxml2 //這裡得到的剛好是gcc編譯時所需要的。

因此gcc語句可以改寫為

gcc 'pkg-config --cflags --libs libxml-2.0' -o erf erf.c

需要提醒的是,不是所有的平臺都又pkg-config,也不是每個庫都用它註冊。

編譯器在鏈接靜態庫時,是將庫裡的相關內容直接複製到最終的可執行文件。而共享庫是你的程序在運行時鏈接進去的,此時需要在運行過程中查找庫文件。如果你的庫在一個非標準的路徑,那你需要找到一個修改運行時搜索路徑的方法。

如果你用autotools打包你的程序,libtools知道如何添加何時的選項。但是如果你使用gcc編譯,就需要添加如下語句:

LDADD=-Llibpath -W1, -Rlibpath

-W1是從gcc傳遞這個選項到連接器。而連接器將給定的-R嵌入所連接的庫的運行時搜索路徑。

後記

下一次講講常用的makefile語法


分享到:


相關文章: