仅在重新构建时运行预构建事件

4
我正在编译一个依赖于其他开源项目(具体来说是Zlib和LibTIFF)的项目,这些项目提供了用于nmake的Windows makefile。我希望安排好一切,以便在我的项目上执行“重建”时,也会使用适当的配置(Debug/Release,32/64位等)重新构建开源项目。
我的项目相当简单但并非微不足道。我浪费了前几天的时间,试图弄清楚如何直接或使用CMake生成自己的nmake makefile。尽管我有相当多的GNU make经验,但这让我失去了生存的意志。在经历了康复之后,我决定继续使用Visual Studio项目文件来构建自己的项目,并定义一个“预构建事件”来在我的开源库的供应商提供的makefile上执行nmake。
例如,在我的Visual Studio 2010项目页面上,对于32位Release构建,使用Intel C++编译器,我将我的预构建事件命令行编写为:
call "C:\Program Files (x86)\Intel\Composer XE 2013 SP1\bin\ipsxe-comp-vars.bat" ia32 vs2010
cd ..\..\..\zlib-1.2.8
nmake /f win32\Makefile.msc zlib.lib
cd ..\tiff-4.0.3
nmake /f Makefile.vc lib

我意识到我可以把上述内容放到批处理文件中,并调用该批处理文件,但我不想再添加一个需要跟踪的文件。无论如何,这个方法非常好用,除了一件事:如果我决定更改我的配置,我希望在这两个库上执行“nmake clean”以确保它们是根据我的新配置重新构建的,类似于:

call "C:\Program Files (x86)\Intel\Composer XE 2013 SP1\bin\ipsxe-comp-vars.bat" ia32 vs2010
cd ..\..\..\zlib-1.2.8
IF "%BUILDACTION%"=="REBUILD" nmake /f win32\Makefile.msc clean
nmake /f win32\Makefile.msc zlib.lib
cd ..\tiff-4.0.3
IF "%BUILDACTION%"=="REBUILD" nmake /f Makefile.vc clean
nmake /f Makefile.vc lib

很不幸,我似乎找不到满足BUILDACTION角色的任何环境变量,也看不出定义环境变量的简单方法。那么,在这里做我正在尝试的事情有什么办法吗,还是说我在无法实现它?

4个回答

6

一旦你意识到Rebuild目标只是一个存根,并实际上由调用Clean后跟Build(就像在典型的gnu makefile中一样),解决方案就呈现出来了:使用两个单独的目标,一个用于Clean,另一个用于Build。您可以将预构建事件保留不变,并添加一个用于Clean的事件。在文本编辑器中打开项目文件,然后在末尾添加类似以下内容:

<Target Name="OnCleanOnly" AfterTargets="Clean">
  <Message Text="OnCleanOnly" Importance="High"/>
</Target>

当调用 Clean 目标时,此目标会自动调用。当您在VS内部执行 Clean 或 Rebuild,或通过命令行调用 msbuild myproject /t:Rebuild 时,就是这种情况。

需要注意的是,你说:"我意识到我完全可以将上述内容放入批处理文件中并调用该批处理文件,但我不想再给自己增加另一个需要跟踪的文件。" 但是我不建议您这么快地拒绝这个想法,因为它确实有一个主要优点,您可以通过运行批处理文件来测试构建事件本身是否正常。如果您想对嵌入在项目文件中的目标执行相同操作,则必须启动命令行,确定要调用哪个目标,并运行msbuild projectfile /t:target 进行测试。这样做需要更多的工作 :) 此外,跟踪文件的工作应该由您的版本控制系统完成,所以您不必担心它。


1
这看起来很有前途,但GUI似乎没有提供指定“后清理事件”的机会,所以看起来我必须直接编辑.vcxproj文件。关于此有一些文档(实际上比我能找到的nmake文档要多得多!),所以我会去看看它。 - Eos Pengwern
确实需要手动编辑它。但不用担心,这是相当易读的xml:]特别是在使用能够识别它的文本编辑器时。最简单的方法是使用VS本身编辑项目文件,因为它具有项目文件的智能感知/自动完成/...。或者使用带有msbuild插件的SublimeText。 - stijn
我差不多走出了困境,但如果您能提供一些建议,我会很感激。当我加入您建议的 XML 项并添加了(在 <Message.. /> 后一行)"<Exec Command="cd ..\..\..\zlib-1.2.8 (回车) nmake /f win32\Makefile.msc clean"/> (根据文档,Exec 命令中的回车是可以的),我收到了错误信息“'nmake' 不是内部或外部命令,也不是可运行的程序或批处理文件”。它没有反对 'cd' 命令,但似乎已经失去了通向 'nmake' 的路径。有办法解决这个问题吗? - Eos Pengwern
你是否调用了 ipsxe-comp-vars.bat?通常情况下,nmake不在你的PATH中,我猜ipsxe-comp-vars.bat设置了所有需要进行正确构建的环境变量。创建一个批处理文件包含这些命令,在“普通”命令行中执行它(即不调用ipsxe-comp-vars.bat或任何VS的xxvars.bat),运行批处理文件,检查是否有效。只有在有效的情况下,你才能使用Exec。 - stijn
是的,就是这样!我以为“本机Microsoft”环境变量已经设置好了,而ipsxe-comp-vars.bat只是设置额外的Intel特定变量。显然情况并非如此,事实证明调用ipsxe-comp-vars.bat或(Microsoft等效)vcvarsall.bat同样适用于确保“nmake”被识别。我还必须转义路径名中所需的引号。我将在稍后发布单独的答案来记录最终解决方案。 - Eos Pengwern

4

Stijn 帮我找到了正确的方向:最终的解决方案是手动在我的 .vcxproj 文件的末尾添加以下部分(紧接在最后一行形成的 </Project> 之前):

  <Target Name="OnCleanOnly" AfterTargets="Clean">
    <Exec Command="call &quot;C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat&quot; x86
                   cd ..\..\..\zlib-1.2.8
                   nmake /f win32\Makefile.msc clean
                   cd ..\tiff-4.0.3
                   nmake /f Makefile.vc clean" />
    <Message Text="Cleaning libraries" Importance="High" />
  </Target>

这样做可以确保每次从“构建”菜单中选择“清理解决方案”或“重新生成解决方案”时都会执行“nmake clean”命令。这正是我希望实现的精确效果。


1
您可以按照以下步骤进行操作:
  1. 将可执行文件添加到您的项目中
  2. 右键单击可执行文件 ->属性。
  3. 将“项目类型”更改为“自定义构建工具”
  4. 应用更改
  5. 转到新创建的“自定义构建工具”选项卡。
  6. 在“命令行”部分中添加您的命令。
  7. 指定命令行生成的输出文件的名称。
  8. 根据您的要求选择其他选项。
  9. 单击“确定”
  10. 对于需要自定义构建的所有文件,都要在Debug和Release配置下执行此操作
完成了!

0

如果你的批处理文件需要重建,可以在调用时带上参数R,否则不需要。例如:Yourbat.bat R,然后就可以通过测试参数(%1)来判断是否需要重建。

call "C:\Program Files (x86)\Intel\Composer XE 2013 SP1\bin\ipsxe-comp-vars.bat" ia32 vs2010
cd ..\..\..\zlib-1.2.8
IF /i "%1"=="R" nmake /f win32\Makefile.msc clean
nmake /f win32\Makefile.msc zlib.lib
cd ..\tiff-4.0.3
IF /i "%1"=="R" nmake /f Makefile.vc clean
nmake /f Makefile.vc lib

我使用了/i参数,使得IF保持不区分大小写(你也可以使用rR


谢谢你的回复,但我还没看出这怎么有帮助,除非我可以在选择重建而不是普通构建时自动添加“R”。如果每次想要进行重建时,都需要打开项目页面并手动更改“call YourBat.bat”为“call YourBat.bat R”,那么我就没有比直接更改批处理文件本身的文本好多少。而且,如果我忘记这样做了,我仍然会受到影响。关键要求是通过某些变量来识别文件是否可以自动测试用户是否请求了重建或普通构建。 - Eos Pengwern
当用户调用重建时,与调用普通构建时有何不同? - SachaDee
通常情况下,当用户想要从Debug切换到Release或从32位切换到64位时,会发生重建。在这些时候,需要重新构建库以确保我们不会尝试将32位Release项目与64位Debug库进行链接。 - Eos Pengwern

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接