我有 Visual Studio 2022,并且安装了 .NET 9。
在构建期间(实际上是在构建开始之前),我需要创建一个符号链接,并且我需要以跨平台的方式这样做,因为我在 Windows 上,但 github actions 在 ubuntu 上运行。
因此,我创建了一个“内联任务”,又名“
UsingTask
”(https://learn.microsoft.com/en-us/visualstudio/msbuild/usingtask-element-msbuild?view=vs-2022)我想从中调用System.IO.File.CreateSymbolicLink()
。 (https://learn.microsoft.com/en-us/dotnet/api/system.io.file.createsymboliclink?view=net-6.0)
这是我的代码:
<Project Sdk="Microsoft.NET.Sdk">
...
<UsingTask TaskName="CreateFileSymbolicLink"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
<ParameterGroup>
<path ParameterType="System.String" Required="true" />
<pathToTarget ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
//System.Console.WriteLine( $"x" );
System.IO.File.CreateSymbolicLink( path, pathToTarget );
</Code>
</Task>
</UsingTask>
失败了
错误 CS0117:“文件”不包含“CreateSymbolicLink”的定义。
我发现了这个:https://stackoverflow.com/a/51194833/773113(从2018年开始),我尝试使用字符串插值语法,并且该语法有效,但不是
CreateSymbolicLink()
方法。
我怎样才能让它工作,或者以其他方式实现我最初的目标,即在构建开始之前以跨平台方式创建到文件的符号链接?
所以,我不得不放弃跨平台的想法。
这就是我最终所做的:
<UsingTask TaskName="CreateFileSymbolicLink" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
<ParameterGroup>
<path ParameterType="System.String" Required="true" />
<targetPath ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
//PEARL: We cannot simply use System.IO.File.CreateSymbolicLink() here, because RoslynCodeTaskFactory
// tasks target .NET Standard. See https://stackoverflow.com/q/79308054/773113
[System.Runtime.InteropServices.DllImport( "Kernel32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode )]
[return: System.Runtime.InteropServices.MarshalAs( System.Runtime.InteropServices.UnmanagedType.I1 )]
static extern bool CreateSymbolicLink( string lpSymlinkFileName, string lpTargetFileName, uint dwFlags );
System.IO.File.Delete( path );
//PEARL: The SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE has to be used, or else this will fail,
// and for this flag to be used, "Developer Mode" must be enabled in Windows.
if( !CreateSymbolicLink( path, targetPath, /* File + SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE */ 0x2 ) )
throw new System.ComponentModel.Win32Exception( System.Runtime.InteropServices.Marshal.GetLastWin32Error(), $"Failed to create symbolic link {path} {targetPath}" );
</Code>
</Task>
</UsingTask>