Sdk: Dotnet publish no-build switch disappeared

Created on 15 Jan 2017  路  48Comments  路  Source: dotnet/sdk

Steps to reproduce

Dotnet publish -no-build

Expected behavior

It is supported

Actual behavior

No longer supported

Environment data

dotnet --info output:

This is a useful switch. We would like to understand why it's removed and if there is a replacement.

Most helpful comment

Thanks all for the feedback. As I mentioned above, I'm in strong agreement on this. We will add --no-build in v2.1.0.

All 48 comments

@dsplaisted @nguerrera @eerhardt Is there a way to trigger a publish without build?

@hongdai It would be useful if you can share how you used this flag. I think there was some debate about whether it is still useful.

It would be useful if you can share how you used this flag

Agreed. Getting all the use cases for why this switch is useful helps us understand whether to put it back or not.

One of the use cases I've recently encountered was the F# team (specifically @KevinRansom) was using this switch to publish a project's references, but he didn't want the project's output (its .dll) published. The replacement in that case is to add the MSBuild property <CopyBuildOutputToPublishDirectory>false</CopyBuildOutputToPublishDirectory> in your .csproj. That way, the current project's .dll isn't published.

FYI - @livarcocc and @piotrpMSFT, we could use this switch in the dotnet/cli ourselves in https://github.com/dotnet/cli/blob/rel/1.0.0/src/redist/redist.csproj. Then we wouldn't need to delete the redist.dll after publish, like we are currently doing.

It will be great to have --no-build supported.

We do the following in vstest repo:

  1. Build the sln file (all product, tests are built)
  2. Publish only the product projects
  3. Zip the published project for distribution

~In step 2, all the product dlls are built again. Depending on the number projects published, some of the common dependencies could be built multiple times.~

Update: our build process had a race condition on resources files which was slowing down the process. As @eerhardt notes below, msbuild incremental build does kick in, it is not a significant overhead for us now.

In step 2, all the product dlls are built again.

Why is incremental building not kicking in? MSBuild knows if a project is already built, and doesn't need to build it again.

@piotrpMSFT We used to have our own publish target and run in AfterBuild. Without no-build switch, the publish target will invoke a build and cause a infinite loop, unless we add a condition.

dotnet pack still supports no-build switch. I think the usage should be similar.

+1

As I see it, there should be an option to have the output of a build be the output of what you call "publish". I'd say that this should be the default behavior but that is debatable. As far as I understand it from reading the issues and documentation, this discrepancy is a workaround to speed up the build time of console apps (e.g. use the nuget cache to save on checksum calculations?!).

.Net is used for more than console apps and as such that workaround is not applicable to hosts different than dotnet run. For those cases, the actual dependencies are needed as part of the build output so it is runnable.

For such cases, I've managed to make dotnet publish output what is the real build output. To have it integrated with the VS Run command, I'd like to have the MSBuild Build target run the Publish target logic. This leads me to the infinite loop that @hongdai is talking about.

For me the no-build switch is a workaround. Ideally I would like you to support the case where the output of the build contains all the required runtime dependencies.

Same issue here -- Why wasn't this BREAKING CHANGE announced on the announcement repo? I've just converted all our stuff to csproj and now this broke our whole ci/azure setup.

We have 3 deployments setup on AppVeyor for a single solution, so we have 3 configurations that do the following:

  1. Build all the specific projects for this config
  2. Run all the specific tests for this config
  3. Publish to folder to be deployed by AppVeyor to Azure

@eamodio - same question as above - Why is incremental building not kicking in?

Let's say it is kicking in (which I think it is) -- just the fact the it has to run msbuild, scan for the project(s), see if they need building, etc -- all takes time; time I don't want to be waiting for my CI to finish. For example, on one of my projects it takes about 23s to build it the first time and then 9s to build it the second time (the one that used to be skipped). Yeah, 9s isn't that long in the scheme of things, but it isn't nothing either.

Also, given this flag is seemingly just a simple -- don't run msbuild -- I don't understand why it is so desirable to not support it?

I think this is caused by the current situations that large package graphs (netstandard.library, m.n.app) slow down msbuild projects which is causing project references to slow down linear (1 project 1 sec, 10 projects 10 sec) and has been discussed in https://github.com/dotnet/cli/issues/5918, https://github.com/dotnet/sdk/issues/1116, https://github.com/Microsoft/msbuild/issues/1276 and maybe even more.

Even if build targets are avoided for publish, I believe RunResolvePackageDependencies and ResolveAssemblyReferences would still need to be run to determine the proper publish output (I might be wrong) - and those are the targets that cause the slow incremental builds.

Also, given this flag is seemingly just a simple -- don't run msbuild -- I don't understand why it is so desirable to not support it?

@dasMulli hit the nail on the head.

What does --no-build mean? In reality in project.json world, it really meant something closer to --no-compile. But the Build target in MSBuild does so much more than just Compile your source code.

  • It resolves references
  • It resolves NuGet assets (managed and native libraries, content files, even pre-processed content files)
  • It gathers your project's Content files that need to be copied to the output

Doing a Publish without the things that happen during the Build target in MSBuild is almost pointless. What do you expect to have happened?

Another thing to understand is that dotnet publish really means "run the Publish MSBuild target". So it obviously isn't as simple as "don't run msbuild", since you can't run the Publish target without MSBuild.

So the reason there is push back to supporting it is because it isn't clear what the option is supposed to do/mean. And once we settle on a definition, the next decision to make is - is the scenario we are enabling a high-priority scenario that many customers need?

From that description why wouldn't --no-build mean don't run the Build target and only run the Publish target. Because if you've already run it without the --no-build flag then the Build target has already been run -- so everything is all prepared for the Publish target?

Like @dasMulli says above, there are shared targets between Build and Publish that will still need to be executed when just executing Publish. And the savings above and beyond an incremental build is usually negligible.

For example, on one of my projects it takes about 23s to build it the first time and then 9s to build it the second time (the one that used to be skipped). Yeah, 9s isn't that long in the scheme of things, but it isn't nothing either.

If you are interested in tracking down why the 2nd time is taking 9s, you can pass /v:diag into both dotnet build and dotnet publish. This will print out a lot of information (you probably want to pipe it to a file), but what you are interested in comes at the end. There is a table that shows where all the time is being spent in the build. For example, here is the table of publishing an ASP.NET 2.0 app on my local machine:

First Time

Project Performance Summary:
     6806 ms  F:\DotNetTest\TestWeb\TestWeb.csproj       1 calls
               6806 ms  Publish                                    1 calls

Target Performance Summary:
        0 ms  _DotNetCLIPrePublish                       1 calls
        0 ms  ComputeAndCopyFilesToPublishDirectory      1 calls
        0 ms  BeforeResGen                               1 calls
        0 ms  PrepareResourceNames                       1 calls
        0 ms  _DotNetCLIPostPublish                      1 calls
        0 ms  ResGen                                     1 calls
        0 ms  AfterBuild                                 1 calls
        0 ms  GetFrameworkPaths                          1 calls
        0 ms  ResolveReferences                          1 calls
        0 ms  GetReferenceAssemblyPaths                  1 calls
        0 ms  PrepareResources                           1 calls
        0 ms  _AspNetCoreProjectSystemPrePublish         1 calls
        0 ms  BeforeBuild                                1 calls
        0 ms  Compile                                    1 calls
        0 ms  AfterResGen                                1 calls
        0 ms  SetWin32ManifestProperties                 1 calls
        0 ms  CreateCustomManifestResourceNames          1 calls
        0 ms  GenerateUserSecretsAttribute               1 calls
        0 ms  CoreBuild                                  1 calls
        0 ms  GenerateAssemblyInfo                       1 calls
        0 ms  BeforePublish                              1 calls
        0 ms  _AspNetCoreProjectSystemPostPublish        1 calls
        0 ms  AfterPublish                               1 calls
        0 ms  _CopySourceItemsToOutputDirectory          1 calls
        0 ms  CreateSatelliteAssemblies                  1 calls
        0 ms  AfterCompile                               1 calls
        0 ms  PrepareForRun                              1 calls
        0 ms  AfterResolveReferences                     1 calls
        0 ms  InjectReference_efa7ce74-36bd-481a-bac0-42e316fc1d57   1 calls
        0 ms  IncludeTransitiveProjectReferences         1 calls
        0 ms  InjectReference_095e2d6d-4484-4c4e-b23a-d4bd8983312a   1 calls
        0 ms  BeforeCompile                              1 calls
        0 ms  BeforeResolveReferences                    1 calls
        0 ms  Build                                      1 calls
        0 ms  CopyFilesToPublishDirectory                1 calls
        0 ms  PrepareProjectReferences                   1 calls
        0 ms  _DefaultMicrosoftNETPlatformLibrary        1 calls
        0 ms  ResolvePackageDependenciesForBuild         1 calls
        0 ms  ResolveSDKReferences                       1 calls
        0 ms  _SetTargetFrameworkMonikerAttribute        1 calls
        0 ms  ResolveLockFileAnalyzers                   1 calls
        0 ms  BuildOnlySettings                          1 calls
        0 ms  PublishWithAspNetCoreTargetManifest        1 calls
        0 ms  ComputePrivateAssetsPackageReferences      1 calls
        0 ms  ExpandSDKReferences                        1 calls
        0 ms  GetInstalledSDKLocations                   1 calls
        0 ms  GetTargetPath                              1 calls
        0 ms  InjectReference_324b1a06-f466-4b33-a9b7-baf91ae299f2   1 calls
        0 ms  ComputeDependencyFileCompilerOptions       1 calls
        0 ms  _CheckForUnsupportedSelfContained          1 calls
        0 ms  _ComputeNetPublishAssets                   1 calls
        0 ms  _GenerateRunCommandFile                    1 calls
        0 ms  _SplitProjectReferencesByFileExistence     1 calls
        0 ms  _GenerateCompileInputs                     1 calls
        0 ms  CoreResGen                                 1 calls
        0 ms  _DetermineProjectType                      1 calls
        0 ms  Publish                                    1 calls
        0 ms  _InitPublishIntermediateOutputPath         1 calls
        0 ms  _InitProjectCapabilityProperties           1 calls
        0 ms  _CheckForCompileOutputs                    1 calls
        0 ms  PrepareForPublish                          1 calls
        0 ms  _GenerateEFSQLScripts                      1 calls
        0 ms  _GenerateSatelliteAssemblyInputs           1 calls
        0 ms  _ComputeLockFileFrameworks                 1 calls
        0 ms  _TransformAppSettings                      1 calls
        0 ms  ResolveProjectReferences                   1 calls
        1 ms  _ComputeNETCoreBuildOutputFiles            1 calls
        1 ms  SplitResourcesByCulture                    1 calls
        1 ms  _SetEmbeddedWin32ManifestProperties        1 calls
        1 ms  ComputeFilesToPublish                      1 calls
        1 ms  GeneratePublishRuntimeConfigurationFile    1 calls
        1 ms  GetAssemblyVersion                         1 calls
        1 ms  GetCopyToOutputDirectoryItems              1 calls
        2 ms  DefaultCopyToPublishDirectoryMetadata      1 calls
        2 ms  _HandlePublishFileConflicts                1 calls
        2 ms  IncrementalClean                           1 calls
        2 ms  AssignTargetPaths                          1 calls
        2 ms  GenerateTargetFrameworkMonikerAttribute    1 calls
        2 ms  _ComputeCopyToPublishDirectoryItems        1 calls
        2 ms  GetCopyToPublishDirectoryItems             1 calls
        2 ms  _ComputeLockFileAnalyzers                  1 calls
        3 ms  CoreGenerateUserSecretsAttribute           1 calls
        3 ms  _ComputeActiveTFMFileDependencies          1 calls
        4 ms  _GetProjectReferenceTargetFrameworkProperties   1 calls
        4 ms  PrepareForBuild                            1 calls
        4 ms  _ComputeTransitiveProjectReferences        1 calls
        4 ms  _CheckForInvalidConfigurationAndPlatform   1 calls
        4 ms  CheckForDuplicateItems                     1 calls
        5 ms  _ComputeTFMOnlyFileDependencies            1 calls
        5 ms  CopyFilesToOutputDirectory                 1 calls
        6 ms  CoreGenerateAssemblyInfo                   1 calls
        6 ms  _CopyOutOfDateSourceItemsToOutputDirectory   1 calls
        6 ms  _ComputeActiveTFMPackageDependencies       1 calls
        7 ms  _CheckForUnsupportedTargetFramework        1 calls
       15 ms  CheckForImplicitPackageReferenceOverrides   1 calls
       19 ms  _TransformWebConfig                        1 calls
       22 ms  _ComputeResolvedFilesToPublishTypes        1 calls
       24 ms  RunResolvePublishAssemblies                1 calls
       26 ms  _GenerateCompileDependencyCache            1 calls
       27 ms  _CleanGetCurrentAndPriorFileWrites         1 calls
       30 ms  _IncludePrePublishGeneratedContent         1 calls
       40 ms  ComputeRefAssembliesToPublish              1 calls
       62 ms  _CopyResolvedFilesToPublishPreserveNewest   1 calls
       64 ms  GenerateBuildRuntimeConfigurationFiles     1 calls
       74 ms  _ComputeLockFileReferences                 1 calls
       81 ms  GeneratePublishDependencyFile              1 calls
       82 ms  ResolveLockFileReferences                  1 calls
       87 ms  RunProduceContentAssets                    1 calls
      148 ms  GenerateBuildDependencyFile                1 calls
      244 ms  _ComputeLockFileCopyLocal                  1 calls
      247 ms  _HandlePackageFileConflicts                1 calls
      249 ms  _CopyResolvedFilesToPublishAlways          1 calls
      276 ms  RunResolvePackageDependencies              1 calls
     1166 ms  CoreCompile                                1 calls
     3721 ms  ResolveAssemblyReferences                  1 calls

Task Performance Summary:
        0 ms  Delete                                     1 calls
        0 ms  ReadLinesFromFile                          1 calls
        0 ms  AssignCulture                              1 calls
        0 ms  RemoveDuplicates                           2 calls
        0 ms  GetFrameworkPath                           1 calls
        1 ms  FindAppConfigFile                          1 calls
        1 ms  FindUnderPath                              5 calls
        1 ms  MSBuild                                    1 calls
        1 ms  GetAssemblyVersion                         1 calls
        1 ms  Message                                    4 calls
        2 ms  AssignTargetPath                           6 calls
        2 ms  WriteLinesToFile                           2 calls
        3 ms  MakeDir                                    2 calls
        4 ms  CheckForDuplicateItems                     3 calls
        7 ms  CheckForImplicitPackageReferenceOverrides   1 calls
        8 ms  WriteCodeFragment                          2 calls
       10 ms  Hash                                       1 calls
       17 ms  TransformWebConfig                         1 calls
       18 ms  ProduceContentAssets                       1 calls
       22 ms  ConvertToAbsolutePath                      2 calls
       24 ms  ResolvePublishAssemblies                   1 calls
       64 ms  GenerateRuntimeConfigurationFiles          2 calls
      144 ms  ResolvePackageFileConflicts                2 calls
      229 ms  GenerateDepsFile                           2 calls
      274 ms  ResolvePackageDependencies                 1 calls
      316 ms  Copy                                       5 calls
     1164 ms  Csc                                        1 calls
     3719 ms  ResolveAssemblyReference                   1 calls

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:07.19

Second Time

Project Performance Summary:
     5923 ms  F:\DotNetTest\TestWeb\TestWeb.csproj       1 calls
               5923 ms  Publish                                    1 calls

Target Performance Summary:
        0 ms  ResGen                                     1 calls
        0 ms  BeforeResGen                               1 calls
        0 ms  PrepareResourceNames                       1 calls
        0 ms  ResolveReferences                          1 calls
        0 ms  Compile                                    1 calls
        0 ms  _DotNetCLIPostPublish                      1 calls
        0 ms  _DotNetCLIPrePublish                       1 calls
        0 ms  ComputeAndCopyFilesToPublishDirectory      1 calls
        0 ms  _AspNetCoreProjectSystemPrePublish         1 calls
        0 ms  AfterBuild                                 1 calls
        0 ms  GetFrameworkPaths                          1 calls
        0 ms  PrepareResources                           1 calls
        0 ms  AfterResGen                                1 calls
        0 ms  SetWin32ManifestProperties                 1 calls
        0 ms  BeforeBuild                                1 calls
        0 ms  PrepareProjectReferences                   1 calls
        0 ms  CreateSatelliteAssemblies                  1 calls
        0 ms  BeforePublish                              1 calls
        0 ms  CreateCustomManifestResourceNames          1 calls
        0 ms  GenerateUserSecretsAttribute               1 calls
        0 ms  BeforeCompile                              1 calls
        0 ms  CoreBuild                                  1 calls
        0 ms  AfterCompile                               1 calls
        0 ms  AfterResolveReferences                     1 calls
        0 ms  GenerateAssemblyInfo                       1 calls
        0 ms  CopyFilesToPublishDirectory                1 calls
        0 ms  _CopySourceItemsToOutputDirectory          1 calls
        0 ms  ResolvePackageDependenciesForBuild         1 calls
        0 ms  InjectReference_efa7ce74-36bd-481a-bac0-42e316fc1d57   1 calls
        0 ms  Build                                      1 calls
        0 ms  BuildOnlySettings                          1 calls
        0 ms  GetReferenceAssemblyPaths                  1 calls
        0 ms  _AspNetCoreProjectSystemPostPublish        1 calls
        0 ms  AfterPublish                               1 calls
        0 ms  BeforeResolveReferences                    1 calls
        0 ms  PrepareForRun                              1 calls
        0 ms  IncludeTransitiveProjectReferences         1 calls
        0 ms  ExpandSDKReferences                        1 calls
        0 ms  ResolveLockFileAnalyzers                   1 calls
        0 ms  _DefaultMicrosoftNETPlatformLibrary        1 calls
        0 ms  InjectReference_095e2d6d-4484-4c4e-b23a-d4bd8983312a   1 calls
        0 ms  _SetTargetFrameworkMonikerAttribute        1 calls
        0 ms  PublishWithAspNetCoreTargetManifest        1 calls
        0 ms  ComputePrivateAssetsPackageReferences      1 calls
        0 ms  ResolveSDKReferences                       1 calls
        0 ms  ComputeDependencyFileCompilerOptions       1 calls
        0 ms  _CheckForUnsupportedSelfContained          1 calls
        0 ms  _ComputeNetPublishAssets                   1 calls
        0 ms  GetTargetPath                              1 calls
        0 ms  _SplitProjectReferencesByFileExistence     1 calls
        0 ms  PrepareForPublish                          1 calls
        0 ms  _GenerateRunCommandFile                    1 calls
        0 ms  GetInstalledSDKLocations                   1 calls
        0 ms  CoreResGen                                 1 calls
        0 ms  InjectReference_324b1a06-f466-4b33-a9b7-baf91ae299f2   1 calls
        0 ms  _DetermineProjectType                      1 calls
        0 ms  _CheckForCompileOutputs                    1 calls
        0 ms  _InitProjectCapabilityProperties           1 calls
        0 ms  _GenerateSatelliteAssemblyInputs           1 calls
        0 ms  GenerateBuildDependencyFile                1 calls
        0 ms  _GenerateCompileInputs                     1 calls
        0 ms  _InitPublishIntermediateOutputPath         1 calls
        0 ms  Publish                                    1 calls
        0 ms  ResolveProjectReferences                   1 calls
        0 ms  _GenerateEFSQLScripts                      1 calls
        0 ms  _ComputeLockFileFrameworks                 1 calls
        0 ms  _TransformAppSettings                      1 calls
        1 ms  _ComputeNETCoreBuildOutputFiles            1 calls
        1 ms  SplitResourcesByCulture                    1 calls
        1 ms  IncrementalClean                           1 calls
        1 ms  _SetEmbeddedWin32ManifestProperties        1 calls
        1 ms  DefaultCopyToPublishDirectoryMetadata      1 calls
        1 ms  GetCopyToOutputDirectoryItems              1 calls
        1 ms  _HandlePublishFileConflicts                1 calls
        1 ms  GeneratePublishRuntimeConfigurationFile    1 calls
        2 ms  CoreGenerateUserSecretsAttribute           1 calls
        2 ms  ComputeFilesToPublish                      1 calls
        2 ms  CoreGenerateAssemblyInfo                   1 calls
        2 ms  CopyFilesToOutputDirectory                 1 calls
        2 ms  _ComputeLockFileAnalyzers                  1 calls
        2 ms  AssignTargetPaths                          1 calls
        2 ms  GenerateTargetFrameworkMonikerAttribute    1 calls
        2 ms  GetAssemblyVersion                         1 calls
        3 ms  PrepareForBuild                            1 calls
        3 ms  _GetProjectReferenceTargetFrameworkProperties   1 calls
        3 ms  _ComputeActiveTFMFileDependencies          1 calls
        3 ms  _ComputeCopyToPublishDirectoryItems        1 calls
        3 ms  CheckForDuplicateItems                     1 calls
        3 ms  GetCopyToPublishDirectoryItems             1 calls
        4 ms  _ComputeTFMOnlyFileDependencies            1 calls
        4 ms  _CheckForInvalidConfigurationAndPlatform   1 calls
        4 ms  _ComputeTransitiveProjectReferences        1 calls
        6 ms  _ComputeActiveTFMPackageDependencies       1 calls
        8 ms  _CheckForUnsupportedTargetFramework        1 calls
       13 ms  CheckForImplicitPackageReferenceOverrides   1 calls
       14 ms  CoreCompile                                1 calls
       16 ms  _TransformWebConfig                        1 calls
       16 ms  _ComputeResolvedFilesToPublishTypes        1 calls
       24 ms  _CleanGetCurrentAndPriorFileWrites         1 calls
       25 ms  RunResolvePublishAssemblies                1 calls
       36 ms  _CopyOutOfDateSourceItemsToOutputDirectory   1 calls
       41 ms  ComputeRefAssembliesToPublish              1 calls
       50 ms  _GenerateCompileDependencyCache            1 calls
       72 ms  _IncludePrePublishGeneratedContent         1 calls
       72 ms  _ComputeLockFileReferences                 1 calls
       80 ms  GenerateBuildRuntimeConfigurationFiles     1 calls
       83 ms  ResolveLockFileReferences                  1 calls
       86 ms  RunProduceContentAssets                    1 calls
      159 ms  GeneratePublishDependencyFile              1 calls
      202 ms  _CopyResolvedFilesToPublishAlways          1 calls
      228 ms  _HandlePackageFileConflicts                1 calls
      236 ms  _ComputeLockFileCopyLocal                  1 calls
      273 ms  _CopyResolvedFilesToPublishPreserveNewest   1 calls
      275 ms  RunResolvePackageDependencies              1 calls
     3835 ms  ResolveAssemblyReferences                  1 calls

Task Performance Summary:
        0 ms  Delete                                     1 calls
        0 ms  AssignCulture                              1 calls
        0 ms  RemoveDuplicates                           2 calls
        1 ms  GetFrameworkPath                           1 calls
        1 ms  FindAppConfigFile                          1 calls
        1 ms  ReadLinesFromFile                          1 calls
        1 ms  MSBuild                                    1 calls
        1 ms  FindUnderPath                              5 calls
        1 ms  WriteLinesToFile                           1 calls
        1 ms  Message                                    4 calls
        2 ms  MakeDir                                    2 calls
        2 ms  AssignTargetPath                           6 calls
        2 ms  GetAssemblyVersion                         1 calls
        3 ms  CheckForDuplicateItems                     3 calls
        6 ms  CheckForImplicitPackageReferenceOverrides   1 calls
       10 ms  Hash                                       1 calls
       14 ms  TransformWebConfig                         1 calls
       18 ms  ProduceContentAssets                       1 calls
       20 ms  ConvertToAbsolutePath                      2 calls
       25 ms  ResolvePublishAssemblies                   1 calls
       81 ms  GenerateRuntimeConfigurationFiles          2 calls
      143 ms  ResolvePackageFileConflicts                2 calls
      159 ms  GenerateDepsFile                           1 calls
      204 ms  Copy                                       3 calls
      268 ms  ResolvePackageDependencies                 1 calls
     3833 ms  ResolveAssemblyReference                   1 calls

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:06.18

As you can see, CSC is only taking a little over 1s the first time. However, even in the 2nd time ResolveAssemblyReference is taking ~65% of the time (3835 ms / 5923 ms). As I asked above, do you expect that when you dotnet publish --no-build that you shouldn't get any referenced assemblies copied to your output directory?

(Now granted, we probably have some sort of perf bug in ResolveAssemblyReference, but that is a different discussion.)

Anyway, I'd be interested in learning what you find is taking 9s on your 2nd build. I'm sure you would be too 馃槈.

Thanks for the information! I will try that out and see what the bottleneck is.

As for the ResolveAssemblyReference -- If that isn't done as part of the Build task, then I would expect it to be done, but if it isn't done as part of the Build task, then I would expect it to be done.

Basically I just want to avoid doing duplicate work.

The result of ResolveAssemblyReference isn't saved to disk after the call to Build. So when a new process comes along for dotnet publish, it needs to be run again.

(Now granted, we probably have some sort of perf bug in ResolveAssemblyReference, but that is a different discussion.)

That different discussion is here; https://github.com/Microsoft/msbuild/issues/2015

Here is my use case. I'm working on adding CI to our process for an ASP.Net Core site we are building. I want to be able to build once, test those binaries, and then publish the tested binaries as part of the CI workflow. This flag still works with package, which we are using for publishing internal nuget packages in our CI workflow.

To my mind, publishing a project should operate on it's built assets - therefore publishing is obviously dependent on a build having occurred! I think it would be rare in the world of CI that you would want to publish something from a vanilla state (i.e without already having just done a build to test the assets you are publishing). So the reason for wanting to specify "no build" is because at the point of the workflow you want to publish you have already done the build - mixed in with the fact that an "incremental build" doesn't seem to be as fast as it should be. If an incremental build truly was neglible (i.e zero overhead if build already done) then I don't think this would be such an issue. I guess it's debatable what an acceptable level of overhead would be. I'd be ok if, for large projects, an incremental build didn't incur more than a couple of seconds penalty when nothing has changed. If it takes more than that, and you know ahead of time nothing has changed then you can see why people would be looking to use that "no build" flag if it's available.

This brings me to another point - the willingness to remove this and break peoples CI's processes to seemingly force some feedback on the issue seems a little bit hostile :-/ don't you think?

@eerhardt

As I asked above, do you expect that when you dotnet publish --no-build that you shouldn't get any referenced assemblies copied to your output directory?

I am wondering why it should need to look at references at this point? If the build has already occurred, then the build output (including referenced assemblies / content files etc that had "copy to output") has already been produced. In other words, the assets are already all produced and publish just needs to do something with those existing assets. Why would it need to check references?

@dazinator Exactly. Even if the "incremental build" is negligible, that is still shipping a different set of compiled binaries than the ones that were tested, and in some environments that is unacceptable.

I think we should add the --no-build. I encountered an issue internally where the build portion of publish overwrote binaries that were signed in the build output directory with unsigned copies.

I worked around it with:

    <Target Name="PublishWithoutBuilding"
            DependsOnTargets="PreventProjectReferencesFromBuilding;
                              ResolveReferences;
                              ComputeAndCopyFilesToPublishDirectory;
                              GeneratePublishDependencyFile;
                              GeneratePublishRuntimeConfigurationFile" />                                                           

    <Target Name="PreventProjectReferencesFromBuilding">
      <PropertyGroup>
        <BuildProjectReferences>false</BuildProjectReferences>
      </PropertyGroup>
    </Target>

which is the same as the real Publish, with PreventProjectReferencesFromBuilding;ResolveReferences replacing Build.

cc @jaredpar @agocke

I think we should add the --no-build.

Strongly agree. Build is basically a composition of two operations: compile and deploy. Once I've compiled there is simply no need to re-compile when I want to deploy for a new platform. Compiling is just wasting CPU cycles and developer time at that point.

I'll note, for the case where publish was overwriting binaries that had a separate post-build step applied: the incremental build is a perf optimization and shouldn't be relied on for semantic guarantees. so it should never be used as a solution to this problem.

The PublishWithoutBuilding above won't be materially faster than an up-to-date incremental build (compile step would no-op but we still need to resolve references in both cases), so it is really more about semantics than speed.

The fact that reference resolution can be slow is orthogonal and something that is being worked on. It will benefit both incremental builds and things that resolve but don't build.

https://github.com/Microsoft/msbuild/issues/2015

@nguerrera Not sure you can make that assertion without knowing the writeread speed of the user's output directory, which could theoretically be on a remote network share.

You mean read speed to determine what's up to date?

@nguerrera Yes :)

My assertion should have had more qualifications, but my main point was that you need the semantics of --no-build even more importantly than the speed.

My assertion should have had more qualifications, but my main point was that you need the semantics of --no-build even more importantly than the speed.

100% agree.

Is it possible to approximate the semantics of --no-build by using publish earlier in the build process. I.e.

  1. Run publish (instead of build)
  2. Run unit tests
  3. If they pass, then actually use the output from the publish

I can imagine this could be problematical for users who want to build lots of projects, but only publish some. (E.g. don't publish the unit test projects). Any other issues with it?

BTW, even if this is workable, it still seems like a workaround. I agree with the @nguerrera and @jaredpar that the semantics of --no-build are desirable.

@JohnRusk that works on small projects but not on bigger ones. Consider Roslyn which has ~160+ projects in our solution and eventually will have ~10-20 test projects that in theory need publishing. There is really no way to publish all of them without rebuilding their shared dependencies.

Having an explicit, and supported, no build publish is the only reasonable solution here.

We have a post build script in our dev environments which publishes our service and then restarts a docker container running in a VM which is hosting the service. Without the --no-build switch the post build step causes an infinite loop.

I agree with bringing back the --no-build switch option - unless there is another way to achieve the above?

Whatever the solution will be, it seems clear from the comments above that Build -> Test -> Publish is a highly desired workflow, for myself included. Thus, a publish command that can take pre-existing output is a highly desirable requirement, whether this is a --no-build flag or some equivalent. Even more so using a hosted build agent service where build time = money.

My CI is based on Build, Test and finally publish those binaries that were tested. It made sure that the binaries that were tested were the ones published. Now when I publish, it rebuilds, giving me a brand new set of binaries... Please bring back that switch, it broke my CI.

Just got here looking for this. Trying to run dotnet publish with visual studio open breaks hard. Using --no-build would work. Incremental build is still broken here for quite unobvious reasons.

In answer to others above, --no-build should assume dotnet build finished and pick up the output binaries from that.

Read through the above posts, and not clear as to what the holdup is.

In my case it broke my CI step and I am now deploying manually.

Can't --no-build be added back in so we can continue to work while the debate goes on? At the very least it should have been deprecated rather than removed, as it is a breaking change.

Thanks all for the feedback. As I mentioned above, I'm in strong agreement on this. We will add --no-build in v2.1.0.

Another use case (after the horse has bolted):

We have a .NET Core solution with a number of docker containers with APIs. The solution also includes a developer-only console app for Dev investigation. When a Developer presses F5 and the whole solution builds and runs up docker, I want the console app (and only the console app) to republish itself to a Win 10 x64 target so that the devs can use the console app from Powershell. I would normally put publish in a post-build event in the .csproj but that creates an infinite loop. I need the --no-build parameter to stop that.

I appreciate that my Devs can still do dotnet c:/blah/myapp.dll params but they find that upsetting.

Same problem. Trying to automate publishing Asp.NET Core project. There is no way to force publish after build, so I ended up adding a 'dotnet publish' post-build event. Sadly it results in recursive builds that never end. A --no-build switch would fix something that I will now have to spend hours trying to work around.

try dotnet msbuild /t:publish /p:NoBuild=True

Hey @gulbanana : thanks for the tip but for me msbuild still rebuilds dependent projects. So it's different than the former --no-build options that didn't even tried to build anything and just assumed the right dll was here.

There's also the /p:BuildProjectReferences=false switch that indicates that all dependencies are up-to-date and don't need to be rebuilt (see ProjectReference protocol)

@dasMulli : thanks a lot! works great! (and I can finally publish my 5 projects without having to rebuild everything all the time :-) )

Here's how our build process used to look like with the 1.0.4 .NET Core SDK:

dotnet restore
dotnet build /p:Version=6.6.6
dotnet test
dotnet publish 
docker build <using publish output folder>
docker push 

As you can see, we use a /p msbuild option for dotnet build to specify the version that we want for our assembly. This used to work great.

With .NET Core 2, since the dotnet publish does on dotnet build, the result of dotnet publish recompiles the assembly without using the 6.6.6 assembly version. We therefore end-up with a docker container that contains assemblies that:

  1. were not used during the tests
  2. don't have the good assembly version

I can fix this problem using dotnet publish /p:Version=6.6.6. But in fact, the problem is more complex since we also use dotnet lambda package that does an implicit dotnet publish that does not allow me to specify the /p:Version=6.6.6 parameters. See https://github.com/aws/aws-lambda-dotnet/issues/210 for more details.

Please add the --no-build option ;)

Is there plans to add the no-build option back? Not building the references isn鈥檛 quite the same thing.. thanks!

@diegohb At the top of this issue, you can see that it's slated for release with milestone 2.1.3xx.
Check out all the issues in that milestone here: https://github.com/dotnet/cli/milestone/17

I will try to get to this soon.

dotnet/sdk#2111 (in PR) implements the dotnet/sdk half of this. After that, we just need to wire --no-build to /p:NoBuild=true here.

Was this page helpful?
0 / 5 - 0 ratings