Step into custom nuget c++ package - c++

I am trying to release a C++ nuget package into our company Nuget feed. The problem is that we can't step into functions during debugging (F11). We need to be able to debug inside the package sources but it seems i cannot made it work.
I enabled in VS the option "Debug not only my code", included the generated vc110.pdb files in the package and finally added in the .nuspec the line
<repository type="git" url="http://xxxx" />
Unfortunately, VS17 does not step into the code of my package. We are pretty desperate and we really need a solution to this problem in order to make our toolchain leaner.
This is a C++ question so please do not link me to C#/.NET solutions because they don't work.
NOTE 1: When i pack with nuget i do not use the -Symbols option because it generates 2 packages and the second one cannot be pushed on our nuget feed (dupikcated package)
NOTE 2: I looked into the /SourceLink option but it seems to be supported only in C#
NOTE 3: I cannot use the .vcxproj when packing (it does not work, nuget says that i didn't give it any input file so i have to use my own .nuspec:
<package >
<metadata>
<id>x</id>
<version>1.0.2</version>
<title>$title$</title>
<authors>x</authors>
<projectUrl>yyy</projectUrl>
<description>static .lib</description>
<tags>native</tags>
<repository type="git" url="yyy" />
</metadata>
<files>
<file src="include\**\*.*" target="include" />
<file src="x64\**\*.lib" target="lib\x64" />
<file src="x64\**\*.pdb" target="lib\x64" />
<file src="build\**\*.*" target="build" />
</files>
</package>
NOTE 4: Ours GIT repo is on a Azure Devops TFS machine
NOTE5 : We are using VS17 but compiling with vc110 toolset (yeah know, don't comment on that please)
Thanks all

Related

TextTemplating target in a .Net Core project

I have recently migrated a test project to .NET Core 2.0. That test project used text templates to generate some repetitive code. The previous project had a build target to generate all T4-templates before build. Therefore, the generated code is also not checked in into the VCS.
I had used this snippet in the project to ensure that templates are built:
<PropertyGroup>
<!-- Default VisualStudioVersion to 15 (VS2017) -->
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<!-- Determinate VSToolsPath -->
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<!-- Run T4 generation if there are outdated files -->
<TransformOnBuild>True</TransformOnBuild>
<TransformOutOfDateOnly>True</TransformOutOfDateOnly>
</PropertyGroup>
<!-- Import TextTemplating target -->
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
My first approach was to keep this fragment and copy it to the new .NET Core project file.
Inside Visual Studio, this works because apparently, VSToolsPath is set correctly. However, when I run the .NET Core SDK tools, as for example dotnet test (as I do on the build server), VSToolsPath maps to Program Files\dotnet\sdk\2.0.3 and there, the text templating targets cannot be found.
Because that did not work, I also tried to simply install the Microsoft.VisualStudio.TextTemplating package from Nuget but that has two problems:
it does not officially support .NET Core and installs for .NET 4.6.1 and
Nuget does not seem to install anything, so I cannot adjust the paths in the project file.
To support building T4 templates while building dotnet build you need to use Custom Text Template Host, which already exists for .NET Core (https://github.com/atifaziz/t5). To include it, add to your project in any ItemGroup this element:
<DotNetCliToolReference Include="T5.TextTransform.Tool" Version="1.1.0-*" />.
As Visual Studio already has it's own Text Template Host implementation, your added element should be conditioned only for .NET Core. For example:
<ItemGroup Condition="'$(MSBuildRuntimeType)'=='Core'">
<DotNetCliToolReference Include="T5.TextTransform.Tool" Version="1.1.0-*" />
</ItemGroup>
And at the same time you should condition out of .NET Core your settings for Visual Studio's Text Template Host, like this: Condition="'$(MSBuildRuntimeType)'=='Full'".
You should also add <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition="'$(MSBuildRuntimeType)'=='Full'" /> before importing Microsoft.TextTemplating.targets to make everything work correctly with .NET Core csproj in Visual Studio.
If you need to be able to clean up all generated code, you should rename your templates from *.tt to *.Generated.tt, all the code will be generated under *.Generated.cs and it will be possible to filter these file out at dotnet clean action.
The complete example of what it will look like in your csproj:
<!-- T4 build support for .NET Core (Begin) -->
<ItemGroup Condition="'$(MSBuildRuntimeType)'=='Core'">
<DotNetCliToolReference Include="T5.TextTransform.Tool" Version="1.1.0-*" />
<TextTemplate Include="**\*.Generated.tt" />
<Generated Include="**\*.Generated.cs" />
</ItemGroup>
<Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild" Condition="'$(MSBuildRuntimeType)'=='Core'">
<ItemGroup>
<Compile Remove="**\*.cs" />
</ItemGroup>
<Exec WorkingDirectory="$(ProjectDir)" Command="dotnet tt %(TextTemplate.Identity)" />
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
</Target>
<Target Name="TextTemplateClean" AfterTargets="Clean">
<Delete Files="#(Generated)" />
</Target>
<!-- T4 build support for .NET Core (End) -->
<!-- T4 build support for Visual Studio (Begin) -->
<PropertyGroup Condition="'$(MSBuildRuntimeType)'=='Full'">
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<!-- This is what will cause the templates to be transformed when the project is built (default is false) -->
<TransformOnBuild>true</TransformOnBuild>
<!-- Set to true to force overwriting of read-only output files, e.g. if they're not checked out (default is false) -->
<OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
<!-- Set to false to transform files even if the output appears to be up-to-date (default is true) -->
<TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition="'$(MSBuildRuntimeType)'=='Full'" />
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" Condition="'$(MSBuildRuntimeType)'=='Full'" />
<!-- T4 build support for Visual Studio (End) -->
If you don't want to rename your template files and you don't need to clean up them, then replace:
<TextTemplate Include="**\*.Generated.tt" />
<Generated Include="**\*.Generated.cs" />
with:
<TextTemplate Include="**\*.tt" />
And delete:
<Target Name="TextTemplateClean" AfterTargets="Clean">
<Delete Files="#(Generated)" />
</Target>
For more information see:
How to set up code generation on dotnet build:
https://notquitepure.info/2018/12/12/T4-Templates-at-Build-Time-With-Dotnet-Core/
How to set up code generation on build for Visual Studio and .NET Core csproj:
https://thomaslevesque.com/2017/11/13/transform-t4-templates-as-part-of-the-build-and-pass-variables-from-the-project/
The full example of the generation of multiple files from a single T4 template:
https://github.com/Konard/T4GenericsExample
Update:
GitHub.com/Mono/T4 is even better.
You are at the mercy of someone writing a port for dotnet core.
This is old: http://www.bricelam.net/2015/03/12/t4-on-aspnet5.html
Or use a different templating tool entirely, though of course I understand if that’s not an option.
Or just use T4Executer. You can set which templates to execute before build, after build or ignore specific templates. Works good with VS2017-19
To expand on Konard's comment of "Update: https://github.com/mono/t4 is even better."
Install Mono/T4 (dotnet-t4) as a tool
If you are running an Azure devops pipeline, you can add it as a step - see the first part of https://stackoverflow.com/a/60667867/1901857.
If you are building in a linux dockerfile, add this before you build (we were using .net 6 on alpine, but it should be fine with other distros and versions):
# you will see a warning if this folder is not on PATH
ENV PATH="${PATH}:/root/.dotnet/tools"
RUN dotnet tool install -g dotnet-t4
If you want to use the tool on your dev machine, instead of VS TextTemplating, run a one-off install from powershell (but every dev in your team will need to do this):
dotnet tool install -g dotnet-t4
Run t4 on build - dev machine and pipeline
dotnet-t4 is setup very similarly to t5 in Konard's answer
Option 1 - dotnet-t4 installed on your dev machine
Add this to your csproj file. No conditional settings required.
<!-- T4 build support for .NET Core (Begin) -->
<ItemGroup>
<TextTemplate Include="**\*.tt" />
</ItemGroup>
<Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild">
<ItemGroup>
<Compile Remove="**\*.cs" />
</ItemGroup>
<Exec WorkingDirectory="$(ProjectDir)" Command="t4 %(TextTemplate.Identity)" />
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
</Target>
<!-- T4 build support for .NET Core (End) -->
Option 2 - use VS templating on your dev machine
If you don't want everyone to install the tool locally, you can still add conditional build steps to the project, as per Konard's answer. Note that Visual Studio is now 64-bit, so you can use MSBuildExtensionsPath instead of MSBuildExtensionsPath32:
<!-- T4 build support for .NET Core (Begin) -->
<ItemGroup Condition="'$(MSBuildRuntimeType)'=='Core'">
<TextTemplate Include="**\*.tt" />
</ItemGroup>
<Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild" Condition="'$(MSBuildRuntimeType)'=='Core'">
<ItemGroup>
<Compile Remove="**\*.cs" />
</ItemGroup>
<Exec WorkingDirectory="$(ProjectDir)" Command="t4 %(TextTemplate.Identity)" />
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
</Target>
<!-- T4 build support for .NET Core (End) -->
<!-- T4 build support for Visual Studio (Begin) -->
<PropertyGroup Condition="'$(MSBuildRuntimeType)'=='Full'">
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TransformOnBuild>true</TransformOnBuild>
<!--Other properties can be inserted here-->
<!--Set to true to force overwriting of read-only output files, e.g. if they're not checked out (default is false)-->
<OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
<!--Set to false to transform files even if the output appears to be up-to-date (default is true)-->
<TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" Condition="'$(MSBuildRuntimeType)'=='Full'" />
<!-- T4 build support for Visual Studio (End) -->

How to use the Web Publishing Pipeline and Web Deploy (MSDEPLOY) to Publish a Console Application?

I would like to use web deploy to publish a Visual Studio "Console" application to a folder on the target system.
I have had some luck, and have been able to produce something similar to what I need, but not quite.
I've added the following to the console .csproj:
added the following projectName.wpp.targets file
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
and I've added the following projectName.wpp.targets:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<DeployAsIisApp>false</DeployAsIisApp>
<IncludeSetAclProviderOnDestination>false</IncludeSetAclProviderOnDestination>
</PropertyGroup>
<ItemGroup>
<FilesForPackagingFromProject Include="$(IntermediateOutputPath)$(TargetFileName).config">
<DestinationRelativePath>bin\%(RecursiveDir)%(FileName)%(Extension)</DestinationRelativePath>
<FromTarget>projectName.wpp.targets</FromTarget>
</FilesForPackagingFromProject>
</ItemGroup>
</Project>
I then edit the .SetParameters.xml file as follows:
<parameters>
<setParameter name="IIS Web Application Name" value="c:\company\project" />
</parameters>
When I then deploy using the generated .cmd file, I get all the files deployed to C:\company\project\bin.
That's not bad, but I'd like to do better. In particular, I'd like to omit the "bin" folder and put all files in the "C:\company\project" folder, and I'd like to be able to specify the ACLs
Has anybody been able to work around these problems?
Ok, so here's the way how to omit the 'bin' folder.
First of all, I'd like to emphasize that all this msdeploy-related stuff is for web apps deployment, and 'bin' folder seems for me to be almost hardcoded deeply inside. So if you want to get rid of it - you have to do some dirty things. Which I did.
We'll have to change $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets project a little bit, so it's better to change not it, but it's copy.
Steps:
1.Backup $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets(alternatively, you could install MSBuild.Microsoft.VisualStudio.Web.targets package, redirect your csproj file to Microsoft.WebApplication.targets file obtained from package and work with it).
2. In the $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplicaton.targets find the xml node which looks like <CopyPipelineFiles PipelineItems="#(FilesForPackagingFromProject)"(there are several ones of them, take the one from the line ~2570).
3. Comment the node out, replace with the custom one, so eventually it will look like:
<!--
<CopyPipelineFiles PipelineItems="#(FilesForPackagingFromProject)"
SourceDirectory="$(WebPublishPipelineProjectDirectory)"
TargetDirectory="$(WPPAllFilesInSingleFolder)"
SkipMetadataExcludeTrueItems="True"
UpdateItemSpec="True"
DeleteItemsMarkAsExcludeTrue ="True"
Condition="'#(FilesForPackagingFromProject)' != ''">
<Output TaskParameter="ResultPipelineItems" ItemName="_FilesForPackagingFromProjectTempory"/>
</CopyPipelineFiles>-->
<!-- Copying files to package folder in 'custom'(dirty) way -->
<CreateItem Include="$(OutputPath)\**\*.*">
<Output TaskParameter="Include" ItemName="YourFilesToCopy" />
</CreateItem>
<Copy SourceFiles="#(YourFilesToCopy)"
DestinationFiles="#(YourFilesToCopy->'$(WPPAllFilesInSingleFolder)\%(RecursiveDir)%(Filename)%(Extension)')" />
Then
4. Your projectName.wpp.targets don't have to have FilesForPackagingFromProject, so it will look like:
<!-- targets -->
<PropertyGroup>
<DeployAsIisApp>false</DeployAsIisApp>
<IncludeSetAclProviderOnDestination>false</IncludeSetAclProviderOnDestination>
</PropertyGroup>
<ItemGroup>
<!-- intentionally left blank -->
</ItemGroup>
</Project>
That's it. Worked for me(tm), tested. Let me be honest, I don't like this approach, but that was the only way I made it working in the needed way. It's up to you whether you'll use it in your project or not.
My opinion is not to use msdeploy here - it was not for you task.
Better to write msbuild-scripts from scratch or accept the 'bin' folder, and fight against the framework again once next customization is required.

Compiling SSIS Projects with Team City

Has anyone done this? If so, what tools/techniques/approaches did you use?
Is it possible to do with installing the SQL Business Studio Version of Visual Studio?
Thanks in advance!
Got it folks...
1) Install MSBuild Extensions
2) Created a Build.Xml file as so...
<Project ToolsVersion="3.5" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>
<Target Name="Default">
<PropertyGroup>
<OutputRoot>../../../build-artifacts</OutputRoot>
</PropertyGroup>
<ItemGroup>
<SSISProjectFile Include="SSISProject.dtproj"/>
<SSISProject Include="#(SSISProjectFile)">
<OutputDirectory>$(OutputRoot)</OutputDirectory>
</SSISProject>
</ItemGroup>
<ItemGroup>
<Namespaces Include="Mynamespace">
<Prefix>DTS</Prefix>
<Uri>www.microsoft.com/SqlServer/Dts</Uri>
</Namespaces>
</ItemGroup>
<MSBuild.ExtensionPack.Xml.XmlFile
TaskAction="UpdateElement"
File="EnclarityDataImport.dtsx"
XPath="//DTS:Property[#DTS:Name='ConfigurationString']"
InnerText="$(MSBuildProjectDirectory)\EnclarityDataImport.dtsConfig"
Namespaces="#(Namespaces)"/>
<MSBuild.ExtensionPack.SqlServer.BuildDeploymentManifest InputProject="#(SSISProject)"/>
</Target>
The only trick was the last part of the build here. By default visual studio adds the absolute path to your config and connection string files for your dtsx package. Team City will use these in conjunction with MSBuild extensions to build the package so a local path will break the build because the paths to the build directories in Team City are automatically generated. So using the code above and the $(MSBuildProjectDirectory) you can twiddle the value of the path on your dtsx file so that it points to the path where your compilation is exectuing.
Like booyaa says SSIS projects don't need to be compiled, but what i have done is make the .dtconfigs configurable by the build/deployment process.
I do this so that i can run the packages on deployment in different environments. So the build will copy a template of the dtconfig file.
this contains tokens- $(Servername) $(ConnectionString)
And then i do the replacement on deployment and then execute by wrapping the dtexec in an command.
Not sure about 2012.

VS 2010 pre-compile web sites with build process?

VS 2010; TFS 2010; ASP.Net 4.0; Web Deployment Projects 2010;
I am using the build process templates in order to do one-click deploys (for dev and QA only). I want my sites to be pre-compiled. I can do it with the command line, using:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler
-v /site_name
-p "C:\...\site_name"
-f "C:\...\site_name1"
and this works fine if I copy the files over from site_name1 to site_name...
but is there an option in the IDE for this?? It seems really silly to have to do this from the command line. I've read a lot about different options, but none seem applicable to building with the build definitions.
You can do this by adding the following to your .csproj file
<PropertyGroup>
<PrecompileVirtualPath>/whatever</PrecompileVirtualPath>
<PrecompilePhysicalPath>.</PrecompilePhysicalPath>
<PrecompileTargetPath>..\precompiled</PrecompileTargetPath>
<PrecompileForce>true</PrecompileForce>
<PrecompileUpdateable>false</PrecompileUpdateable>
</PropertyGroup>
<Target Name="PrecompileWeb" DependsOnTargets="Build">
<Message Importance="high" Text="Precompiling to $(PrecompileTargetPath)" />
<GetFullPath path="$(PrecompileTargetPath)">
<Output TaskParameter="fullPath" PropertyName="PrecompileTargetFullPath" />
</GetFullPath>
<Message Importance="high" Text="Precompiling to fullpath: $(PrecompileTargetFullPath)" />
<GetFullPath path="$(PrecompilePhysicalPath)">
<Output TaskParameter="fullPath" PropertyName="PrecompilePhysicalFullPath" />
</GetFullPath>
<Message Importance="high" Text="Precompiling from fullpath: $(PrecompilePhysicalFullPath)" />
<AspNetCompiler PhysicalPath="$(PrecompilePhysicalPath)" VirtualPath="$(PrecompileVirtualPath)" TargetPath="$(PrecompileTargetPath)" Debug="true" Force="$(PrecompileForce)" Updateable="$(PrecompileUpdateable)" FixedNames="true" />
Then in TFS2010's default template
your build definition
Process tab
Advanced parameters section
MSBuild Arguments
set /target="PrecompileWeb"
As it currently stands, I can not find any IDE option to pre-compile websites using the build process templates. I would love to be proved wrong, as using the command line aspnet_compiler requires us (in our setup) to crack open the actual build process template, which we are trying to avoid.
I would love to be proved wrong! :)
We have a website that is stored in TFS2010 as a Web application. I use a MSBuild command to deploy from TFS2010. If you open your project in VS2010 Team Explorer you will see there is a "Builds" option. If you add a build and in the process tab use a build argument like ...:/p:DeployOnBuild=True /p:DeployTarget=MsDeployPublish /p:CreatePackageOnPublish=True /p:MSDeployPublishMethod=RemoteAgent /p:MSDeployServiceUrl=http://111.111.111.111/msdeployagentservice /p:DeployIisAppPath=MySiteNameInIIS /p:UserName=myDomain\BuildUser /p:Password=BuildUserPassword In the Process tab where it says "Items to Build" you just point it to your .sln file (might work with a .cspro but then the syntax changes slightly)
We have a TFS2010 server and I deploy a few of our sites to a dev, qa, pre-production or production IIS server. I do unit testing on the dev build and if the test fail then I do not deploy.
The MSBuild command does the pre-compile, would that work for you?
A setting for precompiling has been added. The following works in Visual Studio 2015
Open a solution
Right click on the project
Select "Publish..."
Go to settings, expand "File
Check "Precompile during Publishing"

How do I add a custom build target to a Visual C++ 2010 project?

There are plenty of guides out there which help you mimic VS2008's "Custom Build Step" in VS2010 with MSBuild. However, I'd like my build to be smarter and make use of MSBuild. I've written a little MSBuild task which invokes the ANTLR parser generator. That build task works flawlessly when I run it in a simple test MSBuild file. However, when I try to add my task to a C++ project, I run into problems. Essentially I've added this to the top of my project file (Right after the <project> element):
<UsingTask TaskName="ANTLR.MSBuild.AntlrGrammar"
AssemblyName = "ANTLR.MSBuild, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d50cc80512acc876" />
<Target Name="BeforeBuild"
Inputs="ConfigurationParser.g"
Outputs="ConfigurationParserParser.h;ConfigurationParserParser.cpp;ConfigurationParserLexer.h;ConfigurationParserLexer.cpp">
<AntlrGrammar
AntlrLocation="$(MSBuildProjectDirectory)Antlr.jar"
Grammar="ConfigurationParser.g"
RenameToCpp="true" />
</Target>
However, my target is not being called before build.
How can I add my task to a C++ build?
Before reading this answer, you'll probably want to see:
General .vcxproj File Reference
The New Way of doing Build Extensibility in .NET 4
The old way of extending MSBuild, and the one mentioned by the reference book I have, essentially is based on overriding default-empty targets supplied by Microsoft. The new way, as specified in the second link above, is to define your own arbitrary target, and use the "BeforeTargets" and "AfterTargets" properties to force your target to run before or after your intended target.
In my specific case, I needed the ANTLR Grammars task to run before the CLCompile target, which actually builds the C++ files, because the ANTLR Grammars task builds .cpp files. Therefore, the XML looks like this:
<Project ...
<!-- Other things put in by VS2010 ... this is the bottom of the file -->
<UsingTask TaskName="ANTLR.MSBuild.AntlrGrammar"
AssemblyName = "ANTLR.MSBuild, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d50cc80512acc876" />
<Target Name="AntlrGrammars"
Inputs="Configuration.g"
Outputs="ConfigurationParser.h;ConfigurationParser.cpp;ConfigurationLexer.h;ConfigurationLexer.cpp"
BeforeTargets="ClCompile">
<AntlrGrammar
AntlrLocation="$(MSBuildProjectDirectory)\Antlr.jar"
Grammar="Configuration.g"
RenameToCpp="true" />
</Target>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
As for why this is superior to a PreBuildEvent and/or PostBuildEvent; this is smart enough to not rebuild the .cpps when the grammar itself is not updated. You'll get something like:
1>AntlrGrammars:
1>Skipping target "AntlrGrammars" because all output files are up-to-date with respect to the input files.
1>ClCompile:
1> All outputs are up-to-date.
1> All outputs are up-to-date.
This also silences Visual Studio's incessant complaining every time you run the program that it needs to rebuild things, like it does with plain pre- and post- build steps.
Hope this helps someone -- took me frickin forever to figure out.