嵌入字体强制Silverlight项目始终重建 [英] Embedding fonts forces Silverlight project to always rebuild

查看:164
本文介绍了嵌入字体强制Silverlight项目始终重建的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的Silverlight 4项目有一个奇怪的问题,虽然这是我以前见过的。基本上,嵌入字体强制我的Silverlight应用程序始终重建,即使一切都是最新的。这种糟糕的字体嵌入任务需要大量的内存,并最终崩溃VS.我希望能够从命令行构建项目,但不管我的本地项目是什么过时,所以运行命令强制另一个重建。我试图从我的msbuild日志中删除一些相关的日志信息。

 项目D:\Projects\Test\Test.Web\Test.Web.csproj(10)正在构建节点1(默认目标)上的D:\Projects\Test\Test.SL\Test.SL.csproj(2:4)。 
建立工具版本4.0。
//构建操作正常启动(当然,服务器项目上的依赖关系也会强制SL应用程序的构建)。
...
跳过目标ResolveReferences。以前建成成功。
//一堆任务被跳过(像这样)
...
目标文件C:\ Program Files \ MSBuild\Microsoft\Expression中的SubsetFontsSilverlight \Blend\Silverlight\v4.0\SubsetFontSilverlight.targets从项目D:\Projects\Test\Test.SL\Test.SL.csproj(目标PrepareResources取决于它) :
使用程序集C:\\ Program Files \ MSBuild \Microsoft\Expression\Blend\Silverlight\v4.0\SubsetFontTask.dll中的SubsetFontsSilverlight任务。
任务SubsetFontsSilverlight
完成执行任务SubsetFontsSilverlight。
在项目Test.SL.csproj中完成构建目标SubsetFontsSilverlight。
//这个任务不会被跳过
...
在文件C:\ Program Files \ MSBuild \ Microsoft \ Silverlight \ v4.0 \\中的目标MainResourcesGeneration从项目D:\Projects\Test\Test.SL\Test.SL.csproj(目标PrepareResources取决于它)\\ Microsoft \\ Silver \\ Silverlight.Common.targets:
构建目标 MainResourcesGeneration完全。
输入文件obj\Debug\Fonts\Fonts.zip比输出文件obj\Debug\Test.SL.g.resources更新。
//注意Fonts.zip文件现在使资源文件过期
...
目标CoreCompile在文件C:\ WINDOWS \Microsoft.NET\\ \\ Framework \v4.0.30319\Microsoft.CSharp.Targets从项目D:\Projects\Test\Test.SL\Test.SL.csproj(目标编译依赖于它):
完全构建目标CoreCompile。
输入文件obj\Debug\Test.SL.g.resources比输出文件obj\Debug\Test.SL.pdb更新。
//完全重新编译开始...

无论如何,有没有办法如果字体文件没有改变,停止运行字体任务?更新:项目文件中的一个示例字体。

$ pre

更新: < BlendEmbeddedFont Include =Fonts \MyriadPro-BoldIt.otf>
< IsSystemFont> True< / IsSystemFont>
<全部>真实< /所有>
<自动填充>真实< /自动填充>
<字符>
< /字符>
<大写> True< /大写>
<小写>真< /小写>
< Numbers> True< / Numbers>
<标点>真< /标点>
< / BlendEmbeddedFont>

更新2:



喜欢发布一个小的repro项目,但我不知道在哪里折腾的zip文件。在任何情况下,都可以在几秒钟内掀平。这里是步骤:
$ b


  1. 创建Sillverlight应用程序(Blend或者VS,尽管你需要Blend才能工作)使用Blend中的字体管理器(工具 - >字体管理器),您可能必须打开MainPage.xaml才能使其变为启用状态。嵌入Tahoma字体。




现在,每次点击重建时,都可以验证csc.exe每次都运行,不管是否有任何改变。

解决方案

通过破解我的SubsetFontSilverlight.target文件一点。这不是一个完整的解决方案,它不一定适用于每个人,但它适用于我。

目标文件可以在C:Program Files \ MSBuild\Microsoft\Expression\Blend\Silverlight\v4.0找到,至少在我的机器上。

这里的主要思想是使用MSBUILD目标输入/输出属性来查看是否需要更新中间的Font.zip文件。我简单地硬编码输出文件路径,因为我总是使用默认的Blend字体位置 - 但是可以从单个字体文件中构建它。

我设置的条件是,如果Font.zip文件比嵌入的字体文件和项目文件更新,则应该跳过该任务。这样,如果您添加/减少字体或替换其中一个字体将被重新嵌入,但是如果没有更改(或只是代码更改),font.zip将被保留。



如果字体没有嵌入,那么手工添加fonts.zip到资源集合是非常重要的 - 如果代码需要重新编译,但字体可以单独保留,msbuild记得包含字体文件放入资源中。这就是为什么我在主嵌入任务之后添加了一个新的任务。

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

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

< ItemGroup>
<! - 我们指定为msbuild目标时间戳检查的目标输入的文件 - >
< FontEmbedRelatedFile Include =$(MSBuildProjectFile)/>
< FontEmbedRelatedFile Include =@(BlendEmbeddedFont)/>

<! - 预期的字体文件位置 - >
< FontOutputFile Include =$(IntermediateOutputPath)\Fonts\Fonts.zip/>
< / ItemGroup>

<! -
这个任务在主子集任务之后运行 - 基本上它检查任务是否被跳过,如果是这样的话
它将投影的字体输出文件添加到资源集合
- >
< Target Name ='AfterFontEmbed'AfterTargets =SubsetFontsSilverlight
Condition ='@(BlendEmbeddedFont)'!=''AND'@(BlendSubsettedFont)'==''>
< ItemGroup>
< Resource Include =@(FontOutputFile)/>
< / ItemGroup>
< / Target>

< Target Name ='SubsetFontsSilverlight'
Inputs =@(FontEmbedRelatedFile)Outputs =@(FontOutputFile)
DependsOnTargets =$(SubsetFontsDependsOn)
Condition ='@(BlendEmbeddedFont)'!=''>
< Message Text =嵌入字体子集Importance =normal/>
SubsetFontsSilverlight
Fonts =@(BlendEmbeddedFont)XamlFiles =@(Page)Resources =@(Resources)
IntermediateFilesDirectory =$(IntermediateOutputPath)
>
< Output TaskParameter =SubsettedFontsItemName =Resource/>
<! - 保存我们的嵌入式字体文件清单供以后使用 - >
< Output TaskParameter =SubsettedFontsItemName =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在注意到项目是最新的时候仍然不是很好,但是当它生成它们时核心编译任务不会每次都运行,dll文件不会被不必要地覆盖。这意味着你可以在命令行运行编译器,在调试时将VS设置为Never Build,并且仍然加载正确的调试符号。

我测试了这个与我能想到的大多数情况(在清理之前/之后,缺少文件,仅更改代码,更改项目等),它似乎很好 - 这意味着字体在那里,一切都不总是得到重新编译。

I'm having a weird issue with my Silverlight 4 project, although it's one I've seen before. Basically, embedding fonts forces my Silverlight app to always rebuild even if everything is up to date. This kind of sucks as the font embed task takes a lot of memory and will eventually crash VS. I'd like to be able to build the project from the command line, but no matter what my local projects are out of date so the "Run" command forces another rebuild. I've tried to snip out some of the relevant log information out of 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...

Anyhow, is there a way to stop the font task from running if the font files have not changed? Because constant rebuilds are really annoying.

Update: a sample font from the project file.

<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>

Update 2:

I'd like to post a little repro project, but I'm not sure where to toss the zip file. In any case, one can be whipped up in a few seconds flat. Here are the steps:

  1. Create Sillverlight Application (Blend or VS, though you need Blend for this to work anyhow)

  2. Use the Font Manager (Tools -> Font Manager) in Blend, you may have to open MainPage.xaml for it to become enabled. Embed the "Tahoma" font.

Now, every time you hit "Rebuild" you can verify that csc.exe runs every time, regardless of whether anything was changed or not.

解决方案

I got around this issue by hacking up my SubsetFontSilverlight.target file a little. It's not a complete fix and it won't necessarily work for everyone, but it works for me.

The target file can be found in C:\Program Files\MSBuild\Microsoft\Expression\Blend\Silverlight\v4.0, at least on my machine.

The main idea here is to use the MSBUILD target Input/Ouput properties to see if the intermediate Font.zip file(s) need to be updated. I simply hardcoded the output file path, because I always use default Blend font locations - but it's possible to construct it out of the individual font files.

The condition I set was that the task should be skipped if the Font.zip file is newer than the embedded font files and the project file. That way if you add/subtract a font or replace one of them the fonts will get re-embedded, but if there are no changes (or just code changes) the font.zip will be left alone.

It's important to add the fonts.zip to the resources collection manually if the fonts are not embedded - that way if the code needs to be recompiled but the fonts may be left alone, msbuild remembers to include the fonts file into the resources. This is why I added a new task to run after the main embed task.

<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 is still not great at noticing that the projects are up to date, but when it builds them the corecompile task won't run every time and the dll file won't be overwritten needlessly. This means that you can run the compiler on the command line, set VS to "Never Build" on debug, and still have the correct debug symbols loaded.

I tested this with most of the situations I could think of (before/after clean, missing files, code changes only, project changes, etc) and it seems to do fine - meaning that the fonts are there, and everything isn't always getting recompiled.

这篇关于嵌入字体强制Silverlight项目始终重建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆