主頁 >  其他 > qt creator原始碼全方面分析(3-2)

qt creator原始碼全方面分析(3-2)

2020-09-12 13:04:58 其他

目錄
  • qtcreator.pri
    • 判斷重復包含
    • 定義版本資訊
      • VERSION
    • 定義IDE名稱
    • 啟用C++14
      • CONFIG
    • 自定義函式
      • Replace Functions
      • Test Functions
      • _PRO_FILE_PWD_
      • _PRO_FILE_
    • 設定macOS最小版本
    • 設定QTEST模塊
    • 設定源目錄和構建目錄
      • re_escape(string)
      • clean_path(path)
    • 設定IDE和INSTALLS相關路徑
    • 設定字串宏
      • shell_quote
      • qmake定義字串宏
    • 設定INCLUDEPATH
      • INCLUDEPATH
      • Whitespace
    • 設值庫鏈接路徑和編譯選項
    • 解決插件和庫依賴

qtcreator.pri

前面我們介紹了qtcreator.pro,下面我們開始介紹qtcreator.pri,來看看pro中include的pri到底是干什么用的,

注意,許多函式/變數/關鍵字的含義,某些基礎用法,在qtcreator.pro中進行了介紹,

判斷重復包含

qtcreator.pri第一部分是

!isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included")
QTCREATOR_PRI_INCLUDED = 1

很明顯,isEmpty()為false,則呼叫error報錯退出編譯,那么只能是為true,即要求QTCREATOR_PRI_INCLUDED為空,并在下一行立即定義為1,

那么這個是在干什么呢?我們看變數的名稱就能略窺一二,INCLUDED就是已包含的意思,那么這里就是為了避免在其他地方重復包含qtcreator.pri檔案,類似于C/C++頭檔案中的

# ifndef XXX_H
# define XXX_H

#endif

定義版本資訊

接下來是

QTCREATOR_VERSION = 4.6.2
QTCREATOR_COMPAT_VERSION = 4.6.0
VERSION = $$QTCREATOR_VERSION
QTCREATOR_DISPLAY_VERSION = 4.6.2
QTCREATOR_COPYRIGHT_YEAR = 2018
BINARY_ARTIFACTS_BRANCH = 4.6

VERSION

如果TEMPLATE值為app,則指定應用程式的版本號;如果TEMPLATE值為lib,則指定庫的版本號,

在Windows上,如果未設定RC_FILE和RES_FILE變數,則自動生成.rc檔案, 生成的.rc檔案將具有FILEVERSION和PRODUCTVERSION條目,并用主,次,補丁和構建版本號填充, 每個數字的范圍必須在0到65535之間,有關.rc檔案生成的更多詳細資訊,請參見Platform Notes,

示例:

win32:VERSION = 1.2.3.4 # major.minor.patch.build
else:VERSION = 1.2.3    # major.minor.patch

很明顯,是在定義QtCreator的版本,兼容性版本,著作權,以及git分支,

定義IDE名稱

接下來是

isEmpty(IDE_DISPLAY_NAME):           IDE_DISPLAY_NAME = Qt Creator
isEmpty(IDE_ID):                     IDE_ID = qtcreator
isEmpty(IDE_CASED_ID):               IDE_CASED_ID = QtCreator

isEmpty(PRODUCT_BUNDLE_IDENTIFIER): PRODUCT_BUNDLE_IDENTIFIER = org.qt-project.$$IDE_ID

我們在qtcreator.pro中已經介紹過isEmpty這種用法,這里在給相關變數設定默認值,

啟用C++14

接下來是

CONFIG += c++14

CONFIG

指定專案配置和編譯器選項, 這些值由qmake內部識別,并具有特殊含義,

以下CONFIG值控制編譯標志:

選項 描述
release 該專案將以release模式構建, 如果還指定了debug,則最后那個生效,
debug 該專案將以debug模式構建,
debug_and_release 該專案將同時構建debug和release模式,
debug_and_release_target 默認情況下設定此選項, 如果還設定了debug_and_release,則debug和release版本最終將放置在單獨的debug和release目錄中,
build_all 如果指定了debug_and_release,則默認情況下專案同時構建debug和release模式,
autogen_precompile_source 自動生成一個.cpp檔案,其中包含.pro檔案中指定的預編譯頭檔案,
ordered 當TEMPLATE為subdirs時,此選項指定應按給出的順序處理列出的目錄,
注意:不建議使用此選項, 如SUBDIRS變數檔案中所述指定依賴項,
precompile_header 使能支持在專案中使用precompiled headers,
precompile_header_c (MSVC only) 使能支持在C檔案中使用precompiled headers,
warn_on 編譯器應盡可能多的輸出警告, 如果還指定了warn_off,則最后那個生效,
warn_off 編譯器應盡可能少的輸出警告,
exceptions 使能例外支持,默認設定該選項,
exceptions_off 禁用例外支持,
rtti 使能RTTI支持,默認情況下,使用編譯器默認值,
rtti_off 禁用RTTI支持,默認情況下,使用編譯器默認值,
stl 使能STL支持,默認情況下,使用編譯器默認值,
stl_off 禁用STL支持,默認情況下,使用編譯器默認值,
thread 使能Thread支持,當CONFIG包含qt(默認設定)時,將使能此功能,
c99 使能C99支持, 如果編譯器不支持C99或無法選擇C標準,則此選項無效, 默認情況下,使用編譯器默認值,
c11 使能C11支持, 如果編譯器不支持C11或無法選擇C標準,則此選項無效, 默認情況下,使用編譯器默認值,
strict_c 禁用對C編譯器擴展的支持, 默認情況下,它們是使能的,
c++11 使能C++11支持, 如果編譯器不支持C++11或無法選擇C++標準,則此選項無效, 默認情況下,使用編譯器默認值,
c++14 使能C++14支持, 如果編譯器不支持C++14或無法選擇C++標準,則此選項無效, 默認情況下,使用編譯器默認值,
c++1z 使能C++17支持, 如果編譯器不支持C++17或無法選擇C++標準,則此選項無效, 默認情況下,使用編譯器默認值,
c++17 同c++1z
c++2a 使能C++2a支持, 如果編譯器不支持C++2a或無法選擇C++標準,則此選項無效, 默認情況下,使用編譯器默認值,
c++latest 如果編譯器支持,使能最新C++語言標準的支持, 默認情況下,此選項是禁用的,
strict_c++ 禁用對C++編譯器擴展的支持, 默認情況下,它們是使能的,
depend_includepath 使能將INCLUDEPATH的值附加到DEPENDPATH, 默認設定此選項,
lrelease 對TRANSLATIONS 和EXTRA_TRANSLATIONS中列出的所有檔案運行lrelease, 如果未設定embed_translations,則將生成的.qm檔案安裝到QM_FILES_INSTALL_PATH中, 使用QMAKE_LRELEASE_FLAGS向lrelease呼叫添加引數選項, 默認情況下未設定此選項,
embed_translations 將lrelease生成的翻譯內容嵌入QM_FILES_RESOURCE_PREFIX下的可執行檔案中, 也需要同時設定lrelease, 默認情況下未設定此選項,
create_libtool 為當前構建的庫創建一個libtool.la檔案,
create_pc 為當前構建的庫創建一個pkg-config .pc檔案,
no_batch 僅限NMake:關閉NMake批處理規則或推斷規則的生成,
skip_target_version_ext 在Windows上禁止附加自動版本號到DLL檔案名,
suppress_vcproj_warnings 禁止VS專案生成器的警告,
windeployqt 鏈接后自動呼叫windeployqt,并將輸出添加為部署項,
dont_recurse 禁止對當前子專案的qmake遞回,
no_include_pwd 不要將當前目錄添加到INCLUDEPATHS,

當您使用debug_and_release選項(在Windows下是默認設定)時,專案將被處理三次:一次生成元Makefile,再兩次生成Makefile.Debug和Makefile.Release,

在后面的程序中,將build_pass和相應的debug或release選項附加到CONFIG, 這樣就可以執行特定構建任務, 例如:

build_pass:CONFIG(debug, debug|release) {
 unix: TARGET = $$join(TARGET,,,_debug)
 else: TARGET = $$join(TARGET,,,d)
}

作為手動撰寫構建型別條件的替代方法,除了常規QMAKE_LFLAGS外,某些變數還提供特定構建變數,例如 QMAKE_LFLAGS_RELEASE, 這些應在可用時使用,

元Makefile通過debug和release目標進行子構建呼叫,并可通過all目標進行聯合構建呼叫, 使用build_all選項時,聯合構建為默認設定, 否則,CONFIG中最后指定的來自集合(debug,release)的選項會變為默認選項, 在這種情況下,您可以顯式呼叫all以一次構建兩個配置:

make all

注意:在生成Visual Studio和Xcode專案時,詳細資訊略有不同,

鏈接庫時,qmake依賴基礎平臺,來了解該庫應該鏈接的其他庫, 但是,如果是靜態鏈接,qmake不會獲取此資訊,除非使用以下CONFIG選項:

選項 描述
create_prl 此選項使qmake可以跟蹤這些依賴性, 使能此選項后,qmake將創建擴展名為.prl的檔案,該檔案將保存有關庫的元資訊(有關更多資訊,請參見Library Dependencies),
link_prl 使能此選項后,qmake將處理該應用程式鏈接的所有庫并找到其元資訊(有關更多資訊,請參見Library Dependencies),
no_install_prl 此選項禁用創建.prl檔案的安裝規則的生成,

注意:構建靜態庫時,需要create_prl選項,而使用靜態庫時,則需要link_prl選項,

以下選項定義應用程式或庫的型別:

選項 描述
qt 目標是Qt應用程式或庫,并且需要Qt庫和頭檔案, Qt庫正確的包含和庫路徑將自動添加到專案中, 這是默認定義的,可以使用\l{#qt}{QT}變數進行微調,
x11 目標是X11應用程式或庫, 正確的包含路徑和庫將自動添加到專案中,
testcase 目標是一個自動測驗, 一個檢查目標將被添加到生成的Makefile中,以運行測驗, 僅在生成Makefile時相關,
insignificant_test 自動測驗的退出代碼將被忽略, 僅當還設定了testcase時才相關,
windows 目標是Win32視窗應用程式(僅適用于TEMPLATE為app), 正確的包含路徑,編譯器標志和庫將自動添加到專案中,
console 目標是Win32控制臺應用程式(僅適用于TEMPLATE為app), 正確的包含路徑,編譯器標志和庫將自動添加到專案中,考慮將選項cmdline用于跨平臺應用程式,
cmdline 目標是跨平臺的命令列應用程式, 在Windows上,這意味著CONFIG += console, 在macOS上,這意味著CONFIG -= app_bundle,
shared 目標是共享物件/DLL, 正確的包含路徑,編譯器標志和庫將自動添加到專案中, 請注意,dll也可以在所有平臺上使用, 將創建帶有目標平臺的適當后綴(.dll或.so)的共享庫檔案,
dll 同上,
static 目標是靜態庫(僅lib), 正確的編譯器標志將自動添加到專案中,
staticlib 同上,
plugin 目標是插件(僅lib), 這也會使能dll,
designer 目標是Qt Designer的插件,
no_lflags_merge 確保存盤在LIBS變數中的庫串列在使用前不減少為值唯一(去除了重復的)串列,

這些選項僅在Windows上定義特定功能:

選項 描述
flat 使用vcapp模板時,這會將所有源檔案置于源組中,并將頭檔案置于頭組中,而不管它們位于哪個目錄中,關閉此選項,將根據檔案所在目錄歸類, 默認情況下是打開的,
embed_manifest_dll 將清單檔案嵌入到作為庫專案一部分的DLL中,
embed_manifest_exe 將清單檔案嵌入到作為應用程式專案一部分的EXE中,

有關嵌入清單檔案的選項的更多資訊,請參見Platform Notes,

以下選項僅在macOS上有效:

選項 描述
app_bundle 將可執行檔案放入捆綁包(這是默認設定),
lib_bundle 將庫放入庫包(這是默認設定),
plugin_bundle 將插件放入插件包中, Xcode專案生成器不支持此值,

捆綁軟體的構建程序也受QMAKE_BUNDLE_DATA變數內容的影響,

以下選項僅在Linux / Unix平臺上有效:

選項 描述
largefile 支持大檔案的包含
separate_debug_info 把庫的除錯資訊放到單獨的檔案中

決議作用域時,將檢查CONFIG變數, 您可以為該變數分配任何內容,

例如:

CONFIG += console newstuff
...
newstuff {
    SOURCES += new.cpp
    HEADERS += new.h
}

自定義函式

接下來是

defineReplace(qtLibraryTargetName) {
   unset(LIBRARY_NAME)
   LIBRARY_NAME = $$1
   CONFIG(debug, debug|release) {
      !debug_and_release|build_pass {
          mac:RET = $$member(LIBRARY_NAME, 0)_debug
              else:win32:RET = $$member(LIBRARY_NAME, 0)d
      }
   }
   isEmpty(RET):RET = $$LIBRARY_NAME
   return($$RET)
}

defineReplace(qtLibraryName) {
   RET = $$qtLibraryTargetName($$1)
   win32 {
      VERSION_LIST = $$split(QTCREATOR_VERSION, .)
      RET = $$RET$$first(VERSION_LIST)
   }
   return($$RET)
}

defineTest(minQtVersion) {
    maj = $$1
    min = $$2
    patch = $$3
    isEqual(QT_MAJOR_VERSION, $$maj) {
        isEqual(QT_MINOR_VERSION, $$min) {
            isEqual(QT_PATCH_VERSION, $$patch) {
                return(true)
            }
            greaterThan(QT_PATCH_VERSION, $$patch) {
                return(true)
            }
        }
        greaterThan(QT_MINOR_VERSION, $$min) {
            return(true)
        }
    }
    greaterThan(QT_MAJOR_VERSION, $$maj) {
        return(true)
    }
    return(false)
}

# For use in custom compilers which just copy files
defineReplace(stripSrcDir) {
    return($$relative_path($$absolute_path($$1, $$OUT_PWD), $$_PRO_FILE_PWD_))
}

Replace Functions

qmake提供了一些內置函式,以允許處理變數的內容, 這些函式處理提供給它們的引數,并回傳一個值或值串列, 要將結果分配給變數,可以將$$運算子與此類函式一起使用,就像將一個變數的內容分配給另一個一樣:

HEADERS = model.h
HEADERS += $$OTHER_HEADERS
HEADERS = $$unique(HEADERS)

此類函式應在賦值的右側(即,作為運算元),

您可以定義自己的函式來處理變數的內容,如下所示:

defineReplace(functionName){
    #function code
}

以下示例函式將變數名作為唯一引數,使用內置函式eval()從變數中提取值串列,并編譯檔案串列:

defineReplace(headersAndSources) {
    variable = $$1
    names = $$eval($$variable)
    headers =
    sources =

    for(name, names) {
        header = $${name}.h
        exists($$header) {
            headers += $$header
        }
        source = $${name}.cpp
        exists($$source) {
            sources += $$source
        }
    }
    return($$headers $$sources)
}

引數$$1

Test Functions

qmake提供了內置函式,可以在撰寫作用域時用作條件, 這些函式不回傳值,而是指示成功或失敗:

count(options, 2) {
    message(Both release and debug specified.)
}

此類函式應僅在條件運算式中使用,

可以定義自己的函式以提供作用域條件, 以下示例測驗串列中的每個檔案是否存在,如果全部存在,則回傳true,否則回傳false:

defineTest(allFiles) {
    files = $$ARGS

    for(file, files) {
        !exists($$file) {
            return(false)
        }
    }
    return(true)
}

引數串列$$ARGS

_PRO_FILE_PWD_

包含正在使用的專案檔案的目錄的路徑,(即使該變數出現在 .pri 檔案,也是指包含該 .pri 檔案的 .pro 檔案所在目錄的路徑,)

例如,以下行導致包含專案檔案的目錄的位置寫入控制臺:

message($$_PRO_FILE_PWD_)

注意:請勿嘗試覆寫此變數的值,

_PRO_FILE_

包含正在使用的專案檔案的路徑,

例如,以下行導致專案檔案的位置寫入控制臺:

message($$_PRO_FILE_)

注意:請勿嘗試覆寫此變數的值,

現在我們來分析pri中定義的三個函式,

因為這兩個函式在 Qt Creator 中使用了多次,并且完全可以拷貝復制到其它專案繼續使用,

自定義替換函式qtLibraryTargetName

  1. 取消LIBRARY_NAME的定義,設定LIBRARY_NAME為 $$1,即函式的第一個引數,
  2. CONFIG測驗函式判斷debug或release模式,
    1. 如果是debug模式,再次進行判斷,
    2. 如果CONFIG沒有設定debug_and_release或者是構建程序build_pass,則設定RET變數,對于 mac,LIBRARY_NAME值后面添加_debug賦給RET,對于win,LIBRARY_NAME值后面添加d賦給RET,
  3. 如果RET為空,則把LIBRARY_NAME值賦給RET,
  4. 回傳RET,

簡單來說,該函式實作功能:在debug環境下,在庫名后面添加_debug或_d尾綴,來跟release模式進行區分,當然,也有其他方式來實作上述功能,譬如使用join()函式,見CONFIG小節,

自定義替換函式qtLibraryName

  1. 使用qtLibraryTargetName()函式,對輸入的第一個引數進行替換,并賦值給RET,
  2. 如果 是win32 系統,
  3. 使用split()函式,將前面定義的QTCREATOR_VERSION(即4.6.2),使用'.'進行分隔得到串列,賦值給VERSION_LIST
  4. 使用first()函式,獲取VERSION_LIST的第一個元素(即4),與RET拼接,并賦值給RET,
  5. 回傳RET,

簡單來說,該函式實作功能:為了在win32系統中避免出現 dll hell,在win32系統下,在庫名后面添加主版本號,

自定義測驗函式minQtVersion

  1. 獲取三個引數(即,主/次/補丁),并賦值給maj,min,patch,
  2. maj <= QT_MAJOR_VERSION,min <= QT_MINOR_VERSION和patch <= QT_PATCH_VERSION,則回傳true,其他回傳false,

簡單來說,該函式實作功能:函式引數的版本號小于等于當前Qt的版本號,

自定義替換函式stripSrcDir

  1. 獲取絕對路徑,absolute_path回傳$$OUT_PWD/$$1,
  2. 獲取相對路徑,步驟1中獲取的絕對路徑相對與$$_PRO_FILE_PWD_的相對路徑,

簡單來說,該函式實作功能(見自帶的注釋):用于自定義編譯器拷貝檔案,

設定macOS最小版本

接下來是:

darwin:!minQtVersion(5, 7, 0) {
    # Qt 5.6 still sets deployment target 10.7, which does not work
    # with all C++11/14 features (e.g. std::future)
    QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.8
}

如果是基于Darwin作業系統的,并且Qt 的版本低于5.7.0時,設定應用程式支持的macOs最小版本,可以從注釋看出,10.7不支持C++11/14特性,

設定QTEST模塊

接下來是

QTC_BUILD_TESTS = $$(QTC_BUILD_TESTS)
!isEmpty(QTC_BUILD_TESTS):TEST = $$QTC_BUILD_TESTS

!isEmpty(BUILD_TESTS):TEST = 1

isEmpty(TEST):CONFIG(debug, debug|release) {
    !debug_and_release|build_pass {
        TEST = 1
    }
}

isEmpty(IDE_LIBRARY_BASENAME) {
    IDE_LIBRARY_BASENAME = lib
}

equals(TEST, 1) {
    QT +=testlib
    DEFINES += WITH_TESTS
}
  1. 如果設定了QTC_BUILD_TESTS,則賦值給TEST,
  2. 如果設定了BUILD_TESTS,則給TEST賦值1,
  3. 如果TEST沒有值,且為debug模式,并且沒有設定debug_and_release,則在構建程序中,設定TEST為1,
  4. 如果IDE_LIBRARY_BASENAME為空,則為庫賦值基礎名為lib,
  5. 如果TEST等于1,則添加QTEST模塊功能,

設定源目錄和構建目錄

接下來是

IDE_SOURCE_TREE = $$PWD
isEmpty(IDE_BUILD_TREE) {
    sub_dir = $$_PRO_FILE_PWD_
    sub_dir ~= s,^$$re_escape($$PWD),,
    IDE_BUILD_TREE = $$clean_path($$OUT_PWD)
    IDE_BUILD_TREE ~= s,$$re_escape($$sub_dir)$,,
}

re_escape(string)

對每個string中的特殊正則運算式字符,使用反斜杠轉義,回傳轉義后的字串, 該函式是QRegExp::escape的包裝,

例如:

s1 = QRegExp::escape("bingo");   // s1 == "bingo"
s2 = QRegExp::escape("f(x)");    // s2 == "f\\(x\\)"

clean_path(path)

處理path,對目錄分隔符進行規范化(轉換為"/"),洗掉了多余的目錄分隔符,并且決議"."和".."(盡可能), 該函式是QDir::cleanPath的包裝,

另請閱absolute_path(), relative_path(), shell_path(), system_path().

我們在代碼后面插樁輸出陳述句

build_pass:message($$PWD) # 當前pri檔案所在目錄
build_pass:message($$OUT_PWD) # 生成makefile所在目錄
build_pass:message($$_PRO_FILE_) # 包含當前pri的pro所在路徑
build_pass:message($$_PRO_FILE_PWD_) # 包含當前pri的pro所在目錄

現在,我們來看一下部分輸出,

Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2
Project MESSAGE: F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info/bin
Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/bin/bin.pro
Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/bin

Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2
Project MESSAGE: F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info/src/app
Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/src/app/app.pro
Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/src/app

我們可以發現

  1. PWD沒有發生變化,
  2. 對比OUT_PWD和_PRO_FILE_PWD_,輸出目錄和源目錄的子檔案夾組織架構一樣,

下面我們分析pri中的陳述句

  1. 設定源目錄IDE_SOURCE_TREE,

  2. 如果構建目錄IDE_BUILD_TREE為空,

    1. 設定sub_dir,并進行替換,可以認為是從_PRO_FILE_PWD_減去PWD,剩下子檔案夾相對路徑,如bin/和app/,
    2. 初始化IDE_BUILD_TREE,并進行替換,可以認為是從OUT_PWD減去相對路徑,剩下相同的根目錄,

大家可以用我們上面的message輸出結果來簡單的計算下即可,

IDE_SOURCE_TREE為F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2,

IDE_BUILD_TREE為F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info,

設定IDE和INSTALLS相關路徑

接下來是

IDE_APP_PATH = $$IDE_BUILD_TREE/bin
osx {
    IDE_APP_TARGET   = "$$IDE_DISPLAY_NAME"

    # check if IDE_BUILD_TREE is actually an existing Qt Creator.app,
    # for building against a binary package
    exists($$IDE_BUILD_TREE/Contents/MacOS/$$IDE_APP_TARGET): IDE_APP_BUNDLE = $$IDE_BUILD_TREE
    else: IDE_APP_BUNDLE = $$IDE_APP_PATH/$${IDE_APP_TARGET}.app

    # set output path if not set manually
    isEmpty(IDE_OUTPUT_PATH): IDE_OUTPUT_PATH = $$IDE_APP_BUNDLE/Contents

    IDE_LIBRARY_PATH = $$IDE_OUTPUT_PATH/Frameworks
    IDE_PLUGIN_PATH  = $$IDE_OUTPUT_PATH/PlugIns
    IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/Resources
    IDE_DATA_PATH    = $$IDE_OUTPUT_PATH/Resources
    IDE_DOC_PATH     = $$IDE_DATA_PATH/doc
    IDE_BIN_PATH     = $$IDE_OUTPUT_PATH/MacOS
    copydata = https://www.cnblogs.com/codeForFamily/p/1

    LINK_LIBRARY_PATH = $$IDE_APP_BUNDLE/Contents/Frameworks
    LINK_PLUGIN_PATH  = $$IDE_APP_BUNDLE/Contents/PlugIns

    INSTALL_LIBRARY_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Frameworks
    INSTALL_PLUGIN_PATH  = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/PlugIns
    INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Resources
    INSTALL_DATA_PATH    = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Resources
    INSTALL_DOC_PATH     = $$INSTALL_DATA_PATH/doc
    INSTALL_BIN_PATH     = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/MacOS
    INSTALL_APP_PATH     = $$QTC_PREFIX/
} else {
    contains(TEMPLATE, vc.*):vcproj = 1
    IDE_APP_TARGET   = $$IDE_ID

    # target output path if not set manually
    isEmpty(IDE_OUTPUT_PATH): IDE_OUTPUT_PATH = $$IDE_BUILD_TREE

    IDE_LIBRARY_PATH = $$IDE_OUTPUT_PATH/$$IDE_LIBRARY_BASENAME/qtcreator
    IDE_PLUGIN_PATH  = $$IDE_LIBRARY_PATH/plugins
    IDE_DATA_PATH    = $$IDE_OUTPUT_PATH/share/qtcreator
    IDE_DOC_PATH     = $$IDE_OUTPUT_PATH/share/doc/qtcreator
    IDE_BIN_PATH     = $$IDE_OUTPUT_PATH/bin
    win32: /
        IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/bin
    else: /
        IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/libexec/qtcreator
    !isEqual(IDE_SOURCE_TREE, $$IDE_OUTPUT_PATH):copydata = 1

    LINK_LIBRARY_PATH = $$IDE_BUILD_TREE/$$IDE_LIBRARY_BASENAME/qtcreator
    LINK_PLUGIN_PATH  = $$LINK_LIBRARY_PATH/plugins

    INSTALL_LIBRARY_PATH = $$QTC_PREFIX/$$IDE_LIBRARY_BASENAME/qtcreator
    INSTALL_PLUGIN_PATH  = $$INSTALL_LIBRARY_PATH/plugins
    win32: /
        INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/bin
    else: /
        INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/libexec/qtcreator
    INSTALL_DATA_PATH    = $$QTC_PREFIX/share/qtcreator
    INSTALL_DOC_PATH     = $$QTC_PREFIX/share/doc/qtcreator
    INSTALL_BIN_PATH     = $$QTC_PREFIX/bin
    INSTALL_APP_PATH     = $$QTC_PREFIX/bin
}

我們可以發現上面的內容大部分是基于IDE_BUILD_TREE和QTC_PREFIX的,

代碼首先設定了可執行程式的目錄,

接下來,我們重點分析else分支的內容,

  1. 如果TEMPLATE包含vc.*,其實就是vcapp或vclib,設定vcproj為1,表示是vs工程,

  2. 設定可執行程式檔案名為IDE_ID(默認為qtcreator),

  3. 設定輸出路徑IDE_OUTPUT_PATH默認為IDE_BUILD_TREE,

  4. 設定IDE相關子檔案夾路徑,可以發現都是相對于IDE_OUTPUT_PATH的,

    image-20200229193843851
  5. 如果輸出路徑不是源目錄,則設定copydata為1,表示需要拷貝資料,

  6. 考慮到IDE_BUILD_TREE與IDE_OUTPUT_PATH可能不一樣,設定IDE庫和插件的鏈接路徑,

  7. 設定INSTALLS用的相關子檔案夾路徑,

設定字串宏

接下來是

RELATIVE_PLUGIN_PATH = $$relative_path($$IDE_PLUGIN_PATH, $$IDE_BIN_PATH)
RELATIVE_LIBEXEC_PATH = $$relative_path($$IDE_LIBEXEC_PATH, $$IDE_BIN_PATH)
RELATIVE_DATA_PATH = $$relative_path($$IDE_DATA_PATH, $$IDE_BIN_PATH)
RELATIVE_DOC_PATH = $$relative_path($$IDE_DOC_PATH, $$IDE_BIN_PATH)
DEFINES += $$shell_quote(RELATIVE_PLUGIN_PATH=\"$$RELATIVE_PLUGIN_PATH\")
DEFINES += $$shell_quote(RELATIVE_LIBEXEC_PATH=\"$$RELATIVE_LIBEXEC_PATH\")
DEFINES += $$shell_quote(RELATIVE_DATA_PATH=\"$$RELATIVE_DATA_PATH\")
DEFINES += $$shell_quote(RELATIVE_DOC_PATH=\"$$RELATIVE_DOC_PATH\")

shell_quote

在qmake中的介紹很簡單:為shell對arg加引號,當構建構建專案時,

在linux man page中的介紹:可讓您通過shell傳遞任意字串,shell不會更改它們, 這使您可以安全地處理帶有嵌入式空格或shell globbing字符的命令或檔案,

qmake定義字串宏

有時候,我們想定義字串宏,并在源代碼中進行使用,假設你想在qmake中定義字串宏,這里有三種途徑

image-20200229215423993

我們先來看一下qmake編譯得到的Makefile.Debug,符合makefile語法的形式

image-20200229215353865

現在我們來介紹下DEFINES中的含義:

  1. NAME1中第一個"對,告訴qmake引導里面的是字串,里面的\"對,是對引號的轉義,在makefile中變為",再里面的\\對,也是轉義,在makefile中變為\,在里面的\"同樣,最終變為",最終得到我們想要的字串,

  2. NAME2使用shell_quote()函式,該函式對引數加引號,

  3. NAME0對比NAME1,少了最外面的"對,這導致NAME0只能定義沒有空格的字串,如果存在空格,這會導致內容發生變化,中間多了個-D,

    qmake: DEFINES += NAME0=\"\\\"app1 .0\\\"\"
    makefile: -DNAME0="\"app1 -D.0\""
    

    此外,對于沒有空格的字串宏定義,我們甚至可以不需要最外層的引號轉義,

    qmake: DEFINES += NAME0=\\\"app1\\\"
    makefile: -DNAME0=\"app1\"
    

分析代碼:

  1. 設定了PLUGIN,LIBEXEC,DATA和DOC相對于BIN的相對路徑,譬如PLUGIN的為../lib/qtcreator/plugins,
  2. 使步驟1中的變數稱為字串,添加到DEFINES中,變為宏,

設定INCLUDEPATH

接下來是

INCLUDEPATH += \
    $$IDE_BUILD_TREE/src \ # for <app/app_version.h> in case of actual build directory
    $$IDE_SOURCE_TREE/src \ # for <app/app_version.h> in case of binary package with dev package
    $$IDE_SOURCE_TREE/src/libs \
    $$IDE_SOURCE_TREE/tools

win32:exists($$IDE_SOURCE_TREE/lib/qtcreator) {
    # for .lib in case of binary package with dev package
    LIBS *= -L$$IDE_SOURCE_TREE/lib/qtcreator
    LIBS *= -L$$IDE_SOURCE_TREE/lib/qtcreator/plugins
}

QTC_PLUGIN_DIRS_FROM_ENVIRONMENT = $$(QTC_PLUGIN_DIRS)
QTC_PLUGIN_DIRS += $$split(QTC_PLUGIN_DIRS_FROM_ENVIRONMENT, $$QMAKE_DIRLIST_SEP)
QTC_PLUGIN_DIRS += $$IDE_SOURCE_TREE/src/plugins
for(dir, QTC_PLUGIN_DIRS) {
    INCLUDEPATH += $$dir
}

QTC_LIB_DIRS_FROM_ENVIRONMENT = $$(QTC_LIB_DIRS)
QTC_LIB_DIRS += $$split(QTC_LIB_DIRS_FROM_ENVIRONMENT, $$QMAKE_DIRLIST_SEP)
QTC_LIB_DIRS += $$IDE_SOURCE_TREE/src/libs
for(dir, QTC_LIB_DIRS) {
    INCLUDEPATH += $$dir
}

CONFIG += \
    depend_includepath \
    no_include_pwd

INCLUDEPATH

指定編譯專案時應搜索的#include目錄,

例如:

INCLUDEPATH = c:/msdev/include d:/stl/include

要指定包含空格的路徑,請使用Whitespace中所述的技術對路徑添加引號,

win32:INCLUDEPATH += "C:/mylibs/extra headers"
unix:INCLUDEPATH += "/home/user/extra headers"

Whitespace

通常,空格在變數賦值是分隔值, 要指定包含空格的值,必須將值用雙引號引起來:

DEST = "Program Files"

引號引起來的文本在變數所保存的值串列中被視為單個條目,使用類似的方法可處理包含空格的路徑,尤其是在為Windows平臺定義INCLUDEPATH 和LIBS變數時:

win32:INCLUDEPATH += "C:/mylibs/extra headers"
unix:INCLUDEPATH += "/home/user/extra headers"

<app/app_version.h>

我們在原始碼中搜索app_version.h,可以在src/app/app.pro中發現定義:

# an hidden functionality in qmake that take a file with '.in' suffix
# and creates a copy in the build directory without the suffix in which
# variables have been expanded
QMAKE_SUBSTITUTES += $$PWD/app_version.h.in

注釋很明白,qmake中的隱藏功能,對于后綴為".in"的檔案,在構建目錄中創建一個沒有后綴的副本,并對其中變數進行擴展,

那么app_version.h.in就變為了app_version.h,現在我們簡單看下該檔案

...
const char IDE_DISPLAY_NAME[] = \"$${IDE_DISPLAY_NAME}\";
const char IDE_ID[] = \"$${IDE_ID}\";
const char IDE_CASED_ID[] = \"$${IDE_CASED_ID}\";
#define IDE_VERSION $${QTCREATOR_VERSION}
...

上面截取的內容,就是對qtcreator.pri中定義的變數,進行了展開,賦值給同名的char []變數,

其實app_version.h.in中包含了Qt Creator的相關IDE版本資訊,

代碼首先添加#include搜索路徑,特別說明<app/app_version.h>,為了參考構建目錄中創建的app_version.h,需要在INCLUDEPATH中添加$$IDE_BUILD_TREE/src,

image-20200301092319099

展開的app_version.h的內容如下

image-20200301092609307

接下來的判斷win32系統下,是否在源目錄中存在lib/qtcreator子目錄,存在就過濾重復的鏈接路徑,

接下來是對插件檔案夾QTC_PLUGIN_DIRS按照分隔符QMAKE_DIRLIST_SEP進行分隔,得到插件檔案夾串列,上述可能為空,所以又添加了源目錄下的src/plugins子目錄,現在QTC_PLUGIN_DIRS至少為src/plugins,

for陳述句和c++11中的新增的for陳述句很像,不再展開,意思也很明確,遍歷插件檔案夾串列中的每個條目,添加進#include搜索路徑,

對于QTC_LIB_DIRS,同QTC_PLUGIN_DIRS,

CONFIG的depend_includepath和no_include_pwd含義,見上面的CONFIG子小節,

這么操作后,對于每個包含qtcreator.pri的子專案,可能很方便的統一添加相同的plugins和libs中的頭檔案,

設值庫鏈接路徑和編譯選項

接下來是

LIBS *= -L$$LINK_LIBRARY_PATH  # Qt Creator libraries
exists($$IDE_LIBRARY_PATH): LIBS *= -L$$IDE_LIBRARY_PATH  # library path from output path

!isEmpty(vcproj) {
    DEFINES += IDE_LIBRARY_BASENAME=\"$$IDE_LIBRARY_BASENAME\"
} else {
    DEFINES += IDE_LIBRARY_BASENAME=\\\"$$IDE_LIBRARY_BASENAME\\\"
}

DEFINES += \
    QT_CREATOR \
    QT_NO_CAST_TO_ASCII \
    QT_RESTRICTED_CAST_FROM_ASCII \
    QT_DISABLE_DEPRECATED_BEFORE=0x050600 \
    QT_USE_FAST_OPERATOR_PLUS \
    QT_USE_FAST_CONCATENATION

unix {
    CONFIG(debug, debug|release):OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared
    CONFIG(release, debug|release):OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared

    CONFIG(debug, debug|release):MOC_DIR = $${OUT_PWD}/.moc/debug-shared
    CONFIG(release, debug|release):MOC_DIR = $${OUT_PWD}/.moc/release-shared

    RCC_DIR = $${OUT_PWD}/.rcc
    UI_DIR = $${OUT_PWD}/.uic
}

msvc {
    #Don't warn about sprintf, fopen etc being 'unsafe'
    DEFINES += _CRT_SECURE_NO_WARNINGS
    QMAKE_CXXFLAGS_WARN_ON *= -w44996
    # Speed up startup time when debugging with cdb
    QMAKE_LFLAGS_DEBUG += /INCREMENTAL:NO
}

qt {
    contains(QT, core): QT += concurrent
    contains(QT, gui): QT += widgets
}

QBSFILE = $$replace(_PRO_FILE_, \\.pro$, .qbs)
exists($$QBSFILE):DISTFILES += $$QBSFILE

!isEmpty(QTC_PLUGIN_DEPENDS) {
    LIBS *= -L$$IDE_PLUGIN_PATH  # plugin path from output directory
    LIBS *= -L$$LINK_PLUGIN_PATH  # when output path is different from Qt Creator build directory
}

我們依次分析:

  1. LIBS中添加qt creator的lib庫鏈接路徑,并去除重復項,

  2. DEFINES添加字串宏,看樣子vcproj下宏的定義不需要對引號進行轉義哈,

  3. DEFINES添加其他相關宏,看樣子就是用來設定編譯選項,

  4. unix系統下,首先分別對debug和release模式設定對應的obj檔案夾,然后設定qt資源編譯輸出檔案RCC和用戶介面檔案UI的檔案夾,

  5. msvc平臺下,設定相關編譯指令,

  6. 目標是Qt應用程式或庫,并且包含core核心模塊或gui影像用戶界面模塊,則添加concurrent并發模塊和widget視窗模塊,

  7. 對于每個pro檔案,替換擴展名為qbs,如果同一目錄下存在該qbs檔案,則添加到dist目標檔案串列中,

  8. 最后,如果插件依賴QTC_PLUGIN_DEPENDS有值,則LIBS添加插件依賴路徑,并去除重復項,

這么操作后,對于每個包含qtcreator.pri的子專案,可能很方便的統一添加相同的庫鏈接路徑和編譯選項,

解決插件和庫依賴

接下來是

# recursively resolve plugin deps
done_plugins =
for(ever) {
    isEmpty(QTC_PLUGIN_DEPENDS): \
        break()
    done_plugins += $$QTC_PLUGIN_DEPENDS
    for(dep, QTC_PLUGIN_DEPENDS) {
        dependencies_file =
        for(dir, QTC_PLUGIN_DIRS) {
            exists($$dir/$$dep/$${dep}_dependencies.pri) {
                dependencies_file = $$dir/$$dep/$${dep}_dependencies.pri
                break()
            }
        }
        isEmpty(dependencies_file): \
            error("Plugin dependency $$dep not found")
        include($$dependencies_file)
        LIBS += -l$$qtLibraryName($$QTC_PLUGIN_NAME)
    }
    QTC_PLUGIN_DEPENDS = $$unique(QTC_PLUGIN_DEPENDS)
    QTC_PLUGIN_DEPENDS -= $$unique(done_plugins)
}

# recursively resolve library deps
done_libs =
for(ever) {
    isEmpty(QTC_LIB_DEPENDS): \
        break()
    done_libs += $$QTC_LIB_DEPENDS
    for(dep, QTC_LIB_DEPENDS) {
        dependencies_file =
        for(dir, QTC_LIB_DIRS) {
            exists($$dir/$$dep/$${dep}_dependencies.pri) {
                dependencies_file = $$dir/$$dep/$${dep}_dependencies.pri
                break()
            }
        }
        isEmpty(dependencies_file): \
            error("Library dependency $$dep not found")
        include($$dependencies_file)
        LIBS += -l$$qtLibraryName($$QTC_LIB_NAME)
    }
    QTC_LIB_DEPENDS = $$unique(QTC_LIB_DEPENDS)
    QTC_LIB_DEPENDS -= $$unique(done_libs)
}

注釋說的很明白,一個遞回解決插件依賴,一個遞回解決庫依賴,

首先我們來看下依賴檔案示例,源目錄src\plugins\cppeditor\cppeditor_dependencies.pri,

QTC_PLUGIN_NAME = CppEditor
QTC_LIB_DEPENDS += \
    extensionsystem \
    utils \
    cplusplus
QTC_PLUGIN_DEPENDS += \
    texteditor \
    coreplugin \
    cpptools \
    projectexplorer
QTC_TEST_DEPENDS += \
    qmakeprojectmanager

內容顯而易見,首先指定插件名稱(同檔案夾名,用于查找),然后在依賴項指定其他插件,

首先,我們分析插件依賴,for(ever)顧名思義是死回圈,只能通過break()或者error()退出,

  1. 如果QTC_PLUGIN_DEPENDS為空,則退出回圈,

  2. 遍歷QTC_PLUGIN_DEPENDS中的每一個依賴dep,

    1. 對于dep,遍歷QTC_PLUGIN_DIRS中的每一個插件檔案夾dir,譬如源目錄中的src/plugins,如果{dep}子檔案夾中存在{dep}_dependencies.pri檔案,則找到需要的依賴,

    2. 如果遍歷完畢都沒有找到,則報錯退出,

    3. 如果找到了,則include加載之,并從依賴檔案中獲取QTC_PLUGIN_NAME,添加到LIBS用于鏈接,

  3. 由于include時,會加入該插件的依賴插件,可能重復,所以需要去除重復項,

  4. 去除已經解決依賴的插件,

  5. 回到步驟1,重復,直到每一個依賴都被解決,

這段代碼,允許用戶在編譯時直接通過QTC_PLUGIN_DEPENDS指定插件依賴,

庫依賴函式同上,


原創造福大家,共享改變世界

獻出一片愛心,溫暖作者心靈


轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/14321.html

標籤:其他

上一篇:和科比一起打籃球Github精美作品

下一篇:qt creator原始碼全方面分析(3-3)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more