16

我们目前正在从 Delphi XE 切换到 Delphi XE3,并且我们的预构建事件存在严重问题。

我们的预构建事件如下所示:

  SubWCRev "<SVN-Path>" "<InputFile>" VersionInfo.rc
  brcc32 -foProject.res VersionInfo.rc

(请注意,这两个命令出现在不同的行中;并且在我们的“真实”命令中包含绝对路径)即我们首先从工作副本中提取当前 SVN 版本,将此信息写入 VersionInfo.rc,然后使用 Borland 资源编译器生成资源文件。

这在以前的 Delphi 版本中运行良好,但每当我们在 XE3 中打开项目选项时,XE3 会将其转换为:

  SubWCRev "<SVN-Path>" "<InputFile>" VersionInfo.rc &brcc32 -foProject.res VersionInfo.rc

(请注意,这是一行,两个命令由一个 & 号分隔)。这会导致构建失败。

我们当前的解决方法是手动将其更改为

  SubWCRev "<SVN-Path>" "<InputFile>" VersionInfo.rc && brcc32 -foProject.res VersionInfo.rc

即,如果第一个命令成功,我们使用两个与号来执行第二个命令。

这有效,但只有在我们再次编辑项目选项之前 - Delphi XE3 总是搞乱预构建事件:-(

有人知道解决方案/解决方法吗?我想我们可以编写一个简单的命令行工具来调用 SubWCRev 和 brcc32,但我更喜欢更简单的解决方案。

更新:轻松重现此错误的步骤

IDE

  • 文件 -> 新建 -> VCL 表单应用程序 (Delphi)
  • 构建项目1
  • 文件 -> 全部保存,保留建议的名称 Unit1.pas / Project1.dpr
  • 项目 -> 选项
  • 选择目标“所有配置 - 所有平台”
  • Build Events -> Pre-build events,输入这个(两行,抱歉格式化):

    回声一> out.txt

    回显二 >> out.txt

  • 从 IDE 构建项目

  • 保存并关闭项目

RAD Studio command prompt

  • Navigate to the project directory
  • msbuild Project1.dproj => OK

IDE

  • Project -> Options
    • click into "Search path"
      • Enter "a"
      • delete the "a"
    • click ok
  • Project -> Build project
  • Save & close the project

RAD Studio command prompt

  • msbuild Project1.dproj => ERROR
4

3 回答 3

2

We ended up using a workaround similar to what was proposed by David Heffernan:

  • combine all our calls into a single (Ruby) script PreBuild.rb
  • compile this Ruby script into a standalone executable (since not all developers have Ruby installed)
  • use a single pre-build event in Delphi

In case anyone's interested, here's our PreBuild event:

PreBuild "<path_to_SVN_working_copy>" "VersionInfo.rc.in" $(OUTPUTNAME).res

and here's the script PreBuild.rb:

  #!/usr/bin/env ruby

  require 'tempfile'

  if ARGV.length < 3
    puts "usage: #{$0} <path> <infile> <outfile>"
    exit 1
  end
  # svnversion.exe is part of the SVN command line client
  svnversion = "svnversion.exe"
  path, infile, outfile = ARGV[0], ARGV[1], ARGV[2]
  # call svnversion executable, storing its output in rev
  rev_str = `#{svnversion} "#{path}"`.chop

  # extract the first number (get rid of M flag for modified source)
  rev = /^[0-9]+/.match(rev_str)[0]

  # get current date
  date = Time.new

  # remove old output file (ignore errors, e.g. if file didn't exist)
  begin
    File.delete(outfile)
  rescue
  end

  input = File.new(infile, "r")
  tmpname = "VersionInfo.rc"
  tmp = File.new(tmpname, "w+")
  input.each do |line|
    # replace $WCREV$ with revision from svnversion call
    outline = line.gsub(/\$WCREV\$/, rev) 
    # replace $WCDATE$ with current date + time
    outline = outline.gsub(/\$WCDATE\$/, date.to_s)
    # write modified line to output file
    tmp.puts(outline)
  end
  input.close
  tmp.close

  puts "SubWCRev: Revision: #{rev}, date: #{date}, written to #{tmpname}"

  call = "brcc32 -fo#{outfile} #{tmpname}"
  puts call
  system(call)
于 2013-03-18T12:08:52.707 回答
2

I'm using Delphi XE4, and I had the same problem with almost the same commands. Our PreBuildEvent has 4 lines, I tried what is described here, put all on 1 line and separating my commands with &&, and it worked. I then tried to modify to see if XE4 will mess my prebuild, but after putting back my prebuild on 4 lines, it was still working.

I finally figured out with other projects where I was able to reproduce this error, that simply editing the script by removing the CRLF at the end of each line, and putting it back, from XE4 environment, it fixed the PreBuildEvent.

于 2013-12-06T19:41:19.900 回答
0

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 dennies@ms4.hinet, dennies226@gmail.com
///
///   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 dennies@ms4.hinet.net 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 + '&amp;&amp;', '&amp;', [rfReplaceAll]);
               src.SaveToFile(currentFile, TEncoding.UTF8);
            finally
               src.Free;
            end;
         end;
      end;
   except
      on E: Exception do
         writeln(E.ClassName, ': ', E.Message);
   end;

end. 
于 2019-05-05T04:35:49.847 回答