Skip to content
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

Build with dotnet.exe #517

Closed
fredericDelaporte opened this issue Sep 17, 2017 · 8 comments
Closed

Build with dotnet.exe #517

fredericDelaporte opened this issue Sep 17, 2017 · 8 comments

Comments

@fredericDelaporte
Copy link

fredericDelaporte commented Sep 17, 2017

It seems building with dotnet.exe command line is currently unsupported.

This fails by example like this (line breaks manually added):

E:\Projets\nhibernate\nhibernate-core\doc>dotnet msbuild NHibernate.shfbproj
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

C:\Program Files (x86)\EWSoftware\Sandcastle Help File Builder\SandcastleHelpFileBuilder.targets(40,3):
error MSB4062: The "SandcastleBuilder.Utils.MSBuild.BuildHelp" task could not be loaded from the
assembly C:\Program Files (x86)\EWSoftware\Sandcastle Help File Builder\\SandcastleBuilder.Utils.dll.
Could not load type 'System.ComponentModel.Composition.ExportAttribute' from assembly
'System.ComponentModel.Composition, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
Confirm that the <UsingTask> declaration is correct, that the assembly and all its dependencies are
available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.
[E:\Projets\nhibernate\nhibernate-core\doc\NHibernate.shfbproj]

E:\Projets\nhibernate\nhibernate-core\doc>

While building the same project with msbuild 15 succeeds.

This forces to still use (and locate...) msbuild.exe for generating the doc while all the other parts of the project use dotnet.exe.

@EWSoftware
Copy link
Owner

That is correct. You will need at least MSBuild 14.0 to build SHFB projects. The SHFB build engine itself has dependencies on MSBuild assemblies so you can't get rid of it completely.

@ritchiecarroll
Copy link
Contributor

ritchiecarroll commented Jan 15, 2020

FYI, if I use dotnet build or dotnet msbuild from the command line on a Sandcastle Project I get the following:

C:\Program Files (x86)\EWSoftware\Sandcastle Help File Builder\SandcastleHelpFileBuilder.targets
(40,3):error MSB4062: The "SandcastleBuilder.Utils.MSBuild.BuildHelp" task could not be loaded
from the assembly C:\Program Files (x86)\EWSoftware\Sandcastle Help File Builder\
SandcastleBuilder.Utils.dll. Could not load file or assembly 'System.Windows.Forms,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
The system cannot find the file specified. Confirm that the <UsingTask> declaration is correct,
that the assembly and all its dependencies are available, and that the task contains a public
class that implements Microsoft.Build.Framework.ITask. 
[D:\Projects\gemstone\common\src\DocGen\docgen.shfbproj]

As mentioned above, calling msbuild directly seems to work fine, but it's strange since dotnet build uses msbuild in the background:

C:\>msbuild -version
Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

16.4.0.56107

C:\>dotnet msbuild -version
Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

16.4.0.56501

Since the error message is specifically about the fact that it cannot load System.Windows.Forms, this makes me suspect that the dotnet build is trying to treat the SandCastle project as a .NET Core app? Not really sure, especially since building within Visual Studio doesn't seem to be an issue.

However, this basically means you can't script a build to include SandCastle output only using the dotnet build command on a solution that contains both .NET core projects and a SandCastle project. Currently the only way I can script a build is by:

  1. Removing the SandCastle project from the Visual Studio solution build configuration, and
  2. Manually calling msbuild to explicitly build the SandCastle shfbproj file

Not a show stopper since there is a work around, however, since building using dotnet build is the recommended future way of scripting builds in .NET, I am thinking this issue should be reevaluated.

Thanks!
Ritchie

@ritchiecarroll
Copy link
Contributor

After some research, looks like dotnet build only supports .NET Standard, .NET Core and .NET Framework project types.

To get this to work with SandCastle, you would need to either multi-target the MSBuild task -- or -- convert everything to .NET Standard, which "should" work in both environments.

Here is an article that talks about multi-targeting MSBuild:
https://natemcmaster.com/blog/2017/07/05/msbuild-task-in-nuget/

This article answered my question about why it works in Visual Studio and not from the command line, the answer is Visual Studio still uses MSBuild not dotnet build. The dotnet build command is platform portable and currently only supports projects using Microsoft.NET.Sdk.

This issue was captured as an issue on the microsoft/msbuild GitHub project site, but was subsequently closed: dotnet/msbuild#2111

Also, several projects with a similar dilemma are basically going down the multi-targeting path:

For more information, this google query was the most insightful:
usingtask "dotnet" "could not load file or assembly"

Well, I hope this is was at least somewhat insightful and helps you with thinking about possible options.

Certainly I think testing the .NET Standard approach would be the more simple / lowest effort of the two options since this only entails converting the SandcastleBuilder.Utils.dll to a .NET Standard project DLL which should technically work for both environments. If not, minimal effort invested.

Thanks!
Ritchie

@EWSoftware
Copy link
Owner

I don't think it's as simple as just updating SandcastleBuilder.Utils to support .NET Standard. While that drives the build process, it calls all the other tools as well executing them with MSBuild, all of which are built against the full framework too. They'd have to be updated to run on .NET Standard too. That's a whole lot more work and may not be possible considering that some of the stuff they use may not be available on .NET Standard. You'd have to run the portability analyzer on the entire tool set to figure out what's missing.

Many of the components offer interactive configuration, hence the references to the WPF and Windows Forms assemblies. Getting rid of those would require some other method of invoking the configuration dialogs. All the build components, plug-ins, and presentation styles use MEF as well which I'm not sure is available or fully supported yet outside of the full framework.

@ritchiecarroll
Copy link
Contributor

Yeah - I went down trying .NETStandard path. This failed at MSBuild, which is available on both platforms, but only for explicit .NET Framework or .NET Core implementations. As a result, I posted a pull request so you can see what it took to get Sandcastle.Utils.dll, the assembly containing MSBuild task code, built using .NET core. Next task would be to put code in a shfbproj file that basically conditionally references proper DLL based on target framework - per this:
https://natemcmaster.com/blog/2017/07/05/msbuild-task-in-nuget/

I've ran out of time to test today...

@EWSoftware
Copy link
Owner

I think the SHFB projects are okay. The targets file included by them is probably where you'd make the changes to multi-target the assembly.

That would probably get the project to load and start to build but aren't you going to have issues with all the other tools invoked by the build engine?

@ritchiecarroll
Copy link
Contributor

ritchiecarroll commented Jan 16, 2020

Yes - that's where I am testing now - making some progress with this:

<Project DefaultTargets="Build" TreatAsLocalProperty="TaskAssembly" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <!-- Sandcastle Help File Builder Tasks.  https://GitHub.com/EWSoftware/SHFB -->

    <PropertyGroup>
        <TaskAssembly Condition=" '$(MSBuildRuntimeType)'!='Core'">$(SHFBROOT)\SandcastleBuilder.Utils.dll</TaskAssembly>
        <TaskAssembly Condition=" '$(MSBuildRuntimeType)'=='Core'">$(SHFBROOT)\DotNetCore\SandcastleBuilder.Utils.dll</TaskAssembly>
    </PropertyGroup>

    <UsingTask TaskName="SandcastleBuilder.Utils.MSBuild.BuildHelp" AssemblyFile="$(TaskAssembly)" />
    <UsingTask TaskName="SandcastleBuilder.Utils.MSBuild.CleanHelp" AssemblyFile="$(TaskAssembly)" />

@ritchiecarroll
Copy link
Contributor

FYI - I had to add a small dotnet core only build task to load needed assemblies to get everything to work (see XML below for how it's applied).

Now I am down to an error that looks like it comes from SHFB:

D:\Projects\gemstone\common\src\DocGen>dotnet msbuild
Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Building D:\Projects\gemstone\common\src\DocGen\docgen.shfbproj
  Initializing
SHFB : error BE0071: Unable to locate information for the project framework version 'Cross-platform (.NET Core/.NET Standard)' or a suitable redirected version on this system.  See error number help topic for details. [D:\Projects\gemstone\common\src\DocGen\docgen.shfbproj]
  Failed
  Build details can be found in D:\Projects\gemstone\common\docs\help\LastBuild.log

This is as far as I've gotten.

Thanks,
Ritchie

<Project DefaultTargets="Build" TreatAsLocalProperty="TaskAssembly" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <!-- Sandcastle Help File Builder Tasks.  https://GitHub.com/EWSoftware/SHFB -->

    <PropertyGroup>
        <TaskAssembly Condition=" '$(MSBuildRuntimeType)'!='Core'">$(SHFBROOT)\SandcastleBuilder.Utils.dll</TaskAssembly>
        <TaskAssembly Condition=" '$(MSBuildRuntimeType)'=='Core'">$(SHFBROOT)\DotNetCore\SandcastleBuilder.Utils.dll</TaskAssembly>
    </PropertyGroup>

    <UsingTask TaskName="MSBuildAssemblyLoader.LoadAssemblies" AssemblyFile="$(SHFBROOT)\DotNetCore\MSBuildAssemblyLoader.dll" Condition=" '$(MSBuildRuntimeType)'=='Core'" />
    <UsingTask TaskName="SandcastleBuilder.Utils.MSBuild.BuildHelp" AssemblyFile="$(TaskAssembly)" />
    <UsingTask TaskName="SandcastleBuilder.Utils.MSBuild.CleanHelp" AssemblyFile="$(TaskAssembly)" />

...

    <!-- The Core Build Help target -->
    <Target Name="CoreBuildHelp">
        <MSBuildAssemblyLoader.LoadAssemblies Condition=" '$(MSBuildRuntimeType)'=='Core'" />
        <SandcastleBuilder.Utils.MSBuild.BuildHelp...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants