Russian Qt Forum

Qt => Установка, сборка, отладка, тестирование => Тема начата: kambala от Декабрь 16, 2012, 00:20



Название: хранить номер версии приложения в одном месте
Отправлено: kambala от Декабрь 16, 2012, 00:20
Здравствуйте. Когда я хочу сменить версию приложения, мне приходится менять её в разных файлах:
  • в .pro: VERSION = 0.3.1
  • в .rc (для Windows): #define APP_VERSION 0,3,1,0 (используется в FILEVERSION и PRODUCTVERSION) и #define APP_VERSION_STR "0.3.1.0\0" (используется в "FileVersion" и "ProductVersion")
  • в info.plist (для Mac OS X): <key>CFBundleShortVersionString</key><string>0.3.1</string>
  • в коде программы: qApp->setApplicationVersion("0.3.1");

Это слегка напрягает, плюс где-нибудь могу и забыть поменять. Хотелось бы унифицированного решения: прописать версию в каком-то одном месте, а она оттуда автоматически разойдётся куда нужно. Вариант написать какой-то скрипт (shell/batch/perl/etc.), который будет заменять номер версии в указанных файлах, понятен, но может есть другой способ (через дефайн может как-нибудь)?


Название: Re: хранить номер версии приложения в одном месте
Отправлено: V1KT0P от Декабрь 16, 2012, 01:50
Вариант написать какой-то скрипт (shell/batch/perl/etc.), который будет заменять номер версии в указанных файлах
И прописать его запуск перед билдом, как по мне лучший способ в плане не морочить себе голову.


Название: Re: хранить номер версии приложения в одном месте
Отправлено: Dancing_on_water от Декабрь 16, 2012, 15:35
Не знаю как у вас, но, я делаю так в pro пишу:

Код
C++ (Qt)
VERSIONINFO = $$system(git log --pretty=format:\\\"%cd\\ %H\\\" -n1 | cat)
isEmpty(VERSIONINFO){
VERSIONINFO =1.0
}
DEFINES += VERSIONINFO=$$quote(\\\"$$VERSIONINFO\\\")

Затем в Qt Creator удаляем этап qmake. Вставляем этап особый, где вручную запускаем qmake с нужными параметрами (нужно это, т.к. этап qmake по умолчанию имеет одну особенность: если .pro не меняли, то этап пропускается)

А в коде юзаем макрос VERSIONINFO


Название: Re: хранить номер версии приложения в одном месте
Отправлено: kambala от Декабрь 16, 2012, 20:05
этот способ не подходит по нескольким причинам:
1) жёсткая привязка к гиту (хоть у меня и в гите исходники, но всё же). к тому же, результат какой-то не такой как ожидается:
Код
Bash
$ git log --pretty=format:"%cd %H" -n1
Sat Dec 15 23:29:53 2012 +0200 577dab733c05e556e3e837721f54a989e2f2478e
2) результат распространяется лишь на исходный код, а никак не на внешние файлы.

чувствую, что единственным канонічным выходом является скрипт (лучше перл или питон, чтобы от платформы не зависеть).


Название: Re: хранить номер версии приложения в одном месте
Отправлено: vregess от Декабрь 16, 2012, 20:12
Если есть возможность не использовать qmake, то я бы перешел на cmake. Там можно генерировать файлы: config.h.in -> config.h
Переменные в config.h.in заменяются на значения, прописаные в cmake скрипте.
Если надо qmake, то видимо да - писать отдельный скрипт (который будет делать то же самое).


Название: Re: хранить номер версии приложения в одном месте
Отправлено: kambala от Декабрь 16, 2012, 20:27
возможность-то есть (Qt проекты можно же собирать через cmake вместо qmake, да?), но есть ли автоматические средства перевода на cmake? или там всё просто делается ручками?

кстати, если не ошибаюсь, то ли уже в релизе Qt 5, то ли в ближайшем будущем, будет улучшенный qmake (где-то в блоге Qt об этом писали)


Название: Re: хранить номер версии приложения в одном месте
Отправлено: vregess от Декабрь 16, 2012, 22:10
Да, qt4 проекты собирать можно, есть встроенная поддержка.
Не пользовался, но первое попавшееся: http://sourceforge.net/projects/qmake2cmake/ (http://sourceforge.net/projects/qmake2cmake/)
Но я бы с нуля переписал скрипт.
По поводу просто. Ну как сказать. Так-то да, особенно, если вникнешь. Можно достаточно быстро накидать скрипт для мелких проектов (я для ряда утилит и библиотек писал скрипты, чтоб под виндой собрать, типа lau, sqlcipher). Постоянно пользуюсь cmake, и мне кажется он лучше qmake. "Скриптовый язык" там достаточно низкоуровневый, так что всякие хитрые штуки делать возможно. Если тролли/digia создадут систему сборки лучше cmake (надеюсь), то с удовольствием перелезу, тк cmake тоже не идеален. Но пока out-of-the-box фичи лучше, чем у других систем, имхо.

А та новая утилита называется qbs (https://blog.qt.digia.com/blog/2012/02/15/introducing-qbs/). И это будет не улучшенный qmake, а совсем другая вещь, тк qmake и cmake - это всего лишь генераторы makefile, а qbs сам будет вызывать компилятор и линкер, навроде scons + декларативный язык (что-то схожее с maven, как я понимаю) + низкоуровневые штуки на js.
Когда они ее допилят, не известно, но я бы еще полгода подождал. cmake более зрелый.
Такая вот петрушка.


Название: Re: хранить номер версии приложения в одном месте
Отправлено: twp от Декабрь 16, 2012, 22:57
по поводу генерации версии под маком.
qmake же умеет генерировать info.plist, то почему бы не воспользоваться этим?
переменная QMAKE_INFO_PLIST по идее должна помочь в этом
а что касается винды и установки версии в qApp то самый простой способ это генерация файла версии version.h по шаблону  version.h.in из pro-файла.
Этот файл соответсвенно включается RC-файл и исходник, где устанавливается версия для qApp.
В итоге версия приложения указывается только в pro-файле
для генерации version.h я просто написал небольшую тулзовину на qt чтоб не привязываться ко всяким скриптовым языкам.

Код
C++ (Qt)
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QDebug>
 
int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
 
   Q_ASSERT(argc > 3);
 
   const QString splitter = QLatin1String("=");
 
   const QString inputName = a.arguments().at(1);
   const QString outputName = a.arguments().at(2);
 
   QString content;
   {
       QFile input(inputName);
       if (!input.open(QIODevice::ReadOnly | QIODevice::Text)) {
           qWarning() << "Unable to open file" << inputName;
           return 1;
       }
 
       QTextStream inStream(&input);
       content = inStream.readAll();
   }
 
   for (int i = 3; i < argc; ++i) {
       QString arg = a.arguments().at(i);
       QStringList params = arg.split(splitter, QString::SkipEmptyParts);
       Q_ASSERT(params.size() == 2);
       QString paramName = params.at(0);
       QString dest = params.at(1);
       QString source = QString(QLatin1String("%%1%")).arg(paramName);
       content = content.replace(source, dest);
   }
 
   QFile output(outputName);
   if (!output.open(QIODevice::WriteOnly | QIODevice::Text)) {
       qWarning() << "Unable to open file" << outputName;
       return 1;
   }
 
   QTextStream outStream(&output);
   outStream << content;
 
   return 0;
}
 

в pro-файле просто передаются номер версии в командной строке
Код
Javascript
   MAJOR_VERSION = 1
   MINOR_VERSION = 3
   VERSION = $${MAJOR_VERSION}.$${MINOR_VERSION}.0
   VERSION_HEADER = version.h
   version.target = $$VERSION_HEADER
   version.commands = $$PATH_TO_YOUR_TOOL/your_tool \
                      $$PATH_TO_YOUR_PATTERN/version.h.in \
                      ./$$VERSION_HEADER \
                      MAJOR_VERSION=$$MAJOR_VERSION \
                      MINOR_VERSION=$$MINOR_VERSION
 
   QMAKE_EXTRA_TARGETS += version
 
   PRE_TARGETDEPS += $$VERSION_HEADER
 

файл шаблона version.h.in
Код
C++ (Qt)
#ifndef VERSION_H
#define VERSION_H
 
#define MAJOR_VERSION       %MAJOR_VERSION%
#define MINOR_VERSION       %MINOR_VERSION%
 
#endif //VERSION_H
 


Название: Re: хранить номер версии приложения в одном месте
Отправлено: kambala от Декабрь 16, 2012, 23:19
по поводу генерации версии под маком.
qmake же умеет генерировать info.plist, то почему бы не воспользоваться этим?
переменная QMAKE_INFO_PLIST по идее должна помочь в этом
я только знаю, что в шаблоне info.plist можно использовать @EXECUTABLE@ и @ICON@, что я и делаю. хотя вот только что заглянул в документацию — там обновилась информация:
Цитировать
In the .plist file, you can define some variables, e.g., @EXECUTABLE@, which qmake will replace with the actual executable name. Other variables include @ICON@, @TYPEINFO@, @LIBRARY@, and @SHORT_VERSION@.
по идее @SHORT_VERSION@ — как раз самое оно, сейчас буду пробовать.

спасибо за код.


Название: Re: хранить номер версии приложения в одном месте
Отправлено: twp от Декабрь 16, 2012, 23:27
да, @SHORT_VERSION@ скорее всего как раз то что нужно, хотя сам я не еще пробовал


Название: Re: хранить номер версии приложения в одном месте
Отправлено: kambala от Декабрь 16, 2012, 23:32
увы, не то. для VERSION = 0.3.1 @SHORT_VERSION@ выдаёт 0.3 :(

а @TYPEINFO@ вообще ???? выдало (ну может это предназначено только для библиотек).


Название: Re: хранить номер версии приложения в одном месте
Отправлено: Alex Custov от Декабрь 17, 2012, 15:19
Для 1) 2) и 4) я делаю всё вручную так (mingw-only):

Код
C++ (Qt)
# pro файл
 
# это центральное место хранения версии, 1.2.0 в данном случае
NVER1=1
NVER2=2
NVER3=0
 
VERSION=$$sprintf("%1.%2.%3", $$NVER1, $$NVER2, $$NVER3)
 
DEFINES += NVER1=$$NVER1
DEFINES += NVER2=$$NVER2
DEFINES += NVER3=$$NVER3
DEFINES += NVER_STRING=$$sprintf("\"\\\"%1\\\"\"", $$VERSION)
 

Код
C++ (Qt)
// rc файл
 
#define stringify(v1) #v1
#define quote(v1) stringify(v1)
 
#define NVER NVER1.NVER2.NVER3
 
...
1 VERSIONINFO
       PRODUCTVERSION NVER1, NVER2, NVER3, 0
...
BEGIN
       BLOCK "StringFileInfo"
       BEGIN
         BLOCK "040904e4"
         BEGIN
         ...
         VALUE "FileVersion",        quote(NVER)
         ...
 

Код
C++ (Qt)
// в коде
ui->label->setText(NVER_STRING);
 


Название: Re: хранить номер версии приложения в одном месте
Отправлено: lesav от Декабрь 17, 2012, 16:42
Поиск по форуму решает все проблемы, и не создает новые.
http://www.prog.org.ru/index.php?topic=19099.msg128736#msg128736


Название: Re: хранить номер версии приложения в одном месте
Отправлено: kambala от Декабрь 17, 2012, 18:05
указанная тема точно так же не решает проблему с info.plist


Название: Re: хранить номер версии приложения в одном месте
Отправлено: Alex Custov от Декабрь 17, 2012, 18:18
версию в plist можно менять скриптом, вызов которого записать в QMAKE_POST_LINK


Название: Re: хранить номер версии приложения в одном месте
Отправлено: kambala от Декабрь 17, 2012, 18:28
именно к этому и склоняюсь. но почему в POST_LINK? вроде ж info.plist обрабатывается и копируется до начала сборки, так что надо в PRE_LINK.


Название: Re: хранить номер версии приложения в одном месте
Отправлено: Alex Custov от Декабрь 17, 2012, 18:35
именно к этому и склоняюсь. но почему в POST_LINK? вроде ж info.plist обрабатывается и копируется до начала сборки, так что надо в PRE_LINK.

Вообще да, тебе лучше знать, т.к. я не знаком с Mac, просто предложил мысль.  Думаю, что даже скрипт писать не нужно, а сразу записать нужную команду прямо в PRE_LINK.


Название: Re: хранить номер версии приложения в одном месте
Отправлено: kambala от Декабрь 17, 2012, 19:25
командой вряд ли получится обойтись — ведь надо менять содержимое файла. или можно как-то так?
Код
Bash
cat info.plist | sed /(?<=<key>CFBundleShortVersionString</key><string>)(.+?)(?=</string>)/$$VERSION/ > info.plist
(с sed не знаком, написал замену в perl-style)


Название: Re: хранить номер версии приложения в одном месте
Отправлено: Alex Custov от Декабрь 17, 2012, 20:16
командой вряд ли получится обойтись — ведь надо менять содержимое файла. или можно как-то так?
Код
Bash
cat info.plist | sed /(?<=<key>CFBundleShortVersionString</key><string>)(.+?)(?=</string>)/$$VERSION/ > info.plist
(с sed не знаком, написал замену в perl-style)

sed -i меняет файл сразу:

Код:
sed -i 's/trololo//' info.plist

Расположение опции -i может зависеть GNU это версия или нет.


Название: Re: хранить номер версии приложения в одном месте
Отправлено: kambala от Январь 27, 2013, 04:15
в общем, воспользовался кодом, приведенным Alex Custov и lesav, плюс sed для мак ос, всё работает на ура, за что им большое спасибо.

но поскольку под виндой разработка ведётся в студии, а не в креаторе, то тут уже без внешнего скрипта не обошлось (может такого же эффекта, как и для .pro, можно достичь через ручное редактирование .vcxproj, но я в этом не силён). дефайны нужно лишь один раз прописать в свойствах проекта как для компиляции, так и для обработки ресурсов (сначала NVERX (X=1-4), а потом NVER_STRING), а потом, при обновлении версии, просто запускать незатейливый перл-скрипт с новой версией в качестве параметра, который обновит дефайны:
Код
Perl
#!/usr/bin/perl -w
 
use strict;
use File::Slurp qw(edit_file); # File::Slurp надо установить из CPAN
 
die "new version wasn't passed" if scalar(@ARGV) == 0;
 
my $newVersion = shift;
my @versionNumbers = split /\./, $newVersion;
push @versionNumbers, (0) x (4 - scalar(@versionNumbers)); # добиваем номера нулями если они не указаны
 
my $newDefines = "NVER1=$versionNumbers[0];NVER2=$versionNumbers[1];NVER3=$versionNumbers[2];NVER4=$versionNumbers[3];NVER_STRING=\"$newVersion\";";
edit_file { s/NVER1=.+";/$newDefines/g } 'myproject.vcxproj'; # скрипт должен находиться в одной папке с .vcxproj
 
примеры запуска:
Код
Bash
perl script.pl 0.1.2.3
perl script.pl 1.2


Название: Re: хранить номер версии приложения в одном месте
Отправлено: twp от Май 14, 2013, 10:53
недавно на Qt Project повилась небольшая статья (http://qt-project.org/wiki/QMake-top-level-srcdir-and-builddir) в которой описывается недокументированная переменная QMAKE_SUBSTITUTES. Она позволяет генерировать файлы на основе шаблонов, что избавляет от использования дополнительных скритов. Я уже перевел генерацию Info.plist используя эту переменную и работает отлично. Странно что эту переменную не задокументировали и ее нет среди обзоров недокументированных возможностей qmake.