如何用C寫一個web服務(wù)器之GCC項(xiàng)目編譯
前言
本想著接下來大概實(shí)現(xiàn)一下 CGI 協(xié)議,但是實(shí)現(xiàn)過程中被一個問題卡住了:
C進(jìn)程與php進(jìn)程的交互數(shù)據(jù)類型問題:
在 C 進(jìn)程中我準(zhǔn)備將服務(wù)器處理后的請求數(shù)據(jù)存儲在一個結(jié)構(gòu)體內(nèi),然后將此結(jié)構(gòu)體中的信息傳給 PHP,而 PHP 進(jìn)程內(nèi)也會有一個全局?jǐn)?shù)組與之對應(yīng),可是眾所周之,結(jié)構(gòu)體是 C 進(jìn)程內(nèi)的內(nèi)存數(shù)據(jù),是無法直接傳給 PHP 使用的。
這時候我們也需要一種“協(xié)議”來解決進(jìn)程數(shù)據(jù)類型的異構(gòu)性。當(dāng)然這個解決方案確定起來還是很簡單的,無非是對C結(jié)構(gòu)體進(jìn)行序列化,使用xml,json,protobuf(沒用過)之一,花費(fèi)時間多的地方在實(shí)現(xiàn)過程。 原來想自己造個輪子,實(shí)現(xiàn)一下json類型的編解碼,覺得有些偏離了主題了,于是考慮使用一個開源庫cJSON;
可是自己沒有過 C 大型項(xiàng)目的開發(fā)經(jīng)驗(yàn),寫的都是小 demo,gcc -o name source.c 足以解決問題了,沒有過編譯多個文件、組織項(xiàng)目的經(jīng)驗(yàn),下載到源碼后一臉懵逼,搜索到的編譯資料都是一些較為零散的內(nèi)容,不成體系,不過在自己的多次嘗試下終于成功地將 cJSON 引入到項(xiàng)目中了,這里稍做一下總結(jié)。
繞了好久,終于來到了本篇文章的主題:項(xiàng)目編譯,主要介紹一些用 GCC 在 linux 下項(xiàng)目編譯鏈接的步驟。
編譯步驟
先說一下一個C源文件的編譯一般步驟:
1.預(yù)處理(preprocess):主要是在代碼層面的處理,包括文件的引入,展開宏定義,刪除注釋,添加行號等,生成的文件以.i結(jié)尾。
gcc -E test.c -o test.i
2.編譯(compilation):編譯是在代碼語法層面的處理,生成對應(yīng)的匯編語言代碼,生成以.s為后綴的匯編語言文件;
gcc -S test.i -o test.s
3.匯編(Assembly):將匯編語言代碼生成可執(zhí)行的機(jī)器碼,生成以.o為后綴的目標(biāo)文件。
gcc -c test.s -o test.o
4.鏈接(Linking):將各個.o目標(biāo)文件連接起來,并解決庫依賴,生成無后綴的可直接執(zhí)行文件。
gcc -o test test.o
如果我們直接使用后面的命令,那么前面的步驟也會自動執(zhí)行。如我們常使用的 gcc -o 實(shí)際上是一次性完成了所有的步驟的。
以上的中間文件,大家可以使用文本查看工具來查看其中內(nèi)容來驗(yàn)證其功能。
靜態(tài)庫和動態(tài)庫
庫文件有動態(tài)和靜態(tài)之分,他們的命名規(guī)范為 lib庫名.后綴,在鏈接目標(biāo)文件和庫時,使用 -l 庫名(空格可省略)選項(xiàng),也可以添加-L /path來規(guī)定優(yōu)先搜索庫文件的目錄。
例如:C中的數(shù)學(xué)函數(shù)庫math.h的動態(tài)庫文件名為libm.so,那么我們編譯連接文件時就需要添加-lm的選項(xiàng)。如果要指定庫文件路徑為/usr/lib64/libm.so,那么可添加-L /usr/lib64來指定庫文件優(yōu)先查找目錄。
另外靜態(tài)和動態(tài)庫文件搜索目錄順序不一樣,下面分別詳細(xì)介紹:
靜態(tài)庫
靜態(tài)庫文件一般是以.a為后綴的庫文件,它在編譯連接時會將庫文件的內(nèi)容全部添加到可執(zhí)行文件中,在編譯連接完成后,靜態(tài)庫文件便不再影響可執(zhí)行文件。
它的優(yōu)點(diǎn)是簡單粗暴,但如果庫文件內(nèi)部有改動的話需要重新對所有引用此庫文件的可執(zhí)行文件重新編譯。
一般編譯步驟如下:
gcc -c static.c -o static.o // 編譯靜態(tài)庫文件的源文件 ar -r static.a static.o // 生成靜態(tài)庫文件 gcc -o main -lstatic // 連接靜態(tài)庫文件生成可執(zhí)行文件
編譯連接時,靜態(tài)庫文件搜索目錄順序?yàn)椋?/p>
1.編譯連接時 -L 參數(shù)指定的目錄;
2.環(huán)境變量目錄 LIBRARY_PATH;
3.固定目錄 /lib、/usr/lib、/usr/local/lib等;
動態(tài)庫
動態(tài)庫文件一般以.so結(jié)尾,它在編譯連接時只把動態(tài)庫的文件添加到可執(zhí)行文件,只在程序運(yùn)行時才加載庫文件。這種方式的優(yōu)點(diǎn)是非常靈活,如果動態(tài)庫文件內(nèi)部有變動,那么只需重要重新編譯庫文件即可。
它的一般編譯步驟如下:
gcc -c dynamic.c -fpic -o dynamic.o // 編譯動態(tài)庫文件的源文件 -fpic 表示編譯為位置獨(dú)立的代碼,使之可以被放在可執(zhí)行文件內(nèi)存中的任何地方 gcc -shared dynamic.o -o dynamic.so // 生成動態(tài)庫文件 gcc -o main -L . -ldynamic // 連接當(dāng)前文件夾下的動態(tài)庫文件
編譯連接時,動態(tài)庫文件搜索目錄順序?yàn)椋?/p>
1.編譯連接時 -L 參數(shù)指定目錄;
2.環(huán)境變量目錄 LD_LIBRARY_PATH;
3.配置文件/etc/ld.so.conf中配置的目錄
4.固定目錄 /lib、/usr/lib等。
CMakeLists
寫到這里還不是結(jié)尾,我們要考慮如果文件非常多怎么辦,難道每一次都要輸入n多個源文件名嗎?如果軟件完成后,用戶使用時可不想記住這些復(fù)雜的命令和文件。
自動化才是目標(biāo),我們考慮使用自動化編譯工具 cmake,那么接下來我們就要編寫適合項(xiàng)目文件的編譯配置文件 CMakeLists。
CMakeLists 是一個 txt 文件,它就像是項(xiàng)目的編譯指南,是給用 cmake 工具用的。其語法類似于 shell,但內(nèi)置了許多函數(shù),這里我們介紹幾個簡單的語法,編寫一個簡單的 CMakeLists.txt。
當(dāng)前文件結(jié)構(gòu):
|__ CMakeLists.txt
|__ test.c
|__ cJSON.c
|__ include
| |__ cJSON.h
|__ lib
下面是一個動態(tài)庫的編譯CmakeList,將解釋放在注釋中。
PROJECT(test) # 項(xiàng)目名稱
cmake_minimum_required(VERSION 2.8) # 選擇一個cmake版本
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) # 設(shè)定產(chǎn)生庫的目錄
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) # 設(shè)定產(chǎn)生的可執(zhí)行文件的目錄
ADD_EXECUTABLE(test test.c) # 這里要先聲明產(chǎn)生的可執(zhí)行文件,以便后面連接
SET(cJSON cJSON.c) # 設(shè)置文件變量
ADD_LIBRARY(cJSON SHARED ${cJSON}) # 此語句用文件變量生成一個動態(tài)鏈接庫
TARGET_LINK_LIBRARIES(test cJSON) # 連接可執(zhí)行文件與動態(tài)鏈接庫
FIND_LIBRARY(MATH_LIB libm.so /usr/lib64) # 在/usr/lib64文件夾下找libm.so(cJSON需要)
IF(MATH_LIB)
TARGET_LINK_LIBRARIES(test ${MATH_LIB}) # 找到之后連接上
ENDIF()
MESSAGE("cmake complete, use make to compile!") # 在命令行輸出提示語句
運(yùn)行 cmake . && make完成項(xiàng)目的構(gòu)建。
此時的目錄結(jié)構(gòu)為(略過了 cmake 產(chǎn)生的臨時文件):
|__ CMakeLists.txt
|__ test.c
|__ cJSON.c
|__ include
| |__ cJSON.h
|__ lib
| |__ libcJSON.so
|__ bin
|__ test
以上就是如何用C寫一個web服務(wù)器之GCC項(xiàng)目編譯的詳細(xì)內(nèi)容,更多關(guān)于用C寫一個web服務(wù)器之GCC項(xiàng)目編譯的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
淺析Boost智能指針:scoped_ptr shared_ptr weak_ptr
雖然通過弱引用指針可以有效的解除循環(huán)引用,但這種方式必須在程序員能預(yù)見會出現(xiàn)循環(huán)引用的情況下才能使用,也可以是說這個僅僅是一種編譯期的解決方案,如果程序在運(yùn)行過程中出現(xiàn)了循環(huán)引用,還是會造成內(nèi)存泄漏的2013-09-09
C++調(diào)用EasyX庫實(shí)現(xiàn)嫦娥奔月小游戲
這篇文章主要為大家詳細(xì)介紹了C++如何調(diào)用EasyX庫編寫一個簡單的嫦娥奔月小游戲,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2023-09-09
C語言MultiByteToWideChar和WideCharToMultiByte案例詳解
這篇文章主要介紹了C語言MultiByteToWideChar和WideCharToMultiByte案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
c++之std::get_time和std::put_time
std::get_time和std::put_time是C++中用于日期和時間的格式化和解析的函數(shù),它們都包含在<iomanip>頭文件中,std::get_time用于從輸入流中解析日期時間字符串,而std::put_time則用于將std::tm結(jié)構(gòu)格式化為字符串2024-10-10
C語言 結(jié)構(gòu)體數(shù)組詳解及示例代碼
本文主要介紹C語言 結(jié)構(gòu)體數(shù)組,這里整理了相關(guān)資料及簡單示例代碼,以便大家學(xué)習(xí)參考,有興趣的小伙伴可以看下2016-08-08

