這篇文章算是一個學習的筆記吧,在很多的程序構建過程中的一些東西
gcc編程的四個步驟
命令格式如下
Gcc [選項] 要編譯的文件 [選項] [目標文件]
其中[目標文件]可以缺省,Gcc默認生成可執行的文件名爲:要編譯的文件.out
例子:
# vi hello.c
#include <stdlib.h>
#include <stdio.h>
void main(void)
{
printf("hello world!\r\n");
}
編譯的命令爲
gcc hello.c -o hello.exe
輸出的是可執行文件 hello.exe
預處理
Gcc –E hello.c –o hello.i
主要處理#include和#define
把#include包含進來的.h文件插入到#include所在的位置
把源程序中使用到的#define定義,用實際定義的字符串代替
上面命令中輸出的是.i文件,該文件是經過預處理的C源程序。這個文件是可以查看的文本文件
編譯
首先檢查代碼規範,是否有語法錯誤
把代碼翻譯成彙編語言
該階段的命令如下,它也可以接受.c後綴的文件
gcc -S hello.i -o hello.s
輸出的是.s後綴名的文件,可以查看的文本文件
彙編
這個階段是把上面的彙編程序翻譯成二進制的機器指令文件
這個階段接受的是.c或者.i或者.s文件都是沒有問題的
命令行如下,它可以接受.c或者.i或者.s
Gcc –c hello.s –o hello.o
生成的是二進制文件,需要反彙編器GDB幫助才能讀懂
鏈接
這裏涉及到兩種函數庫:
靜態庫:編譯鏈接時,把庫代碼全部加入到可執行文件中去,生成的文件比較大,運行時不在需要庫文件,後綴名一般爲.lib(win).a(Linux)
動態庫:在編譯鏈接時並沒有把庫文件代碼,加入到可執行文件中,而是在程序執行時,由運行時的鏈接文件加載庫,節省系統開銷,後綴一般爲.dll(win).so(linux)
這裏生成庫的方法爲:
生成靜態庫的方法:
ar cr libxxx.a file1.o file2.o
就是把file1.o和file2.o打包生成libxxx.a靜態庫
使用的時候
gcc test.c -L/path -lxxx -o test
動態庫的話:
gcc -fPIC -shared file1.c -o libxxx.so
也可以分成兩部來寫:
gcc -fPIC file1.c -c //這一步生成file1.o
gcc -shared file1.o -o libtest.so
在運行程序時,需要在環境變量中指定動態庫的位置,這裏舉例在Linux中的配置
export LD_LIBRARY_PATH=path
這裏需要說明一個情況:
庫中有同名的動態庫和靜態庫文件時,系統會優先選擇鏈接動態庫,如果想要指定用靜態庫,則在編譯的時候加入編譯選項 -static,就會找到靜態庫。
靜態庫鏈接時的搜索路徑順序
1 ld會去找GCC命令中的參數-L
2 再找gcc的環境變量LIBRARY_PATH
3 再找內定目錄 /lib /usr/lib /usr/local/lib 這是當初compile gcc時寫在程序內的
動態庫鏈接執行時的搜索路徑順序
1 編譯目標代碼時指定的動態庫搜索路徑
2 環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑
3 配置文件/etc/ld.so.conf中指定的動態庫搜索路徑
4 默認的動態庫搜索路徑/lib
5 默認的動態庫搜索路徑/usr/lib
於是這個階段的命令如下
Gcc hello.o –o hello
生成可執行文件 hello
上面是用一個個命令行來對一個簡單的程序進行生產的過程,然而很多的工程需要很多的代碼,然後就有一個叫make的工具來管理這些文件。
Makefile文件的一些知識
make工具是根據Makefile文件來對編譯過程建立一個描述數據庫,這個數據庫記錄了所有各個文件之間的相互關係,以及它們的的關係描述,當其中一個文件修改時,他通過比較前後兩個文件修改的時間來決定是不是需要重新編譯。
1 所有的文件都沒有被編譯過,則對各個C源文件進行編譯鏈接,生成可執行程序
2 每一個在上次執行make之後修改過的C源代碼文件,在本次執行make時會被重新編譯
3 頭文件在上一次執行make之後被修改。則所有的包含這個頭文件的C源文件在本次執行Make時會被重新編譯
這些文件重新編譯生成中間文件.o文件,這些.o文件重新連接,就能形成可執行文件
makefile簡單規則:
target ...:prerequisites .......
command
...
....
target是一個目標文件,
1 可以是Object File
2 也可以是可執行文件
3 標籤
prerequisites
是生成這個target所需要的文件或者目標
command 是
make需要執行的命令
target 這個目標文件依賴於prerequisites這些文件,生成的規則在command裏面,如果prerequisites裏面有至少一個文件的時間比target要新的話,那就會執行command命令
這個command命令是以一個Tab鍵作爲開頭
make的工作方式:
這裏舉個例子
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
輸入make命令
“`
1 make會在當前目錄下找到名字叫Mkaefile或者makefile的文件
2 如果找到了,它會找文件中的第一個目標文件,並把它(上面的edit)作爲最終的目標文件
3 如果edit不存在或者後面所依賴的.o文件比它要新,就會執行後面所定義的命令來生成這個edit文件
4 如果edit所依賴的.o文件也存在,那麼make會在當前文件中找目標爲.o文件的依賴性,如果找到了,就根據規則生成.o文件
“`
就像是剝洋蔥一樣,一層套着一層,直到最後的c代碼文件和H文件,最後編譯吃第一個目標文件
make只是找文件之間的依賴關係,像clean這樣的,沒有被目標文件關聯或者間接關聯的,那麼它後面的命令將不會被自動執行,但是可以用make指令顯式的要求執行它 make clean
當然 clean是放在最後的,這是一個不成文的規定吧
當然還有很多的編譯選項沒有說明,會再接着學習記錄
福利答謝大家!
感謝您閱讀本篇文章,對此特別發放一個無門檻的現金紅包,打開支付寶掃碼領取,可以領到錢的哦!