答案很简单:在程序一中,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'试试 –