1. 程式人生 > >xmake新增對WDK驅動編譯環境支持

xmake新增對WDK驅動編譯環境支持

說明 down 插件 level x86 可讀性 ocs 不能 根據

xmake v2.2.1新版本現已支持WDK驅動編譯環境,我們可以直接在系統原生cmd終端下,執行xmake進行驅動編譯,甚至配合vscode, sublime text, IDEA等編輯器+xmake插件去開發WDK驅動。

下面是xmake支持的一些編輯器插件,用戶可以挑選自己喜歡的編輯器配合xmake來使用:

  • xmake-idea
  • xmake-vscode
  • xmake-sublime

WDK環境介紹

首先,我們先簡單介紹下WDK10的編譯環境的安裝方式,我們可以看下微軟的官方文檔:Download the Windows Driver Kit (WDK)

裏面介紹了兩種環境:

  1. 下載WDK開發包,直接安裝到系統並集成到VS的開發環境中
  2. 下載EWDK iso鏡像(內含完整WDK開發環境),直接掛載後,運行LaunchBuildEnv進入cmd環境

xmake對於這兩種環境都是完全支持的,如果用戶直接下載安裝WDK環境到本地系統,那麽不需要任何配置,只需要執行:

$ xmake

xmake會自動檢測到WDK的安裝環境,然後編譯相關驅動項目,如果用戶是直接掛載的EWDK iso開發鏡像,那麽編譯前配置下WDK所在路徑即可:

$ xmake f --wdk="G:\Program Files\Windows Kits\10" 
$ xmake

更多詳情可以參考:#159

WDK驅動實例

xmake支持umdf, kmdf, wdm驅動項目的維護,也是采用一系列擴展的WDK rule規則來實現,類似:Qt編譯環境的支持。

目前支持的規則有如下這些:

  • rule("wdk.driver")
  • rule("wdk.binary")
  • rule("wdk.static")
  • rule("wdk.shared")

  • rule("wdk.env.kmdf")
  • rule("wdk.env.umdf")
  • rule("wdk.env.wdm")

其中,wdk.env.*規則描述驅動編譯的環境,wdk.driver, wdk.static描述編譯的目標類型,兩者可以互相結合使用,我們既可以用來編譯驅動程序,也可以用來編譯基於wdk環境的靜態庫、可執行程序。

下面,通過一些例子可以簡單看下使用方式,具體例子代碼見wdk-examples,其中的項目代碼是從Windows-driver-samples移植過來的。

umdf驅動程序

我們通過同時應用wdk.driver, wdk.env.umdf規則,來描述這個target作為umdf驅動程序來編譯:

target("echo")
    add_rules("wdk.driver", "wdk.env.umdf")
    add_files("driver/*.c") 
    add_files("driver/*.inx")
    add_includedirs("exe")

我們也可以通過wdk.binary, wdk.env.umdf規則,來描述一個基於wdk/umdf編譯環境的上層可執行程序:

target("app")
    add_rules("wdk.binary", "wdk.env.umdf")
    add_files("exe/*.cpp") 

kmdf驅動程序

kmdf的項目描述跟剛才的umdf類似,只需要把wdk.env.umdf換成wdk.env.kmdf的環境規則就行了。

target("nonpnp")
    add_rules("wdk.driver", "wdk.env.kmdf")
    add_values("wdk.tracewpp.flags", "-func:TraceEvents(LEVEL,FLAGS,MSG,...)")
    add_values("wdk.tracewpp.flags", "-func:Hexdump((LEVEL,FLAGS,MSG,...))")
    add_files("driver/*.c", {rule = "wdk.tracewpp"}) 
    add_files("driver/*.rc")

target("app")
    add_rules("wdk.binary", "wdk.env.kmdf")
    add_files("exe/*.c") 
    add_files("exe/*.inf")

這個項目裏面,需要特別註意的是,我們還用到了tracewpp對一些源文件的預處理,對於tracewpp任務的介紹,可以看下官方文檔tracewpp-task,這裏就不多做說明了。

我們直接說下,如何在xmake的項目裏應用tracewpp規則吧,由於這個規則並不是對當前target所有源文件都去處理的,因此我們只對需要的源文件進行應用這個規則,例如:

add_files("driver/*.c", {rule = "wdk.tracewpp"}) 
add_files("driver/dir/test.c", {rule = "wdk.tracewpp"}) 

當然tracewpp還會有一些自己的特殊選項,用戶有時候需要自己根據需要來設置,例如:

add_values("wdk.tracewpp.flags", "-func:TraceEvents(LEVEL,FLAGS,MSG,...)")
add_values("wdk.tracewpp.flags", "-func:Hexdump((LEVEL,FLAGS,MSG,...))")

關於add_values的使用說明,可以看下文檔:add_values和set_values的使用說明,簡單來說,就是用來給對應規則傳遞擴展參數設置的。

wdm驅動程序

wdm的項目描述也跟umdf類似,只需要把wdk.env.umdf換成wdk.env.wdm的環境規則就行了。

target("kcs")
    add_rules("wdk.driver", "wdk.env.wdm")
    add_values("wdk.man.flags", "-prefix Kcs")
    add_values("wdk.man.resource", "kcsCounters.rc")
    add_values("wdk.man.header", "kcsCounters.h")
    add_values("wdk.man.counter_header", "kcsCounters_counters.h")
    add_files("*.c", "*.rc", "*.man") 

上述代碼,還添加了一些.man文件用來預處理一些manifest,具體相關的任務藐視,可以參考官方文檔說明:ctrpp-task。
裏面也有相關的一些特殊配置選項,目前xmake支持的配置有:

add_values("wdk.man.flags", "-prefix Kcs")
add_values("wdk.man.prefix", "Kcs")
add_values("wdk.man.resource", "kcsCounters.rc")
add_values("wdk.man.header", "kcsCounters.h")
add_values("wdk.man.counter_header", "kcsCounters_counters.h")

下面再貼個wdm驅動的例子,這個例子中,除了之前講的tracewpp,我們還加了.mof的文件處理,對於.mof文件,xmake會自動應用內置的wdk.mof規則,詳細說明見:mofcomp-task

target("msdsm")
    add_rules("wdk.driver", "wdk.env.wdm")
    add_values("wdk.tracewpp.flags", "-func:TracePrint((LEVEL,FLAGS,MSG,...))")
    add_files("*.c", {rule = "wdk.tracewpp"}) 
    add_files("*.rc", "*.inf")
    add_files("*.mof|msdsm.mof")
    add_files("msdsm.mof", {values = {wdk_mof_header = "msdsmwmi.h"}}) 

對於.mof的配置選項,有些配置並不是全局應用於target的,對每個文件需要單獨配置,這個時候,就不能直接使用set_valuesadd_values了,需要在add_files中設置相關values。

add_files("msdsm.mof", {values = {wdk_mof_header = "msdsmwmi.h"}}) 
add_files("msdsm.mof", {values = {["wdk.mof.header"] = "msdsmwmi.h"}}) 

上面兩種設置方式都是有效的,由於受限於lua的語法,為了考慮可讀性,xmake通過_下劃線來簡化key的設置,這個設置相當於單獨對msdsm.mof文件設置了set_values("wdk.mof.header", "msdsmwmi.h")

生成驅動包

如果平常開發調試通過後,我們也可以通過以下命令生成.cab驅動包來發布驅動程序:

$ xmake [p|package]
$ xmake [p|package] -o outputdir

輸出的目錄結構如下:

  - drivers
    - sampledsm
       - debug/x86/sampledsm.cab
       - release/x64/sampledsm.cab
       - debug/x86/sampledsm.cab
       - release/x64/sampledsm.cab

驅動簽名

默認編譯我們是禁用簽名的,如果想要在編譯的同時,啟用簽名,可以通過set_values("wdk.sign.mode", ...)設置簽名模式來啟用。
只要啟用了簽名,那麽平常的驅動構建、包括打包生成的.cab文件,都會自動對其進行簽名。

測試簽名

測試簽名一般本機調試時候用,可以使用xmake自帶的test證書來進行簽名,例如:

target("msdsm")
    add_rules("wdk.driver", "wdk.env.wdm")
    set_values("wdk.sign.mode", "test")
    add_files("src/*.c")

不過這種情況下,需要用戶手動在管理員模式下,執行一遍:$xmake l utils.wdk.testcert install,來生成和註冊test證書到本機環境。
這個只需要執行一次就行了,後續就可以正常編譯和簽名了。

當然也可以使用本機已有的有效證書去簽名,例如直接從sha1來選擇合適的證書進行簽名:

target("msdsm")
    add_rules("wdk.driver", "wdk.env.wdm")
    set_values("wdk.sign.mode", "test")
    set_values("wdk.sign.thumbprint", "032122545DCAA6167B1ADBE5F7FDF07AE2234AAA")
    add_files("src/*.c")

或者從store/company來選擇合適的證書進行簽名:

target("msdsm")
    add_rules("wdk.driver", "wdk.env.wdm")
    set_values("wdk.sign.mode", "test")
    set_values("wdk.sign.store", "PrivateCertStore")
    set_values("wdk.sign.company", "tboox.org(test)")
    add_files("src/*.c")

正式簽名

對於正式簽名,我們可以通過指定對應的正式簽名證書文件進行簽名:

target("msdsm")
    add_rules("wdk.driver", "wdk.env.wdm")
    set_values("wdk.sign.mode", "release")
    set_values("wdk.sign.company", "xxxx")
    set_values("wdk.sign.certfile", path.join(os.projectdir(), "xxxx.cer"))

生成低版本驅動

如果想在wdk10環境編譯生成win7, win8等低版本系統支持的驅動,我們可以通過設置wdk.env.winver來切換系統版本:

set_values("wdk.env.winver", "win10")
set_values("wdk.env.winver", "win10_rs3")
set_values("wdk.env.winver", "win81")
set_values("wdk.env.winver", "win8")
set_values("wdk.env.winver", "win7")
set_values("wdk.env.winver", "win7_sp1")
set_values("wdk.env.winver", "win7_sp2")
set_values("wdk.env.winver", "win7_sp3")

如果覺得每次修改xmake.lua去切換編譯非常繁瑣,我們也可以手動指定編譯的目標程序支持的windows版本,來快速切換到對應的版本進行編譯:

$ xmake f --wdk_winver=[win10_rs3|win8|win7|win7_sp1]
$ xmake

目前支持的一些版本有:nt4, win2k, winxp, ws03, win6, vista, ws08, longhorn, win7, win8, win81, winblue, win10

然後通過_下劃線,組合指定子版本:sp1, sp2, sp3, th2, rs1, rs2, rs3

xmake還提供了一些內置的版本值,在切換winver版本是,會自動改變,用於一些更加定制化的配置需求,例如:

target("test")
    
    on_load(function (target)
        local winnt_version = target:values("wdk.env.winnt_version")
        if winnt_version > "0x0A000000" then
            target:add("defines", "TEST")
        end
    end)

上述代碼通過判斷WIN32_WINNT的版本值,來定制添加一些相關配置,這個版本值會根據wdk.env.winver的配置自動適配更新,目前提供的這些內置版本值還有:

target:values("wdk.env.winnt_version"): WIN32_WINNT
target:values("wdk.env.ntddi_version"): NTDDI_VERSION
target:values("wdk.env.winver_version"): WINVER

關於更多xmake下WDK開發相關介紹,請參考文檔:WDK驅動程序開發

原文出處:http://tboox.org/cn/2018/06/14/support-wdk/

xmake新增對WDK驅動編譯環境支持