-
Notifications
You must be signed in to change notification settings - Fork 162
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
Add proposal for simplified output paths (version 2) #281
base: main
Are you sure you want to change the base?
Conversation
This looks good 👍🏻 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Big improvement over the previous proposal. Other than the minor point about renaming obj
, I see no issues with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really liking this iteration! I'll try to dig into some of the open questions around how other ecosystem layout their artifacts.
Co-authored-by: Rolf Bjarne Kvinge <[email protected]> Co-authored-by: Alexander Köplinger <[email protected]> Co-authored-by: Chet Husk <[email protected]>
df6df4c
to
8d3d67f
Compare
Hi folks! I've made another update to the proposal:
Have a look and keep the feedback coming. Thanks! |
This will be a major breaking change and generate work for every other project out there. We should think twice whether this cosmetic change is really worth it. |
|
||
If a project is multi-targeted to `net7.0` and `net8.0` and doesn't specify the output path format, then different formats will be used for the output for the different target frameworks. The .NET 7 build output will be in `bin\Debug\net7.0`, while the .NET 8 output will be in `artifacts\bin\debug_net8.0`. | ||
|
||
To prevent the output from one target framework to be globbed as part of the inputs to another target framework, both the `bin` and `artifacts` folder will need to be excluded from the default item globs (via the `DefaultItemExcludes` property). This means that even projects that target .NET 7 or lower could be impacted by breaking changes if they currently have source files or other assets in an `artifacts` folder. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this require an update to .NET 7 to not add default items from the artifacts
folder?
A .NET 8 build will generate source files and put them in artifacts/intermediates, and if the project also targets .NET 7, those files will be picked up as default items unless the artifacts
folder is excluded.
@jkotas Are you referring to any change we make to the output path format, or specifically this version of the proposal which would switch to using an I'm not sure that switching to an |
I feel that the For reference, I have spent almost a day earlier this week on debugging and working around a much smaller breaking change in the directory layout in .NET 7.0.200 SDK (dotnet/sdk#29177). I expect that the cost to update for the breaking change proposed here in any larger project is going to be very non-trivial. |
It'd be great to have a list of actual properties that are being changed at some point. |
Building software as a concept always needs two contexts at minimum, temporary one which can be discarded or overwritten and a permanent one which can be used, shared or published. That's why I proposed two root paths, one for building/testing and one for publishing/staging the final artifacts. Initial Proposals: The original structure I proposed is in dotnet/msbuild#6105. This has the following changes... Summary
The pros to this structure are...
The only con against this is having two directories instead of one. But I'm sure you can solve this with a simple property switch to make the publish come under build if users want it that way. Ultimately, I recommend this way if we want to have a structure that works for all projects and still have the ability to customize it when required. |
@alexrp I think that since you are not following the standard naming convention it would make sense for you to configure @dsplaisted Would it make sense for the artifact folder name to default to the |
I may be breaking with common .NET convention, but:
This point still stands. If you look at virtually any build tool that supports out-of-tree builds, they all replicate the relative project directory structure in the build output directory. If memory serves, this is true of Autotools, Meson, and CMake just off the top of my head. So I think it's reasonable for there to at least be a property in the SDK that I can flip to get this behavior, rather than having to roll it myself.
The issue is that the project name is added to the artifacts path in |
It's actually crucial to do this in many cases, because often, you'll have data that isn't the output of a compiler, and must be hierarchical in order to function (usually but not always at deploy time). Languages such as python are a good example of this. When this is the case, you need hierarchical build outputs as well, to:
For meson in particular, we "support" both a flat and a mirror layout, but the flat one is considered a failed experiment, is full of bugs, and has been deprecated (we will no longer accept bugfixes for it). There are a lot of routine things people do in a build system that depend on exact structure, and generally very little reason not to respect this by default. |
Took a closer look at the code and it seems the logic is repeated in |
I responded via the survey as well, but wanted to share some thoughts here....
The For my own setup, I have
For For
Under these folders there is then This setup ensures no overall conflicts, helps separate different types of shipping vs non-shipping files, makes it easy for artifact collection for different publishing steps/scenarios, and makes it trivial for users to find the relevant output files for manual copying, testing, or other considerations. |
Haven't tried it out in depth yet, but I also think that the |
A small thing: It would be nice if there was an
|
We could probably still use ArtifactsPath for that if we check whether it is already a fully-qualified path or not. |
Any thoughts on the output of test results? They're still written to a |
Not everyone who uses .NET is a power user of their operating system. macOS also makes this harder than it needs to be by not having a way to toggle hidden files without using the keyboard (unless something changed recently).
Many of those ( |
@alexrp You can do this with the following Directory.Build.props file: <Project>
<PropertyGroup>
<UseArtifactsOutput>true</UseArtifactsOutput>
<ArtifactsProjectName>$([System.IO.Path]::GetRelativePath('$(MSBuildThisFileDirectory)','$(MSBuildProjectDirectory)'))</ArtifactsProjectName>
</PropertyGroup>
</Project> I'm not sure if we want to add a property for this, since in most cases you would probably need to be explicit about what the "root" directory is that you're calculating the relative path from. As for using |
What about inserting a |
Would you though? Isn't it just going to be the same directory that |
I have been using multiple levels of props. A repo root and then a separate props for tests, source and samples. This is because each level of projects has different things that need setting. We also have sub folders with groups, so have a source folder with maybe core, graphics, and maybe compatibility. And in each of those we have a src, tests, samples. And we would still want outputs in the top level folder. |
Something I stumbled upon when working on a project that uses dockerfile. Currently, a project would likely have a dockerfile at the same (or at a deeper) level as the project's .\bin folder, and the dockerfile would have commands similar to the this:
|
This is a good point @RussKie. Generally though, it's normal for the Docker build to be run in the context of the .sln file in .NET projects, so that solution-level config like nuget.config and global.json are honored correctly. This is how the VS Container tools for Docker are setup to run by default. |
The finicky nature of handling paths within Dockerfiles was also a big driver for our SDK-native container builds, which are entirely in-box for 7.0.3xx and onwards and mitigate the need to manage paths. There are a few feature gaps (e.g. lack of RUN command support) but we could encourage the use of that tech more for this layout potentially. |
Is there a way of switching off the project name directory layer in the |
You can set |
Aaah so close. I can't imagine any situation your would ever want to remove the project name from the obj tree, unless you have a solution with only one project. I suspect removing the project name from the bin tree would be very common, in fact maybe more common than wanting it there IMHO! As a work around I found that you can add
I suspect nobody really cares where obj goes, although it is nice to have it out of tree, sort of |
Will the proposal document be updated regarding not using Also this line:
is off the mark. On Unix (macOS) and Unix-like (Linux) OSs files and folders that begin with |
I like the proposal, it more or less does what we had to do manually. One question though: We have introduced categories: Apps, Assemblies, Plugins, Tools and each assembly is built into this subcategory, otherwise we get a very long list of inidividual outputs. So the question is if we are able to adjust these. In the proposal I have read about
is this what is meant to do the above and should it already work? |
IMHO this does not solve the biggest problem there currently is with builds and containers. FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"] but this means EVERY SINGLE TIME I rebuild this application, it has to make a layer that contains both my application code and library. FROM base AS final
COPY --from=publish /app/publish/library /library
ENV DOTNET_EXTRA_DLL_PATH=/library
WORKDIR /app
COPY --from=publish /app/publish/application .
ENTRYPOINT ["dotnet", "WebApplication1.dll"] |
Please pay attention to this case:
It seems to me that everyone who wanted to move the Output of their projects did it a long time ago, via adding Output with $(ProjectName). What we really need - a way to build .sln of 300 projects with shared DLLs and independent EXE to the SINGLE output folder (not a Per-project). With correct resolving of NuGet dependencies, build order, error handling when two projects trying to CopyLocal different files with the same name, and avoid access denied because two projects want to copy .pdb of a shared DLL to the output during multi-threaded build. Think about it. |
Based on feedback from a discussion of #278, this is another attempt at simplifying output paths which should be more consistent.
Rendered view