Adding a custom preprocessing task in Visual C++ - visual-studio

I'm migrating my project build toolchain from python/MinGW to msbuild/MSVC.
I need to perform additional preprocessing on some c++ files before each build.
This is performed by my own python script.
Is there a way to do this without writing a extension? 'Custom Build Tool' doesn't allow to modify current source files. Is there any option to "chain" this with build step?

Adding a custom preprocessing task in Visual C++
Since you do not want to modify the source file, you can use the copy task to back up your scource files to the intermediate directory:
<ItemGroup>
<MySourceFiles Include="c:\MySourceTree\**\*.cpp"/>
</ItemGroup>
<Target Name="CopyFiles">
<Copy
SourceFiles="#(MySourceFiles)"
DestinationFolder="Destination\Intermediate directory"
/>
</Target>
Then use the csc task to compile it before build:
<ItemGroup>
<Compile Include="…\Intermediate directory\filename">
</Compile>
</ItemGroup>
<Target Name="BeforeBuild">
<Message Text="Running your python script on the Intermediate directory folder..."/>
</Target>
See "Preprocessing" each source file before compilation? for more details.
Update for comment:
Question is all about whether you can call your own target on build
failed.
You can use MSBuild command line with specify your custom target to build it:
msbuild.exe "YouProjectName.vcxproj" /t:BeforeBuild;Build
Then MSBuild will build your custom build first whether your build is failed or successfully.
Hope this helps.

Related

How to build project in multiple configurations to automate the build process?

I have a solution, which contains a native project. For the main project to properly work, the following steps should be taken:
The native project has to be built in Release/x86 configuration
The native project has to be built in Release/x64 configuration
All .NET projects have to be built
Both binaries from steps 1 and 2 have to be placed in the main project's output folder.
Is there a way to configure project, so that all of those steps happen upon simply choosing "Build | Rebuild all"? I know of the batch build option, but I'd still have to execute step 4 manually.
I think you have to use msbuild script to build your project rather than VS IDE. Scripts are more flexible and can realize your requirements.
1) create a new file called build.proj and then add these on that file:
<Project>
<ItemGroup>
<!--include all c# csproj files to build these projects all at once-->
<NetProjectFile Include="**\*.csproj" />
<!--include the c++ proj files-->
<NativeProjectFile Include="**\*.vcxproj" />
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="#(NetProjectFile)" Targets="Restore;Build" Properties="Configuration=Debug;Platform=AnyCPU"/>
<!--OutDir is the path of the execute file ,pdb.... if you also want the intermediate files to be in the same folder, you should also use IntDir -->
<MSBuild Projects="#(NativeProjectFile)" Targets="Build" Properties="Configuration=Release;Platform=x86;OutDir=xxx\xxx\"/>
<MSBuild Projects="#(NativeProjectFile)" Targets="Build" Properties="Configuration=Release;Platform=x64;OutDir=xxx\xxx\"/>
</Target>
</Project>
3) Just run msbuild build.proj -t:Build to get what you want.

Make visual studio build when output won't change?

In my project I have a json file I use for configuration that I have git set to ignore. When the repository is first cloned, the configuration file that is part of the project and that is copied to the output directory doesn't exist. I've gotten this to work using tasks in the 'BeforeBuild' target in the project that will copy the sample file to the actual config file if it doesn't exist.
<Target Name="BeforeBuild">
<ItemGroup>
<MySourceFiles Include="Configuration.sample.json" />
</ItemGroup>
<ItemGroup>
<MyDestinationFiles Include="Configuration.json" />
</ItemGroup>
<Message Importance="high" Condition="!Exists('#(MyDestinationFiles)')"
Text="Copying #(MySourceFiles) to #(MyDestinationFiles)" />
<Copy Condition="!Exists('#(MyDestinationFiles)')"
SourceFiles="#(MySourceFiles)"
DestinationFiles="#(MyDestinationFiles)" />
</Target>
So if I build the project, then delete the configuration file and do a build, nothing happens because no changes have been made that would change the outputs I think. Is there a way to change the project file so that a build will be flagged as necessary? It shouldn't come up very often and I can always do a 'Clean' or 'Rebuild' manually, but it's nagging at me since I'm just starting to learn MSBuild files.
From the documentation on a Target's Outputs attribute:
The files that form outputs into this target. Multiple files are
separated by semicolons. The timestamps of the files will be compared
with the timestamps of files in Inputs to determine whether the Target
is up to date
So if you add the paths to the outputfiles created by your Beforebuild target to it's Outputs attribute, at the start of every build msbuild will check if those files exist and if not it will start a build because now the project is considered to not be up-to-date anymore. In practice use:
<Target Name="BeforeBuild" Outputs="#(MyDestinationFiles)">

MSBuild or NAnt script that generates C# files, adds them to a project and compiles the project

I've just written a code generator app for FluentMigrator API that emits an unknown number of C# class files. I wish to compile the code generator, run it to emit the C# classes then add the new C# files to an existing C# project and then compile final solution.
What's the best approach for adding the code generated C# files to a project?
Given what we know from your post, there could be a couple approaches.
You have an API that will generate some class files and want to integrate this into your build process so you would make an API call to generate new class files, then incorporate those class files into your build.
If your executable emits output files into it's current working directory, you could use an Exec task to run your command in the $(IntermeidateOutputPath) so as to not clutter up your project's source tree:
<Exec Command="MyExe.exe " WorkingDirectory="$(IntermediateOutputPath)\AutoGenClasses\" />
Following this command, you could append those output classes into the default compile group:
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)\AutoGenClasses\**\*.cs" />
</ItemGroup>
Now you'd probably want to control when this occurs, so you'd embed this code into a separate <Target /> and schedule it to occur before the build occurs.
<Target Name="AutoGenClasses" BeforeTargets="Compile">
<Message Text="Starting the AutoGenClasses task..." Importance="high" />
<Exec Command="MyExe.exe " WorkingDirectory="$(IntermediateOutputPath)\AutoGenClasses\" />
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)\AutoGenClasses\**\*.cs" />
</ItemGroup>
<Message Text="... completed the AutoGenClasses." Importance="high" />
</Target>

How to add a command line code generator to Visual Studio?

I'm working on a project that uses code generation to generate C# classes using a command line tool from a text-based description. We are going to start using these descriptions for javascript too.
Currently these classes are generated and then checked in, however, I would like to be able to make the code generate automatically so that any changes are propagated to both builds.
The step that is run manually is:
servicegen.exe -i:MyService.txt -o:MyService.cs
When I build I want MSBuild/VS to first generate the CS file then compile it. It is possible to do this using, by modifying the csproj, perhaps using a MSBuild Task with Exec, DependentUpon & AutoGen?
Normally I would recommend a pre-build command be placed in a pre-build event, but since your command line tool will be creating C# classes needed for compiling, this should be done in the BeforeBuild target in the .csproj file. The reason for this is because MSBuild looks for the files it needs to compile between the time BeforeBuild is called and the time when PreBuildEvent is called in the overall process (you can see this flow in the Microsoft.Common.targets file used by MSBuild).
Call the Exec task from within the BeforeBuild target to generate the files:
<Target Name="BeforeBuild">
<Exec Command="servicegen.exe -i:MyService.txt -o:MyService.cs" />
</Target>
See the Exec task MSDN documentation for more details about specifying different options for the Exec task.
Antlr has an example of a process that can be used to add generated code to a project. This has the advantage of showing the files that are generated nested under the source file, although it is more complex to add.
You need add an item group with the file to be generated from, for example:
<ItemGroup>
<ServiceDescription Include="MyService.txt"/>
</ItemGroup>
Then add the cs file to be generated to the ItemGroup containing the rest of the source code.
<ItemGroup>
...
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
...etc..
<Compile Include="MyService.txt.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>MyService.txt</DependentUpon> <!--note: this should be the file name of the source file, not the path-->
</Compile>
</ItemGroup>
And then finally add the build target to execute the code generation (using % to execute the command for each item in the ItemGroup). This could be put into a separate file, so that it can be included from many projects.
<Target Name="GenerateService">
<Exec Command="servicegen.exe -i:%(ServiceDescription.Identity) -o:%(ServiceDescription.Identity).cs" />
</Target>
<PropertyGroup>
<BuildDependsOn>GenerateService;$(BuildDependsOn)</BuildDependsOn>
</PropertyGroup>

Visual Studio Project - MSBuild Target - AfterBuild - Condition - Only When Binary File Updated

I have a long afterbuild process on my Visual Studio project file's after build target, as show below.
The issue is that it always runs the AfterBuild target when I hit build even when the actual source code has not changed and the project is not compiled.
How can I have this only run when the project has been compiled and the physical binary is written or update on the disk?
<Target Name="AfterBuild">
<Exec Command=""$(ProgramFiles)\Microsoft\ILMerge\ILMerge.exe" /copyattrs /log /target:library /targetplatform:4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /Lib:"$(TargetDir)\" /keyfile:"$(ProjectDir)\Plugin.snk" /out:"$(TargetDir)\$(AssemblyName).merged.dll" "$(AssemblyName).dll" "PluginCommandCommon.dll" "Common.dll"" />
<Copy SourceFiles="$(TargetDir)\$(AssemblyName).merged.dll" DestinationFolder="$(ProjectDir)..\PluginPackage\bin\$(Configuration)\" />
</Target>
Option 1:
Instead of AfterBuild use AfterRebuild (one of MSBuild's many undocumented features):
<Target Name="AfterRebuild" >...</Target>
Option 2:
Hook up one of the incremental build's conditions:
<Target Name="AfterBuild" Condition=" '#(_SourceItemsToCopyToOutputDirectory)' != '' " >
UPDATE:
Using MSBuild Extension Pack's ILMerge task will allow better control, I.E check for each file existence:
<Target Name="ILMergeItems">
<ItemGroup>
<Input Include="C:\b\MSBuild.ExtensionPack.dll"/>
<Input Include="C:\b\Ionic.Zip.dll"/>
</ItemGroup>
<MSBuild.ExtensionPack.Framework.ILMerge
Condition="Exists('%(Input.FullPath)')"
InputAssemblies="#(Input)"
OutputFile="C:\a\MyNewAssembly.dll"/>
</Target>
There is a ComboBox in Properties>>Build Events>>Run the post-build event...if this is what you mean.

Resources