【Linux】動靜態庫制作

🐼故事背景

假設今天你有一位舍友。你需要幫助他完成老師的作業。而他寫的代碼依賴兩個文件(mymath.h,mystdio.h)。但是這兩個文件的功能他不會寫,他只會調用。他的調用代碼:

#include"mystdio.h"
#include"mymath.h"
#include<string.h>
#include<unistd.h>int main()
{MYFILE* fp = myfopen("log.txt","w");if(!fp){perror("myfp");return 1;}int cnt = 20;const char* s = "hello myfile";while(cnt--){myfwrite(s,strlen(s),fp);if(cnt  ==  5){myfflush(fp);}}myfclose(fp);printf("10+20 = %d\n",Add(10,20));return 0;
}

但是你會這兩個文件具體功能的實現啊。出于熱心腸的你現在要幫助他。你會怎么幫助他呢?


🐼靜態庫制作?

1??直接把源文件給他

處于熱心腸的你。將你寫好的代碼mystd.c, mymath.c, mystdio.h, mymath.h這四個文件都給了你舍友。你的舍友通過編譯鏈接完美應付了考試。你幫他順利過關了。

2??給他.o文件

我們知道。形成一個可執行程序最關鍵的步驟就是先把源文件編譯成.o文件。再把這些.o文件通過鏈接器鏈接成.exe文件。如圖:

你出于安全考慮,這次不給他源文件了。而是直接將鏈接好的.o文件交給他。并且給了他說明書(.h)文件

gcc -c *.c 

他再將他的test.c編譯形成.o文件。和你給的.o大家再一鏈接又編譯形成了可執行程序。這次又順利過關了!

gcc -c  test.c #-rw-rw-r-- 1 lsg lsg    59 Aug  3 18:09 mymath.c
#-rw-rw-r-- 1 lsg lsg    34 Aug  3 18:09 mymath.h
#-rw-rw-r-- 1 lsg lsg  1232 Aug  3 18:17 mymath.o
#-rw-rw-r-- 1 lsg lsg  2098 Aug  3 18:09 mystdio.c
#-rw-rw-r-- 1 lsg lsg   560 Aug  3 18:09 mystdio.h
#-rw-rw-r-- 1 lsg lsg  3336 Aug  3 18:17 mystdio.o
#-rw-rw-r-- 1 lsg lsg   463 Aug  3 17:58 test.c
#-rw-rw-r-- 1 lsg lsg  2200 Aug  3 18:15 test.ogcc -o myexe *.o

3??將.o文件打包形成靜態庫

出于安全考慮。連.o都不想給他了。于是你把你編譯好.o打包形成一個靜態庫。交給了你的舍友并給了他說明書。

為什么能這么做呢?因為你心里清楚。靜態庫文件的本質就是將.obj進行打包。他的文件最后也要變成.o的。所有.o的文件鏈接就成了可執行程序。

你:

# 編譯將所有.c形成.o 
gcc -c *.c # 將所有.o 文件打包成靜態庫
ar -rc libmyc.a *.o// 將形成好的libmyc.a交給你的舍友并且把說明書.h文件也給他。

你的舍友:

#直接編譯鏈接
gcc -o myexe test.c # error

?發現報錯了!為什么呢?根據報錯信息。編譯器不認識我給他提供的函數。于是他上網查閱。

發現需要帶-l 標明要連接哪個庫。因為庫多了

為什么要帶-l啊。為什么鏈接C語言不需要帶-lc

因為gcc就是編譯C語言的。默認就要認識。

而我們如果使用任何第三方庫。至少要使用-l表明庫名稱,指明你要鏈接誰

# 表明要連接mylibc庫
gcc -o myexe test.c -lmyc
# 注意 lib 和.a不需要帶

但是發現還是不行根據報錯原因。原來是庫路徑找不到(編譯器不認識)。

通過-L指定你要鏈接庫的位置(搜索目錄)

gcc -o myexe test.c -L. -lmyc 

鏈接成功!

但是你的舍友想把#include"mystdio.h"? ?#include"mymath.h"換成#include <mystdio.h>
#include <mymath.h> 可以嗎?

通過-I指定一個搜索路徑。表明頭文件搜索路徑。這樣編譯器默認從指定的路徑下查找依賴頭文件

gcc -o myexe test.c -L. -lmyc -I.

通過上述做法。你的舍友就成功的使用了你給他提供的靜態庫!?


?但是當你舍友查看庫所依賴的文件時。發現并沒有查到libmyc.a,這是為什么??

ldd myexelinux-vdso.so.1 (0x00007ffc62cb8000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0a80d2d000)/lib64/ld-linux-x86-64.so.2 (0x00007f0a80f64000)

因為鏈接的是靜態庫。靜態庫本質是.o文件的集合。一旦鏈接,形成.exe,就不再依賴靜態庫了。因為靜態庫早已合并自已的代碼到可執行程序中了

?現在還有一個問題。就是為什么我們鏈接其他庫時(比如pthread庫)。并不需要帶-L -I 這樣的選項。

其實當庫沒有在系統默認的路徑下時。gcc/g++編譯器找庫。默認會在系統默認路徑下查找,而所謂庫的安裝。就是把庫文件拷貝到系統默認路徑下。

這里以ubuntu為例。我的庫文件系統默認路徑是/lib/x86_64-linux-gnu/ (怎么找的,ldd 查看/usr/bin/ls依賴的系統庫目錄即可)

這是不是意味著。只要我們把庫文件拷貝到/lib/x86_64-linux-gnu/。就不用帶-L選項。編譯器能根據系統指定路徑來找到我們的庫目錄。

并且只要我們把頭文件拷貝到/usr/include/?。就不用帶-I選項。編譯器能根據系統指定路徑來找到我們的源文件依賴的頭文件目錄。

# 拷貝庫文件到系統指定目錄下 --->省去了 -L
sudo cp *.a /lib/x86_64-linux-gnu/# 拷貝頭文件到系統執行目錄下  ---> 省去了 -I
sudo cp *.h /usr/include/# 直接連接我們的庫即可 -l必須帶!!!(因為是第三方庫)
gcc -o myexe test.c -lmyc

所以庫安裝的本質就是將頭文件和庫文件根據特定目錄結構組織好拷貝到系統指定目錄下,編譯器默認能夠找到的目錄下!

??最佳實踐

如果我們想批量化的向別人提供我們寫好的庫,并以庫文件,頭文件目錄形式打包給給人使用。可以借助Makefile:

開發者:

# 將所有.o打包形成 .a
libmyc.a: mystdio.o mymath.oar -rc $@ $^# 編譯并將.c->.o
%.o:%.cgcc -c $<.PHONY:clean
clean: rm -rf *.a *.o output *.tgz# 發布
.PHONY:output
output:mkdir -p outputmkdir -p output/lib/mkdir -p output/include/cp *.h output/includecp *.a output/lib/tar -czf mylib.tgz output

使用者:?

tar -xzf mylib.tgz 
# 最終將目錄樹長這樣
#tree output
#output
#├── include
#│?? ├── mymath.h
#│?? └── mystdio.h
#└── lib
#    └── libmyc.agcc -o myexe test.c -I./output/include/ -L./output/lib -lmyc

如果嫌麻煩。開發者也可以在安裝時。自帶一個腳本幫使用者把庫文件和頭文件。拷貝到系統指定目錄下。這樣就不需要使用者指定頭文件位置和庫文件位置了


🐼動態庫制作

跟形成靜態庫原理類似。

第一步。將源文件.c編譯形成.o文件。注意。在編譯形成.o文件時。要帶上-fPIC(與位置無關碼)

# .c -> .o
gcc -fPIC -c *.c

將.o打包形成動態庫

gcc -o libmyc.so *.o -shared

編譯并鏈接動態庫

gcc -o myexe test.c -lmyc -L. -I.

運行程序。./myexe

結果報錯了!why???

#./myexe
#./myexe: error while loading shared libraries: libmyc.so: cannot open shared object file: #No such file or directory#lsg@hcss-ecs-0228:~/code/code/25_8_3/person$ ldd myexe
#	linux-vdso.so.1 (0x00007ffd9d53f000)
#	libmyc.so => not found
#	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbb1946d000)
#	/lib64/ld-linux-x86-64.so.2 (0x00007fbb196a4000)

我們不是已經告訴了系統。庫在哪個路徑下嗎。為什么還是會報錯呢??并且在鏈接這個庫時。系統找不到。這是為什么?

因為我們只告訴了編譯器。我們的動態庫在哪。而動態庫是運行時才會加載到內存中。而此時已經和編譯器無關了。所以結論就是在加載可執行程序的時候,也要找到所依賴的庫。換句話說。為了運行時,系統(加載器)也能找到動態庫,我們需要將庫顯示拷貝到系統指定目錄下。當然,這只是方法之一。只要保證系統(加載器)在加載動態庫時也能找到動態庫即可。

sudo cp libmyc.so /lib/x86_64-linux-gnu/ #ldd myexe
#	linux-vdso.so.1 (0x00007ffc7834c000)
#	libmyc.so => /lib/x86_64-linux-gnu/libmyc.so (0x00007f2c3c987000)
#	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2c3c75e000)
#	/lib64/ld-linux-x86-64.so.2 (0x00007f2c3c99a000)

我們也可以通過軟鏈接的方式關聯將庫文件的安裝目錄進行關聯?

我們將動態庫也以目錄形式打包發布出去:

如果我們自已使用(軟連接可以根據你的絕對路徑修改,這里小編就不改了)

libmyc.so:mystdio.o mymath.ogcc -o $@ $^ -shared%.o:%.cgcc -fPIC -c $<.PHONY:clean
clean:rm -rf  *.o *.so sudo unlink /lib/x86_64-linux-gnu/libmyc.so sudo unlink /usr/include/mymath.h  sudo unlink /usr/include/mystdio.h.PHONY:self
self:sudo ln -s /home/lsg/code/code/25_8_3/mylib/libmyc.so /lib/x86_64-linux-gnu/libmyc.sosudo ln -s /home/lsg/code/code/25_8_3/mylib/mymath.h /usr/include/mymath.hsudo ln -s /home/lsg/code/code/25_8_3/mylib/mystdio.h /usr/include/mystdio.h// 自已寫的庫完全可以拷貝到系統指定目錄下。就不用軟連接了(軟連接只能在你指定的路徑下使用你的庫)

??最佳實踐

如果我們自已想用自已寫好的庫,直接拷貝到系統指定目錄下!

libmyc.so:mystdio.o mymath.ogcc -o $@ $^ -shared%.o:%.cgcc -fPIC -c $<.PHONY:clean
clean:rm -rf  *.o *.so sudo rm /lib/x86_64-linux-gnu/libmyc.so sudo rm /usr/include/mymath.h mystdio.h .PHONY:copy
copy:sudo cp mymath.h mystdio.h /usr/include/sudo cp libmyc.so /lib/x86_64-linux-gnu/

發布給別人使用

libmyc.so:mystdio.o mymath.ogcc -o $@ $^ -shared%.o:%.cgcc -fPIC -c $<.PHONY:clean
clean:rm -rf output *.o *.so *.tgz.PHONY:output
output:mkdir -p output mkdir -p output/lib/mkdir -p output/include/cp *.h output/include/cp *.so output/lib/tar -czf mylib.tgz output

當然。運行時找到動態庫的原理還有幾種。比如配置?LD_LIBRARY_PATH環境變量。

更改系統配置文件。將動態庫,查找路徑,使其全局有效。

還需要注意的是:

?動態庫和靜態庫同時存在的時候,gcc/g++優先使用動態庫。默認進行動態鏈接!

?一個可執行程序。可能依賴多個庫,但是如果我們只提供靜態庫,即使動態鏈接。gcc也沒辦法,只能對只提供的靜態的庫,進行靜態鏈接!

?如果我們顯示帶上-static選項。那么我們就一定要提供靜態庫了,否則,會報錯!?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917825.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917825.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917825.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用Database Navigator插件進行連接sqlite報錯invalid or incomplete database

解決方案 &#xff0c;將這個db.sqlite3文件拷貝到盤的文件中 &#xff0c;修改文件夾名字&#xff0c;重新使用絕對路徑訪問 db.sqlite3&#xff0c;將路徑名字的中文去掉 &#xff0c;不能有中文

【Linux】重生之從零開始學習運維之主從MGR高可用

MGR集群部署12、15、18主機環境準備ssh免密碼登錄\rm -rf .ssh/* ssh-keygen ssh-copy-id 127.1 scp -r .ssh 10.0.0.12:/root/ ssh root10.0.0.12還原基礎環境systemctl stop mysqld \rm -rf /var/lib/mysql/* id mysqlvim /etc/my.cnf.d/mysql-server.cnf [mysqld] datadir/v…

如何在虛擬機(Linux)安裝Qt5.15.2

1.進入到阿里的網站下載在線安裝包 qt-official_releases-online_installers安裝包下載_開源鏡像站-阿里云 https://mirrors.aliyun.com/qt/official_releases/online_installers/?spma2c6h.13651104.d-5201.2.60ad4773ZZNPNm 2.下載完畢后&#xff0c;進入到下載地址&…

【運維進階】DHCP服務配置和DNS域名解析

DHCP服務配置和DNS域名解析 DHCP 服務介紹 在大型網絡中&#xff0c;系統靜態分配IP地址面臨問題&#xff1a; 確保不要同時在多個系統上使用同一個地址。部署新系統通常需要手動分配其IP地址。在云環境中&#xff0c;實例的網絡是自動化配置的。 動態主機配置協議&#xff08;…

VisionPro MR環境下虛擬物體與現實的透明度混合

display.rgb (virtualcontent.rgb*1)(passthrough.rgb*(1 - vistualcontent.a) viirtualcontent預乘過a值了&#xff0c;跟透明度混合公式一致 人頭檢測挖孔不清晰問題&#xff0c;這個a值變成設備層動態檢測人頭的a值&#xff0c;當面前的渲染壓力過大時&#xff0c;會導致…

css怪異模式(Quirks Mode)和標準模式(Standards Mode)最明顯的區別

文章目錄css怪異模式&#xff08;Quirks Mode&#xff09;和標準模式&#xff08;Standards Mode&#xff09;最明顯的區別詳細對比示例對比&#xff08;盒模型&#xff09;標準模式&#xff08;Standards Mode&#xff09;怪異模式&#xff08;Quirks Mode&#xff09;如何觸發…

一種簡單的3dnr去噪算法介紹

一段未經過插補的視頻圖像可以分解為若干幀&#xff0c;為了能正確地找到并去除圖像幀中的噪聲污染&#xff0c;由于視頻圖像各幀的連續性&#xff0c;在去噪的過程中就必須考慮幀圖像的空間性和時間性&#xff0c;一個簡單的例子&#xff0c;在去噪算法中就必須考慮&#xff0…

【數據結構初階】--排序(四):歸并排序

&#x1f525;個人主頁&#xff1a;草莓熊Lotso &#x1f3ac;作者簡介&#xff1a;C研發方向學習者 &#x1f4d6;個人專欄&#xff1a; 《C語言》 《數據結構與算法》《C語言刷題集》《Leetcode刷題指南》 ??人生格言&#xff1a;生活是默默的堅持&#xff0c;毅力是永久的…

GaussDB 并行創建索引

1 背景當業務數據在單表存儲達到一定的數量級時&#xff0c;此時對表創建索引是要花費時間的。GaussDB為了解決這個問題采用并行創建索引技術&#xff0c;以提高創建索引的效率。2 示例步驟1&#xff1a;根據實際情況調整maintenance_work_mem參數該大小。[Rubydtest1 ~]$ gsq…

LOOP Finance:一場 Web3 共和國中的金融制度實驗

LOOP Finance 是建構于幣安智能鏈&#xff08;BNB Chain&#xff09;上的定投型DEFI理財協議。 它以凱因斯經濟學為啟發&#xff0c;設計出一套長期、安全、穩定收益的全新DEFI玩法&#xff0c;兼顧穩健利息回報與DEFI高速成長的潛力。 通過生態機制&#xff0c;LOOP要求每位參…

【golang面試題】Golang遞歸函數完全指南:從入門到性能優化

引言&#xff1a;遞歸的本質與挑戰 在Golang中&#xff0c;遞歸函數是一把鋒利的雙刃劍。它通過函數自身調用實現問題分解&#xff0c;讓代碼變得簡潔優雅&#xff0c;但也容易因無限遞歸、棧溢出或性能問題讓開發者陷入困境。本文將從基礎到高級&#xff0c;全面解析Golang遞歸…

功能安全和網絡安全的綜合保障流程

摘要網絡物理系統是控制機械部件的計算機化系統。這些系統必須既功能安全又網絡安全。因此&#xff0c;已建立的功能安全與網絡安全標準需求創建網絡安全檔案&#xff08;ACs&#xff09;&#xff0c;以論證系統是功能安全與網絡安全的&#xff0c;即所有功能安全與網絡安全目標…

數據科學首戰:用機器學習預測世界杯冠軍

數據科學首戰&#xff1a;用機器學習預測世界杯冠軍Scikit-learn實戰&#xff1a;從數據清洗到冠軍預測的完整指南一、足球預測&#xff1a;數據科學的終極挑戰??世界杯數據價值??&#xff1a;歷史比賽數據&#xff1a;44,000場球隊特征指標&#xff1a;200球員數據點&…

一個php 連sqlserver 目標計算機積極拒絕,無法連接問題的解決

一個接口查詢數據耗時15秒&#xff0c;還沒數據&#xff0c;經查報錯日志&#xff1a;SQLSTATE[08001]: [Microsoft][ODBC Driver 17 for SQL Server]TCP 提供程序: 由于目標計算機積極拒絕&#xff0c;無法連接。 命令行執行&#xff1a;netstat -ano | findstr :1433發現結…

生成網站sitemap.xml地圖教程

要生成 sitemap.xml 文件&#xff0c;需要通過爬蟲程序抓取網站的所有有效鏈接。以下是完整的解決方案&#xff1a; 步驟 1&#xff1a;安裝必要的 Python 庫 ounter(line pip install requests beautifulsoup4 lxml 步驟 2&#xff1a;創建 Python 爬蟲腳本 (sitemap_genera…

idea拉取新項目第一次啟動報內存溢出(java.lang.OutOfMemoryError: Java heap space)

背景&#xff1a; 新拉取一個項目后&#xff0c;第一次啟動的時候報錯內存溢出&#xff1a; Java 堆內存溢出 (java.lang.OutOfMemoryError: Java heap space) 這個錯誤表示你的 Java 應用程序需要的內存超過了 JVM 堆內存的分配上限。 解決方案 1.增加堆內存大小 啟動應用時添…

安卓雷電模擬器安裝frida調試

1.在模擬器中設置調試root和adb 2.在vscode中安裝autox.js 3.在github上下載auto.js組件 新地址鏈接看來大佬的項目也經歷了波折https://blog.csdn.net/weixin_41961749/article/details/145669531 github地址https://github.com/aiselp/AutoX/releases 將下載的apk放入雷電…

Godot ------ 初級人物血條制作02

Godot ------ 初級人物血條制作02引言正文血條動態顯示引言 在 Godot ------ 初級人物血條制作01 一文中我們介紹了如何構建一個初級血條&#xff0c;但是我們并沒有涉及如何動態顯示血條。本文我們將介紹如何動態顯示血條。 正文 血條動態顯示 首先&#xff0c;我們為當前…

(Python)待辦事項升級網頁版(html)(Python項目)

源代碼&#xff1a; app.py from flask import Flask, render_template, request, redirect, url_for, jsonify import json import osapp Flask(__name__)# 數據存儲文件 DATA_FILE "todos.json"def load_todos():"""從文件加載待辦事項"&q…

智慧養老破局:科技如何讓“老有所養”變成“老有優養”?

隨著人口老齡化加劇&#xff0c;“養老”成了社會關注的焦點。傳統養老往往停留在“有地方住、有人照顧”的基礎需求&#xff0c;而智慧養老則通過科技與人文的結合&#xff0c;讓老年人的生活從“老有所養”升級到“老有優養”。不僅活得安心&#xff0c;更能活得有尊嚴、有質…