淺談.lib .dll .obj 關係&& .a .so .o關係
一、.obj .exe .dll .lib
(1).obj
- 目標文件,相當於源代碼對應的二進制文件。
- obj文件就是用.c .cpp .h文件經過編譯器編譯之後生成的目標文件。
(2).exe
- 將程序運行所需要的全部.obj文件連接起來,即形成.exe文件。
- 也就是windows下的可執行文件。
- obj只給出了程序的相對地址,而EXE是絕對地址
(3).dll
- .dll是可提供給多個程序同時使用的可執行代碼和數據(資源 )的庫
- 可簡單理解爲封裝好的.cpp,裏面裝的是函數的具體實現
- .dll是動態編譯出來的程序運行時所需要的庫,沒有.dll文件,動態編譯的程序就不能運行
(4).lib
- .lib是編譯程序時所需的,非運行時所需
- .lib分爲靜態和動態
- 靜態.lib包括了方法及其具體實現。
- 動態.lib只有方法的聲明,簡單來看相當於一個h文件,是對實現部分(.dll文件)的導出部分的聲明。作用是告訴鏈接器具體用到了哪個dll文件,以及定位到dll文件內部的函數具體實現位置。
- 利用靜態lib編譯出來的程序,運行時不需要.dll文件的支持。
- 利用動態lib編譯出來的程序,運行時需要.dll文件提供方法的具體實現
- 實際上:.lib文件可看做是若干個.obj文件的集合
(5)一個C/C++工程需要用到其他.c .h .cpp類庫、函數庫時,其包含的方式有如下圖的幾種方式
- 1、最直接的方式就是將該類庫的.h .cpp 直接引入到工程中,直接完全編譯
- 2、另外的方法是先將該類庫生成爲一個靜態的lib庫,引入工程時只需包含.h以及.lib文件,編譯時將所需的方法具體實現從.lib中提取到可執行文件,可執行文件可不需要其他東西的支持就可直接運行
- 3、常用的方法是將該類庫生成一個動態的lib庫,還有與之對應的.dll文件,引入工程時也只需包含.h以及.lib文件,但這個動態的.lib文件僅僅提供方法的聲明,具體的實現被打包在.dll文件中,因此運行生成的可執行文件需要.dll文件的支持
實戰:
1)動態庫的生成(lib和dll)
a、新建項目,win32,win32項目,輸入項目名稱,例如makedll2
b、選擇dll、導出符號
c、自動生成makedll2.h
- #define MAKEDLL2_API __declspec(dllexport)表明這些東西可以被外部函數使用,即(dllexport)是把DLL中的相關代碼(類,函數,數據)暴露出來爲其他應用程 序使用
- class MAKEDLL2_API Cmakedll2 表示導出類,這個類爲Cmakedll2類
- extern MAKEDLL2_API int nmakedll2; 聲明導出變量
- MAKEDLL2_API int fnmakedll2(void); 聲明導出函數
// 下列 ifdef 塊是創建使從 DLL 導出更簡單的
// 宏的標準方法。此 DLL 中的所有文件都是用命令行上定義的 MAKEDLL2_EXPORTS
// 符號編譯的。在使用此 DLL 的
// 任何其他項目上不應定義此符號。這樣,源文件中包含此文件的任何其他項目都會將
// MAKEDLL2_API 函數視爲是從 DLL 導入的,而此 DLL 則將用此宏定義的
// 符號視爲是被導出的。
#ifdef MAKEDLL2_EXPORTS
#define MAKEDLL2_API __declspec(dllexport)
#else
#define MAKEDLL2_API __declspec(dllimport)
#endif
// 此類是從 makedll2.dll 導出的 類名爲Cmakedll2
class MAKEDLL2_API Cmakedll2 {
public:
Cmakedll2(void);
// TODO: 在此添加您的方法。
};
//聲明導出變量
extern MAKEDLL2_API int nmakedll2;
//聲明導出函數
MAKEDLL2_API int fnmakedll2(void);
d、makedll2.cpp
- 導出內容的具體實現
// makedll2.cpp : 定義 DLL 應用程序的導出函數。
//
#include "stdafx.h"
#include "makedll2.h"
// 這是導出變量的一個示例
MAKEDLL2_API int nmakedll2=0;
// 這是導出函數的一個示例。
MAKEDLL2_API int fnmakedll2(void)
{
return 42;
}
// 這是已導出類的構造函數。
// 有關類定義的信息,請參閱 makedll2.h
Cmakedll2::Cmakedll2()
{
return;
}
e、構建
f、檢查生成的.dll和.lib
2)動態庫的使用
方式一、vs2013下進行項目配置
a、新建一個win32控制檯項目
b、在屬性管理器中,雙擊debug或者release
將包含目錄設置爲剛剛生成dll項目的頭文件.h所在文件夾
將庫目錄設置爲剛剛生成dll項目的debug文件夾,也就是.lib所在的文件夾
c、在鏈接器--->輸入頁面中,在附加依賴項中添加剛剛生成的.lib文件
c、新建main.cpp文件,對剛剛封裝的庫進行調用
#include<iostream>
using namespace std;
#include"makedll2.h"
int main()
{
Cmakedll2 testdll; //這個是剛剛封裝成lib裏面的導出類
//輸出導出變量
cout <<"這個是導出變量:"<< nmakedll2 << endl;
//調用的導出函數
cout << "調用導出函數輸出:" << fnmakedll2() << endl;
system("pause");
return 0;
}
d、點擊運行,應該會報錯如下:
e、將上面生成的庫.dll文件複製到這個項目的debug下
f、運行,得到如下結果:
方式二、直接在項目中添加lib文件【適用於lib文件較少的情況】
a)新建完項目後,項目視圖中右鍵,添加,現有項,選擇所生成的lib文件即可
b)庫的.h頭文件放在項目目錄下
c)庫的.dll文件放在項目的debug目錄下
方式三、 直接在源文件中加入代碼
#pragma comment(lib, "makedll2.lib")
這裏引用https://www.cnblogs.com/qinguoyi/p/7257353.html的總結,
動態庫使用方法總結
.h,.lib,.dll的添加方法其實各有很多種。
.h有兩種:
1. 頭文件較少時,直接放在工程目錄下,#include "*.h"
2. 建立include文件夾,放在裏面,然後在項目屬性的“VC++目錄”-》“包含目錄”,添加.h路徑即可。
.lib的方法有兩種
1.lib文件較少時,直接放在工程目錄下,#pragma comment(lib, "testCpp.lib")
2.建立lib文件夾,目屬“VC++目錄”-》“庫目錄”添加路徑,然後在項目屬性的“鏈接器”-》“輸入”-》“附加依賴項”,添加.lib名字。
dll的方法有兩種
1.直接放在debug/release目錄下
2.建立bin文件夾,放在裏面,然後在項目“環境”中添加bin的路徑(PS:最好不要用這個)
3)靜態庫的生成和使用可參考動態庫,使用時不再需要將.dll文件複製到exe目錄,因爲靜態編譯將exe所需的內容都提取到exe裏面了。
二、.a .so .o
(1).o
- 目標文件,相當於windows下的.obj
- 是編譯得到的結果,即源碼編譯後得到的二進制文件
(2).a
- 靜態庫文件
- 相當於windows下的靜態.lib
- 相當於一個或多個.o文件的集合,可直接由.o文件生成
- .a的命名格式:lib+函數庫名+.a
- 構建.a靜態庫方法:使用ar工具
- 使用.a靜態庫方法:gcc生成可執行文件時,使用-l(小寫)參數指定要加入的庫函數。也可以用ld命令的-l和-L參數
- 使用舉例:gcc -o hello main.c -L. –l庫名 #-L 後面指定靜態庫路徑 -l不用空格後直接加靜態庫名(lib後面的東西)
(3).so
- 動態庫文件,一般叫共享庫,share
- 相當於windows下的.dll
- .so的命名格式:lib+函數庫名+.so+版本號信息(但是記住,非常底層的C庫函數都不是以lib開頭命名的)
- 構建.so動態庫方法:gcc -fPIC -shared -o lib庫名.so.1 atoi.c
- 使用.so動態庫方法:gcc -o main main.o -Wl,-rpath=. lib庫名.so.1 #-Wl,-rpath:指定庫所在路徑
- 查看可執行文件所依賴的動態庫情況:ldd 可執行文件