I met this problem in recent weeks, and I solved it with Delphi by myself.
What caused this problem, is the format of dproj.
Since dproj is XML format, and the pre-build/post-build events used "&" as the mark for new line, the dproj will save it as "&".
In somehow, Delphi will save it as "\n&&" when the project is saved. That cause MSBuild misunderstand the symbol and show "Syntax error".
Hence, what we do to solve this problem, is to detect if sLineBreak + '&&' exists in dproj which we will send to MSBuild.
With the modification, MSBuild will process the dproj perfectly.
I share my code in the following block, the program can help us the change the version number, correct the pre/post build events:
program changeProjVer;
////////////////////////////////////////////////////////////////////////////////
/// Created by Dennies Chang [email protected], [email protected]
///
/// If you need to use this utility, please refer the original URL:
/// https://firemonkeylessons.blogspot.com/2019/04/delphiBuildCommandAndTools.html
///
/// And do not remve these lines.
/// The code is opened for all Delphi programmers, you can use it as
/// commercial/non-commercial usage, what you have to do, is to have a notice
/// for the original author.
///
/// And send an Email to [email protected] to me, thanks.
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, IdGlobal, Classes;
var
currentFile, tmpStr, completeStr, tmpMajor, tmpMinor, tmpRelease,
tmpBuild, configName: String;
lineIdx: Integer;
src: TStringList;
bDebug : boolean;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
if ParamCount < 2 then begin
writeln('Usage: changeProjVer.exe dprojFileFullPath versionNo [Debug|Release]');
writeln('versionNo should be contain 3 dots, e.g.,: 107.1.108.321');
writeln;
Readln;
end
else begin
currentFile := ParamStr(1);
tmpBuild := ParamStr(2);
bDebug := False;
if ParamCount >= 3 then begin
configName := ParamStr(3);
bDebug := configName.ToLower = 'debug';
end;
tmpMajor := Trim(Fetch(tmpBuild, '.'));
tmpMinor := Trim(Fetch(tmpBuild, '.'));
tmpRelease := Trim(Fetch(tmpBuild, '.'));
tmpBuild := Trim(Fetch(tmpBuild, '.'));
if FileExists(currentFile) then begin
src := TStringList.Create;
try
src.LoadFromFile(currentFile, TEncoding.UTF8);
for lineIdx := 0 to src.Count - 1 do begin
completeStr := src.Strings[lineIdx];
tmpStr := '';
if Pos('<VerInfo_MajorVer>', completeStr) > 0 then begin
tmpStr := Fetch(completeStr, '<VerInfo_MajorVer>');
tmpStr := #9 + #9 + '<VerInfo_MajorVer>' + tmpMajor +
'</VerInfo_MajorVer>';
// completeStr := tmpStr;
end
else if Pos('<VerInfo_MinorVer>', completeStr) > 0 then begin
tmpStr := Fetch(completeStr, '<VerInfo_MinorVer>');
tmpStr := #9 + #9 + '<VerInfo_MinorVer>' + tmpMinor +
'</VerInfo_MinorVer>';
// completeStr := tmpStr;
end
else if Pos('<VerInfo_Release>', completeStr) > 0 then begin
tmpStr := Fetch(completeStr, '<VerInfo_Release>');
tmpStr := #9 + #9 + '<VerInfo_Release>' + tmpRelease +
'</VerInfo_Release>';
// completeStr := tmpStr;
end
else if Pos('<VerInfo_Build>', completeStr) > 0 then begin
tmpStr := Fetch(completeStr, '<VerInfo_Build>');
tmpStr := #9 + #9 + '<VerInfo_Build>' + tmpBuild +
'</VerInfo_Build>';
// completeStr := tmpStr;
end
else if Pos('FileVersion=', completeStr) > 0 then begin
// FileVersion
completeStr := src.Strings[lineIdx];
tmpStr := '';
while Pos('FileVersion=', completeStr) > 0 do begin
tmpStr := Fetch(completeStr, 'FileVersion=');
tmpStr := tmpStr + 'FileVersion=' +
StringReplace(ParamStr(2), ' ', '',
[rfReplaceAll]) + ';';
Fetch(completeStr, ';');
end;
if Length(completeStr) > 0 then begin
tmpStr := tmpStr + completeStr;
end;
end;
// 這兩個會出現在同一行, 不要加 else
if Pos('ProductVersion=', completeStr) > 0 then begin
completeStr := tmpStr;
tmpStr := '';
// ProductVersion
while Pos('ProductVersion=', completeStr) > 0 do begin
tmpStr := Fetch(completeStr, 'ProductVersion=');
tmpStr := tmpStr + 'ProductVersion=' +
StringReplace(ParamStr(2), ' ', '',
[rfReplaceAll]) + ';';
Fetch(completeStr, ';');
end;
if Length(completeStr) > 0 then begin
tmpStr := tmpStr + completeStr;
end;
end;
if (tmpStr = '') and (tmpStr <> completeStr) then
tmpStr := completeStr;
src.Strings[lineIdx] := tmpStr;
end;
src.Text := StringReplace(src.Text, sLineBreak + '&&', '&', [rfReplaceAll]);
src.SaveToFile(currentFile, TEncoding.UTF8);
finally
src.Free;
end;
end;
end;
except
on E: Exception do
writeln(E.ClassName, ': ', E.Message);
end;
end.
call PreBuild.bat
– David Heffernanif exist PostBuild.bat call PostBuild.bat $(Platform) $(Config) $(OutputDir)
. And then thePostBuild.bat
script calls a Python script so that I can write my scripts in a real language. I actually impose the build actions in a shared option set that I reference from all of my projects. That way I enforce consistency and predictability. I know others use tools like FinalBuilder but building is so important that I feel it's worth my effort in rolling my own tooling. – David Heffernan