xmake新增對WDK驅動編譯環境支持
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)
裏面介紹了兩種環境:
- 下載WDK開發包,直接安裝到系統並集成到VS的開發環境中
- 下載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_values
和add_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驅動編譯環境支持