-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Evaluate a project from the command line #3911
Comments
Take a look at MSBuildDumper and see if it fits your needs: https://github.com/KirillOsenkov/MSBuildTools https://github.com/KirillOsenkov/MSBuildTools/blob/master/src/MSBuildDumper/MSBuildDumper.cs |
@KirillOsenkov thanks, but I know that getting the evaluated values is pretty easy with the MSBuild NuGet package. To clarify, I simply thought that having this possibility from MSBuild itself (without requiring additional tools) would be a useful feature, and I think it would make sense to support that. I wished several times that MSBuild offered that. I could contribute that feature if the MSBuild team thinks it would be valuable. |
Can you elaborate on "This would be useful for scripting purposes."? What specifically? I would have sworn that we already had a work item for this but I don't see one. I think it's a fine idea and would help with various debugging scenarios. I would lean toward the simpler only-dump-values interface; I'm not sure how difficult plumbing the transform mechanism in would be and I think you could get most of the value from just items/properties. I'd suggest that the output should match the text logger, so combining requests would be more clear: $ msbuild SomeProject.csproj -evaluateItems:Compile -evaluateProperty:TargetPath
TargetPath = s:\msbuild\artifacts\Debug\bin\Microsoft.Build.Framework\net472\Microsoft.Build.Framework.dll
Compile
..\Shared\BinaryWriterExtensions.cs
Link = Shared\BinaryWriterExtensions.cs
..\Shared\Constants.cs
Link = Shared\Constants.cs
BuildEngineResult.cs
BuildErrorEventArgs.cs
BuildEventArgs.cs
BuildEventContext.cs |
I originally needed to get the I couldn't just set my own
The problem I see with this approach is that it's well suited for human inspection, but less useful for scripting. My idea was to make MSBuild behave like a Unix utility in this case: only output the desired value so it can be easily consumed by a script or by another tool which could be piped to the MSBuild output. With this approach, a script would additionally have to strip the Also, given that the debugging experience is very good using the binary log viewer, I don't think a text output aimed at debuggability would provide a compelling benefit over that. |
That's interesting. What would you do about item metadata? |
Well, actually item metadata is the reason I suggested the "full" syntax ( So suppose I want a list of linked files from your example, here's how I could get it: $ msbuild SomeProject.csproj -evaluate:"@(Compile->'%(Identity):%(Link)')"
..\Shared\BinaryWriterExtensions.cs:Shared\BinaryWriterExtensions.cs
..\Shared\Constants.cs:Shared\Constants.cs
BuildEngineResult.cs:
BuildErrorEventArgs.cs:
BuildEventArgs.cs:
BuildEventContext.cs: Line breaks could still be an issue though, but a unique delimiter could be inserted at the end of each line to handle these if needed. |
This would be super useful for us. We worked around that currently but our workaround broke and we now have lots of work backporting script-changes :-( |
There's a related consideration here - properties and items are not static, they can be modified during the evaluation of a particular target. That implies to me that the request might look something like to specify a target to run (and maybe just evaluate the project if none is specified):
or
or
(though labeling of the returned values might be interesting) |
@baronfel Great point. We do this in the Docker extension for VSCode to determine the path of the Blazor static web assets manifest, in order to "containerize" it by adjusting the paths. The target "ResolveStaticWebAssetsConfiguration" has to be run before the necessary information is available. More on that here: https://github.com/microsoft/vscode-docker/blob/main/resources/netCore/GetBlazorManifestLocations.targets |
I just want to show our usecase. We do have a msbuild file thats integrated in most of our projects. It contains version info which is used to set assembly metadata like FileVersion, AssemblyVersion and so on. There are properties which are static and calculated using values of other properties. We do have Powershell scripts that have to read this values to do deployments and calculate paths and so on. We've used the msbuild api in the past to evaluate the properties in powershell but this broke with a new version of msbuild/powershell. So we now have a proxy msbuild-script which gets a path to another msbuild-script and a list of properties to evaluate and then does the evaluation and pretty prints the evaluated properties and so on. So we now use msbuild to run the proxy-msbuild script which then prints everything to console and we parse it in powershell. Here is the script we want to have values of:
And thats the proxy-script:
It would be nice to be able to skip this proxy script and just use msbuild with parameters. We dont use the msbuild api in powershell anymore because it broke suddenly and we had to do lots of backporting. Regards, |
@Scordo for advanced scenarios like this I think a C# console app that uses MSBuild APIs would be a good approach. I doubt we can ever put enough flexibility into MSBuild.exe to get what you want, and arguably, at this point just doing what you’re already doing with a proxy project is that kind of extensibility already. |
I like the idea of rendering just one interesting property (as mentioned in the OP), but I also like the idea of rendering the entire xml (as in my closed dupe issue). The fact that some variables cannot be evaluated is true, but many can be, so it's still useful. Quick elaboration: When everything is done by msbuild, this feature request adds no value and seems unimportant. But not everyone uses msbuild as the primary build mechanism. We use bash for everything, and call the msbuild/dotnet CLI to perform work for c# projects. But that means we are outside msbuild's "domain", and so lack data that msbuild doesn't naturally provide - so it would be helpful to have a feature where we can get msbuild to rendering the csproj. In a multi-platform build environment, with many containers, different technologies (not just c#), etc., shell scripting is the lowest common denominator, but acquiring the info required to perform a build is quite hard. |
Here's a proposal for this to see if we can get it moving forward. What do people think? Command line evaluation of MSBuild propertiesWe will add command-line options to MSBuild to support getting the value of properties, items, or target return values.
If no targets are specified on the command line via the By default, the requested values will be printed to the console output in text format, and any other MSBuild output will be suppressed, unless there is an error. The text format for the values will simply put each value on a separate line, and won't include any item metadata. It will be possible to get the values for multiple properties, for example The format for the values can be switched to json by specifying The values can be saved to a file instead of printed to the console with the A possible format for the json output could be as follows: {
"properties":
{
"PropertyName": "PropertyValue",
"PropertyName2": "PropertyValue2"
},
"items":
{
"Sources":
[
{
"ItemSpec": "Program.cs"
},
{
"ItemSpec": "obj\\Debug\\net6.0-windows10.0.19041.0\\ConsoleTest.AssemblyInfo.cs"
}
],
"References":
[
{
"ItemSpec": "C:\\Program Files\\dotnet\\packs\\Microsoft.WindowsDesktop.App.Ref\\6.0.14\\ref\\net6.0\\Accessibility.dll",
"FileVersion": "6.0.1423.7402",
"ReferenceSourceTarget": "ResolveAssemblyReference"
}
]
},
"targets":
{
"GetTargetPath":
{
{
"ItemSpec": "c:\\git\\repro\\ConsoleTest\\bin\\Debug\\net6.0-windows10.0.19041.0\\ConsoleTest.dll",
"TargetFrameworkIdentifier": ".NETCoreApp",
"ReferenceAssembly": "c:\\git\\repro\\ConsoleTest\\obj\\Debug\\net6.0-windows10.0.19041.0\\ref\\ConsoleTest.dll"
}
}
}
} CommentsThis doesn't support evaluating arbitrary expressions from the command line, so something like The |
Thanks, I like it! 🙂 A few comments:
Just to clarify: will the error message go to stderr? I think it would be better for stdout to remain empty in that case.
Excellent idea. It becomes necessary when dealing with multi-line values.
Is there a real use case for this? When used in a script, the command output can be redirected to a file.
|
How would these options interact with the
|
I'm not sure. I don't know if the error messages currently go to stdout or stderr, and if they don't go to stderr it might be tricky to change that.
I think the normal MSBuild output can be useful to have in logs in case something goes wrong. This is more likely to matter if targets are being run instead of just evaluating the project.
We use both.
Yes, this is probably a good idea.
I'm not sure about this, JSON typically uses camelCase. |
Yes, all of this matches what I was thinking. |
An explicit use case for this comes from our friends at the VSCode Docker tooling - they currently do evaluations looking for specific properties and items. They'd love to have a way to get that same information that doesn't require building and shipping an entire .NET application. |
Using stdout in MSBuild for structured data output is something we have not done in past, all structured build artifacts are in form of files. Although convenient, there is lot of corner cases like errors during MSBuild execution which might make it less useful. |
There is already an open PR and there has been lots of discussion both here in the issue and in the PR. Every target available on an MSBuild project is a potential 'endpoint' or 'sub-command'. You don't need to use the I have routinely implemented 'diagnostic' targets whose purpose is to report specific information (from properties and/or items). These targets can require other targets to execute, or not. A common set of 'diagnostic' targets can be applied to a set of projects with a For a one-off ad-hoc circumstance, simple evaluations at the command line have value. For some of the scripting use cases described, expanding the API surface (or the command surface if you prefer) by adding specialized targets is a better approach because it can be tailored to the specific requirements (including the returned data format) and can use the full capabilities of MSBuild. There is a way in which the more complete and the more sophisticated the command line evaluation support is, the more redundant it will be with just executing a project. |
Fixes #3911 (See #3911 (comment) for a spec.)
This will be in RC 2, and we'll have proper documentation on learn.microsoft.com at that time. |
I've been playing with it in the nightlys, it's very cool 😎 |
@slang25 got anything you want to share with the class? 🥹 |
|
The meta project created from a solution file has properties, items, and targets. What is the rationale for the MSB1063 error?
I didn't find anything in the discussion here or in the PR. |
E.g. Given a project with targets <Project>
<Target Name="One">
<PropertyGroup>
<First Condition="$(First) == ''">One</First>
</PropertyGroup>
<Message Text="One" />
<Message Text="First = $(First)" />
</Target>
<Target Name="Two">
<PropertyGroup>
<First Condition="$(First) == ''">Two</First>
</PropertyGroup>
<Message Text="Two" />
<Message Text="First = $(First)" />
</Target>
</Project> and given a command line with The current behavior executes the targets provided to It seems from the discussion that this is not the intended behavior. My own quick take is that |
Implementation annoyances, not anything principled. Because the solution metaproject isn't actually the project that was specified, it's nontrivial to reach "through" the I'd be happy to see this restriction removed, but not enough to block the feature on it. |
Excellent catch, thanks. Let's discuss on #9225. |
Makes sense. Thanks |
The lack of |
Friendly reminder that as of today there's still no trace of the |
@0xced it's in the linked MSBuild command-line docs. |
This is a feature request: Add a command line switch which would make MSBuild evaluate a project and output the value of a property or a list of items. No target would be called. This would be useful for scripting purposes.
Some examples of what I mean:
Or a simpler version:
The text was updated successfully, but these errors were encountered: