- 语言运行时
- 标准库
- JIT编译
- 编译器
【免费下载链接】runtime
.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
本文是 dotnet/runtime 仓库中 CoreCLR 测试体系的 Unix 平台操作指南,覆盖从构建 CoreCLR 本体、编译托管测试(含-test/-dir/-tree子集选择)、生成Core_Root布局,到批量运行与单测调试、以及 PAL 层原生测试的完整链路。读完本文,你将掌握src/tests/build.sh、src/tests/run.sh、runpaltests.sh等核心脚本的用法与底层行为,能够在 Linux、macOS、FreeBSD 上独立完成 CoreCLR 的测试构建、运行与问题定位。
前置:先构建 CoreCLR 本体
所有测试都运行在你自建的 CoreCLR 运行时之上,因此第一步是完成 CoreCLR 产品构建。按 CoreCLR 构建指南 中的说明执行即可,核心命令是:
./build.sh -subset clr <其他参数>从构建指南可知,脚本默认构建Debug配置(无优化、断言全开);若目标是跑测试,推荐使用 CoreCLR 独有的Checked配置——它保留断言但开启原生编译优化,运行速度远快于 Debug,也是 CI 流水线运行测试的常规模式:
./build.sh -subset clr -configuration Checked构建产物位于artifacts/bin/coreclr/<OS>.<架构>.<配置>,其中corerun(命令行宿主)、libcoreclr.so/libcoreclr.dylib(运行时本体)、System.Private.CoreLib.dll是测试运行时的关键组件。完整的测试操作步骤可参见 CoreCLR 测试总览,本文聚焦 Unix 平台实操细节。
构建测试套件
构建测试需要 .NET CLI(Dotnet CLI)。如果目标架构或操作系统本身不支持 Dotnet,可以在任意平台先构建测试再拷贝过去。在 Unix 上构建测试只需:
./src/tests/build.sh默认情况下,测试构建使用Release作为 libraries(类库)配置。要改用其他配置,通过LibrariesConfiguration属性指定,例如:
./src/tests/build.sh /p:LibrariesConfiguration=Debug注意该参数是直接透传给 MSBuild 的(/p:前缀),因此与脚本自有的短横线风格参数不同。
默认只构建Priority 0(优先级 0)的测试,要同时构建优先级 1 的测试:
./src/tests/build.sh -priority1从 src/tests/build.sh 的源码可以印证这套行为:脚本通过__Priority变量记录优先级(默认__Priority=0),所有测试二进制输出统一放入artifacts/tests/coreclr/<OS>.<架构>.<配置>,构建日志(.log/.wrn/.err/.binlog)则落在artifacts/log下。脚本还导出了__TestDir、__SkipManaged、__BuildTestProject等环境变量供 MSBuild 侧消费,最终调用eng/common/msbuild.sh驱动src/tests/build.proj的TestBuild目标,并以--warnAsError false关闭告警即错,避免仓库中历史遗留的告警阻塞测试构建。
生成 Core_Root
src/tests/build.sh会在测试构建过程中生成Core_Root目录,其中包含运行测试所需的测试宿主corerun、类库以及 coreclr 产品二进制。如果只想生成 Core_Root 而不构建测试,使用generatelayoutonly参数:
./src/tests/build.sh generatelayoutonly输出位于:
<仓库根>/artifacts/tests/coreclr/<os>.<arch>.<configuration>/Tests/Core_Root例如 Linux x64 Checked 构建对应artifacts/tests/coreclr/linux.x64.Checked/Tests/Core_Root。在 src/tests/build.sh 中,-generatelayoutonly会将__GenerateLayoutOnly置 1,从而跳过原生组件与托管测试的构建,只执行布局生成。在跑测试前,Core_Root必须由本次测试构建正确生成,它是单测入口脚本定位运行时与类库的依据。
构建测试子集
全量构建src/tests下的整个测试树非常耗时(-priority1模式下尤其明显),而且在只改某一个测试时毫无必要。为此src/tests/build.sh提供了三种限定构建范围的选项,可多次指定,也可用分号分隔多个路径:
1)-test:<测试项目>—— 构建单个测试项目
参数为项目文件路径,绝对路径或相对src/tests的相对路径均可。
示例:
src/tests/build.sh -test:JIT/Methodical/divrem/div/i4div_cs_do.csproj;JIT/Methodical/divrem/div/i8div_cs_do.csproj2)-dir:<测试目录>—— 构建目录内的全部测试项目
参数为目录路径,同样支持绝对路径或相对src/tests的相对路径。
示例:
src/tests/build.sh -dir:JIT/Methodical/Arrays/huge;JIT/Methodical/divrem/div3)-tree:<根目录>—— 构建子树下的全部测试项目
参数为子树根路径,构建该子树范围内的所有测试项目。
示例:
src/tests/build.sh -tree:baseservices/exceptions;JIT/Methodical从 src/tests/build.sh 的参数解析逻辑可见,-test/-dir/-tree分别累积到__BuildTestProject、__BuildTestDir、__BuildTestTree三个变量,再通过%3B(分号转义)拼接传给 MSBuild,最终以-test/-dir/-tree对应的 MSBuild 属性限定TestBuild目标的作用范围。
优先级过滤与子集正交
请特别注意:优先级过滤与测试子集指定是相互正交的。即使你明确指定构建某个测试,只要它是 Pri1 测试,就必须同时在命令行带上-priority1,否则该测试会被跳过。这看起来有些反直觉,但项目文档明确指出,临时"修复"这一行为弊大于利,且团队长期目标是彻底取消测试优先级机制。
构建单个测试
开发过程中经常需要快速构建单个测试。构建所需的全部工具都在coreclr子集产物中,可以直接像使用 MSBuild 一样使用仓库根目录的./dotnet.sh msbuild,但有几点注意事项。
重要提醒:必须传/p:TargetOS=[osx|linux]。
构建单个测试:
./dotnet.sh msbuild src/tests/path-to-proj-file /p:TargetOS=<TargetOS> /p:Configuration=<BuildType>例如在 Linux x64 上以 Checked 配置构建某个 JIT 测试:
./dotnet.sh msbuild src/tests/JIT/Methodical/divrem/div/i4div_cs_do.csproj /p:TargetOS=linux /p:Configuration=Checked除了生成测试程序集,该命令还会在测试输出目录中、紧邻测试程序集生成一个.sh启动脚本(Windows 上对应.cmd)。测试输出目录位于<仓库根>/artifacts/tests/coreclr/<os>.<arch>.<configuration>,其子路径与测试在源码树中的位置一一对应。关于测试入口脚本的生成条件,可参考 src/tests/Directory.Build.targets 中的GenerateRunScript逻辑:默认测试类型BuildAndRun会同时产出可执行文件与运行脚本。
运行测试
以下指令假设 Unix 机器上 CoreCLR 仓库已克隆到/mnt/coreclr(实际使用时可替换为你的仓库路径)。测试构建完成后,src/tests/build.sh已正确设置好Core_Root目录,接着即可批量运行:
./src/tests/run.sh x64 checked其中第一个位置参数是架构(如x64),第二个是构建配置(debug/checked/release)。查看全部参数请使用帮助命令:
./src/tests/run.sh -h从 src/tests/run.sh 的源码看,run.sh实际上是一个参数转译器:它解析位置参数与长选项后,最终调用跨平台的python3 src/tests/run.py完成实际执行(脚本会优先探测python3,否则退回python)。它支持的选项非常丰富,与测试调试强相关的主要有:
| 选项 | 作用 |
|---|---|
--sequential | 串行运行测试(默认并行) |
--jitstress=<n> | 以DOTNET_JitStress=n运行(JIT 压力测试) |
--jitstressregs=<n> | 以DOTNET_JitStressRegs=n运行 |
--jitminopts | 以DOTNET_JITMinOpts=1运行 |
--gcstresslevel=<n> | 以DOTNET_GCStress=n运行(GC 压力测试,0/1/2/4/8/16 分别代表不同压力档位) |
--gcname=<n> | 以DOTNET_GCName=n指定 GC 实现 |
--useServerGC | 启用服务器 GC(DOTNET_gcServer=1) |
--ilasmroundtrip | 对测试做 ilasm 往返(round trip)检查 |
--runincontext | 在每个可卸载的AssemblyLoadContext中运行测试 |
--tieringtest | 运行测试以促使 tier1 重新 JIT |
--runcrossgen2tests | 运行 Crossgen2 编译的 ReadyToRun 测试 |
--tree=<路径> | 只运行指定子树下的测试(如JIT/Regression) |
--testRootDir=<路径> | 指定测试构建根目录 |
--coreRootDir=<路径> | 指定 Core_Root 位置 |
--test-env=<路径> | 指定设置测试环境变量的脚本 |
批跑结束后,结果报告会生成在artifacts/log下(TestRun_<架构>_<配置>.html),失败测试清单写入TestRunResults_<OS>_<架构>_<配置>.err;单个测试的详细输出则落在测试根目录下的Reports子目录中。
不支持与暂时禁用的测试
为了能在单一目标平台上构建所有目标平台的测试,测试项目使用条件属性:
<CLRTestTargetUnsupported Condition="...">true</CLRTestTargetUnsupported>该属性会在默认构建中禁用该测试的构建,同时也会在 bash/batch 包装脚本中禁用其运行。但当build.*脚本传入allTargets选项时,测试仍可在 CI 中为任何目标构建。这一机制在 src/tests/Directory.Build.targets 中有精确实现:_WillCLRTestProjectBuild属性综合判定CLRTestBuildAllTargets与CLRTestTargetUnsupported,当「未指定allTargets且目标不支持」时置为false,从而跳过构建。
仓库中有大量真实用例,例如 GC/API/Frozen/Frozen.csproj:
<CLRTestTargetUnsupported Condition="'$(RuntimeFlavor)' != 'coreclr'">true</CLRTestTargetUnsupported>而永远不应构建或运行的测试则标记为:
<DisableProjectBuild>true</DisableProjectBuild>该属性不应基于 Target 属性做条件化,这样所有测试才能为allTargets构建(在 src/tests/Directory.Build.targets 中,_WillCLRTestProjectBuild同样会对DisableProjectBuild == true的项目返回false,并最终通过导入Common\nobuild.targets让构建目标变成空操作)。
运行单个测试
构建完单个测试后(参见上文「构建单个测试」),按以下两步运行:
- 将
CORE_ROOT环境变量设置为 Core_Root 目录 的路径:
export CORE_ROOT=<仓库根>/artifacts/tests/coreclr/<os>.<arch>.<configuration>/Tests/Core_Root- 运行该测试生成目录下的
.sh脚本:
cd <仓库根>/artifacts/tests/coreclr/<os>.<arch>.<configuration>/<测试子路径> ./<测试名>.sh测试入口脚本还支持-coreroot=<路径>直接指定 Core_Root(此时可省略环境变量)、-debug=<调试器路径>挂载调试器、-env=<.env 文件>注入环境变量,其参数风格与corerun基本一致。构建脚本在构建完成后也会打印单测运行提示(参见 src/tests/build.sh 末尾输出),格式为bash <TestBinDir>/__TEST_PATH__/__TEST_NAME__.sh -coreroot=${CORE_ROOT}。
PAL 测试(仅 macOS 与 Linux)
PAL(Platform Abstraction Layer)测试用于验证 CoreCLR 原生层的平台抽象实现,是 Unix 平台专属的测试套件。
构建 PAL 测试
在 Unix 机器上用clr.paltests子集构建 CoreCLR 及 PAL 测试:
./build.sh clr.paltests运行 PAL 测试
运行全部测试(包含被禁用的测试):
./src/coreclr/pal/tests/palsuite/runpaltests.sh $(pwd)/artifacts/bin/coreclr/$(uname).x64.Debug/paltests # macOS 上请将 $(uname) 替换为 osx只运行构建平台对应的已启用测试:
artifacts/bin/coreclr/$(uname).x64.Debug/paltests/runpaltests.sh $(pwd)/artifacts/bin/coreclr/$(uname).x64.Debug/paltests # macOS 上请将 $(uname) 替换为 osx只运行特定测试:在本地编辑src/coreclr/pal/tests/palsuite/paltestlist.txt,删除不想运行的条目即可(注意不要把本地改动提交入库)。
从 runpaltests.sh 的实现看,脚本会从传入的构建根目录读取paltestlist.txt测试清单,将LD_LIBRARY_PATH指向测试构建目录,然后逐条执行每个测试并记录退出码:退出码 0 记为 Pass,否则记为 Fail 并写入失败列表。每个测试在独立的工作目录中运行以避免脏状态干扰,最终汇总输出 xUnit 风格的结果文件:
/tmp/PalTestOutput/default/pal_tests.xml脚本还支持可选的第二、三个参数分别指定输出拷贝目录与临时工作目录,以便在同一台机器上并行跑多组 PAL 测试。测试结束后脚本以失败测试数量作为退出码。
要在 CI 中禁用测试,编辑src/coreclr/pal/tests/palsuite/issues.targets即可。该文件以 MSBuildExcludeList形式按TargetArchitecture/TargetOS组合排除特定用例并关联 issue,例如 issues.targets 中的真实条目:
<ItemGroup Condition="'$(TargetArchitecture)' == 'x64' and '$(TargetOS)' == 'linux'"> <ExcludeList Include="eventprovider/eventprovidertest"> <Issue>https://github.com/dotnet/runtime/issues/42291</Issue> </ExcludeList> </ItemGroup>这表示在 Linux x64 上跳过eventprovider/eventprovidertest,同时用<Issue>记录追踪链接,便于后续回归修复后移除排除项。
测试失败排查建议
批跑结束后,若存在失败测试,可在每个测试对应的Reports目录(artifacts/tests/coreclr/<OS>.<架构>.<配置>/Reports/<测试路径>)中查看两类关键文件:<测试名>.output.txt(测试自身全部日志输出)与<测试名>.error.txt(测试进程崩溃时corerun报告的错误信息)。报告中还会包含测试的完整执行命令,可据此直接复现:设置好CORE_ROOT后手动运行该命令,或用-debug挂载调试器深入定位。关于测试基础设施的更完整说明,可继续阅读 CoreCLR 测试总览(其中还涵盖测试优先级、merged test runner 与RequiresProcessIsolation等机制)。
- 语言运行时
- 标准库
- JIT编译
- 编译器
【免费下载链接】runtime
.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
相关推荐
如何轻松配置Windows和Office:面向新手的终极解决方案指南
如何轻松配置Windows和Office:面向新手的终极解决方案指南 还在为Windows系统频繁弹出配置提示而烦恼吗?Office突然变成只读模式无法保存文件
语言运行时标准库JIT编译编译器在 .NET 运行时仓库中构建、运行与调试 Android 上的 CoreCLR:完整开发者工作流
在 .NET 运行时仓库中构建、运行与调试 Android 上的 CoreCLR:完整开发者工作流 导读 本文基于 .NET 运行时仓库(dotnet/runt
语言运行时标准库JIT编译编译器dotnet/runtime 如何生成 Core_Root 并构建、运行 CoreCLR 测试套件?
dotnet/runtime 如何生成 Core_Root 并构建、运行 CoreCLR 测试套件? 在 dotnet/runtime 仓库中修改了 CoreC
语言运行时标准库JIT编译编译器
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考