Как определить версию приложения в одном месте для нескольких приложений?

У нас есть система, состоящая из множества приложений. Все приложения имеют свою версию одновременно. В настоящее время, когда мы выпускаем новую версию, мы должны вручную открывать параметры проекта для каждого приложения и менять версию один за другим. Есть ли способ скомпилировать все приложения в одной и той же версии, например, сохранить его в глобальном файле и при компиляции, прочитать этот файл и назначить эту версию проекту? Я просто пытаюсь устранить слишком много шагов, потому что мы планируем чаще менять номера версий. Я бы хотел изменить его только в одном месте. Это можно сделать? и как?

Ответы

Ответ 1

Вы можете создать ресурс VERSIONINFO в текстовом файле (например, Versioninfo.rc)

1 VERSIONINFO
FILEVERSION 2,0,0,0
PRODUCTVERSION 2,0,0,0
FILEOS 0x4
FILETYPE 0x1
{
BLOCK "StringFileInfo"
{
    BLOCK "040904E4"
    {
        VALUE "CompanyName", "Your Company Name Here\0"
        VALUE "FileDescription", "Your File Description Here\0"
        VALUE "FileVersion", "2.0.0.0\0"
        VALUE "InternalName", "Your Internal Name\0"
        VALUE "LegalCopyright", "© Your Copyright Notice\0"
        VALUE "LegalTrademarks", "Your Trademark Notice\0"
        VALUE "OriginalFilename", "YourExeName\0"
        VALUE "ProductName", "Your Product Name\0"
        VALUE "ProductVersion", "2.0.0.0\0"
        VALUE "Comments", "No Comments\0"
    }
}

BLOCK "VarFileInfo"
{
    VALUE "Translation", 0x0409 0x04E4
}
}

Примечание: нулевые терминаторы в стиле C (\0) необходимы в конце каждого элемента, как показано для того, чтобы компилятор ресурсов правильно завершил строки. В противном случае, когда вы используете Explorer для отображения информации о версии исполняемого файла, вы можете получить искаженные или частично объединенные значения.

Добавьте строку в исходный файл вашего проекта:

{$R VersionInfo.res VersionInfo.rc}

Я предлагаю поместить общий информационный ресурс о версии в ссылку на внешнюю версию в вашей системе управления версиями, а затем вы можете просто проверить его в каждой папке проекта и легко обновить.

Выполните Project-> Build, и информация о вашей версии будет встроена в .exe. Вы можете проверить это, используя Windows Explorer и просмотрев свойства вашего приложения.

На форумах Embarcadero Delphi в архивах CodeNewsFast есть пара постов (одно от меня и одно от Джима Флеминга). Мой [здесь], где я опишу пошагово, как использовать событие pre-build в вашем проекте для обновления номера версии в скрипте ресурса, который я выложил выше.

Джим публикует несколько ответов, но около десятка сообщений или около того источника исходного кода для исполняемого файла, который может быть вызван из события предварительной сборки, которое работает для него. (Есть некоторые вещи, которые я бы делал по-другому, например, позволяя IDE передавать имя и местоположение проекта в командной строке; как это сделать, описано в пошаговой статье. я также обработал бы разбор версии и инкрементно увеличивается, но базовое приложение является хорошей отправной точкой.)

Группы Embarcadero в настоящее время недоступны, но я смог также извлечь код Джима из CodeNewsFast и воспроизвести его здесь:

Ken,

Благодаря вам, я заставил его работать.

На случай, если кто-то еще захочет реализовать это решение, ниже вы найдете необходимые шаги и вспомогательную программу.

Джим Флеминг

A) Создайте свой файл ресурсов информации о версии в каталоге вашего проекта или где-то еще, используя следующую

содержимое и расширение файла .rc:

// Note the \000 !!!! Here and elsewhere below !!!! 
// C string terminator !!!
#define CONST_VERSION "4.1.1.1003\000" 

1 VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEOS 0x4
FILETYPE 0x1
{
BLOCK "StringFileInfo"
{

BLOCK "040904E4" // Will need changing if your language is not English and char-set not 1252 (multilingual).
{
VALUE "CompanyName", "Whatever\000"
VALUE "FileDescription", "Whatever\000"
VALUE "FileVersion", CONST_VERSION
VALUE "InternalName", "My Internal Name\000"
VALUE "LegalCopyright", "Copyright © whoever\000"
VALUE "LegalTrademarks", "\000"
VALUE "OriginalFileName", "If you wish\000"
VALUE "ProductName", "What pleases you\000"
VALUE "ProductVersion", CONST_VERSION
VALUE "Comments", "Anything you wish to add\000"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0409 0x04E4
}
}

B) Создайте новый проект в некоторой папке, код только модуля должен быть похож на:

unit FormIncrementBuildNumber;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls, System.IOUtils, System.StrUtils;


type
  TIncrementBuildNumber = class(TForm)
    IncrementingBuildNumberLabel: TLabel;
    procedure FormShow (Sender: TObject);
    procedure FormActivate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  IncrementBuildNumber: TIncrementBuildNumber;

implementation

{$R *.dfm}

procedure TIncrementBuildNumber.FormShow (Sender: TObject);
var
  Resource_File_Contents:       TStringList;
  Full_File_Name_And_Path:      string;
  First_Line_Of_File:           string;
  Position_First_Dot:           Integer;
  Position_Second_Dot:          Integer;
  Position_Third_Dot:           Integer;
  Position_Trailing_Backslash:  Integer;
  Start_of_Build_Number:        Integer;
  Length_of_Build_Number:       Integer;
  Build_Number_In_ASCII:        string;
  Build_Number_Numeric:         Integer;
  Old_Resource_File_Name:       string;
  Success:      Boolean;
begin
  if (System.ParamCount <> 1) then
  begin
    ShowMessage ('Resource File name not in first command-line parameter.');
    Exit;
  end;

  Full_File_Name_And_Path := System.ParamStr(1);
  if (not TFile.Exists(Full_File_Name_And_Path, False)) then
  begin
    ShowMessage ('Resource file ' + Full_File_Name_And_Path + 
                 ' not found.');
    Exit;
  end;

  Resource_File_Contents := TStringList.Create;
  try
    Resource_File_Contents.LoadFromFile(Full_File_Name_And_Path);
    First_Line_Of_File := Resource_File_Contents.Strings[0];

    if (Copy(First_Line_Of_File, 1, 21) <> '#define CONST_VERSION') then
    begin
      ShowMessage ('First line of Version Info must start with "#define CONST_VERSION".' + 
                   #13 + 'Version not incremented.');
      Exit;
    end;

    Position_First_Dot := Pos('.', First_Line_Of_File);
    if (Position_First_Dot = 0) then
    begin
      ShowMessage ('Version must have format "a.b.c.d".' + #13 + 
                   'Build Number not incremented.');
      Exit;
    end;

    Position_Second_Dot := PosEx('.', First_Line_Of_File, 
                                 Position_First_Dot+1);
    if (Position_Second_Dot = 0) then
    begin
      ShowMessage ('Version must have format "a.b.c.d".' + #13 + 
                   'Build Number not incremented.');
      Exit;
    end;

    Position_Third_Dot := PosEx('.', First_Line_Of_File, 
                                Position_Second_Dot+1);

    if (Position_Third_Dot = 0) then
    begin
      ShowMessage ('Version must have format "a.b.c.d".' + #13 + 
                   'Build Number not incremented.');

      Exit;
    end;

    Position_Trailing_Backslash := PosEx('\', First_Line_Of_File, 
                                         Position_Third_Dot+1);

    if (Position_Trailing_Backslash = 0) then
    begin
      ShowMessage ('Version must have format "a.b.c.d\000".' + #13 + 
                   'Build Number not incremented.');
      Exit;
    end;

    Start_of_Build_Number  := Position_Third_Dot + 1;
    Length_of_Build_Number := Position_Trailing_Backslash - 
                              Start_of_Build_Number;

    if (Length_of_Build_Number < 1) then
    begin
      ShowMessage ('Build Number must be present.' + #13 + 
                   'Build Number not incremented.');
      Exit;
    end;

    Build_Number_In_ASCII := Copy (First_Line_Of_File, 
                                   Start_of_Build_Number, 
                                   Length_of_Build_Number);
    Success := TryStrToInt (Build_Number_In_ASCII, Build_Number_Numeric);
    if (not Success) then
    begin
      ShowMessage ('Build Number must be numeric integer.' + #13 + 
                   'Build Number not incremented.');
      Exit;
    end;

    Build_Number_Numeric := Build_Number_Numeric + 1;
    Build_Number_In_ASCII := IntToStr(Build_Number_Numeric);
    Resource_File_Contents.Strings[0] := Copy(First_Line_Of_File, 1, 
                                              Position_Third_Dot) +
                                              Build_Number_In_ASCII + 
                                              '\000"';
    Old_Resource_File_Name := Full_File_Name_And_Path;
    Old_Resource_File_Name := TPath.ChangeExtension(Old_Resource_File_Name, '~rc');

    if TFile.Exists(Old_Resource_File_Name, False) then
      TFile.Delete(Old_Resource_File_Name);

    Success := RenameFile(Full_File_Name_And_Path, Old_Resource_File_Name);
    if (not Success) then
    begin
      ShowMessage ('Error renaming old resource file to have extension "~rc".' + #13 + 
                  'Build Number not incremented.');
      Exit;
    end;

    Resource_File_Contents.SaveToFile(Full_File_Name_And_Path);
  finally
    Resource_File_Contents.Free;
  end;
end;

procedure TIncrementBuildNumber.FormActivate (Sender: TObject);
begin
  Close;
end;

end.

C) В опциях проекта проекта, номер сборки которого должен быть увеличен:

  • Снимите галочку "включить информацию о версии".

  • Добавьте событие перед сборкой со следующим текстом, как написано, включая две пары двойных кавычек, заменяя части внутри & lt; >:

"& lt; полное имя файла и путь к программе автоинкремента exe & gt;" "& lt; полное имя файла и путь к файлу ресурса .rc & gt;"

D) Добавьте к источнику проекта, прямо под ключевым словом "программа":

{$R '<whatever you called it>.res' '<whatever you called it>.rc'} // I think both names must

здесь то же самое: IIRC получил ошибки, когда они отличались.

E) Скомпилируйте, запустите и наслаждайтесь возвращением номеров сборки с автоматическим приращением, несмотря на то, что Embarcadero удалил объект.

Конец содержимого Jim

Вы можете использовать событие предварительной сборки, например, для обновления значений ProductName или FileDescription или любых других, которые должны отличаться от базового сценария.

Ответ 2

UPDATE. Это не часть самого RADStudio, но происходит от Andreas Hausladen DDevExtensions (который я так привык иметь...!).

Вы можете сделать это из среды IDE с помощью ProjectGroup при условии, что вы установили отличный DDevExtensions от Андреаса Хаусадена.

  • Пусть группа проектов будет содержать все ваши проекты.
  • Убедитесь, что в каждом из ваших проектов есть "Включить информацию о версии в проект" в Options|Version Info page.
  • Используйте меню Project|Set Versioninfo..., чтобы открыть диалоговое окно Set Project Versioninfo (только один раз, текущий проект не имеет значения).
  • Здесь вы можете указать всю информацию о версии и выбрать "Применить ко всем" или только выбранным проектам, если вы отметили "Применить к выбранным".

Например, посмотрите, как я сразу установил версию для обоих проектов: Example where I set version to both projects at once

Тогда a Build All в ProjectGroup произвело оба exes с версией, установленной в 1.1.1.9, и всеми остальными деталями...