Skip to content
This repository has been archived by the owner on Oct 18, 2018. It is now read-only.

Update to MSBuild #478

Closed
wants to merge 2 commits into from
Closed

Update to MSBuild #478

wants to merge 2 commits into from

Conversation

pranavkm
Copy link
Contributor

@pranavkm pranavkm commented Mar 7, 2017

No description provided.

@pranavkm pranavkm force-pushed the prkrishn/msbuild branch 2 times, most recently from 88abeff to cddc984 Compare March 7, 2017 15:20
<Message Text="============ Done building $(RepositoryToBuild) ============" Importance="High" />
</Target>

<Target Name="_PinVersions">
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Summary of what we're doing here: prior to building a repository:

  1. We look at the restore graph spec to determine packages with floating versions
  2. Look at artifacts/build/*.nupkg and .deps/build/*.nupkgto determine if we have a package that has the same{Major.Minor.Build}` number as the floated version
  3. Pin the build if we found something in either of the two packages. The resulting file looks like this:
<Project>
  <ItemGroup>
    <PackageReference Update="Microsoft.AspNetCore.Http.Abstractions" Version="1.2.0-preview1-t0041a40df" Condition="'$(TargetFramework)'=='net451'" />
    <PackageReference Update="Microsoft.AspNetCore.Http.Extensions" Version="1.2.0-preview1-t0041a40df" Condition="'$(TargetFramework)'=='net451'" />
    <PackageReference Update="Microsoft.AspNetCore.WebUtilities" Version="1.2.0-preview1-t0041a40df" Condition="'$(TargetFramework)'=='net451'" />
    <PackageReference Update="Microsoft.AspNetCore.Http.Abstractions" Version="1.2.0-preview1-t0041a40df" Condition="'$(TargetFramework)'=='netstandard1.3'" />
    <PackageReference Update="Microsoft.AspNetCore.Http.Extensions" Version="1.2.0-preview1-t0041a40df" Condition="'$(TargetFramework)'=='netstandard1.3'" />
    <PackageReference Update="Microsoft.AspNetCore.WebUtilities" Version="1.2.0-preview1-t0041a40df" Condition="'$(TargetFramework)'=='netstandard1.3'" />
  </ItemGroup>
</Project>
  1. We drop this file in the project's obj directory with the right naming so that the sdk's auto include picks it up.

This removes the need for us to juggle around with the feeds to produce a coherent build. It also works around issues like the one Kestrel hit the other day where a higher version package (that we hadn't mirrored) ended up on NuGet.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could we take this one step farther and replace the PackageReference with a ProjectReference?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could we try that as a follow up? I wanted to keep the Update as simple as possible for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I should have been clearer. This is okay for now. Was just wondering if you had looked into ProjectReference. At one point I played with generating an MSBuild file in obj/ that removed PackageReference and added ProjectReference...but I ran into lingering issues in Package vs Project precedence in ResolveAssemblyReferences.

<Message Text="============ Building $(RepositoryToBuild) ============" Importance="High" />
<Exec
Command="./$(BuildScriptToExecute) $(_RepositoryBuildTargets) /p:BuildNumber=$(BuildNumber) /p:Configuration=$(Configuration)"
IgnoreStandardErrorWarningFormat="true"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For a full build, MSBuild takes super long to collate all our warnings at the end of the build. aspnet/BuildTools#190 might help, but there's a plethora of warning MSB3277: Found conflicts between different versions of the same dependent assembly that could not be resolved. that I'm not sure we are doing anything about. Turning this off causes us to lose colorization, but I think it's an acceptable cost for faster builds.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This might have been completely unrelated. I think I ran in to this: dotnet/msbuild#1808 (comment)

<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="Sake"
Properties="SakeTargets=$(_SakeTargets);RepositoryRoot=$(RepositoryRoot)" />
<Target Name="BuildRepositories"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This always attempts to produce a coherent build from the list of cloned repositories. Doing this includes fiddling around with repo's NuGet.configs + pinning package versions. We could add a different (default?) target that does what .\build used to do with sake - i.e build the repositories in sequence (ever since we broke build install (aspnet/KoreBuild#17).

That said, it might be simpler to say this repo is primarily a way for our build system to co-ordinate builds rather than for users to build all of AspNet. I'm not sure there's a lot of value in doing this. Thoughts @davidfowl ?

<MSBuild
Projects="$(MSBuildThisFileDirectory)RepositoryBuild.targets"
Targets="BuildRepositories"
Properties="
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there a saner way to do this?

Copy link
Contributor

Choose a reason for hiding this comment

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


namespace BuildGraph
{
public class DGMLFormatter : GraphFormatter
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Any C# code we need to review in detail? Or was the build train code already reviewed thoroughly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@anurse would know. I know a couple of folks including me looked at it at some point, but I'm not sure how thorough it was.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd take a look at the code. BuildTrain didn't really get any eyes because it was very prototypey and then kinda just got abandoned :)

{
var project = new Project(name)
{
// PackageReferences = MSBuildEval.GetPackageReferences(path),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will remove

<Target Name="_PinVersions">
<PropertyGroup>
<PinToolBinary>$(RepositoryRoot)tools\PinVersions\bin\$(Configuration)\netcoreapp1.1\PinVersions.dll</PinToolBinary>
<PinVersionArgs>$(DotNetPath) $(PinToolBinary) --graph-specs-root &quot;$(_RestoreGraphSpecsDirectory) &quot; -s &quot;$(BuildDir) &quot; &quot;$(BuildRepositoryRoot) &quot;</PinVersionArgs>
Copy link
Contributor Author

Choose a reason for hiding this comment

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


<Target Name="_BuildRepository" DependsOnTargets="_PinVersions">
<PropertyGroup>
<BuildScriptToExecute Condition="'$(OS)'!='Windows_NT'">build.sh</BuildScriptToExecute>
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of MSBuild => shell script => MSBuild, have you considered going straight to using MSBuild? KoreBuild is designed to key all locations off the RepositoryRoot property.

<MSBuild Projects="$(MSBuildProjectFullPath)" Properties="RepositoryRoot=$(BuildRepositoryRoot)" />

This avoids the pre-flight restore N+1 times for building N repositories, takes advantage of using the MSBuild already loaded in memory, and potentially avoids some thrashing by letting MSBuild orchestrate the entire build top to bottom.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could do that. My only mild concern was if the repos had out-of-sync versions of KoreBuild (like we did during the Tooling migration). Maybe that's an issue we can deal with when it arises.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should totally be the end goal. If we can do it now that'd be great, but there may be some other vestigial things in the build system that prevent it right now. If we can't do it now though, let's file an issue to track it because I think Nate's right that it'll be significantly faster.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe that's an issue we can deal with when it arises.

That's a good concern. I was actually just thinking about that. I don't expect we will hit this soon. In the long run, I'm hoping we can do something like aspnet/KoreBuild#196. In the short run, we could fall back to invoking build.cmd if we need to.


<Copy
SourceFiles="@(ArtifactsToCopy)"
DestinationFolder="$(BuildDir)" />
Copy link
Contributor

Choose a reason for hiding this comment

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

You can reduce disk usage by overriding the BuildDir setting for each repo so that it copies the packages into the Universe artifact folder directly.

<Repository Remove="@(RepositoriesToExclude)" />
</ItemGroup>

<Warning Text="KOREBUILD_REPOSITORY_EXCLUDE AND KOREBUILD_REPOSITORY_INCLUDE are specified."
Copy link
Contributor

Choose a reason for hiding this comment

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

Error? What's the problem here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you want to pick one or the other. It's likely a bad configuration when both are specified. I could make this an Error

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, let's make it an error. Sometimes the only way to find bad configs is to force them to fail.

</_CloneRepository>
</ItemGroup>

<RemoveDir Directories="$(_CloneRepositoryRoot)" Condition="Exists('$(_CloneRepositoryRoot)')" />
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we not do this? When doing cross-repo work, I work inside the Universe folder. It's nice to repeatedly run universe commands without it deleting all my work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can move this to Clean.

Copy link
Contributor

Choose a reason for hiding this comment

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

Awesome, thanks!

SourceFiles="$(MSBuildThisFileDirectory)Repositories.props"
DestinationFiles="$(RepositoryFileWithCommit)" />

<Exec
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you consider using MSBuild instead of a console tool to do this? IIUC what the AddCommitInfo file does, you can probably reduce this to something like:

<GetGitCommitInfo WorkingDirectory="$(_CloneRepositoryRoot)">
  <Output TaskParameter="CommitHash" PropertyName="_Hash" />
</GetGitCommitInfo>
<XmlPoke2 XmlInputPath="$(RepositoryFileWithCommit)" 
    Query="//Repository[@Include='$(RepoName)']/@Commit" Value="$(_Hash)" />

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was under the impression that XmlPoke(2) can't add new attributes.

Copy link
Contributor

Choose a reason for hiding this comment

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

When you generate "RepositoryFileWithCommit", you could add an empty Commit attribute.


private static string ReadCommitHash(string repositoryPath)
{
// Based on https://github.com/aspnet/BuildTools/blob/dev/src/Internal.AspNetCore.BuildTools.Tasks/GetGitCommitInfo.cs
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm against copy + pasting code from other repos. If you don't my suggestion above (implementing this tool in MSbuild instead), let's instead make this tool depend on Internal.AspNetCore.BuildTools.Tasks directly. We can abstract what GetGitCommitInfo to make it more usable if necessary.

using System.IO;
using System.Runtime.InteropServices;

// Copy of code from https://github.com/aspnet/DotNetTools/blob/047e4a8533bbcdf22831c40dd9d9aaf0c80d1953/shared/DotNetMuxer.cs
Copy link
Contributor

Choose a reason for hiding this comment

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

Ahhh! We need to put this in a common place. dotnet/extensions#173

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could reference CLI.Utils here instead and use their version of this type. How about that?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, let's do that for now.

@natemcmaster
Copy link
Contributor

I think this is a great step forward. I'm in favor of the work, but I think we'll get even more benefit from the MSBuild upgrade to make our build system MSbuild top-to-bottom. That means instead of 'Exec'-ing to dotnet-run, let's make those tools MSBuild tasks.

The benefits we get:

  • Makes build components usable.
    • Example: your BuildGraph tool could capture the the solution-to-solution build ordering logic in a reusable, abstract way. If implemented as a task, it could be defined in BuildTools and reused in Universe, Coherence, Coherence-Patch, CoreCLR, etc.
    • Saves some time on re-compiling the build graph tool for every run of Universe. This tool won't change much.
  • consistent programming model
  • unified logging. Tasks can call Log.LogMessage, Log.LogError etc and let MSbuild handle the file logger, coloring, verbosity, etc.
  • avoiding issues with PATH and .NET Core runtime installation. Tasks compile against .NET Standard and aren't bound to a specific version of .NET Core.
    • This opens the door to using MSBuild.exe on Windows. I'm not saying we should as dotnet.exe continues to be the easiest way to ensure we have the right SDKs (for now), but we have some projects that still only work with MSBuild.exe, like Razor. It would be nice if we could just swap to MSBuild.exe for those projects.

Copy link
Contributor

@analogrelay analogrelay left a comment

Choose a reason for hiding this comment

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

LGTM but I haven't been able to look in depth.

<Repository Include="Testing" />
<Repository Include="WebSockets" />
</ItemGroup>
</Project>
Copy link
Contributor

Choose a reason for hiding this comment

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

https://media.tenor.co/images/0331322b1e818d3a30709a519b879935/tenor.gif

(totally serious btw)


<Target Name="_BuildRepository" DependsOnTargets="_PinVersions">
<PropertyGroup>
<BuildScriptToExecute Condition="'$(OS)'!='Windows_NT'">build.sh</BuildScriptToExecute>
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should totally be the end goal. If we can do it now that'd be great, but there may be some other vestigial things in the build system that prevent it right now. If we can't do it now though, let's file an issue to track it because I think Nate's right that it'll be significantly faster.

@pranavkm pranavkm requested a review from dougbu March 8, 2017 00:42
Copy link
Contributor

@natemcmaster natemcmaster left a comment

Choose a reason for hiding this comment

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

Looks good enough for now. I don't want to hold up progress on getting Universe builds onto MSBuild.

Copy link
Member

@dougbu dougbu left a comment

Choose a reason for hiding this comment

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

Agree w/ @natemcmaster. Let's get this in and improve as-needed later.

EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{085280EC-7055-426A-BF9C-1B692B9599AB}"
ProjectSection(SolutionItems) = preProject
tools\shared\DependencyGraphSpecProvider.cs = tools\shared\DependencyGraphSpecProvider.cs
Copy link
Member

Choose a reason for hiding this comment

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

Think I noticed @(Compile) items don't show up in projects. If that's the reason this is here, please file a bug on the project system.

Projects="@(BatchedRepository)"
BuildInParallel="$(BatchBuilds)"
Targets="_BuildRepository"
Properties="BuildGroup=%(BatchedRepository.BuildGroup)" />
Copy link
Member

Choose a reason for hiding this comment

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

What reads the $(BuildGroup) property?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's used to batch the builds. Essentially the GroupBy argument.


namespace BuildGraph
{
public class DGMLFormatter : GraphFormatter
Copy link
Member

Choose a reason for hiding this comment

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

Any C# code we need to review in detail? Or was the build train code already reviewed thoroughly?

@pranavkm pranavkm closed this Mar 8, 2017
@natemcmaster natemcmaster mentioned this pull request Mar 13, 2017
@pranavkm pranavkm deleted the prkrishn/msbuild branch September 20, 2017 22:02
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants