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

Directory.Build.props interferes with target framework determination #923

Closed
Zastai opened this issue Jul 19, 2022 · 12 comments
Closed

Directory.Build.props interferes with target framework determination #923

Zastai opened this issue Jul 19, 2022 · 12 comments

Comments

@Zastai
Copy link

Zastai commented Jul 19, 2022

I have a multitargeting project (net472 and netstandard2.1); while with SHFB 2020.3.6 this works nicely, having set

  <PropertyGroup>
    <TargetFrameworks>net472</TargetFrameworks>
    <TargetFramework>net472</TargetFramework>
    <TargetFrameworkMoniker>.NETFramework,Version=v4.7.2</TargetFrameworkMoniker>
    <FrameworkVersion>.NET Framework 4.7.2</FrameworkVersion>
  </PropertyGroup>

in the project.
(With the small caveat that I have had to set FrameworkVersion to Cross-platform (.NET Core/.NET Standard) instead for some projects, for no obvious reason.)

That same project errors out when updating the SHFB package reference to 2022.2.6:

  Building C:\Stuff\Sources\natural-services.dotnet\Anubex.NaturalServices.Docs\Anubex.NaturalServices.Docs.shfbproj
  Initializing
  ClearWorkFolder
  ValidatingDocumentationSources
SHFB : error BE0065: BUILD FAILED: Unable to determine target framework version for project [C:\...\xxx.shfbproj]
  Failed

The log has:

<buildStep step="ValidatingDocumentationSources">
Validating and copying documentation source information
Source: C:\...\yyy.csproj
    Found project &#39;C:\...\yyy.csproj&#39;

Parsing project files
    Multi-targeted projects where found.  The common target framework &#39;net472&#39; will be used.  Override using the TargetFramework property on the documentation sources.
    Last step completed in 00:00:00,3125
</buildStep>
<buildStep step="Failed">

SHFB: Error BE0065: BUILD FAILED: Unable to determine target framework version for project
   at SandcastleBuilder.Utils.MSBuild.MSBuildProject.get_TargetFrameworkVersion()
   at SandcastleBuilder.Utils.BuildEngine.BuildProcess.ValidateDocumentationSources()
   at SandcastleBuilder.Utils.BuildEngine.BuildProcess.Build()

</buildStep>

So it detects that it's multitarget and correctly picks the first target listed (small note: typo: where -> were).
But then it still errors out, with no reason listed.

Adding targetFramework="net472" to the documentation source makes the "Multi-targeted ..." message go away, but the build error remains.

It would be nice to get some clarity on where exactly the error comes from, given that preceding messages show exactly what the target framework is.

@Zastai
Copy link
Author

Zastai commented Jul 19, 2022

I tried adding

    <TargetFrameworkIdentifier>.NET Framework</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>

to the project, because that's the property it seems to want, but that made no difference.

I also tried dropping FrameworkVersion but that gave me

SHFB : error BE0071: Unable to locate information for the project framework version 'v4.0.30319' or a suitable redirected version on this system.  See error number help topic for details.

(which is fair enough, given it likely defaults to 4.0).

Note: I'm referencing the EWSoftware.SHFB.NETFramework package, and the error description suggests that that should avoid this error, but it clearly does not. In addition, the text says you need to ensure packages is added to Component Path, but that's not needed/applicable when using PackageReference, because there's a .props included in the package that does that (and I thought those applied to packages handled via packages.config too).

@EWSoftware
Copy link
Owner

I don't think there's anything that say you can't put both TargetFramework and TargetFrameworks in the same project but it's likely redundant and with the current version of SHFB, it will confuse it as it's only expecting one or the other, not both. If TargetFrameworks is found, it will use the first target as the documentation source. That can have side effects (#908) and I have plans to address this in a future release (#897).

If you're getting the error about not being able to determine the target framework version, the TargetFrameworkVersion property in the documentation source project is undefined or blank for some reason. Having both of the above properties defined may be contributing to the issue, but I can't say for sure. 2020.3.6. is pretty old and there may be bugs that have been fixed in subsequent releases that I can't recall offhand so it may be worth trying with the latest release.

@Zastai
Copy link
Author

Zastai commented Aug 2, 2022

In the .shfbproj, if I leave out either TargetFramework or TargetFrameworks, I get restore errors about there being duplicate target framework set; I'm guessing there might be some partial MSBuild SDK files imported which do some processing with them. When I have time to look into this again, I'll try to see where that comes from using the binlog viewer.

As for the version: 2020.3.6 is the one that works; I'm trying to use the latest release, but that's the one throwing the error. In fact, it looks like every version past 2020.3.6 has this issue, and I don't see anything obvious in the release notes for any of those releases that would indicate something I should change.

@EWSoftware
Copy link
Owner

Perhaps I'm misunderstanding you, but with the exception of a TargetFrameworkVersion element set to 4.7.2 to satisfy the imported targets files, you shouldn't specify any other target framework elements in the SHFB project itself. My comments above were in regard to the documentation source projects, the ones that build the assemblies being documented.

If you can supply an example that demonstrates the issue you're having, I can investigate it further.

@Zastai
Copy link
Author

Zastai commented Aug 10, 2022

I have tried a few combinations.
The simple "let SHFB figure it out" case:

  <PropertyGroup>
    <FrameworkVersion/>
    <TargetFrameworks/>
    <TargetFramework/>
    <TargetFrameworkMoniker/>
    <TargetFrameworkVersion/>
  </PropertyGroup>

results in SHFB : error BE0065: BUILD FAILED: Unable to determine target framework version for project with the log file containing:

<buildStep step="ValidatingDocumentationSources">
Validating and copying documentation source information
Source: ...\xxx.csproj
    Found project &#39;...\xxx.csproj&#39;

Parsing project files
    Multi-targeted projects where found.  The common target framework &#39;net472&#39; will be used.  Override using the TargetFramework property on the documentation sources.
    Last step completed in 00:00:00,1259
</buildStep>
<buildStep step="Failed">

SHFB: Error BE0065: BUILD FAILED: Unable to determine target framework version for project
   at SandcastleBuilder.Utils.MSBuild.MSBuildProject.get_TargetFrameworkVersion()
   at SandcastleBuilder.Utils.BuildEngine.BuildProcess.ValidateDocumentationSources()
   at SandcastleBuilder.Utils.BuildEngine.BuildProcess.Build()

</buildStep>

Hence my question about what prompts this error when there is explicit logging preceding it that suggests it find a target just fine.

Variations:

  1. I tried adding TargetFramework="net472" to the documentation source. No difference at all.
  2. I tried adding targetFramework="net472" to the documentation source. Note that this is not what the message in the log file suggests (nor is it "normal" in MSBuild, where DocumentationSource would really be an ItemGroup instead.
    • with this, the "Multi-targeted projects where found." message goes away, but the BE0065 persists
  3. I tried setting FrameworkVersion to ".NET Framework 4.7.2"; same error as with it not set.
  4. I tried setting FrameworkVersion to "hello", just to verify that the value gets used; it does (BE0071 in this case).
  5. I tried setting TargetFrameworkVersion to ".NET Framework 4.7.2"; the restore fails (it needs to be a version number only)
  6. I tried setting TargetFrameworkVersion to "4.7.2"; same error as with it not set.

I'll see if I can set up a minimal reproducible test case.
In the meantime any specific suggestions are welcome.

Side Note: I currently have

    <PackageReference Include="EWSoftware.SHFB.NET" Version="5.0.0.2" IsImplicitlyDefined="true" GeneratePathProperty="true" />
    <PackageReference Include="EWSoftware.SHFB.NETFramework" Version="4.8.0.2" IsImplicitlyDefined="true" GeneratePathProperty="true" />

to cover my bases wrt reflection data. Is it alright to have multiple reflection packages (to cover cases where the selected target is net472 as well as cases where it's netstandard2.0, netcoreapp3.1 or net6.0)?

I do see in the log that one of them is put in the component path twice:

Locating components in the following folder(s):
    C:\Users\me\.nuget\packages\ewsoftware.shfb.netframework\4.8.0.2\build\..\tools\
    C:\Users\me\.nuget\packages\ewsoftware.shfb.net\5.0.0.2\build\..\tools\
    C:\Users\me\.nuget\packages\ewsoftware.shfb.netframework\4.8.0.2\build\..\tools\
    <project folder>
    C:\ProgramData\EWSoftware\Sandcastle Help File Builder\Components and Plug-Ins
    C:\Users\me\.nuget\packages\ewsoftware.shfb\2022.2.6\Tools\Components

That's probably not harmful - but it did seem odd.

@EWSoftware
Copy link
Owner

SHFB picks the reflection data set it needs so having multiple packages with different sets won't cause any issues.

@Zastai
Copy link
Author

Zastai commented Sep 8, 2022

Guess I'll file a new issue when I am given the time to set up a reproducible test case by my manager.

@EWSoftware
Copy link
Owner

I closed it due to inactivity. It can be reopened if you can provide a test case.

@Zastai
Copy link
Author

Zastai commented Oct 11, 2022

I think I may see where it's going wrong.

We use Directory.Build.props and Directory.Build.props to set up a bunch of shared build settings across a whole solution.
These are read by MSBuild (or more accurately some of the parts of its SDK) when processing any projects in that tree. That would include any projects in the bin/obj folders (or the top-level output folder in our setup).

One of things these set is the default targets for projects:

  <PropertyGroup>
    <TargetFrameworks>net472;netcoreapp3.1;net6.0</TargetFrameworks>
    <TargetFramework />
  </PropertyGroup>

It is that which seems to trigger the BE0065. However, for .shbproj files this gets overridden later with:

  <PropertyGroup>
    <!-- SHFB does not support multi-targeting yet, so force use of a single target framework. -->
    <TargetFrameworks>net472</TargetFrameworks>
    <TargetFramework>net472</TargetFramework>
    <TargetFrameworkMoniker>.NETFramework,Version=v4.7.2</TargetFrameworkMoniker>
    <!-- Using this seems to resolve issues encountered in some, but not all, projects (specific cause unknown). -->
    <FrameworkVersion>Cross-platform (.NET Core/.NET Standard)</FrameworkVersion>
  </PropertyGroup>

The presence of Directory.Build.* already caused some problems in the past with .proj files SHFB generated as part of its work, so I have a workaround target that will create empty versions of those files in the intermediate root before running CoreBuildHelp.

However, creating such empty files ahead of time did not resolve the issue here.

Similarly, not including the .props file setting TargetFramework to blank when a .shbproj is being loaded makes no difference.

So it looks like the target framework checking is happening outside of a .shbproj context and is picking up the Directory.Build.props. I don't immediately see how I can avoid this happening.
Does SHFB set any MSBuild properties when it's doing its processing that I could check?

I am attaching a case that reproduces the issue. If I comment out the

  <Import Project="CodingGuidelines.props" />

in build/shared-build-config.props, the doc project builds fine (well, it warns about the FrameworkVersion value, but that is fine).
But that import is required for all non-documentation projects, so that's not a viable solution for us.

shfb-923.zip

@Zastai Zastai changed the title What causes "Unable to determine target framework version for project"? Directory.Build.props interferes with target framework determination Oct 11, 2022
@Zastai
Copy link
Author

Zastai commented Oct 11, 2022

Looks like SHFB is running something in .csproj context; if I use

    <TargetFramework Condition=" '$(MSBuildProjectExtension)' != '.csproj' " />

then the doc build works again. But given that this setup is specifically for the code projects, and they build just fine using it, that's not a fix.

So It looks like SHFB is evaluating the documentation source project and getting hung up on the empty default value for TargetFramework despite TargetFrameworks being set.

@Zastai
Copy link
Author

Zastai commented Oct 26, 2022

@EWSoftware Test case has been provided; can you reopen this, or should I file a fresh ticket?

@EWSoftware EWSoftware reopened this Oct 26, 2022
@EWSoftware
Copy link
Owner

The cause was not handling the TargetFramework property if it was blank. All it does now is return the value if the property exists. The fix was to check if it was blank as well and, if so, return the requested target type if specified or the first entry from the TargetFrameworks property if not. It'll be fixed in the next release, no date on when that might be though.

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

2 participants