Java 程序員眼里的 Gcc
作為一名 Java 程序員,對 gcc 的基本使用總是記不住,很不熟練,今天寫篇文章用最簡單的方式記錄下。
編譯的過程
寫個 hello.c 代碼:
#include <stdio.h>
#define STR "hello world\n"
void main() {
printf(STR);
}
第一步:預處理(preprocess)
其實就是以下三個動作:
- 頭文件展開
- 宏定義直接替換
- 條件編譯不成立就去掉
gcc -E hello.c -o hello.i
第二步:編譯(compile)
轉換成匯編語言:
gcc -S hello.i -o hello.s
第三步:匯編(assemble)
轉換成二進制(ELF relocatable):
gcc -c hello.s -o hello.o
第四步:鏈接(link)
具體分為動態(tài)鏈接和靜態(tài)鏈接:
# 動態(tài)鏈接
gcc hello.o -o hello
# 靜態(tài)鏈接
gcc hello.o -o hello -static
靜態(tài)庫制作
寫一個加法函數(shù):
int add(int a, int b) {
return a+b;
}
編譯成 .o:
gcc -c add.c -o add.o
制作成靜態(tài)庫:
ar rcs libadd.a add.o
編寫測試代碼:
#include <stdio.h>
void main(){
printf("%d", add(1,2));
}
編譯成可執(zhí)行文件:
#寫法一
gcc test.c -o test libadd.a
#寫法二
gcc test.c -o test -static -ladd -L ./
執(zhí)行:
./test
3
動態(tài)庫制作
寫一個加法函數(shù):
int add(int a, int b) {
return a+b;
}
編譯成 .o:
gcc -c add.c -o add.o -fPIC
制作成動態(tài)庫:
gcc -shared -o libadd.so add.o
上面兩步也可以直接從源文件一步到位:
gcc -fPIC -shared -o libadd.so add.c
編寫測試代碼:
#include <stdio.h>
void main(){
printf("%d", add(1,2));
}
編譯成可執(zhí)行文件:
gcc test.c -o test -ladd -L ./
執(zhí)行發(fā)現(xiàn)報錯:
./test
error while loading shared libraries: libadd.so:
cannot open shared object file: No such file or directory
因為執(zhí)行的時候找不到指定的動態(tài)庫。
那我們把 libadd.so 放在執(zhí)行時的動態(tài)庫默認搜索路徑下,比如 /lib64:
cp libadd.so /lib64
再次執(zhí)行就成功了:
./test
3
查看二進制文件的鏈接信息,也可以發(fā)現(xiàn)我們的 libadd.so 生效了:
ldd test
linux-vdso.so.1 => (0x00007ffe0f597000)
libadd.so => /lib64/libadd.so (0x00007fa5ab29f000)
libc.so.6 => /lib64/libc.so.6 (0x00007fa5aaed1000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa5ab4a1000)
好了,以上就是編譯、靜態(tài)庫制作、動態(tài)庫制作的過程,先記住這些 gcc 的基本常識,再去研究原理吧!