靜態庫呼叫靜態庫&靜態庫載入靜態庫------談談undefined reference to和linker input file unused because linking not done
靜態庫可以呼叫靜態庫嗎? 靜態庫可以載入靜態庫嗎? 搞清這些東西, 對於linux開發很重要, 本文我們來探討這些問題。
先看程式:
business.h:
#include <iostream>
using namespace std;
void business();
business.cpp:#include <iostream> #include "business.h" using namespace std; void business() { printf("business code\n"); }
main.cpp
#include <iostream>
#include "business.h"
using namespace std;
int main()
{
business();
printf("main code\n");
}
我們來編譯執行看下:
xxxxxx:~/liblearn> g++ -c business.cpp xxxxxx:~/liblearn> ar rcs libbusiness.a business.o xxxxxx:~/liblearn> ls business.cpp business.h business.o libbusiness.a main.cpp xxxxxx:~/liblearn> g++ main.cpp -L. -lbusiness xxxxxx:~/liblearn> ls a.out business.cpp business.h business.o libbusiness.a main.cpp xxxxxx:~/liblearn> ./a.out business code main code xxxxxx:~/liblearn>
一切正常。
我們再看看:
basic.h
#include <iostream>
using namespace std;
void basic();
basic.cpp#include <iostream>
#include "basic.h"
using namespace std;
void basic()
{
printf("basic code\n");
}
business.h:
business.cpp:#include <iostream> using namespace std; void business();
#include <iostream>
#include "basic.h"
#include "business.h"
using namespace std;
void business()
{
basic();
printf("business code\n");
}
main.cpp內容為:
#include <iostream>
#include "business.h"
using namespace std;
int main()
{
business();
printf("main code\n");
return 0;
}
來看看結果:
xxxxxx:~/liblearn> ls
basic.cpp basic.h business.cpp business.h main.cpp
xxxxxx:~/liblearn> g++ -c basic.cpp
xxxxxx:~/liblearn> g++ -c business.cpp
xxxxxx:~/liblearn> strings business.o | grep "basic code"
xxxxxx:~/liblearn>
xxxxxx:~/liblearn>
xxxxxx:~/liblearn> ar rcs libbasic.a basic.o
xxxxxx:~/liblearn> g++ -c business.cpp -L. -lbasic
g++: -lbasic: linker input file unused because linking not done
xxxxxx:~/liblearn> strings business.o | grep "basic code"
xxxxxx:~/liblearn>
xxxxxx:~/liblearn>
xxxxxx:~/liblearn> ar rcs libbusiness.a business.o
xxxxxx:~/liblearn> g++ main.cpp -L. -lbusiness
./libbusiness.a(business.o): In function `business()':
business.cpp:(.text+0x79): undefined reference to `basic()'
collect2: ld returned 1 exit status
xxxxxx:~/liblearn>
xxxxxx:~/liblearn>
xxxxxx:~/liblearn> g++ main.cpp -L. -lbusiness -lbasic
xxxxxx:~/liblearn>
xxxxxx:~/liblearn>
xxxxxx:~/liblearn> ./a.out
basic code
business code
main code
xxxxxx:~/liblearn> strings a.out | grep "basic code"
basic code
xxxxxx:~/liblearn>
分析一下, 我們看到, 在編譯business.cpp後, strings命令的結果沒有basic code資訊, 也就是business沒有載入basic模組的任何東西, 因為這裡只是編譯, 沒有連結. 即使主動連結一下, 也沒有鳥用, 還會有warning提示linker input file unused because linking not done, 所以, 很自然地, g++ main.cpp -L. -lbusiness找不到basic, 很自然地需要g++
main.cpp -L. -lbusiness -lbasic, 這就帶來了一個問題: libbusiness.a/business.h並不能獨立地對外提供能力, 略蛋疼。
怎麼辦呢? 這裡可以考慮兩種方法:
a. 把libbasic.a庫和libbusiness.a庫合成新的libbusiness.a庫, 但我個人不建議這麼做。
b. 專門為libbusiness.a搞一個巨集, 使得每次連結libbusiness.a的時候, 自動也連結到libbasic.a, 這對於使用libbusiness.a的人來說, 是透明的, 不可見的, 不需要管的, 比較爽。
綜上所述:
1. 靜態庫 .a檔案(這裡更準確的說法應該是.o檔案)不能載入其他靜態庫, 因為只涉及到編譯,不涉及到連結。
2. 靜態庫 .a檔案(這裡更準確的說法應該是.o檔案)可以呼叫其他靜態庫(呼叫其中的函式), 此時並不會連結, 也不需要連結, 也連結不了。
很多時候, 當我們的business模組要呼叫新的basic模組的靜態庫時, 要特別特別小心, 否則就會坑後面的同學, 後面同學在編譯main的時候(或者其他so需要依賴於business靜態庫的時候), 肯定會undefined reference to xxx, 不好意思, 我曾經坑過兩位同學
其實, “載入”和“連結”的意思是差不多的。 好了, 本文先說道這裡, 又有進步啦。