C++---初識《通過g++ / makefile 編譯和調用動態庫so文件》(ubuntu)
------------------------目錄-----------------------------
一、通過makefile 編譯和調用動態庫so文件
二、通過makefile 編譯和調用動態庫so文件
-------------------------正文----------------------------
一、通過makefile 編譯和調用動態庫so文件
1、動態庫的編譯
舉例,這里有一個頭文件:test.h,三個.c文件:test_a.c、test_b.c、test_c.c,這幾個文件編譯成一個動態庫:libtest.so。
文件test.h: #include "stdio.h" void test_a(); void test_b(); void test_c();
文件test_a.c: #include "test.h" void test_a() { printf("this is in test_a...\n"); }
文件test_b.c: #include "test.h" void test_b() { printf("this is in test_b...\n"); }
文件test_c.c: #include "test.h" void test_c() { printf("this is in test_c...\n"); }
將這幾個文件編譯成一個動態庫:libtest.so
$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so
2、動態庫的鏈接
在1、中,已經成功生成了一個自己的動態鏈接庫libtest.so,下面通過一個程序來調用這個庫里的函數。程序的源文件為:test.c。
test.c: #include "test.h" int main() { test_a(); test_b(); test_c(); return 0; }
將test.c與動態庫libtest.so鏈接生成執行文件test:
$ gcc test.c -L. -ltest -o test
測試是否動態連接,如果列出libtest.so,那么應該是連接正常了:
$ ldd test
執行:
$ ./test #可以看到它是如何調用動態庫中的函數的。
遇到問題:
u@u1604:~/C_learn/makefile_so$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so u@u1604:~/C_learn/makefile_so$ gcc test.c -L. -ltest -o test u@u1604:~/C_learn/makefile_so$ ldd test linux-vdso.so.1 => (0x00007ffc096bf000) libtest.so => not found libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2e43587000) /lib64/ld-linux-x86-64.so.2 (0x00007f2e43951000)
解決方式一:
u@u1604:~/C_learn/makefile_so$ sudo cp libtest.so /lib # libtest.so復制到/usr/lib下 # 刪除命令 : sudo rm /lib/libtest.so
[sudo] u 的密碼:
u@u1604:~/C_learn/makefile_so$ gcc test.c -L. -ltest -o test
u@u1604:~/C_learn/makefile_so$ ldd test
linux-vdso.so.1 => (0x00007ffd96947000)
libtest.so => /lib/libtest.so (0x00007f07a2820000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f07a2456000)
/lib64/ld-linux-x86-64.so.2 (0x00007f07a2a22000)
成功:
u@u1604:~/C_learn/makefile_so$ ./test
this is in test_a...
this is in test_b...
this is in test_c..
二、通過makefile 編譯和調用動態庫so文件
文件../hello/hello.c #include "hello.h" void hello() { printf("Hello .....\n"); }
文件../hello/hello.h #ifndef _HEAD_H #define _HEAD_H #include <stdio.h> void hello(); #endif
文件../hello/Makefile
CC = gcc OBJS = $(wildcard *.c) TARGET = libhello.so all: $(CC) $(OBJS) -fPIC -shared -o $(TARGET) sudo mv ./$(TARGET) /lib
clean: rm $(SRCS) $(headfile)
【解釋】主要命令: gcc -hello.c -fPIC -shared -o libhello.so,
這里生成的libhello.so並不是在系統 /lib目錄下的,所以將.so文件移動到系統/lib里去
文件 test.c #include "test.h" #include <sys/types.h> #include <sys/wait.h> int main() { hello(); return 0; }
文件 test.h #ifndef _HEAD_H #define _HEAD_H #include <stdio.h> #endif
文件 makefile
CC = gcc OBJS = $(wildcard *.c) TARGET = test all: cd ./hello; make $(CC) $(OBJS) -L/lib -lhello -o $(TARGET) clean: rm -rf *o $(TARGET) cd ./hello; make clean
【解釋】注意這里的makefile,既make此目錄下的,還要進去子目錄hello里去make,
所以首先進去子目錄cd ./hello;make,然后要連接libhello.so,
主要是 gcc test.c -L/lib -lhello -o test,記得要清除.o 和.so文件
結果
u@u1604:~/C_learn/makefile_so$ make cd ./hello; make make[1]: Entering directory '/home/u/C_learn/makefile_so/hello' gcc hello.c -fPIC -shared -o libhello.so sudo mv ./libhello.so /lib [sudo] u 的密碼: make[1]: Leaving directory '/home/u/C_learn/makefile_so/hello' gcc test.c -L/lib -lhello -o test test.c: In function ‘main’: test.c:8:5: warning: implicit declaration of function ‘hello’ [-Wimplicit-function-declaration] hello(); ^ u@u1604:~/C_learn/makefile_so$ ./test Hello .....
問題:
如果在打印出現的信息中,發現有一行: libtest.so => not found 則表明鏈接程序找不到我們的libtest.so文件哦,為什么呢?因為鏈接程序只尋找固定目錄,例如/lib目錄。
如果我們的當前目錄是諸如/home/u/a/b/c這種目錄,那么人家是不會主動了解到的。
怎么辦?辦法一:把libtest.so拷貝到鏈接程序的搜索路徑目錄下。 辦法二:設置環境變量LD_LIBRARY_PATH,增加當前路徑到該變量中。
看看現在LD_LIBRARY_PATH有什么內容吧? 1、執行 echo $LD_LIBRARY_PATH 就打印出來。 2、配置環境變量的方法簡單點就是: LD_LIBRARY_PATH=LD_LIBRARY_PATH:"/root/nana/so" export LD_LIBRARY_PATH 3、好了,再次執行ldd就有新發現了。 4、執行./***, OK,輸出正常。
" 辦法二:設置環境變量LD_LIBRARY_PATH,增加當前路徑到該變量中。 "嘗試設置環境路徑了,可能沒對,幾經折騰還沒編譯通過。回頭編譯通過,再來記錄。
今天收獲了,g++ ----> makefile -----> cmake linux下學習C++編譯的三層境界的思維,前者是后者思維的基礎,后者是前者進一步提升編程效率的優化。學會三者,是在linux下學習c++必會的技能,后面再學習如何寫makelist.txt。