VS編譯linux項目生成靜態庫並在另一個項目中靜態鏈接的方法
VS2017也推出很久了,在單位的時候寫linux的服務端程序只能用vim,這讓用慣了IDE的我很難受。
加上想自己擼一套linux上的輪子,決定用VS開工遠程編寫調試linux程序。
在windows下編寫靜態庫並在另一個項目中引用很簡單
新建項目的時候選擇靜態庫,進去把代碼擼好,即可編譯出靜態庫*.lib
隨後在希望使用該靜態庫的項目中設置一下鏈接器“附加庫目錄”為"../Debug"(和你的輸出路徑有關),然後添加"附加依賴項"靜態庫名.lib",然後就可以順利的編譯靜態庫了。
但是在linux下這件事卻讓我頭疼了幾天,我一開始也準備按照windows下的套路來解決,解決在新建項目的時候壓根沒看到靜態庫這一選項……
不過還好在常規裏面找到了“配置類型”選項,設置成“靜態庫(.a)”就可以了。
在準備使用靜態庫的時候,真正的麻煩來了,一開始我按照windwos下的思路,當前項目鏈接時的工作目錄就是解決方案的路徑,所以按照編譯出來的文件結構寫下了“附加庫目錄”(../common/bin/x64/Debug),然後去填寫“附加依賴項”(“libcommon.a”),編譯的時候就華麗麗的出錯了,提示沒有這個文件……
後來嘗試過吧“libcommon.a”改成““common””、“附加庫目錄”直接指定成linux上的絕對地址等方案,但是很可惜沒有任何一個方案可以。
在linux下自己寫參數指定絕對地址能夠順利將靜態庫鏈接成功,但是用vs的環境卻總是失敗,這個時候有點讓我懷疑人生了。
甚至一度想用VS寫好代碼然後去linux下寫MAKEFILE,手動編譯。但是轉念一想,這豈不是回到遠古時代了?不行,我得幹掉這個問題。
後來突發奇想,寫了一個小程序myhelp,放進了usr/bin/中
int main(int argc,char **argv) { char buf[80]; getcwd(buf, sizeof(buf)); std::ofstream f; f.open("/home/reskai/work.txt"); if (f) { f << buf; f << "View Code\r\n"; while (argc-- > 0) { f << *argv++ << "\r\n"; } f.close(); } return 0; }
myhelp用來獲取當前的工作目錄,以及將調用的參數全部輸出到文件當中。
隨後更改項目的鏈接器,用myhelp替換掉g++來當鏈接器,得到了一些有意思的信息
/home/reskai myhelp -o /home/reskai/projects/projectK/bin/x64/Debug/projectK.out -Wl,--no-undefined -Wl,-L../common/bin/x64/Debug -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack /home/reskai/projects/projectK/obj/x64/Debug/main.o libcommon.a
在遠程調用linux的時候,當前的工作目錄不是項目路徑而是~/……恩……就是這個我想當然的原因導致我一直沒能夠成功編譯
然後我就去改了“附加庫目錄”,設置到了正確的位置,隨後重新鏈接……我再次懷疑人生,仍然無法找到文件。(其實這個時候應該想到的,之前我設置附加庫目錄為絕對地址仍然無法鏈接說明了這個選項還是有bug的)
最後沒有辦法的情況下,我試著將“附加庫目錄”給刪除了,然後在"附加依賴項"中直接填入完整的靜態庫路徑“./projects/common/bin/x64/Debug/libcommon.a”,這次終於通過鏈接了。
雖然終於成功用vs在linux下靜態鏈接了自己寫的庫,但是這個解決方法吧,有點不倫不類的。不知道到底是vs2017的BUG還是我對linux的編譯鏈接體系不太清楚。
用此文記錄下我遇到的這個問題與思考方法以及最終的解決方案。
題外話,就是因為這個問題讓我之前一天到淩晨4點才睡著,第二天上了一天班,晚上又想這個問題到現在這個點才解決。
VS編譯linux項目生成靜態庫並在另一個項目中靜態鏈接的方法