嵌入字体迫使 Silverlight 项目始终重建
我的 Silverlight 4 项目遇到了一个奇怪的问题,尽管我以前见过这个问题。基本上,嵌入字体会强制我的 Silverlight 应用程序始终重建,即使一切都是最新的。这种情况很糟糕,因为字体嵌入任务会占用大量内存,最终会使 VS 崩溃。我希望能够从命令行构建项目,但无论我的本地项目都已经过时,因此“运行”命令会强制进行另一次重建。我试图从我的 msbuild 日志中删除一些相关的日志信息。
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 文件扔到哪里。无论如何,一个人可以在几秒钟内迅速完成。步骤如下:
创建 Silverlight 应用程序(Blend 或 VS,尽管无论如何您都需要 Blend 才能使其工作)
在 Blend 中使用字体管理器(工具 -> 字体管理器),您可能必须打开 MainPage.xaml 才能启用它。嵌入“Tahoma”字体。
现在,每次点击“重建”时,您都可以验证 csc.exe 每次都运行,无论是否更改了任何内容。
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:
Create Sillverlight Application (Blend or VS, though you need Blend for this to work anyhow)
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我通过稍微修改我的 SubsetFontSilverlight.target 文件来解决这个问题。这不是一个完整的解决方案,也不一定对每个人都有效,但它对我有用。
目标文件可以在 C:\Program Files\MSBuild\Microsoft\Expression\Blend\Silverlight\v4.0 中找到,至少在我的机器上是这样。
这里的主要思想是使用 MSBUILD 目标输入/输出属性来查看中间 Font.zip 文件是否需要更新。我只是对输出文件路径进行了硬编码,因为我总是使用默认的 Blend 字体位置 - 但可以从各个字体文件构建它。
我设置的条件是,如果 Font.zip 文件比嵌入字体文件和项目文件新,则应跳过该任务。这样,如果您添加/删除字体或替换其中一种字体,字体将重新嵌入,但如果没有更改(或只是代码更改),font.zip 将保持不变。
如果未嵌入字体,则手动将 fonts.zip 添加到资源集合中非常重要 - 这样,如果需要重新编译代码但字体可能会保留,msbuild 会记住将字体文件包含到资源中。这就是为什么我添加了一个新任务以在主嵌入任务之后运行。
Visual Studio 仍然不能很好地注意到项目是最新的,但是当它构建它们时,核心编译任务不会每次都运行,并且 dll 文件不会被不必要地覆盖。这意味着您可以在命令行上运行编译器,在调试时将 VS 设置为“从不生成”,并且仍然加载正确的调试符号。
我在我能想到的大多数情况下对此进行了测试(清理之前/之后、丢失文件、仅更改代码、项目更改等),它似乎做得很好 - 这意味着字体就在那里,而一切并不总是如此重新编译。
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.
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.
我一直在使用 Egor 的答案,它确实有助于减少我们的构建时间,尤其是在重建时。然而,最近的一项更改打破了一切 - 我们将字体从项目文件夹中的 \Fonts 移至 \Assets\Fonts。目标文件尝试对 obj\Debug\Fonts\Fonts.zip 进行最新检查,但任务正在创建 obj\Debug\Assets\Fonts\Fonts.zip。
我修改了目标文件以检查中间输出路径中相应相对目录中的 Fonts.zip 文件。该目标文件将使用不同文件夹中包含的多种字体。
I've been using Egor's answer and it's really helped reduce our build times, especially when rebuilding. However, a recent change broke things - we moved our font from \Fonts in the project folder to \Assets\Fonts. The targets file was trying to do an up-to-date check for obj\Debug\Fonts\Fonts.zip, but the task was creating obj\Debug\Assets\Fonts\Fonts.zip.
I've amended the targets file to check for Fonts.zip files at the appropriate relative directories in the intermediate output path. This targets file will work with multiple fonts included in different folders.