簡體   English   中英

使用gcc進行靜態和動態鏈接

[英]static and dynamic linking using gcc

我最近一直在閱讀有關靜態和動態鏈接的信息,我了解它們之間的區別以及如何創建靜態和動態庫並將其鏈接到我的項目

但是,我想到一個問題,我無法回答或找到答案,因為這是一個特定的問題……當我使用以下代碼在linux上編譯代碼時

#include <stdio.h>
int main()
{
  printf("hello, world!\n");
}

使用此命令進行編譯

[root@host ~]# gcc helloworld.c -o helloworld

這是哪種鏈接? 所以stdio.h是靜態或動態鏈接到我的項目的???

庫主要用作共享資源,因此幾個不同的程序可以以某種方式重用相同的預編譯代碼。 一些庫作為標准庫提供,它們隨操作系統和/或編譯器軟件包一起提供。 一些圖書館還帶有其他第三方項目。

當以示例方式僅運行gcc時,實際上就是在運行一個編譯器驅動程序,該驅動程序為您提供了一些與編譯相關的功能,調用了編譯過程的不同部分,最后將您的應用程序與一些標准庫鏈接在一起。 庫的類型是根據您提供的限定符選擇的。 默認情況下,它將嘗試查找動態(共享)庫,如果缺少,將嘗試使用靜態庫。 除非您告訴它僅使用靜態庫(-static)。

當您鏈接到項目庫時,您告訴gcc / g ++使用哪種庫(-lname)。 這樣,它將與標准庫相同,除非使用-static,否則首先查找“ .so”,然后查找“ .a”。 您也可以直接指定完整庫名的路徑,實際上告訴它要使用哪個庫。 還有其他幾個限定鏈接過程的限定符,請在man中查找'g ++'和'ld'。

庫必須包含真實的程序代碼和數據。 它鏈接到主要可執行文件(和其他庫)的方式是通過符號表(它們是庫的一部分)進行的。 符號表包含用於全局函數的數據條目。

共享庫和靜態庫的結構略有不同。 前一個實際上是一個預鏈接的對象,類似於一個可執行映像,帶有一些與符號和重定位有關的額外信息(此類庫可以加載到內存中的任何地址,並且仍然可以正常工作)。 靜態庫實際上是'.o'文件的存檔,可以進行完整的鏈接。

創建庫的通常步驟是將程序的多個部分編譯為“ .o”文件,這些文件又可以通過“ ld”(或g ++)鏈接到共享庫中,或通過“ ar”存儲在.a中。 之后,您可以使用它們以上述方式進行鏈接。

每個.cpp源文件創建一個目標文件(.o)。 源文件包含代碼,並且可以包含任意數量的頭文件,在您的情況下(或cstdio)為“ stdio.h”或類似名稱。 這些文件成為由cpp預處理程序保障的源文件的一部分。 后者負責宏並展平所有#include層次結構,以便編譯器僅看到單個文本流,並將其轉換為“ .o”。 通常,頭文件不應包含可執行代碼,而應包含聲明和宏,盡管並非總是如此。 但這並不重要,因為它們已與主源文件融合在一起。

希望這能解釋它。

這是哪種鏈接? 所以stdio.h是靜態或動態鏈接到我的項目的???

stdio.h未鏈接,它是頭文件,並且包含代碼/文本,沒有編譯的對象。

當兩個鏈接都位於同一目錄中時,普通鏈接過程相對於“ .a”存檔更喜歡使用“ .so”庫。 您的簡單命令是與.so(如果在正確的路徑中)或.a(如果在沒有.so等效項的路徑中找到)鏈接。

要實現靜態鏈接,您有幾種選擇,包括

1) copy the '.a' archive to a directory you create, then specify that 
directory (-L)

2) specify the path to the '.a' in the build command.   Boost example:

$(CC) $(CC_FLAGS)  $<  /usr/local/lib/libboost_chrono.a  -o $@  $(LIB_DIRs) $(LIB_NMs)

我已經使用了兩種技術,但我發現第一種更容易。

請注意,存檔代碼可能引用另一個存檔中的符號。 您可以命令鏈接程序多次搜索庫。

如果讓構建與.so鏈接,則不會將整個.so的副本拉入構建。 而是在程序啟動后,在運行時將.so(整個lib)加載到內存中(如果尚未存在)。 對於大多數應用程序,由於程序會調整其內存映射(在后台自動魔術),因此這被認為對啟動性能造成了“小影響”。請注意,應用程序本身可以控制何時加載.so(稱為動態庫)。


無關:

// If your C++ 'Hello World' has no class ... why bother?
#include <iostream>

class Hello_t {
public:
   Hello_t()  { std::cout << "\n  Hello"  << std::flush; }
   ~Hello_t() { std::cout <<    "World!" << std::endl; }
   void operator() () { std::cout << " C++ "; }
};
int main(int, char**) { Hello_t()(); }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM