前一篇文章我學到一個 .NET 組件編譯名詞 - Determinism。是指 .NET 編譯組件時停用加入 Timestamp 及隨機產生的 GUID 的做法,改以原始碼內容、工作路徑... 等條件為依據,確保相同程式碼在相同環境編譯出來的組件二進位內容完全一致,這有助於識別組件是否來自可信任來源(例如:配合雜湊碼驗證),或是某些比對組件二進位差異決定編譯步驟的連續編譯系統。

光看理論沒實地驗證覺得心虛,反正難度不高,動手簡單實驗觀察一下心裡才踏實。我開了一個 .NET Framework Class Library 專案 - FooLibrary。修改 FooLibrary.csproj 以下兩處設定,分別存成 FooLibraryD1.csproj、FooLibraryD2.csproj、FooLibraryND1.csproj、FooLibraryND2.csproj 四個檔案:

四個 FooLibrary*.csproj 的設定差異如下,AssemblyVersion 則寫死 1.0.0.0 (要同時測試 Deterministic = true/false 不能自動跳號):

專案DeterministicOutputPath
FooLibraryD1.csprojtruebin\DebugD1\
FooLibraryD2.csprojtruebin\DebugD2\
FooLibraryND1.csprojfalsebin\DebugND1\
FooLibraryND2.csprojfalsebin\DebugND2\

用一個 DOS 批次檔,使用 MSBuild 依序建置四個 csproj 產生 FooLibrary.dll 分別寫入各自 bin\DebugD* 目錄,稍後再比對各目錄的 FooLibrary.dll,即可驗證二進位內容是否完全相同。(刪除 obj 目錄以確保 MSBuild 不會沿用前次編譯的結果)

msbuild FooLibraryD1.csproj
rmdir /s /q obj
msbuild FooLibraryD2.csproj
rmdir /s /q obj
msbuild FooLibraryND1.csproj
rmdir /s /q obj
msbuild FooLibraryND2.csproj
rmdir /s /q obj

依據理論,DebugD1 與 DebugD2 目錄下的 FooLibrary.dll 使用 <Deterministic>true</Deterministic> 編譯 true,理應完全相同;而 DebugND1 與 DebugND2 為 <Deterministic>false</Deterministic>,每次編譯結果都不會相同。使用 File Compare DOS 工具驗證,一如預期,DebugD1 與 DebugD2 相同,DebugND1 與 DebugND2 不同,實驗成功。

Experiment of how .NET compiler deterministic parameter affects assembly binary.


Comments

Be the first to post a comment

Post a comment