Nesting fonts forces Silverlight to always rebuild

I had a strange problem with my Silverlight 4 project, although I had seen this before. Essentially, embedding fonts makes my Silverlight application always rebuild, even if everything is up to date. This sucks, since the task of inserting a font takes up a lot of memory and will ultimately lead to VS failure. I would like to be able to build a project from the command line, but no matter what my local projects are outdated, the Run command forces another rebuild. I tried to cut some of the relevant log data from my msbuild log.

Project "D:\Projects\Test\Test.Web\Test.Web.csproj" (10) is building "D:\Projects\Test\Test.SL\Test.SL.csproj" (2:4) on node 1 (default targets).
Building with tools version "4.0".
// Build operation starts normally (well, the dependency set on the server project is forcing the SL application to build). 
...
Target "ResolveReferences" skipped. Previously built successfully.
// A bunch of tasks are skipped (like this one)
...
Target "SubsetFontsSilverlight" in file "C:\Program Files\MSBuild\Microsoft\Expression\Blend\Silverlight\v4.0\SubsetFontSilverlight.targets" from project "D:\Projects\Test\Test.SL\Test.SL.csproj" (target "PrepareResources" depends on it):
Using "SubsetFontsSilverlight" task from assembly "C:\Program Files\MSBuild\Microsoft\Expression\Blend\Silverlight\v4.0\SubsetFontTask.dll".
Task "SubsetFontsSilverlight"
Done executing task "SubsetFontsSilverlight".
Done building target "SubsetFontsSilverlight" in project "Test.SL.csproj".
// this task never gets skipped
...
Target "MainResourcesGeneration" in file "C:\Program Files\MSBuild\Microsoft\Silverlight\v4.0\Microsoft.Silverlight.Common.targets" from project "D:\Projects\Test\Test.SL\Test.SL.csproj" (target "PrepareResources" depends on it):
Building target "MainResourcesGeneration" completely.
Input file "obj\Debug\Fonts\Fonts.zip" is newer than output file "obj\Debug\Test.SL.g.resources".
// note that the Fonts.zip file now makes the resources file out of date
...
Target "CoreCompile" in file "C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.Targets" from project "D:\Projects\Test\Test.SL\Test.SL.csproj" (target "Compile" depends on it):
Building target "CoreCompile" completely.
Input file "obj\Debug\Test.SL.g.resources" is newer than output file "obj\Debug\Test.SL.pdb".
// and the full recompile begins...

, , ? .

: .

<BlendEmbeddedFont Include="Fonts\MyriadPro-BoldIt.otf">
  <IsSystemFont>True</IsSystemFont>
  <All>True</All>
  <AutoFill>True</AutoFill>
  <Characters>
  </Characters>
  <Uppercase>True</Uppercase>
  <Lowercase>True</Lowercase>
  <Numbers>True</Numbers>
  <Punctuation>True</Punctuation>
</BlendEmbeddedFont>

2:

, , zip . , . :

  • Sillverlight (Blend VS, , Blend )

  • (Tools → Font Manager) Blend, MainPage.xaml, . "Tahoma".

, , "", , csc.exe , , - .

+3
2

, SubsetFontSilverlight.target. , , .

C:\Program Files\MSBuild\Microsoft\Expression\Blend\Silverlight\v4.0, .

- Input/Ouput MSBUILD, , Font.zip. , Blend, .

, , , , Font.zip , . , / , , ( ), font.zip .

fonts.zip , - , , , msbuild , , .

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask AssemblyFile="SubsetFontTask.dll" TaskName="Microsoft.Expression.SubsetFontTask.SubsetFontsSilverlight" />
    <UsingTask AssemblyFile="SubsetFontTask.dll" TaskName="Microsoft.Expression.SubsetFontTask.CleanSubsetFonts" />

    <ItemGroup Condition="'$(BuildingInsideVisualStudio)'=='true'">
        <AvailableItemName Include="BlendEmbeddedFont"/>
    </ItemGroup>

  <ItemGroup>
    <!-- Files that we specify as target inputs for msbuild target timestamp check -->
    <FontEmbedRelatedFile Include="$(MSBuildProjectFile)" />
    <FontEmbedRelatedFile Include="@(BlendEmbeddedFont)" />

    <!-- Anticipated font file locations -->
    <FontOutputFile Include="$(IntermediateOutputPath)\Fonts\Fonts.zip" />
  </ItemGroup>

  <!-- 
    this task runs after the main subset task - basically it checks if the task got skipped, and if so
    it adds the projected font output files to the resources collection
   -->
  <Target Name='AfterFontEmbed' AfterTargets="SubsetFontsSilverlight"
    Condition="'@(BlendEmbeddedFont)' != '' AND '@(BlendSubsettedFont)' == ''">
    <Message Text="Adding font files to the resource collection because Font embed was skipped" Importance="normal" />
    <ItemGroup>
      <Resource Include="@(FontOutputFile)" />
    </ItemGroup>
  </Target>

    <Target Name='SubsetFontsSilverlight'  
    Inputs="@(FontEmbedRelatedFile)" Outputs="@(FontOutputFile)"
    DependsOnTargets="$(SubsetFontsDependsOn)"  
    Condition="'@(BlendEmbeddedFont)' != ''">
    <Message Text="Embedding font subsets" Importance="normal" />
        <SubsetFontsSilverlight 
            Fonts="@(BlendEmbeddedFont)" XamlFiles="@(Page)" Resources="@(Resources)"
            IntermediateFilesDirectory="$(IntermediateOutputPath)"
            >
            <Output TaskParameter="SubsettedFonts" ItemName="Resource"/>
            <!-- save our list of embedded font files for later use -->
            <Output TaskParameter="SubsettedFonts" ItemName="BlendSubsettedFont"/>
        </SubsetFontsSilverlight>
    </Target>

    <Target Name='CleanSubsetFonts' DependsOnTargets="$(CleanSubsetFontsDependsOn)" Condition="'@(BlendEmbeddedFont)' != ''">
        <CleanSubsetFonts 
            Fonts="@(BlendEmbeddedFont)"
            IntermediateFilesDirectory="$(IntermediateOutputPath)"
            />
    </Target>

    <PropertyGroup>
        <PrepareResourcesDependsOn>
            SubsetFontsSilverlight;
            $(PrepareResourcesDependsOn);
        </PrepareResourcesDependsOn>
    </PropertyGroup>

    <PropertyGroup>
        <CleanDependsOn>
            $(CleanDependsOn);
            CleanSubsetFonts;
        </CleanDependsOn>
    </PropertyGroup>

</Project>

Visual Studio , , , corecompile , dll . , , VS "Never Build" - .

, (/ , , , ..), , , , , , isn .

+2

, , . - \Fonts \Assets\Fonts. obj\Debug\Fonts\Fonts.zip, obj\Debug\Assets\Fonts\Fonts.zip.

, Fonts.zip . , .

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!-- The Blend 4 SDK will always rebuild a xap that has font embedding, rather than
       playing nice and doing up-to-date checks. This targets file replaces the default
       target from the Blend SDK with one that does.
       It checks the input font file and the project file against the fonts.zip file.
       The project file is checked so that any added or removed fonts are picked up -->

  <ItemGroup>
    <!-- Files that we specify as target inputs for msbuild target timestamp check -->
    <FontEmbedRelatedFile Include="$(MSBuildProjectFile)" />
    <FontEmbedRelatedFile Include="@(BlendEmbeddedFont)" />

    <FontOutputFiles Include="@(BlendEmbeddedFont -> '$(IntermediateOutputPath)%(RelativeDir)Fonts.zip')" />
  </ItemGroup>

  <!-- This task runs after the main subset task - basically it checks if the task got skipped, and if so
       it adds the projected font output files to the resources collection -->
  <Target Name='AfterFontEmbed' AfterTargets="SubsetFontsSilverlight"
          Condition="'@(BlendEmbeddedFont)' != '' AND '@(_BlendSubsettedFont)' == ''">
    <ItemGroup>
      <Resource Include="@(FontOutputFiles)" />
    </ItemGroup>
  </Target>

  <Target Name='SubsetFontsSilverlight'
          Inputs="@(FontEmbedRelatedFile)" Outputs="@(FontOutputFiles -> Distinct())"
          DependsOnTargets="$(SubsetFontsDependsOn)" Condition="'@(BlendEmbeddedFont)' != ''">
    <SubsetFontsSilverlight Fonts="@(BlendEmbeddedFont)" 
                            XamlFiles="@(Page)" Resources="@(Resources)" 
                            IntermediateFilesDirectory="$(IntermediateOutputPath)">
      <Output TaskParameter="SubsettedFonts" ItemName="Resource"/>
      <Output TaskParameter="SubsettedFonts" ItemName="_BlendSubsettedFont"/>
    </SubsetFontsSilverlight>
  </Target>
</Project>
+1

Source: https://habr.com/ru/post/1765918/


All Articles