Build/Test Issues

Portable class libraries fail to build if they include metro

Started by Strilanc on 11,151 views

NCrunch fails to build portable class libraries targeting the intersection of .net 4.5 and metro. Also, the build error description does not display in the tests pane: the description from the previously selected thing just persists.

I assume this issue has the same root cause as NCrunch not being able to build metro projects. However, it seems like ncrunch should still be able to build something targeting the subset of .net 4.5 contained in winrt.

Currently I'm working around this issue by having a separate .net 4.5 project containing the same source files. NCrunch builds it fine.

Edited

Hi, thanks for posting!

As Metro/WinRT is still very new, it is not yet a supported platform by NCrunch's build or test process. In the long term I hope to get there, but it may take a little while. Meanwhile the workaround you are using (host the same files in a normal 4.5 project) is the suggested approach.


Cheers,

Remco
I just loaded up NCrunch for the first time and am encountering this issue as well. However, my PCL project does not target .NET 4.5 or Metro / WinRT. It is a basic .NET 4 / Silverlight 4 / Windows Phone 7 portable class library. This leads me to believe NCrunch is incompatible with PCL project types.

Here is the error as reported by NCrunch:

[21:14:50.8245-BuildTask-73] ERROR (Compilation): NContext.Common: (0): System.InvalidOperationException: Failed to resolve type: System.Func`2
at Mono.Cecil.Mixin.CheckedResolve(TypeReference self)
at Mono.Cecil.MetadataBuilder.GetConstantType(TypeReference constant_type, Object constant)
at Mono.Cecil.MetadataBuilder.GetConstantType(TypeReference constant_type, Object constant)
at Mono.Cecil.MetadataBuilder.AddConstant(IConstantProvider owner, TypeReference type)
at Mono.Cecil.MetadataBuilder.AddParameter(UInt16 sequence, ParameterDefinition parameter, ParamTable table)
at Mono.Cecil.MetadataBuilder.AddParameters(MethodDefinition method)
at Mono.Cecil.MetadataBuilder.AddMethod(MethodDefinition method)
at Mono.Cecil.MetadataBuilder.AddMethods(TypeDefinition type)
at Mono.Cecil.MetadataBuilder.AddType(TypeDefinition type)
at Mono.Cecil.MetadataBuilder.AddTypeDefs()
at Mono.Cecil.MetadataBuilder.BuildTypes()
at Mono.Cecil.MetadataBuilder.BuildModule()
at Mono.Cecil.MetadataBuilder.BuildMetadata()
at Mono.Cecil.ModuleWriter.<BuildMetadata>b__0(MetadataBuilder builder, MetadataReader _)
at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TItem item, Func`3 read)
at Mono.Cecil.ModuleWriter.BuildMetadata(ModuleDefinition module, MetadataBuilder metadata)
at Mono.Cecil.ModuleWriter.WriteModuleTo(ModuleDefinition module, Stream stream, WriterParameters parameters)
at Mono.Cecil.ModuleDefinition.Write(Stream stream, WriterParameters parameters)
at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters parameters)
at nCrunch.Compiler.StaticManipulation.BuiltAssembly.#=q6gCeKWiBt6C3qKWXf6lGxLORytITHauyfYLMMEj4PDg=.#=q6y8gMwouK7$ZpvQ$SRm7HYr_OMYAvZNvlS0ZeITaYpI=()
at nCrunch.Compiler.StaticManipulation.BuiltAssembly.#=q7yp7R2vCg7OHrM_sd9tAMw==(Action #=qudRwucEzHbkdlwIjgyJfoQ==)
at nCrunch.Compiler.StaticManipulation.BuiltAssembly.Instrument(ComponentSourceLineMap sourceLineMap, IDictionary`2 instrumentationDirectivesByCodeFileId, IDictionary`2 codeFileIDsByFilePath, Boolean proxyProcessIsActive, Int32 componentId, IInstrumentationFilter[] instrumentationFilters)
at nCrunch.Compiler.RemoteBuildRunner.#=qvNS9Jn_vovPYj$WawPTGDERaQEDfCgulsnXs2PU1wgs=(ComponentBuildParameters #=qGqyIDwsobZMazZ7Y1gEPOQ==, String #=qW2BTg7$3D$rwxs42Kghci$GtNcbbtkdxQLoeiTTjqjM=, BuildOutput #=q6F$cbteKcyUjRVn$ntQutw==, String #=q3QIyw1sHCANAHQHwaUeDi7oPFizAEqs90a5hwUHrid8=)
at nCrunch.Compiler.RemoteBuildRunner.Build(ComponentBuildParameters parameters)



As a side note: I've had the same issue with Telerik's JustMock. TypeMock Isolator seems to work with PCL projects. Hopefully more frameworks will support these project / profile types soon as they're quite handy for ensuring compatibility.

Edited

Yes - this is caused by the same issue. VS2012 changed the way the build process works for Silverlight projects, they are now treated as 'PCL' projects alongside Metro applications. I hope to resolve this properly when Silverlight/Metro support is added to NCrunch.
Much thanks for the info! :D
I've come up with nice work-around for NCrunch / PCL projects to work nicely together and not have to have a (dummy) mirror project in your solution.

1. For your PCL project's configuration within NCrunch, specify a build configuration like ("ncrunch") in the "Use build configuration", component configuration. This should not be a legitimate build configuration, but one to recognize that the build is triggered by NCrunch.

2. Modify your PCL project .proj file.

Here is my example PCL which support multiple build configurations and one specific for NCrunch.


<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="(- BROKEN LINK -)">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <Framework Condition=" '$(Framework)' == '' ">portable-net4+sl4+wp7</Framework>
    <ProjectGuid>{2EC085CE-BF81-46ED-A2D7-8CD0B9AFDEC2}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>NContext.Common</RootNamespace>
    <AssemblyName>NContext.Common</AssemblyName>
    <FileAlignment>512</FileAlignment>
    <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
    <RestorePackages>true</RestorePackages>
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
  </PropertyGroup>


Now we have to reset the $(Configuration) to normal, Debug, and set an NCrunch specific property.

<!-- ================ NCrunch Pre Override ================== -->

  <PropertyGroup Condition=" '$(Configuration)' == 'ncrunch' ">
    <Configuration>Debug</Configuration> <!-- Reset $(Configuration) -->
    <NCrunch>true</NCrunch>
  </PropertyGroup>


Configure the projects for each build target. (If needed)


  <!-- ***********************************************************************************************************
       * .NET 4.5 + Silverlight 4
       *********************************************************************************************************** -->
  <PropertyGroup Condition=" '$(Framework)' == 'portable-net45+sl4' ">
    <!-- ==============================================   DEBUG   ================================================ -->
    <DebugSymbols Condition=" '$(Configuration)' == 'Debug' ">true</DebugSymbols>
    <DebugType Condition=" '$(Configuration)' == 'Debug' ">full</DebugType>
    <DefineConstants Condition=" '$(Configuration)' == 'Debug' ">TRACE;DEBUG;NET45;SILVERLIGHT40</DefineConstants>
    <Optimize Condition=" '$(Configuration)' == 'Debug' ">false</Optimize>
    <PlatformTarget Condition=" '$(Configuration)' == 'Debug DLL and Web' ">$(Platform)</PlatformTarget>
    <!-- =============================================   RELEASE   =============================================== -->
    <DebugType Condition=" '$(Configuration)' == 'Release' ">pdbonly</DebugType>
    <DefineConstants Condition=" '$(Configuration)' == 'Release' ">TRACE;NET45;SILVERLIGHT40</DefineConstants>
    <Optimize Condition=" '$(Configuration)' == 'Release' ">true</Optimize>
    <CodeAnalysisRuleSet Condition=" '$(Configuration)' == 'Release' ">AllRules.ruleset</CodeAnalysisRuleSet>
    <!-- ========================================================================================================= -->
    <DocumentationFile>bin\$(Configuration)\$(Framework)\NContext.Common.xml</DocumentationFile>
    <OutputPath>bin\$(Configuration)\$(Framework)\</OutputPath>
    <WarningLevel>4</WarningLevel>
    <ErrorReport>prompt</ErrorReport>
    <TargetFrameworkProfile>Profile23</TargetFrameworkProfile>
  </PropertyGroup>
  
  <!-- ***********************************************************************************************************
       * .NET 4.0 + Silverlight 4 + Windows Phone 7
       *********************************************************************************************************** -->
  <PropertyGroup Condition=" '$(Framework)' == 'portable-net4+sl4+wp7' ">
    <!-- ==============================================   DEBUG   ================================================ -->
    <DebugSymbols Condition=" '$(Configuration)' == 'Debug' ">true</DebugSymbols>
    <DebugType Condition=" '$(Configuration)' == 'Debug' ">full</DebugType>
    <DefineConstants Condition=" '$(Configuration)' == 'Debug' ">TRACE;DEBUG;NET40;SILVERLIGHT40;WINDOWS_PHONE7</DefineConstants>
    <Optimize Condition=" '$(Configuration)' == 'Debug' ">false</Optimize>
    <PlatformTarget Condition=" '$(Configuration)' == 'Debug DLL and Web' ">$(Platform)</PlatformTarget>
    <!-- =============================================   RELEASE   =============================================== -->
    <DebugType Condition=" '$(Configuration)' == 'Release' ">pdbonly</DebugType>
    <DefineConstants Condition=" '$(Configuration)' == 'Release' ">TRACE;NET40;SILVERLIGHT40;WINDOWS_PHONE7</DefineConstants>
    <Optimize Condition=" '$(Configuration)' == 'Release' ">true</Optimize>
    <CodeAnalysisRuleSet Condition=" '$(Configuration)' == 'Release' ">AllRules.ruleset</CodeAnalysisRuleSet>
    <!-- ========================================================================================================= -->
    <DocumentationFile>bin\$(Configuration)\$(Framework)\NContext.Common.xml</DocumentationFile>
    <OutputPath>bin\$(Configuration)\$(Framework)\</OutputPath>
    <WarningLevel>4</WarningLevel>
    <ErrorReport>prompt</ErrorReport>
    <TargetFrameworkProfile>Profile2</TargetFrameworkProfile>  [color=red]<<<<<<<< NOTICE[/color]
  </PropertyGroup>
  
  <ItemGroup>
    <Compile Include="Error.cs" />
    <Compile Include="Extensions\HierarchicalDataExtensions.cs" />
    <Compile Include="Extensions\IListExtensions.cs" />
    <Compile Include="Extensions\IMaybeIEnumerableExtensions.cs" />
    <Compile Include="Extensions\IResponseTransferObjectIEnumerableExtensions.cs" />
    <Compile Include="IResponseTransferObject.cs" />
    <Compile Include="Extensions\IResponseTransferObjectExtensions.cs" />
    <Compile Include="IToken.cs" />
    <Compile Include="Extensions\IMaybeExtensions.cs" />
    <Compile Include="IMaybe.cs" />
    <Compile Include="Just.cs" />
    <Compile Include="Nothing.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="ServiceResponse.cs" />
    <Compile Include="ValidationError.cs" />
  </ItemGroup>
  <ItemGroup Condition=" '$(Framework)' == 'portable-net45+sl4' ">
    <Compile Include="IStatefulResponseTransferObject.cs" />
    <Compile Include="StateExtensions.cs" />
    <Compile Include="StatefulServiceResponse.cs" />
  </ItemGroup>



If this is an NCrunch build, let's modify a few property's that were just set to trick NCrunch into thinking this is a normal C# Library.
We do this by clearing ProjectTypeGuids and TargetFrameworkProfile

Then we add any references needed. (Make sure to do this in a Choose-When-Otherwise block or you'll run into an issue described here:
http://stackoverflow.com/questions/857379/build-with-msbuild-and-dynamically-set-project-references

<!-- =============== NCrunch Post Override ================== -->

  <Choose>
    <When Condition=" '$(NCrunch)' == '' ">
    </When>
    <Otherwise>
      <PropertyGroup>
        <ProjectTypeGuids></ProjectTypeGuids>
        <TargetFrameworkProfile></TargetFrameworkProfile>
      </PropertyGroup>
      <ItemGroup>
        <Reference Include="System" />
        <Reference Include="System.Core" />
        <Reference Include="System.Xml.Linq" />
        <Reference Include="System.Data.DataSetExtensions" />
        <Reference Include="Microsoft.CSharp" />
        <Reference Include="System.Data" />
        <Reference Include="System.Xml" />
        <Reference Include="System.Runtime.Serialization" />
      </ItemGroup>
    </Otherwise>
  </Choose>
  <Import Condition=" '$(NCrunch)' == 'true' " Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <!-- ======================================================== -->




  <Import Condition=" '$(NCrunch)' == '' " Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />

  <Target Name="AfterBuild" Condition=" '$(NCrunch)' == '' ">
    <MSBuild Condition=" '$(Framework)' != 'portable-net45+sl4' " Projects="$(MSBuildProjectFile)" Properties="Framework=portable-net45+sl4" RunEachTargetSeparately="true" />
  </Target>
</Project>



I'm currently using this for my project on GitHub, NContext. You can view it there. The PCL library is NContext.Common.

[size=8]Hope this helps!

I'll try and write up a blog post on this soon. Any questions, feel free to email me at daniel@dgdev.net.

Edited

Wow! Nice work! This is much cleaner than two projects trying to cross-compile the same code.

Thanks for taking the time to post this!

Something you might find useful is that NCrunch always sets a build property $(NCrunch) equal to '1'. You might be able to use this to help simplify the override.

Edited

Very cool! Never knew about the $(NCrunch) property. This will definitely simplify it all. Thanks for the tip!

Post a reply

Log in to reply.