Come sviluppatore PostgreSQL, occasionalmente ho bisogno di far funzionare il mio codice su Windows. Dato che normalmente non uso Windows e non ho un'installazione permanente di Windows in giro, questo è sempre stato un po' ingombrante. Ho sviluppato alcune tecniche per renderlo più semplice e penso che valga la pena condividerle. E in realtà questo testo è diventato piuttosto lungo, quindi questa sarà una serie di diversi post sul blog.
La prima cosa utile da capire sono le diverse varianti di build target di Windows e come sono simili e diverse.
Probabilmente il modo principale per creare per Windows è l'utilizzo di Microsoft Visual Studio suite di compilatori. Questo è ciò che potresti pensare come l'ambiente più nativo. La maggior parte, se non tutte, le distribuzioni binarie di PostgreSQL per Windows utilizzano questa build. Questa build non usa i normali makefile Unix ma un sistema di build separato sotto src/tools/msvc/
. Questo analizza i makefile e ha una logica personalizzata e crea file di "progetto" specifici per questa catena di strumenti, che puoi quindi eseguire per creare il codice. Chiamiamo questa build MSVC qui. Questa build è soggetta a rompersi in due modi:uno, se il codice non viene effettivamente compilato o eseguito su Windows e due, se si modifica qualcosa nel normale sistema di build (basato su makefiles) che fa sì che quegli script ad hoc rompere. Quindi è sempre molto divertente affrontarlo.
Il secondo modo è utilizzare MinGW . Questo utilizza la toolchain GNU (GCC, GNU binutils, GNU ld, ecc.) per creare codice nativo su Windows. Puoi pensarlo come "GCC su Windows", ma in realtà contiene shim e colla aggiuntivi per interfacciarsi con le librerie di sistema di Windows. Questo utilizza il normale sistema di build Unix che utilizza configure e makefiles, ma il codice che produce è codice Windows nativo, in linea di principio equivalente all'output della build MSVC. Ciò significa anche che se il codice non viene compilato o eseguito con la build MSVC, non verrà nemmeno compilato o eseguito qui. Ma il sistema di compilazione è lo stesso di Linux ecc., quindi sarà più difficile romperlo accidentalmente.
Il terzo modo è Cygwin . Cygwin è un sottosistema che presenta un ambiente simile a POSIX su Windows. Ad esempio, Cygwin aggiunge utenti, gruppi, fork()
, la memoria condivisa SysV e altre funzionalità che non esistono su Windows nativo ma sono standard, ad esempio, su Linux. L'idea è che potresti prendere il codice sorgente pensato per Linux o BSD e compilarlo sotto Cygwin senza modifiche (o almeno con solo modifiche che rientrerebbero nell'intervallo tipico delle modifiche al porting tra sistemi simili a Unix). Per questo motivo, un port Cygwin di PostgreSQL esisteva molto prima del port nativo di Windows, perché si trattava di uno sforzo molto minore. In pratica, l'astrazione si interrompe in alcune aree, specialmente nel codice di rete e nella denominazione e nell'accesso ai file, ma in generale la build di Cygwin si interrompe molto raramente rispetto agli altri target.
C'era un altro modo per costruire su Windows. C'erano win32.mak
file che potresti usare direttamente con nmake su Windows e ad un certo punto c'era anche il supporto per i compilatori Borland. Queste erano fondamentalmente misure di ripiego per costruire solo libpq in modo nativo su Windows prima che arrivasse la porta nativa completa. Ora sono stati rimossi.
C'è un altro termine che appare in questo contesto:MSYS . La ragione di ciò è che MinGW di per sé non è spesso utile. È solo una catena di strumenti del compilatore. Ma per creare un tipico software Unix, sono necessari strumenti aggiuntivi come bash, make, sed, grep e tutte quelle cose che vengono generalmente utilizzate da uno script di configurazione o da un makefile. Questi strumenti non esistono tutti come porte Windows native. Ma puoi eseguirli sul sottosistema Cygwin. Quindi un modo per usare MinGW è dall'interno di Cygwin. Un altro è MSYS, che sta per "sistema minimo", che è più o meno un sottoinsieme su misura di Cygwin e alcuni pacchetti specifici per l'utilizzo di MinGW per la creazione di software. L'MSYS originale è ora abbandonato per quanto ne so, ma esiste una nuova popolare alternativa MSYS2. Maggiori informazioni su questo in un successivo post sul blog. Per ora basta capire la relazione tra tutti questi diversi pacchetti software.
Consideriamo ora come il codice sorgente vede questi diversi ambienti di build.
Una build nativa che utilizza MSVC o MinGW definisce _WIN32
. (Stranamente, questo è il caso sia per le build a 32 bit che per quelle a 64 bit. Una build a 64 bit definisce anche _WIN64
, ma questo è usato raramente.) Il codice sorgente di PostgreSQL usa WIN32
invece, ma è specifico di PostgreSQL, non è fatto dal compilatore.
MSVC definisce anche _MSC_VER
ad un certo numero di versione. Questo a volte è utile per aggirare i problemi con una particolare versione del compilatore (spesso il tipo di cosa per cui le build Unix tenderebbero a usare configure). Nota che MinGW non definisce _MSC_VER
, quindi il codice deve essere scritto con attenzione per gestire anche quello. Ci sono stati alcuni bug minori intorno a questo perché codice come #if _MSC_VER < NNNN
forse per aggirare un problema con un compilatore più vecchio si attiverebbe anche su MinGW, il che potrebbe non essere stato previsto. (Più corretto sarebbe #if defined(_MSC_VER) && _MSC_VER < NNNN
e ovviamente avvolgi in #ifdef WIN32
.) MinGW definisce __MINGW32__
e __MINGW64__
, ma questi sono usati molto raramente. Inoltre, MinGW ovviamente definisce __GNUC__
poiché si tratta di GCC, è possibile utilizzare anche il codice condizionale specifico di GCC o una versione di GCC. In generale, poiché MinGW usa Autoconf, queste cose dovrebbero essere controllate in configure
invece che nel codice.
Cygwin definisce __CYGWIN__
. In particolare, Cygwin non definisce _WIN32
o WIN32
e così via, perché non si considera Windows nativo. Ecco perché in alcune aree del codice in cui Windows sbircia attraverso l'astrazione Cygwin si vede molto codice con #if defined(WIN32) ||
per gestire entrambi i casi.
defined(__CYGWIN__)
(Ci sono alcuni angoli polverosi nel codice che non gestiscono sempre tutte queste definizioni del preprocessore in modo sensato e coerente. In alcuni casi, questo è intenzionale perché la realtà è strana, in altri casi è codice marcio e errato che deve essere ripulito.)
Ciascuno di questi target esiste in linea di principio come variante a 32 bit e 64 bit. Un'installazione del sistema operativo Windows a 64 bit, che è la normale installazione moderna, può eseguire software sia a 32 bit che a 64 bit, quindi puoi installare ed eseguire entrambe le varianti su un tale sistema. Un'installazione di produzione dovrebbe probabilmente utilizzare una build a 64 bit, quindi potresti scegliere di non preoccuparti dell'ambiente a 32 bit. In effetti, la variante a 32 bit di Cygwin sembra essere piuttosto morta e potresti non essere in grado di farlo funzionare affatto. Un problema, tuttavia, è che MinGW a 64 bit ha alcuni bug oscuri, quindi quando si utilizza MinGW in particolare a volte è meglio usare l'ambiente a 32 bit, a meno che tu non voglia combattere i bug del sistema operativo o della toolchain. Tuttavia, l'elaborazione a 32 bit è ovviamente in via di estinzione in generale, quindi questa non è un'opzione a prova di futuro.
Ora la domanda è forse quale di questi ambienti sia “il migliore”. Per quanto riguarda lo sviluppo, non importa perché tutto il codice deve funzionare su tutti loro. Come accennato in precedenza, la build MSVC viene utilizzata per la maggior parte delle distribuzioni di produzione di Windows. L'ambiente MinGW (o meglio MSYS2) è più piacevole da sviluppare se si è abituati a un ambiente simile a Unix, ma in particolare l'ambiente MinGW a 64 bit sembra avere dei bug, quindi è difficile consigliarlo per la produzione. Cygwin potrebbe essere considerato da alcuni una curiosità storica a questo punto. L'esecuzione di un server di produzione con Cygwin non è consigliabile perché le prestazioni sono piuttosto scarse. Ma Cygwin è effettivamente utile in alcune situazioni. Ad esempio, Readline non funziona su nessuna delle build native di Windows, ma funziona su Cygwin, quindi se sei un utente psql, è meglio usare una build Cygwin per quello. Inoltre, Cygwin è utile nella situazione che è l'inverso di questo post sul blog:sei uno sviluppatore principalmente Windows e vuoi assicurarti che il tuo codice sia per lo più compatibile con Unix. Quindi tutti e tre questi ambienti hanno il loro valore e meritano di essere mantenuti in questo momento.
Nella parte successiva di questa serie, discuterò alcune tecniche per testare le modifiche al codice su e per Windows se non è il tuo ambiente di sviluppo principale.