dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.7k stars 1.06k forks source link

InvalidProjectFileException thrown for shared projects (.shproj) when doing a workload restore on Linux #41000

Open SylvainGantois opened 5 months ago

SylvainGantois commented 5 months ago

Describe the bug

When running dotnet workload restore on Ubuntu, the command will throw an InvalidProjectFileException on shared projects (.shproj file)

To Reproduce

Create a new solution including a Shared Project, and run dotnet workload restore on Ubuntu 24.04.

Exceptions (if any)

sylvain@ubuntu:~/MyProject$ dotnet workload restore Unhandled exception: Microsoft.Build.Exceptions.InvalidProjectFileException: The imported file "$(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v$(VisualStudioVersion)/CodeSharing/Microsoft.CodeSharing.Common.Default.props" does not exist and appears to be part of a Visual Studio component. This file may require MSBuild.exe in order to be imported successfully, and so may fail to build in the dotnet CLI. /home/sylvain/MyProject/MySharedProject/MySharedProject.shproj at Microsoft.Build.Shared.ProjectErrorUtilities.ThrowInvalidProject(String errorSubCategoryResourceName, IElementLocation elementLocation, String resourceName, Object[] args) at Microsoft.Build.Shared.ProjectErrorUtilities.ThrowInvalidProject[T1](IElementLocation elementLocation, String resourceName, T1 arg0) at Microsoft.Build.Evaluation.Evaluator4.ExpandAndLoadImportsFromUnescapedImportExpression(String directoryOfImportingFile, ProjectImportElement importElement, String unescapedExpression, Boolean throwOnFileNotExistsError, List1& imports) at Microsoft.Build.Evaluation.Evaluator4.ExpandAndLoadImportsFromUnescapedImportExpressionConditioned(String directoryOfImportingFile, ProjectImportElement importElement, List1& projects, SdkResult& sdkResult) at Microsoft.Build.Evaluation.Evaluator4.ExpandAndLoadImports(String directoryOfImportingFile, ProjectImportElement importElement, SdkResult& sdkResult) at Microsoft.Build.Evaluation.Evaluator4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement) at Microsoft.Build.Evaluation.Evaluator4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) at Microsoft.Build.Evaluation.Evaluator4.Evaluate() at Microsoft.Build.Evaluation.Evaluator4.Evaluate(IEvaluatorData4 data, Project project, ProjectRootElement root, ProjectLoadSettings loadSettings, Int32 maxNodeCount, PropertyDictionary1 environmentProperties, ILoggingService loggingService, IItemFactory2 itemFactory, IToolsetProvider toolsetProvider, IDirectoryCacheFactory directoryCacheFactory, ProjectRootElementCacheBase projectRootElementCache, BuildEventContext buildEventContext, ISdkResolverService sdkResolverService, Int32 submissionId, EvaluationContext evaluationContext, Boolean interactive) at Microsoft.Build.Execution.ProjectInstance.Initialize(ProjectRootElement xml, IDictionary2 globalProperties, String explicitToolsVersion, String explicitSubToolsetVersion, Int32 visualStudioVersionFromSolution, BuildParameters buildParameters, ILoggingService loggingService, BuildEventContext buildEventContext, ISdkResolverService sdkResolverService, Int32 submissionId, Nullable1 projectLoadSettings, EvaluationContext evaluationContext, IDirectoryCacheFactory directoryCacheFactory) at Microsoft.Build.Execution.ProjectInstance..ctor(String projectFile, IDictionary2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectCollection projectCollection, Nullable1 projectLoadSettings, EvaluationContext evaluationContext, IDirectoryCacheFactory directoryCacheFactory, Boolean interactive) at Microsoft.Build.Execution.ProjectInstance..ctor(String projectFile, IDictionary2 globalProperties, String toolsVersion) at Microsoft.DotNet.Workloads.Workload.Restore.WorkloadRestoreCommand.RunTargetToGetWorkloadIds(IEnumerable1 allProjects) at Microsoft.DotNet.Workloads.Workload.Restore.WorkloadRestoreCommand.Execute() at System.CommandLine.Invocation.InvocationPipeline.Invoke(ParseResult parseResult) at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, TimeSpan startupTime, ITelemetry telemetryClient)

Further technical details

Runtime Environment: OS Name: ubuntu OS Version: 24.04 OS Platform: Linux RID: linux-x64 Base Path: /home/sylvain/.dotnet/sdk/8.0.300/

.NET workloads installed: There are no installed workloads to display.

Host: Version: 8.0.5 Architecture: x64 Commit: 087e15321b

.NET SDKs installed: 8.0.300 [/home/sylvain/.dotnet/sdk]

.NET runtimes installed: Microsoft.AspNetCore.App 8.0.5 [/home/sylvain/.dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 8.0.5 [/home/sylvain/.dotnet/shared/Microsoft.NETCore.App]

Other architectures found: None

Environment variables: DOTNET_ROOT [/home/sylvain/.dotnet]

global.json file: Not found

Learn more: https://aka.ms/dotnet/info

Forgind commented 4 months ago

Per the error messsage: ...appears to be part of a Visual Studio component. This file may require MSBuild.exe in order to be imported successfully, and so may fail to build in the dotnet CLI.

Building it with the SDK isn't currently supported. If we can't evaluate it, we can't do a workload restore that includes it either. If there's a shproj that actually does require workloads (directly or indirectly), we couldn't do a workload restore properly, which means failing is expected and desired.

What kind of action are you looking for in this case?

SylvainGantois commented 4 months ago

I run the command at the solution level so I expected my shared projects to be ignored (they just hold files, nothing to build) and all the other supported projects' workloads to be restored, the same behaviour as on Windows.

Edit: sorry I re-tested on Windows and I see the same error as on Linux. But yes I would have expected that the restore would be triggered for the projects that can have a worload restored and it would ignore the shared projects.

Forgind commented 4 months ago

It sounds like dotnet build might already have something like that built in, that is, making it so that you can dotnet build a .sln with an .shproj without erroring. We haven't done much to add support for .shproj in a while, though; they're barely supported in the CLI to any degree. Have you tried Microsoft.Build.NoTargets? I saw marcpopMSFT recommended it in this thread: https://github.com/dotnet/sdk/issues/2511#issuecomment-1374125096