1. 程式人生 > >靜態庫呼叫靜態庫&靜態庫載入靜態庫------談談undefined reference to和linker input file unused because linking not done

靜態庫呼叫靜態庫&靜態庫載入靜態庫------談談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:

#include <iostream>
using namespace std;

void business();
        business.cpp:
#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,  不好意思, 我曾經坑過兩位同學大哭大哭

        其實, “載入”和“連結”的意思是差不多的。 好了, 本文先說道這裡, 又有進步啦。