CMake 04: La versione dell’app

Dopo aver visto come far parlare il nostro programma, ora vediamo cosa devo fare per inserire alcune informazioni quali: la versione dell’applicazione, il nome del progetto, il titolare del Copyright nel file eseguibile dell’applicazione, in modo che lo si possa vedere da file system, senza aprire l’applicazione? In questo articolo vediamo il caso macOS.

Trovate tutte le puntate precedenti alla pagina CMake is the future? e il codice su GitHub.

Nome e versione del progetto

Il nome del progetto è ovviamente il primo campo del comando project().

Quanto alla versione, il comando project() prevede un campo VERSION in cui inserirla. Proviamo a mettere 1.2.3.4, giusto per vedere come poi si combinano i vari campi:

project(CMakeWidgetProject LANGUAGES CXX VERSION 1.2.3.4)

Il campo VERSION poi valorizza la variabile PROJECT_VERSION che viene scomposta in:

  • PROJECT_VERSION_MAJOR
  • PROJECT_VERSION_MINOR
  • PROJECT_VERSION_PATCH
  • PROJECT_VERSION_TWEAK

Combinando queste variabili possiamo costruire sia la stringa con la versione lunga che quella con la versione breve (Major.Minor)

Legal Copyright

In questo caso dobbiamo creare una nostra variabile che chiameremo LEGAL_COPYRIGHT e che useremo per compilare i campi relativi all’autore o al Copyright. La creazione è semplicissima, si usa il comando set().

set(LEGAL_COPYRIGHT "(C) 2020 www.GianbattistaGualeni.it")

Versione dell’eseguibile

Purtroppo qui finisce la gestione comune tra macOS e Windows!

Per inserire la versione nel file compilato, devo usare delle impostazioni separate per macOS e per Windows. Quanto a Linux, non ho capito se esiste un modo standard per inserire la versione. Magari fatemelo sapere nei commenti.

Versione dell’eseguibile per macOS

Se apro la cartella delle applicazioni e seleziono un “Application Bundle”, come per esempio l’applicativo calcolatrice, premendo spazio, ottengo una finestra con alcune informazioni.

Informazioni sulla calcolatrice

Come saprete un “Application bundle” non è altro che una sorta di cartella con una certa struttura e con estensione .app. In effetti se copio una applicazione per macOS su una chiavetta e la apro in windows, vedo proprio una cartella.

Anche in macOS la posso vedere come una cartella a patto di cliccare col tasto destro e selezionare “Show Application Bundle”.

Ecco per esempio il contenuto di Calculator.app

Struttura di Calculator.app

Le informazioni relative alla versione si trovano nel file info.plist, un file xml che viene generato dal compilatore partendo da un template, mentre l’eseguibile vero e proprio lo trovate nella cartella macOS.

Generare un application bundle

Se apriamo la cartella con il compilato della nostra applicazione, non troviamo alcun file .app ma solo il file eseguibile:

Come mai il nostro progetto non crea un application bundle?

Per attivare la creazione del bundle, dobbiamo modificare il file CMakeLists.txt attivando il flag CMAKE_MACOSX_BUNDLE:

set(CMAKE_MACOSX_BUNDLE ON)

Questa è la forma che preferisco, dato che mi consente di tenere unite tutte le opzioni relative ad un sistema operativo. In alternativa possiamo anche impostare l’opzione MACOSX_BUNDLE nel comando add_executable().

Se ora lanciamo la compilazione, il file CMakeWidgetProject.app viene creato.

Ora abbiamo CMakeWidgetProject.app

Aprendo il file vediamo che contiene il file Info.plist e l’eseguibile CMakeWidgetProject

Ecco il nostro Application Content

Impostare manualmente info.plist

Facendo doppio click sul file info.plist si attiva Xcode ed è possibile editarlo a mano. Ecco come appare.

Ecco il nostro info.plist aperto con Xcode.

Inserire la versione con CMake

Nel caso macOS, questo è relativamente veloce da fare, basta compilare alcune variabili specifiche di CMake, che poi automaticamente finiscono in info.plist.

Da quando programmo per macOS usando Qt, e sono ormai 5 anni, penso sia la prima volta che trovo più facile programmare per macOS rispetto a fare la stessa operazione per Windows. Mi sembra incredibile!

Alcuni campi possono essere riempiti con la stessa variabile. Per esempio il nome del progetto lo usiamo per:

set(MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "${PROJECT_NAME}")

La versione del progetto la vado ad usare per valorizzare 3 campi:

set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING 
    "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")

Per finire la variabile LEGAL_COPYRIGHY, cha abbiamo creato in precedenza, la usiamo per costruire 2 campi informativi:

set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME} - ${LEGAL_COPYRIGHT}")
set(MACOSX_BUNDLE_COPYRIGHT ${LEGAL_COPYRIGHT})

Compilando, ecco che le informazioni compaiono nella anteprima dell’applicazione.

Anche la nostra applicazione ora contiene delle informazioni.

Ed ecco come diventa il file info.plist

Le informazioni sono state aggiunte al file info.plist

Ma cos’è sta schifezza?

Ovvero MacOS e retina display

Pensavo di aver finito tutto, un post rapido e indolore, incece…

Testando l’applicativo, mi sono reso conto che il testo appariva sgranato, quasi sfocato. Non è facile da vedere, perché è più una impressione che un dato oggettivo, pertanto non l’ho notato subito!

Ma una volta notato il problema non sono più riuscito ad ignorarlo.

Vi ricordate quando ho detto che per la prima volta la configurazione per macOS era più facile di quella per windows? Ecco, ho appena scoperto che mi sono sbagliato!

Il problema nasce con l’introduzione degli schermi ad alta risoluzione (retina display), che per il MacBook Pro avviene con la terza generazione, nel 2010. Avendo lo schermo 4 volte i pixel della versione precedente (il doppio in orizzontale e il doppio in verticale), l’immagine prodotta dalle “vecchie” applicazioni viene visualizzata ingrandita, o meglio raddoppiata. Ed è quello che succede nel nostro caso!

Di seguito ho messo due ritagli ingranditi di come appare l’applicazione, in un caso e nell’altro. Se osservate il testo, noterete le differenze.

Applicazione a bassa risoluzione
Applicazione ad alta risoluzione

Per evitare questo si deve specificare nel file Info.plist che il software è adatto a gestire schermi ad alta risoluzione, aggiungendo due parametri:

  • Principal class: NSApplication
  • Supports Automatic Graphics Switching: YES

Ma siccome il file Info.plist viene creato partendo da un modello in cui alcune macro vengono espanse con dei valori presi da CMake, la soluzione corretta è creare un nostro modello di file Info.plist, fare in modo che CMake lo converta e poi lo infili dentro la cartella dell’application bundle.

Creare info.plist modello

Dove si trova il template? Per prima cosa dovete trovare la cartella in cui si trova CMake. Se state usando la versione fornita con Qt, si trova in Qt, Tools, CMake

Poi dovete aprire l’application bundle usando tasto destro, “Show Package Contents” e infine aprire la cartella “Contents”, “share”, “cmake-3.16”, “Modules”.

Ora copiate il file MacOSXBundleInfo.plist.in nella cartella del progetto, rinominandolo in:

Info.plist.in

Utilizzare il template usato da CMake è vantaggioso perché così possiamo continuare ad usare le macro che abbiamo usato per inserire la versione, come per esempio:

MACOSX_BUNDLE_BUNDLE_VERSION

Avendo modificato l’estensione da plist a plist.in, il modo più rapido per aprirlo e modificarlo è usare Qt Creator, solo che in questo caso il file viene aperto come un semplice file di testo e le modifiche vanno fatte aggiungendo a mano i seguenti 4 tag:

<key>NSPrincipalClass</key>
<string>NSApplication</string>

<key>NSHighResolutionCapable</key>
<string>True</string>

Come riferimento potete consultare la pagina: High DPI Displays direttamente nella documentazione di Qt.

Compilare usando il nostro Info.plist.in

Ora dobbiamo dire a CMake qual’è il template da usare per compilare il nostro target (ovvero il nostro progetto). Questo si fa impostando la variabile MACOSX_BUNDLE_INFO_PLIST per il nostro target. Il comando da inserire è il seguente:

set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST 
    ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in)

Il senso del comando è: per il target CMakeWidgetProject, imposta la proprietà MACOSX_BUNDLE_INFO_PLIST, assegnando come valore il file Info.plist.in che si trova nella cartella dei sorgenti. Poi il file Info.plist.in verrà convertito in info.plist e salvato nell’Application Bundle.

Attenzione: mettere il comando set_target_properties() dopo avere definito il target, ovvero dopo add_executable(). Se lo mettete all’inizio del file, ove ci sono tutte le altre impostazioni del tipo set(CMAKE_xxx..) non funziona.

Finalmente l’applicazione ad alta risoluzione

Ora non resta che compilare e godersi il risultato. Se non funziona:

  • controllate di avere messo il comando dopo add_executable().
  • provate a ricompilare il tutto dopo aver cancellato la cartella con la build.

Questo è il risultato finale, a risoluzione piena, ma come vi ho detto non è facile rendere percepibile la differenza di risoluzione.

Controllate il risultato

È bene a questo punto dare una controllata al file Info.plist per verificare che le variabili siano state inserite nel punto giusto e che le due proprietà Principal class e High Resolution Capable siano al loro posto.

Per farlo apriamo l’Application Bundle e carichiamo il file con Xcode.

Ora info.plist è adatto al retina display

Conclusioni

Questa gestione del file info.plist la trovo un poco laboriosa, e spero di poterla trasformare in un template da riutilizzare.

Vi ricordo che il codice del progetto lo trovate su GitHub.

Nel prossimo post vedremo la stessa cosa per Windows, impostando il file .rc per Visual Studio.

Newsletter QtQB

Se vuoi ricevere i miei post e le mie notizie via mail, iscriviti!

Autore: Gianbattista

Appassionato di tecnologia, sono l'autore di Qt5 Quanto Basta. Per lavoro mi occupo di elaborazione delle immagini per applicazioni industriali, ma nel tempo libero adoro creare applicazioni con Qt (www.qt.io)

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *