day01:動態庫與Qt環境的學習與作業

  • 2020/6/21

序言

  1. IDE工具

    • VSCode
      • 語法檢測:頭文件(include頭文件) + 編譯器內置的語法
      • 添加頭文件檢測:ctrl + shift + p->C++配置編輯,添加頭文件所在目錄;
  2. 控制終端

    • 命令
    • 環境變量
      • PATH: echo %PATH%
      • set指令顯示所有環境變量
      • PATH:window執行程序所搜索的路徑;每個路徑使用分號分隔
      • 有可視化的設置的
  3. VisualStudio 開發環境的設置

    • 使用腳本的文件來設置,腳本是vcvars64.bat
    • 設置vcvars64.bat的目錄到PATH環境變量;
      • PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build
    • 使用可視化設置環境變量,需要重啟終端;
  4. 開發工具

    • cl 編譯器
    • link 連接器 (PE格式)
    • lib 庫歸檔工具(靜態庫:目標文件的歸檔)
    • dumpbin PE與目標文件格式分析工具

工程組織與編譯器

  1. 編譯器

    • cl 源代碼 編譯/鏈接為執行文件
      • /EHsc
      • /MD
      • /utf-8
        • /source-charset:utf-8
        • /execution-charset:utf-8
      • 頭文件目錄
  2. 說明:

    • 第一次輸出,漢字可能是亂碼
      1. 使用chcp命令改變終端的代碼頁。utf-8的code page= 65001
        • chcp 65001
      2. 在區域/語言中直接設置編碼(整個系統設置為utf-8)
        • opencv不識別中文目錄;(系統設置編碼)
  3. 鏈接器

    • link
      • cl負責編譯 : 檢測語法,生成目標文件
      • link負責鏈接:負責生成PE格式文件,需要信息動態庫信息
    • link 選項 目標文件s
      • /out
      • /MACHINE:X64
      • 第三方的庫的庫目錄
      • 第三方的庫名

靜態庫

  • 前提:lib/dll這兩個文件解釋清楚;
    • lib:靜態庫
    • dll:動態庫

實現一個庫函數

  • gk_math.h
#ifndef GK_MATH_H
#define GK_MATH_H
extern int gk_add(int, int);
#endif

  • gk_math.cpp
#include "gk_math.h"

int gk_add(int p1, int p2){
    return p1 + p2;
}

編譯成靜態庫

@rem 靜態庫的編譯
@rem 編譯
@cl /c /EHsc /MD /nologo /source-charset:utf-8  /execution-charset:utf-8 /Fo:gkmath.obj  gk_math.cpp
@rem 靜態庫鏈接
lib /MACHINE:X64 /nologo /OUT:gkmath.lib  gkmath.obj

代碼的組織

  • 使用shell腳本或者bat處理腳本,比較麻煩的是多個操作需要寫成多個bat文件;實際引入一個專門的工程組織腳本Makefile;

  • 工程組織的方式:

    • 通用
      • Makefile
      • CMake
      • QMake
    • 個性化:
      • Visual Studio
      • Qt Creator
      • QMake
      • Eclipse C++
      • C++ Builder
  • Makefile腳本的語法:Makefile

    1. 定義變量
    2. 任務(Task)
      • 依賴(任務依賴另外一任務)
    3. 指令
  • Makfile例子

CL_FLAGS   = /c \
             /EHsc \
             /MD  \
             /nologo \
             /source-charset:utf-8 \
             /execution-charset:utf-8

LINK_FLAGS = /MACHINE:X64 \
             /nologo

OBJS       = gkmath.obj
SOURCES    = gk_math.cpp
TARGETS    = gkmath.lib

main:$(TARGETS) main.cpp
    @ cl /nologo /MD /Fe:main.exe main.cpp  $(TARGETS) 

$(TARGETS):$(OBJS)
    @lib $(LINK_FLAGS) /OUT:$(TARGETS)  $(OBJS)

$(OBJS): gk_math.h  gk_math.cpp
    @cl  $(CL_FLAGS) /Fo:$(OBJS)  $(SOURCES)

clean:
    @del *.exe *.obj *.lib 2>/Nul

使用靜態庫

  1. 在鏈接的時候使用靜態庫
#include <stdio.h>
#include "gk_math.h"
int main(int argc, char **argv, char **arge){
    printf("C++程序編程!靜態庫調用結果:%d\n", gk_add(45, 55));
    return 0;
}

  • 編譯腳本

CL_FLAGS   = /c \
             /EHsc \
             /MD  \
             /nologo \
             /source-charset:utf-8 \
             /execution-charset:utf-8

LINK_FLAGS = /MACHINE:X64 \
             /nologo

OBJS       = gkmath.obj
SOURCES    = gk_math.cpp
TARGETS    = gkmath.lib

main:$(TARGETS) main.cpp
    @ cl /nologo /MD /Fe:main.exe main.cpp  $(TARGETS) 

$(TARGETS):$(OBJS)
    @lib $(LINK_FLAGS) /OUT:$(TARGETS)  $(OBJS)

$(OBJS): gk_math.h  gk_math.cpp
    @cl  $(CL_FLAGS) /Fo:$(OBJS)  $(SOURCES)

clean:
    @del *.exe *.obj *.lib 2>/Nul

  1. 在代碼中使用靜態庫
#include <stdio.h>
#include "gk_math.h"

#pragma comment(lib, "gkmath.lib")

int main(int argc, char **argv, char **arge){
    printf("C++程序編程!靜態庫調用結果:%d\n", gk_add(45, 55));
    return 0;
}
// cl /nologo /MD /Fe:main.exe main_lib.cpp

  • 編譯命令:
    • cl /nologo /MD /Fe:main.exe main_lib.cpp

  • 回顧
    1. 開發工具
      1. cl編譯器 (mac:clang/g++,posix:gnu g++,hp:acc: intel:cc, sun:cc)

        • 默認是調用link默認鏈接
          • /link 后面直接包含link選項
      2. link連接器(posix:ld)

        • link步驟很多編譯器中默認自動調用
      3. lib(ar)

        • 靜態庫
      4. dumpbin(nm)

        • 分析目標文件與PE執行文件
      5. nmake(make)

        • nmake task
        • nmake task -f makefile文件
    2. vcvars64.bat / vcvars32.bat (mac/linux不需要單獨的設置,默認在系統設置)
      • 空格轉義: "C:\Program Files (x86)\Microsoft Visual Studio"
    3. makefile的語法
      • 任務目標:依賴
        • 指令(使用tab開始)
      • 偽任務目標:
        • 文件不存在

動態庫

實現代碼

  1. gkmath.h文件
#ifndef GK_MATH_H
#define GK_MATH_H
extern int gk_add(int, int);
#endif

  1. gkmath.cpp文件
#include "gkmath.h"

int gk_add(int p1, int p2){
    return p1 + p2;
}

編譯動態庫

  • 準備:link選項

    • /DLL:不需要main入口
    • /IMPLIB : 指定鏈接的時候產生導入的符號,使用lib靜態庫的方式存放;
    • /EXPORT : 指定哪些函數可以被別人調用 = /DEF:DEF導出函數的描述文件
    • /MACHINE:指定CPU結構X64/X86/ARM/ARM64/EBC
    • /OUT:指定輸出文件名,dll輸出名字
  • 編譯腳本

# 編譯選項設置一個變量
CL_ARGS=/EHsc /MD /source-charset:utf-8 /execution-charset:utf-8 /nologo
# 鏈接選項設置一個變量
LINK_ARGS=/MACHINE:X64 /NOLOGO /DLL

# 文件設置成變量
SOURCES      = gkmath.cpp
OBJS         = gkmath.obj
OUTLIBS      = gkmath.lib
OUTDLLS      = gkmath.dll

# 目標指令實現
$(OUTDLLS):$(SOURCES)
    @cl /c  $(CL_ARGS) /Fo:$(OBJS)  gkmath.cpp
    @link /MACHINE:X64 /NOLOGO /DLL /OUT:$(OUTDLLS)  /IMPLIB:$(OUTLIBS) /EXPORT:gk_add  $(OBJS)
clean:
    @del *.obj *.lib *.dll *.ilk *.exe *.exp 2>/Nul

main1:call_auto_dll.cpp
    @cl /c $(CL_ARGS) /Fo:main1.obj call_auto_dll.cpp
    @link /OUT:main1.exe  main1.obj

動態庫的調用方式1

  • 直接使用dll調用函數(lib根本不需要,只需要dll) 【不推薦】

  • 準備技術:

    1. HMODULE = LoadLibraryA(LPCSTR dllfilename): 加載動態庫到內存
    2. FARPROC = GetProcAddress(HMODULE hModule, LPCSTR functioname)
    3. 函數類型轉換
    4. 調用
    5. 釋放dll空間:BOOL FreeLibraray(HMODULE)
  • 代碼實現
#include <stdio.h>
#include <windows.h>

// typedef int(*type_f)(int,int);

int main(int argc, const char**argv){
    // 加載dll模塊
    HMODULE h = LoadLibraryA("gkmath.dll");
    if (h == NULL){
        printf("加載失敗!\n");
        return -1;
    }
    printf("加載成功!");
    // 查找函數
    FARPROC f = GetProcAddress(h, "gk_add");  // ?gk_add@@YAHHH@Z
    printf("%p\n", f);
    // 類型轉換
    // type_f myfunc = (type_f)f;
    int (*myfunc)(int, int) = (int(*)(int, int))f;
    // 調用
    printf("結果:%d\n", myfunc(45,55));
    // 釋放模塊
    FreeLibrary(h);
}

  • /I : 指定頭文件的路徑
@cl /c /utf-8 /nologo /MD  /Fo:call_manual_dll.obj  call_manual_dll.cpp
@link /NOLOGO /OUT:main.exe /DYNAMICBASE  Kernel32.lib call_manual_dll.obj

動態庫的調用方式2

  • 在編譯的時候調用函數(根本不需要dll,只需要lib,但是運行的時候需要dll,不需要lib)

  • 代碼實現:

#include <stdio.h>
#include "gkmath.h"

#pragma comment(lib, "gkmath.lib")   // 強調,不推薦使用

int main(int argc, const char*argv[]){
    printf("調用結果:%d\n", gk_add(55,55));
    return 0;
}

  • 調用動態庫基地址
main1:call_auto_dll.cpp
    @cl /c $(CL_ARGS) /Fo:main1.obj call_auto_dll.cpp
    @link /OUT:main1.exe  main1.obj

Qt編譯環境設置

  • 掌握的重點:

    1. GUI (Qt應用 + QtWidgets(QDialog))
    2. QApplication
  • Qt程序繪制簡單窗體

#include <iostream>

// Qt GUI模塊:QtWidgets
// Qt 底層模塊:QtCore
// Qt 圖形的繪制模塊QtGui
#include <QtWidgets/QApplication>
#include <QtWidgets/QDialog>

int main(int argc, char **argv){
    // 1. 構建Qt應用:QApplication
    QApplication app(argc, argv);
    // 2. 窗體創建QDialog
    QDialog dlg;
    // 窗體的屬性(函數對getter/setter)
    dlg.setWindowTitle("Qt開發");
    dlg.resize(640, 480);
    dlg.move(200,200);
    dlg.setFixedSize(dlg.width(), dlg.height());   // 不允許改變窗體大小
    dlg.show();
    // 3. 消息循環處理int QApplication.exec()
    int status = app.exec();  // block函數(消息循環)
    // 4. 退出程序,返回狀態碼給系統0-255(-1=255)
    return status;
}

// dll所在的路徑,必須設置到PATH環境變量
  • 編譯腳本
INCLUDES = /I "D:/Qt/Qt5.13.0/5.13.0/msvc2017_64/include"

LIBS     = /LIBPATH:"D:/Qt/Qt5.13.0/5.13.0/msvc2017_64/lib" \
           /DYNAMICBASE  \
             "Qt5Widgets.lib"  \
             "Qt5Gui.lib" \
             "Qt5Core.lib"
CL_ARGS  = /EHsc \
           /MDd \
           /source-charset:utf-8 \
           /execution-charset:utf-8 \
           /nologo

LINK_ARGS = /MACHINE:X64  /NOLOGO 

main:qmain.cpp
    @cl /c $(CL_ARGS) /Fo:main.obj  $(INCLUDES) qmain.cpp
    @link $(LINK_ARGS) $(LIBS) /OUT:main.exe  main.obj

clean:
    @del *.exe *.obj *.exp 2>/Nul

  • 問題
    如果出現 qt.qpa.plugin: Could not find the Qt platform plugin "windows" in""
    解決方法:windeployqt main.exe

OpenCV的環境

    • 打開cmake;
    • 將opencv目錄和處理結果存放目錄依次鍵入;
    • Configure后調試無誤;
    • 單擊Generate在指定的存放目錄生成項目工程;
    • 在項目工程目錄下找到OpenCV.sln;
    • 用VS2019打開OpenCV.sln文件,加載項目;
    • 將BUILD_ALL與INSTALL重新生成。

作業

  • 寫Qt程序,并編譯鏈接成執行文件,且能執行成功;

    • 動態的使用
    • 編譯器/連接器
  • 提交作業

#include <iostream>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDialog>

int main(int argc, char **argv){
    // 1. 構建Qt應用
    QApplication app(argc, argv);
    // 2. 窗體創建
    QDialog dlg;
    // 窗體的屬性設置
    dlg.setWindowTitle("作業1");
    dlg.resize(1000, 800);
    dlg.move(300,300);
    dlg.setFixedSize(dlg.width(), dlg.height());   // 不允許改變窗體大小
    dlg.show();
    // 3. 消息循環處理
    int status = app.exec();  // block函數(消息循環)
    // 4. 退出程序,返回狀態碼給系統
    return status;
}

  • 作業所用編譯腳本
INCLUDES = /I "D:/Qt/Qt5.13.0/5.13.0/msvc2017_64/include"

LIBS     = /LIBPATH:"D:/Qt/Qt5.13.0/5.13.0/msvc2017_64/lib" \
           /DYNAMICBASE  \
             "Qt5Widgets.lib"  \
             "Qt5Gui.lib" \
             "Qt5Core.lib"
CL_ARGS  = /EHsc \
           /MDd \
           /source-charset:utf-8 \
           /execution-charset:utf-8 \
           /nologo

LINK_ARGS = /MACHINE:X64  /NOLOGO 

main:qmain.cpp
    @cl /c $(CL_ARGS) /Fo:main.obj  $(INCLUDES) qmain.cpp
    @link $(LINK_ARGS) $(LIBS) /OUT:main.exe  main.obj

clean:
    @del *.exe *.obj *.exp 2>/Nul

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374