C
C#•3mo ago
peppy

Publishing a mixed C++/.NET solution all at once

I have a solution with a mix of C++ and C#/.NET 9 projects. For the .NET part of the solution, I can publish with dotnet publish {SOLUTION_FILE_NAME} /p:PublishProfile="PROFILE_NAME". This invokes a publish profile with the given name for all C# projects in the solution, and works as intended. However, obviously dotnet publish cannot deal with the C++ projects in the solution. Is there a way- given all projects have the artifact output path specified- for the entire solution to be published at once using either VS or a Developer PowerShell?
25 Replies
reflectronic
reflectronic•3mo ago
does it work if you use msbuild instead
peppy
peppyOP•3mo ago
Doesn't seem so. Replacing dotnet with msbuild in that invocation gives MSB1008: Only one project can be specified. - and it seems to call MSBuild {...} for .NET Framework I'm not sure how exactly to do that properly.
reflectronic
reflectronic•3mo ago
msbuild -t:Publish -p:_IsPublishing=true ...
peppy
peppyOP•3mo ago
Hm. That does indeed do something more, but all the .NET projects complain that:
"D:\fh\Fahrenheit.sln" (Publish target) (1) ->
"D:\fh\base\core\Fahrenheit.Core.csproj" (Publish target) (2) ->
(ResolvePackageAssets target) ->
C:\Program Files\dotnet\sdk\9.0.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(
266,5): error NETSDK1047: Assets file 'D:\fh\artifacts\obj\Fahrenheit.Core\project.assets.json' doesn't have a targ
et for 'net9.0/win-x86'. Ensure that restore has run and that you have included 'net9.0' in the TargetFrameworks fo
r your project. You may also need to include 'win-x86' in your project's RuntimeIdentifiers. [D:\fh\base\core\Fahre
nheit.Core.csproj]
"D:\fh\Fahrenheit.sln" (Publish target) (1) ->
"D:\fh\base\core\Fahrenheit.Core.csproj" (Publish target) (2) ->
(ResolvePackageAssets target) ->
C:\Program Files\dotnet\sdk\9.0.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(
266,5): error NETSDK1047: Assets file 'D:\fh\artifacts\obj\Fahrenheit.Core\project.assets.json' doesn't have a targ
et for 'net9.0/win-x86'. Ensure that restore has run and that you have included 'net9.0' in the TargetFrameworks fo
r your project. You may also need to include 'win-x86' in your project's RuntimeIdentifiers. [D:\fh\base\core\Fahre
nheit.Core.csproj]
but the project does define:
<!-- ASSEMBLY BASIC PROPERTIES -->
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
...
<!-- ASSEMBLY BASIC PROPERTIES -->
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
...
(where the publish profiles all indicate a win-x86 target)
reflectronic
reflectronic•3mo ago
msbuild -restore -t:Publish -p:_IsPublishing=true
peppy
peppyOP•3mo ago
Right. That did the job for all the .NET projects. I only pieced together now that VS doesn't let me use its publish profile editor for the C++ projects. How does one make a publish profile for a C++ project? What ends up happening with no profile for the C++ bits is:
Project "D:\fh\Fahrenheit.sln" (1:2) is building "D:\fh\base\stage0\Fahrenheit.Loader.Stage0.vcxproj" (13:6) on nod
e 1 (Publish target(s)).
{...}
Link:
All outputs are up-to-date.
Fahrenheit.Loader.Stage0.vcxproj -> D:\fh\artifacts\build\Fahrenheit.Loader.Stage0\fhstage0.exe
C:\opt\programs\visualstudio\2022\professional\MSBuild\Current\Bin\amd64\Microsoft.Common.CurrentVersion.targets(55
24,5): error MSB3030: Could not copy the file "D:\fh\\artifacts\obj\Fahrenheit.Loader.Stage0\fhstage0.exe.manifest"
because it was not found. [D:\fh\base\stage0\Fahrenheit.Loader.Stage0.vcxproj]
Done Building Project "D:\fh\base\stage0\Fahrenheit.Loader.Stage0.vcxproj" (Publish target(s)) -- FAILED.

Project "D:\fh\Fahrenheit.sln" (1:2) is building "D:\fh\base\stage1\Fahrenheit.Loader.Stage1.vcxproj" (14:6) on nod
e 1 (Publish target(s)).
_DeploymentUnpublishable:
Skipping unpublishable project.
Done Building Project "D:\fh\base\stage1\Fahrenheit.Loader.Stage1.vcxproj" (Publish target(s)).
Project "D:\fh\Fahrenheit.sln" (1:2) is building "D:\fh\base\stage0\Fahrenheit.Loader.Stage0.vcxproj" (13:6) on nod
e 1 (Publish target(s)).
{...}
Link:
All outputs are up-to-date.
Fahrenheit.Loader.Stage0.vcxproj -> D:\fh\artifacts\build\Fahrenheit.Loader.Stage0\fhstage0.exe
C:\opt\programs\visualstudio\2022\professional\MSBuild\Current\Bin\amd64\Microsoft.Common.CurrentVersion.targets(55
24,5): error MSB3030: Could not copy the file "D:\fh\\artifacts\obj\Fahrenheit.Loader.Stage0\fhstage0.exe.manifest"
because it was not found. [D:\fh\base\stage0\Fahrenheit.Loader.Stage0.vcxproj]
Done Building Project "D:\fh\base\stage0\Fahrenheit.Loader.Stage0.vcxproj" (Publish target(s)) -- FAILED.

Project "D:\fh\Fahrenheit.sln" (1:2) is building "D:\fh\base\stage1\Fahrenheit.Loader.Stage1.vcxproj" (14:6) on nod
e 1 (Publish target(s)).
_DeploymentUnpublishable:
Skipping unpublishable project.
Done Building Project "D:\fh\base\stage1\Fahrenheit.Loader.Stage1.vcxproj" (Publish target(s)).
I would have expected both to be 'unpublishable'. No idea why it tried to build the first one.
reflectronic
reflectronic•3mo ago
it doesn't seem like C++ supports PublishProfile
peppy
peppyOP•3mo ago
Ouch. Well, I could do with it simply copying the build output where I tell it to for those two specific projects. I guess another way of doing this is just to force a .NET publish on every build... and then a post-build copy task for those two C++ projects only. I found https://github.com/dotnet/msbuild/issues/3138 which uses:
<Target Name="PublishAsBuildAfterTarget" AfterTargets="Build" DependsOnTargets="Publish">
<!-- placeholder task to force Publish to happen during build -->
</Target>
<Target Name="PublishAsBuildAfterTarget" AfterTargets="Build" DependsOnTargets="Publish">
<!-- placeholder task to force Publish to happen during build -->
</Target>
to force a publish on build, but doesn't seem to take a profile name parameter. I'll look further into it.
reflectronic
reflectronic•3mo ago
i suppose you could add something which reads PublishProfile to your vcxproj files why are you using publish profiles
peppy
peppyOP•3mo ago
I figured they were the way to specify an output directory and RID/platform target all at once. Since I am compiling specifically for Windows x86 and some dependencies (ImGui C# bindings) have to select the correct native DLL to copy based on the target arch.
reflectronic
reflectronic•3mo ago
i mean. for publish, yes. if you are trying to do publish on build, just to use publish profiles, then you don't want publish profiles
peppy
peppyOP•3mo ago
Sure. What should I have gone for then?
reflectronic
reflectronic•3mo ago
Customize your build with extensibility hooks - MSBuild
Customize your build with several extensibility hooks that you can use to modify MSBuild projects that use the standard build process.
peppy
peppyOP•3mo ago
Sorry. I'm confused. Maybe I should explain how I got here: - I have a solution with 12-13 projects, some .NET, some C++ - On build (or explicitly) I'd like to arrange them in output directories of my choice - I used to define <CopyToDir> in every .csproj or .vcxproj and had a Directory.Build.targets in the root solution folder like:
<!-- LOCAL TESTING COPY TASK -->
<Target Name="CopyAfterBuild" AfterTargets="Build" Condition="'$(CopyToDir)' != ''">
<ItemGroup>
<ProjectFiles Include="$(TargetDir)\**\*.*" />
</ItemGroup>

<Message Text="$(MSBuildProjectName): Copying to $(CopyToDir)." Importance="High" />

<Copy SourceFiles="@(ProjectFiles)" DestinationFolder="$(CopyToDir)" />

<Message Text="Copied build files to $(CopyToDir)." Importance="High" />
</Target>
<!-- LOCAL TESTING COPY TASK -->
<Target Name="CopyAfterBuild" AfterTargets="Build" Condition="'$(CopyToDir)' != ''">
<ItemGroup>
<ProjectFiles Include="$(TargetDir)\**\*.*" />
</ItemGroup>

<Message Text="$(MSBuildProjectName): Copying to $(CopyToDir)." Importance="High" />

<Copy SourceFiles="@(ProjectFiles)" DestinationFolder="$(CopyToDir)" />

<Message Text="Copied build files to $(CopyToDir)." Importance="High" />
</Target>
- What ended up happening here is that I wouldn't properly copy over everything. I'd end up with either more files than intended (because it wouldn't pick out only the relevant parts for the selected RID) or fewer - Publishing with a profile with a given RID didn't have this problem (and allowed me to do ex. single-file deployment), but now I'd have to first build C++ projects with this "CopyAfterBuild" target then publish to get everything I need - I was hoping to condense that down to one action, whichever of the two (building or publishing)
reflectronic
reflectronic•3mo ago
you should not be using custom targets to customize the output folder at all
peppy
peppyOP•3mo ago
I figured that at some point. So publish profiles were me trying to move away from that.
reflectronic
reflectronic•3mo ago
you are able to set the output directories that the build will use yourself using these extensibility points
peppy
peppyOP•3mo ago
Alright. I'll look into them. Thank you very much for the help and patience.
reflectronic
reflectronic•3mo ago
like, here is an example of using it to change the output directory for all projects in a folder https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022#directorybuildprops-example
peppy
peppyOP•3mo ago
Okay. And if I specify <RuntimeIdentifier>win-x86</RuntimeIdentifier> in a .csproj that would ensure the build is done for the correct arch? (or, rather, is that the same as me previously giving that in a publish profile?)
reflectronic
reflectronic•3mo ago
yes publish profile is the same as putting it in a project
peppy
peppyOP•3mo ago
Great, thanks a ton. I think I've figured it out now. šŸ˜„ Alright. I managed to figure it out. One final question. Can single-file deployment for .NET executables be specified for builds as well or is it a publishing-only thing?
reflectronic
reflectronic•3mo ago
it is publish-only
peppy
peppyOP•3mo ago
Unfortunate, but I'll make do, at least now the build is all neatly placing things where they belong with Directory.Build.props
Chet Husk
Chet Husk•3mo ago
re: Publish Profiles - in VS it's the same as putting it in your project file, but in the CLI today there are subtle differences that we haven't yet papered over. Here's the tracking issue we have for this: https://github.com/dotnet/sdk/issues/11474

Did you find this page helpful?