Qt Moc'ing multiple files in parallel under msbuild - visual-studio-2010

Using the Qt Visual studio plugin it seems to take care of most of almost everything in a seemless manner. Unfortunately it does the moc'ing using a CustomBuild step in msbuild. This results in a serial moc'ing, one after another. Is there a way to convince msbuild to do them in parallel - I'm tired of 7 cores sitting on their laurels like me.
I've seen msbuild's BuildInParallel, but I'm not sure how to make that apply here.
msbuild snippet:
<Project>
...
<ItemGroup>
<CustomBuild Include="a_class4.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_CORE_LIB -DQT_GUI_LIB "-I." "-I.\GeneratedFiles" "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\qtmain" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I." "-I." "-I." "-I."</Command>
</CustomBuild>
<CustomBuild Include="a_class3.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_CORE_LIB -DQT_GUI_LIB "-I." "-I.\GeneratedFiles" "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\qtmain" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I." "-I." "-I." "-I."</Command>
</CustomBuild>
</ItemGroup>
...
</Project>

You can build in parallel using jom:
http://labs.qt.nokia.com/2009/03/27/speeding-up-visual-c-qt-builds/

I am not very familiar with Visual Studio projects ... so don't know if the "CustomBuild" ItemGroup name and its metadata names bear significance. If they do, you might need to
Modify the ItemGroup name to something else
Identify the msbuild targets file which handles that and fix it for parallel processing
Here is a standalone msbuild file that can execute things in parallel.
Notes:
The ping -n 30 -w 1000 127.0.0.2>nul command has been added so that I could launch process explorer and find enough time to count how many instances of ping.exe were spawned.
I was trying to ping 127.0.0.2 because I wanted ping not to finish earlier.
There is nothing practically useful happening in the file ... only echoing properties as a proof of concept.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="RunMe">
<ItemGroup>
<CustomBuild Include="a_class4.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_CORE_LIB -DQT_GUI_LIB "-I." "-I.\GeneratedFiles" "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\qtmain" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I." "-I." "-I." "-I."</Command>
</CustomBuild>
<CustomBuild Include="a_class3.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_CORE_LIB -DQT_GUI_LIB "-I." "-I.\GeneratedFiles" "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\qtmain" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I." "-I." "-I." "-I."</Command>
</CustomBuild>
</ItemGroup>
<Target Name="RunMe">
<Message Text="First populate an ItemGroup such that we can use it for parallel processing"/>
<ItemGroup>
<InputForParallelInvoke Include="$(MSBuildThisFileFullPath)">
<Properties>InputFile=%(CustomBuild.Identity);
AdditionalInputs=%(CustomBuild.AdditionalInputs);
Message=%(CustomBuild.Message);
Outputs=%(CustomBuild.Outputs);
Command=%(CustomBuild.Command)</Properties>
</InputForParallelInvoke>
</ItemGroup>
<MSBuild Projects="#(InputForParallelInvoke)" Targets="InvokeInParallel" BuildInParallel="True" />
</Target>
<Target Name="InvokeInParallel">
<Exec Command="ping -n 30 -w 1000 127.0.0.2>nul & echo Properties=$(InputFile) ##### $(AdditionalInputs) ##### $(Message) ##### $(Outputs) ##### $(Command)"/>
</Target>
</Project>
When I invoke it on via msbuild thus msbuild /m \path\to\file /p:Configuration=Debug;Platform=Win32 I see 2 instances of ping.exe.
Hope this helps solve your problem.

Related

msbuild target - AfterTargets="Build" for the solution?

I am looking for a way to run my defined Target only once per build process and not for every project that gets build.
I have defined the following in Directory.Build.props
<Target Name="MyTarget" AfterTargets="AfterBuild" >
<Message Text="Hello World!!!" Importance="High" />
</Target>
Should only run once no matter how many projects the msbuild process is building, currently it happens for each project.
It shouldn't matter if I hit (Re-)Build Soltution or (Re-)Build [ProjectName] or hit F5 in Visual Studio, as long any build happens I want to exectue MyTarget only once.
Just answer this situation:
If my guess is right, pure msbuild function is not enough and you have to use a external file to help it work.
create a file called test.txt on the solution folder and write 0 in the txt file.
Then, modify your Directory.Build.props like this:
<Project>
<PropertyGroup>
<Record></Record>
</PropertyGroup>
<ItemGroup>
<File Include="..\test.txt"></File>
</ItemGroup>
<Target Name="GetConditionValue" BeforeTargets="PrepareForBuild">
<ReadLinesFromFile File="#(File)">
<Output TaskParameter="Lines" PropertyName="Record"/>
</ReadLinesFromFile>
</Target>
<Target Name="MyTarget" AfterTargets="Build" Condition="'$(Record)'=='0'">
<WriteLinesToFile File="#(File)" Lines="2" Overwrite="true"></WriteLinesToFile>
<Message Text="Hello World!!!" Importance="High" />
</Target>
</Project>
When you start a new build process, you should clear the test.txt file to 0 to make a new start.

use post build events with Fody.Costura installed

Once I added Fody.Costura to my project, my post build event that was copying the resulting assembly into a different location started failing with access denied message. That makes sense since Costura uses MSBuild to embed the assemblies. Is there a way to force my post builds to execute after Costura is finished? Example of a post build command:
copy /Y "$(TargetPath)" "%ALLUSERSPROFILE%\Autodesk\Revit\Addins\2019\HOK-Addin.bundle\Contents"
Basically the solution to my own question is the following.
<Target Name="CopyFiles" AfterTargets="AfterBuild;NonWinFodyTarget">
<Message Text="Signing file..." Importance="high" />
<Exec Command=""C:\Program Files (x86)\Windows Kits\10\bin\10.0.17134.0\x64\signtool.exe" sign /c "Code Signing - DTM" /v "$(TargetPath)"" />
<Message Text="Copy files..." Importance="high" />
<Message Text="$(TargetPath) > $(ALLUSERSPROFILE)\Autodesk\Revit\Addins\$(Configuration)\HOK-Addin.bundle\Contents" Importance="high" />
<Message Text="$(TargetDir)$(TargetName).addin > $(ALLUSERSPROFILE)\Autodesk\Revit\Addins\$(Configuration)" Importance="high" />
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(ALLUSERSPROFILE)\Autodesk\Revit\Addins\$(Configuration)\HOK-Addin.bundle\Contents" ContinueOnError="true" />
<Copy SourceFiles="$(TargetDir)$(TargetName).addin" DestinationFolder="$(ALLUSERSPROFILE)\Autodesk\Revit\Addins\$(Configuration)" ContinueOnError="true" />
</Target>
What I did, was to replace the standatd Post Build Command that runs Command Line routines, with a MSBuild Target and a Task.Giving it flags to run after Build is finished and Fody is done merging assemblies resolves my issue.
What also helps is the fact that Tasks have flags like ContinueOnError="true" that allow the task to keep trying until the file is available (if that was the issue) as opposed to command line utilities that would just fail.
Cheers!

Convert Makefile content to Apache Ant

What would be the syntax in 'build.xml' of an Ant build system
that corresponds to the following content of a Makefile (GNU Make):
target: dependency0 dependency1
shell command 1 # Not java, cc or the like
shell command 2
shell command 3
Example
$ ant
dependency0:
[echo] Hello world one
dependency1:
[echo] Hello world two
build:
[exec] command 1
[exec] command 2
[exec] command 3
build.xml
<project name="demo" default="build">
<target name="dependency0">
<echo>Hello world one</echo>
</target>
<target name="dependency1">
<echo>Hello world two</echo>
</target>
<target name="build" depends="dependency0,dependency1">
<exec executable="echo">
<arg line="command 1"/>
</exec>
<exec executable="echo">
<arg line="command 2"/>
</exec>
<exec executable="echo">
<arg line="command 3"/>
</exec>
</target>
</project>

LINK : fatal error LNK1104: cannot open file 'SDL.lib'

I've been trying to learn SDL, but haven't been successful at linking the .lib
When compiling my C++ program I'm told the file cannot be opened.
Build started 8/8/2014 1:08:01 AM.
1>Project "C:\Users\Steven\Documents\Visual Studio 2013\Projects\KinectTest\KinectTest\KinectTest.vcxproj" on node 2 (Build target(s)).
1>Link:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\link.exe /ERRORREPORT:PROMPT /OUT:"C:\Users\Steven\Documents\Visual Studio 2013\Projects\KinectTest\Debug\KinectTest.exe" /INCREMENTAL /NOLOGO /LIBPATH:"C:\Program Files\Microsoft SDKs\Kinect\v1.8\lib\x86" /LIBPATH:"C:\SDL2-2.0.3\lib\x86" Kinect10.lib SDL.lib SDLmain.lib opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG /PDB:"C:\Users\Steven\Documents\Visual Studio 2013\Projects\KinectTest\Debug\KinectTest.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"C:\Users\Steven\Documents\Visual Studio 2013\Projects\KinectTest\Debug\KinectTest.lib" /MACHINE:X86 Debug\KinectTest.res
Debug\KinectTest.obj
1>LINK : fatal error LNK1104: cannot open file 'SDL.lib'
1>Done Building Project "C:\Users\Steven\Documents\Visual Studio 2013\Projects\KinectTest\KinectTest\KinectTest.vcxproj" (Build target(s)) -- FAILED.
Build FAILED.
Time Elapsed 00:00:00.22
Directory Contents:
Directory of c:\SDL2-2.0.3\lib\x86
03/15/2014 07:34 PM <DIR> .
03/15/2014 07:34 PM <DIR> ..
03/15/2014 07:33 PM 1,007,104 SDL2.dll
03/01/2014 11:23 AM 116,400 SDL2.lib
03/01/2014 11:23 AM 40,536 SDL2main.lib
03/01/2014 11:23 AM 821,670 SDL2test.lib
4 File(s) 1,985,710 bytes
2 Dir(s) 69,829,705,728 bytes free
As you can see above the directory of the lib was included and the file is in fact in that location
Props File:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>C:\SDL2-2.0.3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>C:\SDL2-2.0.3\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL.lib;SDLmain.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>
You are trying to link the library calling it SDL.lib when in fact it should be SDL2.lib
In the directory:
03/01/2014 11:23 AM 116,400 SDL2.lib
From Additional Dependencies:
<AdditionalDependencies>SDL.lib;...</AdditionalDependencies>
This is the same for SDLmain.lib which should be SDL2main.lib

Before and AfterBuild Target in Visual Studio not firing

I am doing the following:
I have created a default class file project
Edited the csproj file to include Pre and Post BuildEvents
Uncomment the default commented out BeforeBuild and AfterBuild targets
The BeforeBuild and AfterBuild targets are not called form within Visual Studio but are from msbuild command line, why is that?
I would rather use msbuild targets rather than the PostBuildEvent as if gives me more power and flexibility, assuming it works.
Cheers,
adam
I shortened some of the paths in the output, so if they are inconsistent that is why
ClassLibrary1.csproj changes
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="BeforeBuild">
<Message Text="### BeforeBuild ###" />
</Target>
<Target Name="AfterBuild">
<Message Text="### AfterBuild ###" />
</Target>
<PropertyGroup>
<PreBuildEvent>echo PRE_BUILD</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>echo POST_BUILD</PostBuildEvent>
</PropertyGroup>
my build output from VS 2010 is
------ Rebuild All started: Project: ClassLibrary1, Configuration: Debug Any CPU ------
PRE_BUILD
ClassLibrary1 -> c:\ClassLibrary1\bin\Debug\ClassLibrary1.dll
POST_BUILD
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
and from the command line
#>msbuild ClassLibrary1.sln
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.239]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 09/05/2012 13:27:42.
Project "c:.sln" on node 1 (default targets).
ValidateSolutionConfiguration:
Building solution configuration "Debug|Any CPU".
Project "c:.sln" (1) is building "c:\ClassLibrary1.csproj" (2) on node 1 (default targets).
BeforeBuild:
### BeforeBuild ###
PreBuildEvent:
echo PRE_BUILD
PRE_BUILD
GenerateTargetFrameworkMonikerAttribute:
Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
CoreCompile:
Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files.
CopyFilesToOutputDirectory:
ClassLibrary1 -> c:\bin\Debug\ClassLibrary1.dll
PostBuildEvent:
echo POST_BUILD
POST_BUILD
AfterBuild:
### AfterBuild ###
Done Building Project "c:\ClassLibrary1.csproj" (default targets).
Done Building Project "c:.sln" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.18
Your build events are firing, you're just not seeing them in Visual Studio.
By default VS sets the msbuild verbosity to minimal. You can get your message to show by changing the message importance to high
<Target Name="BeforeBuild">
<Message Text="### BeforeBuild ###" Importance="high" />
</Target>
<Target Name="AfterBuild">
<Message Text="### AfterBuild ###" Importance="high" />
</Target>
You can also change the verbosity setting in VS under Tools->Options then under Projects and Solutions->Build and Run.
Just for others help, when they encounter similar issue but the reason could be different.
If you have import after the target then also AfterBuild may not work.
Make sure all the import you have should be before Target Definition, Target Definition should be at the end

Resources