Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Comments

Fix stdlib inconsistency between core and fx compiler#79911

Merged
jjonescz merged 14 commits intodotnet:mainfrom
jjonescz:79907-StdLib
Aug 25, 2025
Merged

Fix stdlib inconsistency between core and fx compiler#79911
jjonescz merged 14 commits intodotnet:mainfrom
jjonescz:79907-StdLib

Conversation

@jjonescz
Copy link
Member

Resolves #79907.

}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79907")]
public void StdLib()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 This file contains only moved code (to share it) except this test which is new (and also shared).

.FirstOrDefault()
?? throw new InvalidOperationException("Visual Studio instance not found.");
return vsInstance.MSBuildPath;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 This didn't work but all the tests using it were skipped.

@jjonescz jjonescz marked this pull request as ready for review August 15, 2025 16:08
@jjonescz jjonescz requested review from a team as code owners August 15, 2025 16:08
@jjonescz
Copy link
Member Author

@jaredpar @RikkiGibson PTAL

commandLine.AppendSwitchIfNotNull("/nullable:", Nullable);
commandLine.AppendWhenTrue("/nosdkpath", _store, nameof(DisableSdkPath));

// Pass sdkpath if we are invoking core compiler from framework to preserve the behavior that framework compiler would have.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this perfectly preserves the original behavior here where /sdkpath was used whenever we used msbuild. This compiler argument doesn't really make sense in a .NET SDK world though for the following reasons:

  1. It means that project builds would be different when using msbuild and dotnet build because the compiler would get meaningfully different build parameters
  2. It means that when we're building .NET Core projects we're giving them an /sdkpath that points to .NET Framework assemblies.

I'm wondering if there is a way we can constrain this shim a bit to narrow the impact. Would be nice if we could remove (2).

Copy link
Member Author

@jjonescz jjonescz Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To get rid of (1) perhaps we could use RuntimeEnvironment.GetRuntimeDirectory() even on .NET Core, that also points to a directory which contains mscorlib.dll (albeit the core one, not the framework one, so it's still different). Then we could also get rid of the new /sdkpath: option. That might be a different breaking change though (all core msbuild based builds would now reference mscorlib.dll implicitly).

Getting rid of (2) would still be a breaking change though. Let's say I have this project:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net10.0</TargetFramework>
        <OutputType>Exe</OutputType>
    </PropertyGroup>
    <Target Name="CustomTarget">
        <Csc Sources="File.cs" />
    </Target>
</Project>

It's a .NET Core project that previously worked and now would be broken.

Btw, if you are building a normal .NET Core app, it should use NoStdLib=true anyway, so mscorlib.dll won't be referenced. I guess the .NET Framework path would still be added to search paths though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanest solution might be to close this PR and accept the break :) If we want dotnet build and msbuild to behave in the same way and invoke core compiler by default, it would make sense to say that there will be no implicit reference of framework mscorlib.dll.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would a fix for the break look like? Essentially what code snippet would a customer write in order to get this scenario working again? The fear of the full break is this is most likely to impact customers in older project styles. That is where breaks are the most costly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They would need to set RoslynCompilerType=Framework (or FrameworkPackage to avoid tearing).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. Yeah that will work but ideally we're slowly deprecating RoslynCompilerType=Framework over the next few years. Don't want to have any scenarios where we're pushing people to use this while we're deprecating it.

each error
-preferreduilang Specify the preferred output language name.
-nosdkpath Disable searching the default SDK path for standard library assemblies.
-sdkpath:&lt;path&gt; Location of the .NET Framework SDK directory (mscorlib.dll).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-sdkpath:&lt;path&gt; Location of the .NET Framework SDK directory (mscorlib.dll).
-sdkpath:&lt;path&gt; Path used to search for standard library assemblies

Wanted to remove the Framework reference here as it's possible in the future we'd use this for .NET SDK as well. Consider for example that the RSP file we're generating for dotnet run app.cs could one day take advantage of this. Intstead of full pathing everything in the RSP it could be relative path + using /sdkpath to control where to look.

Tried to pattern the message no the wording of -nosdkpath

@jaredpar
Copy link
Member

@RikkiGibson PTAL

@RikkiGibson RikkiGibson self-assigned this Aug 21, 2025
protected override void AddResponseFileCommands(CommandLineBuilderExtension commandLine)
{
// Pass sdkpath if we are invoking core compiler from framework to preserve the behavior that framework compiler would have.
// Pass this option only to the built-in compiler (customer-supplied compiler might not support it).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am somewhat confused by this, if user-supplied compiler doesn't respect this option, don't we have a reason to believe their compiler will not behave correctly? So why avoid passing the argument?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you are right. I was worried about this causing another regression (the custom compiler failing with unknown argument).

protected override void AddResponseFileCommands(CommandLineBuilderExtension commandLine)
{
// Pass sdkpath if we are invoking core compiler from framework to preserve the behavior that framework compiler would have.
// Pass this option only to the built-in compiler (customer-supplied compiler might not support it).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment

[Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/79907")]
public void StdLib_Csc(bool useSharedCompilation, bool disableSdkPath)
{
if (_msbuildExecutable == null) return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be helpful to log that we are essentially skipping the test in this scenario and in similar place in StdLib_Vbc test below?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We log that in the constructor which runs for each test separately, so the test's log contain the information:

protected IntegrationTestBase(ITestOutputHelper output)
{
if (s_msbuildDirectory == null)
{
output.WriteLine("Could not locate MSBuild");
}

});

[Fact]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/79923")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally I really do not like to skip tests if it can be avoided, but, it feels like the non-deterministic behavior makes this necessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is completly unrelated to this PR and it has not worked for some time but my infra fixes made it actually run in the CI.

@jjonescz jjonescz merged commit 091085e into dotnet:main Aug 25, 2025
28 checks passed
@jjonescz jjonescz deleted the 79907-StdLib branch August 25, 2025 09:16
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Aug 25, 2025
@akhera99 akhera99 modified the milestones: Next, 18.0 P1, 18.0 P2 Sep 22, 2025
jjonescz added a commit that referenced this pull request Nov 14, 2025
Follow up on #79911.

Fixes another inconsistency between the core and fx compilers: if the
`<Csc>` task is used manually on a C# file which has `using
System.Linq;` (for example), the fx compiler handles that fine (because
there is `csc.rsp` deployed with it which has a set of default
references) whereas the core compiler fails. A real-world use-case can
be seen in
https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequest/684436.

The fix is to include this default `csc.rsp` in scenarios where we
invoke the core compiler on fx msbuild (to avoid a break there). We
continue to not include that `csc.rsp` in scenarios where just the core
csc is being used (again, to avoid a break in those scenarios).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Breaking change in default imports when core compiler is used from netfx builds

5 participants