Tyr*_*rrz 5 .net c c# msbuild roslyn
我有一个 .NET Framework 3.5 项目,我想为其启用框架翻转,以便用户可以在安装了 .NET Framework 3.5 或 .NET Framework 4.x 运行时的系统上运行它。这应该允许用户通过从 Windows 7 开始的任何开箱即用的 Windows 安装来运行我的应用程序。
\n我已经使用以下App.config
文件进行了此工作:
<?xml version="1.0" encoding="utf-8" ?>\n\n<!-- This configuration file is required by the apphost which runs on legacy .NET Framework for compatibility reasons -->\n\n<configuration>\n <!-- Prefer .NET 3.5 (preinstalled on Windows 7), rollover to .NET 4.x (preinstalled on Windows 8+) -->\n <startup useLegacyV2RuntimeActivationPolicy="true">\n <supportedRuntime version="v2.0.50727" />\n <supportedRuntime version="v4.0" />\n </startup>\n</configuration>\n
Run Code Online (Sandbox Code Playgroud)\n但是,我不想将配置文件与应用程序一起分发。我读过Michal Strehovsk\xc3\xbd 写的这篇很棒的文章,它解释了我可以通过在执行程序的入口点之前COMPLUS_OnlyUseLatestCLR=1
设置环境变量来获得相同的行为。
Michal 通过将 C# 代码编译为程序netmodule
集而不是完整程序集,然后将结果与实现 TLS 回调的 C 程序集合并来实现此目的。该回调在程序执行时但在 .NET 运行时获取托管代码之前设置环境变量:
#include <windows.h>\n\nVOID WINAPI tls_callback(\n PVOID DllHandle,\n DWORD Reason,\n PVOID Reserved)\n{\n if (Reason == DLL_PROCESS_ATTACH)\n SetEnvironmentVariableW(L"COMPLUS_OnlyUseLatestCLR", L"1");\n}\n\n#ifdef _M_AMD64\n #pragma comment (linker, "/INCLUDE:_tls_used")\n #pragma comment (linker, "/INCLUDE:p_tls_callback")\n #pragma const_seg(push)\n #pragma const_seg(".CRT$XLAAA")\n EXTERN_C const PIMAGE_TLS_CALLBACK p_tls_callback = tls_callback;\n #pragma const_seg(pop)\n#endif\n#ifdef _M_IX86\n #pragma comment (linker, "/INCLUDE:__tls_used")\n #pragma comment (linker, "/INCLUDE:_p_tls_callback")\n #pragma data_seg(push)\n #pragma data_seg(".CRT$XLAAA")\n EXTERN_C PIMAGE_TLS_CALLBACK p_tls_callback = tls_callback;\n #pragma data_seg(pop)\n#endif\n
Run Code Online (Sandbox Code Playgroud)\n我想实现他的方法,但使用 MSBuild 项目系统来完成尽可能多的繁重工作。
\n在 Michal 的帖子中,他曾经csc
将 C# 代码编译到 .NET 模块中。我尝试通过将项目的输出类型从更改为来复制它,Exe
如下Module
所示:
<Project Sdk="Microsoft.NET.Sdk">\n\n <PropertyGroup>\n <TargetFramework>net35</TargetFramework>\n <OutputType>module</OutputType>\n </PropertyGroup>\n\n</Project>\n
Run Code Online (Sandbox Code Playgroud)\n然而,这导致了我的第一个障碍——编译器产生了许多与 C# 的NRT 功能相关的错误:
\nC:\\Users\\Tyrrr\\.nuget\\packages\\quickjson\\1.0.0\\contentFiles\\cs\\any\\QuickJson\\JsonNull.cs(6,23): error CS0518: Predefine\nd type \'System.Runtime.CompilerServices.NullableAttribute\' is not defined or imported [e:\\Projects\\Software\\DotnetRunti\nmeBootstrapper\\DotnetRuntimeBootstrapper.AppHost.Cli\\DotnetRuntimeBootstrapper.AppHost.Cli.csproj]\n\nC:\\Users\\Tyrrr\\.nuget\\packages\\quickjson\\1.0.0\\contentFiles\\cs\\any\\QuickJson\\JsonNull.cs(4,20): error CS0518: Predefine\nd type \'System.Runtime.CompilerServices.NullableContextAttribute\' is not defined or imported [e:\\Projects\\Software\\Dotn\netRuntimeBootstrapper\\DotnetRuntimeBootstrapper.AppHost.Cli\\DotnetRuntimeBootstrapper.AppHost.Cli.csproj]\n\ne:\\Projects\\Software\\DotnetRuntimeBootstrapper\\DotnetRuntimeBootstrapper.AppHost.Cli\\Utils\\ConsoleEx.cs(8,31): error CS\n0518: Predefined type \'System.Runtime.CompilerServices.NullableContextAttribute\' is not defined or imported [e:\\Project\ns\\Software\\DotnetRuntimeBootstrapper\\DotnetRuntimeBootstrapper.AppHost.Cli\\DotnetRuntimeBootstrapper.AppHost.Cli.csproj\n]\n\n...\n\n\n294 Error(s)\n
Run Code Online (Sandbox Code Playgroud)\n我的项目确实使用了 NRT(它以最新版本的 C# 为目标,并使用 .NET 7 进行构建,尽管以 .NET Fx 3.5 运行时为目标),但它们是使用PolySharp 库进行多填充的。我还尝试使用Nullable polyfill 库,但它导致了同样的问题。
\n设置<Nullable>disable</Nullable>
也无法解决问题,因为我的代码包含 NRT 注释(即public MyClass? Foo()
)。有没有办法在不放弃 NRT 的情况下继续进行?
我尝试谷歌搜索并在 Roslyn 存储库上发现了这个问题。.NET Core 似乎不正式支持编译为 .NET 模块。尽管如此,考虑到我的目标是 .NET Framework 并仅在 SDK 方面使用 .NET Core(csc
两种方式都相同),我怀疑可能有一种方法可以破解构建系统以使其工作?
最后,假设这个问题得到解决,编译 C 代码的最佳方法是什么?我可能可以将 C 文件作为<None>
项目包含在我的项目结构中,并cl
在之前的 MSBuild 目标中运行CoreBuild
,模仿 Michal 所做的事情。但是,也许有一些内置方法可以实现相同的目的,也许可以通过引用 MSBuild 用于 C/C++ 工作负载的现有目标?