Delphi XE custom build target is always disabled
DelphiMsbuildDelphi XeDelphi Problem Overview
I've created a custom MSBuild .targets
file that I've included in a Delphi XE project via the IDE and enabled it from the Project Manager's context menu. Although the file validates, it always gets disabled after I re-save the project file.
Here's a simplified version of the targets file, named Custom.targets
.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Hello">
<Message Text="Hello from custom target"/>
</Target>
</Project>
As a stand alone file this works as expected: typing...
MSBuild Custom.target /t:Hello
...at the command line gives the expected message.
Adding Custom.targets
to a Delphi project via the IDE displays the file in the Project Manager as expected, and the .dproj
file now contains the line...
<TargetsFile Include="Custom.targets"/>
I right-clicked the file in the IDE's Project Manager and selected Enable
. But when the project is built the Build
message window displays:
> [MSBuild Warning] Custom.targets(1): Ignoring disabled import: PathToProjectSource\\Custom.targets
Right-clicking again in Project Manager still shows the Enable
option instead of the expected Disable
.
At the command line MSBuild ProjectName.dproj /t:Hello
also fails.
I've tried hacking the .dproj
file to add the line...
<Import Project="Custom.targets"/>
Typing MSBuild ProjectName.dproj /t:Hello
now works. But the next time I save the project file from the IDE the <Import>
statement gets removed.
Anyone got any idea what's going wrong please?
Delphi Solutions
Solution 1 - Delphi
Delphi generates the entire dproj content itself and this custom import will always be deleted.
You could write your own msbuild xml files but the dproj belongs to Delphi.
Unless you have source code or are willing to monkey patch the ide you cant do that.
If you really want a flexible xml way to build delphi projects and create targets galore try want or want vnext (my fork on bitbucket)
Solution 2 - Delphi
I would include the targets file manually and build externally using MSBuild rather than from the IDE, because when compiling from the IDE its a bit messy to know which configuration and target have you applied (is the one clicked on the project? or the one from enabled target? you dont get any visual hint that a custom target is enabled).
I usually do it before the Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets"
so they will not show on the IDE (they exist, but are hidden to developers).
For example my Delphi XE4 projects end with:
<Import Project="..\BuildServer.Targets"/>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
</Project>
My .targets file defines a custom "PropertyGroup" and "Target" with a condition, so they will only apply when called from MSBuild:
<PropertyGroup Condition="'$(Config)'=='CustomConfig'">
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
...
</PropertyGroup>
<Target Name="DisplayProjectInfo">
<Message Text="Project File Name = $(MSBuildProjectFile)"/>
<Message Text="Version = $(VerInfo_Keys)"/>
<Message Text="OutputDir = $(DCC_ExeOutput)"/>
</Target>
<Target Name="CustomTarget" Condition="'$(Config)'=='CustomConfig'">
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Clean" />
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Build" />
<CallTarget Targets="DisplayProjectInfo"/>
</Target>
Then compile it with:
msbuild /t:CustomTarget /p:config=CustomConfig poject.dproj
Using this approach lets you customize build targets to make sure every application gets the correct settings without being affected by changes made by anyone.