答案很簡單:在程序一中,unittests實際上是由運行程序在程序2中運行的,它們並不是因爲單元測試函數從未被調用過,因爲聲明瞭自己的WinMain(甚至是extern C)main)繞過運行時初始化和設置,通常在它調用在C main中完成的D主代碼之前自動完成。
打開您的dmd zip並獲取文件dmd2/src/druntime/src/rt/dmain2.d。找到函數_d_run_main()。
當啓動一個具有常規D main的D程序時,編譯器會插入一個調用_d_run_main()的C main。這個功能,你可以看到翻翻源,做了一堆東西:
- 它初始化浮點硬件模式d預計
- 它格式化的命令行參數爲d弦
- 它初始化運行時間
- 它運行單元測試< < ---對你來說非常重要!
- 它運行d主裹在try/catch塊爲默認異常處理
- 它終止運行時
- 它刷新輸出並返回
是,在線399(的版本我有,可能是你的druntime的源代碼版本稍有不同),你會看到這幾行:
if (rt_init() && runModuleUnitTests())
tryExec({ result = mainFunc(args); });
是的,單元測試是從rt_init(又稱Runtime.initialize單獨運行)。編譯器-unittest開關工作的方式是僅編譯unittest函數,因此runModuleUnitTests會看到一堆空測試,它會跳過它。因此,您可以在自定義主體中調用該函數,而不用擔心編譯器開關。
既然你有一個自定義的主,並沒有調用runModuleUnitTests
(定義在core.runtime
btw),單元測試從未發生。他們之前叫D主,但仍在c main或贏主。
我的建議是避免在D中使用WinMain
,而寧願編寫常規D電源。您可以使用API函數GetCommandLineW
和GetModuleHandle
傳遞給WinMain
的參數。 (nCmdShow
很少使用無論如何,我認爲hPrevInstance
是從16位天遺留殘留物,所以我懷疑你會關心他們呢!)
的WinMain
存在也預示着你正在寫一個GUI鏈接程序,因此應該使用Windows子系統 - 你不能獲得控制檯。您也可以通過在Windows 32位編譯時將-L/SUBSYSTEM:WINDOWS:5.0
傳遞給dmd來明確地執行此操作。 (/ SUBSYSTEM參數是optlink的開關之一。)在Windows 64上,我不確定,但如果不相同,它可能類似 - 請檢查Microsoft鏈接器的文檔以選擇子系統,我相信它在那裏。
在該鏈接器開關和兩個API調用來獲取參數之間,您不再需要WinMain,所以它可以爲您節省重新實現運行時的函數自身的功能的麻煩。
如果您確實想要使用它,有兩種選擇:只需撥打_d_run_main
- 查看它期望的簽名的源代碼。它需要一個指向主函數的指針,所以你可以重用所有這些。或者,您可以import core.runtime;
並自己撥打Runtime.initialize(); runModuleUnitTests(); your main here... Runtime.terminate();
。不要忘記檢查返回值並處理異常!您需要按照正確的順序執行並正確處理錯誤,否則您將看到崩潰。
所有這一切同樣適用,如果你正在編寫自己的extern(C) main
以及你自己的WinMain
。
雖然如此,你可能會更好地避免它,只需編寫一個常規的D主函數,並使用鏈接器開關關閉gui應用程序中的控制檯。
你是否也在調試模式下編譯? –
是的,我也直接用'dmd'('dmd -unittest winmain.d')在Visual Studio外編譯 –
用'dmd -debug -unittest winmain.d'試試 –