cake-build / cake

:cake: Cake (C# Make) is a cross platform build automation system.
https://cakebuild.net
MIT License
3.84k stars 722 forks source link

MSBuild ProjectParser only parses default configuration OutputPath #1255

Open cpx86 opened 7 years ago

cpx86 commented 7 years ago

What You Are Seeing?

MSBuild ProjectParser only parses settings for the default build configuration (normally Debug). E.g. OutputPath is by default different for Debug/Release in a Visual Studio project.

What is Expected?

All build configurations and their OutputPaths are accessible in the ProjectParserResult.

What version of Cake are you using?

0.15.2+Branch.main.Sha.c2ca4f7ca51c59dc9c47c9830125b4e66cf14e7a

The piece of code handling this is here: https://github.com/cake-build/cake/blob/develop/src/Cake.Common/Solution/Project/ProjectParser.cs#L84 It explicitly only reads OutputPath from the PropertyGroup that matches the default Configuration. For example, this is how a typical (redacted) VS project XML looks:

<PropertyGroup>
  <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  <OutputPath>bin\Release\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
  <OutputPath>bin\Debug\</OutputPath>
</PropertyGroup>

The code will read the value of the initial Configuration element, then parse the PropertyGroups and pick the one that has a matching condition.

I'm not sure what I think the most appropriate solution for this would be. Perhaps add a dictionary to ProjectParserResult, of type IDictionary<string,FilePath> with the Configuration names and OutputPaths?

kcamp commented 7 years ago

I have run into this issue in the version(s) prior to 15.x where the output was introduced as a property in the ProjectParserResult type in 5faa048cf153527cadd510a68a48a3d50b6e1974

I don't think exposing a dictionary will yield much of a return because there isn't likely going to be a good way to query the file that will represent all the permutations of conditions that could be in play to determine $(OutputPath), especially if they aren't necessarily constrained to $(Platform) and $(Configuration).

I found the most reliable resolution for my own experimentation was to build out an add-in and reference the MSBuild lib to get live parsing of the csproj file, see snippet below. no idea how viable this might be across versions or as something that could be distributed.

bear in mind this predates the version of Cake that included the properties in the result, so there would be no need to have the ExtendedProjectParserResult to expose those properties; the footprint of my solution could be simplified with the newest Cake lib. options is just a wrapper around a Dictionary<string,string>.

// get basic information from base Cake impl
var parser = new ProjectParser(_fileSystem, _environment);
var result = ExtendedProjectParserResult.From(projectPath, parser.Parse(projectPath));

// now load the csproj live
using(var stream = file.OpenRead())
using (var xml = new XmlTextReader(stream))
{
    var project = new Microsoft.Build.Evaluation.Project(xml);

    // set properties & reevaluate
    foreach (var prop in options.GetAllProperties())
    {
        project.SetProperty(prop.Key, prop.Value);
    }

    project.ReevaluateIfNecessary();
    // now we can get additional information about the project
    result.OutputPath = project.GetPropertyValue("OutputPath");
    result.Configuration = project.GetPropertyValue("Configuration");
    result.Platform = project.GetPropertyValue("Platform");
}
cpx86 commented 7 years ago

@kcamp I have been thinking along the same lines. As you say, there's a lot that can influence the value of e.g. OutputPath, so making it work for anything but typical project files would be hard. OTOH, the functionality is there now and if it is to exist then the expected behavior would be that you could get the OutputPath of the configuration that you are actually building.

wwwlicious commented 7 years ago

I have created some extensions and a customprojectparser alias that requires a config argument to handle getting the correct output paths and assemblies Details here if it helps