Jako programista PostgreSQL od czasu do czasu muszę sprawić, by mój kod działał w systemie Windows. Ponieważ normalnie nie używam systemu Windows i nie mam stałej instalacji systemu Windows, zawsze było to trochę kłopotliwe. Opracowałem kilka technik, które to ułatwiają i uważam, że warto się nimi podzielić. I właściwie ten tekst stał się dość długi, więc będzie to seria kilku wpisów na blogu.
Pierwszą rzeczą, którą warto zrozumieć, są różne warianty celów kompilacji systemu Windows oraz ich podobieństwa i różnice.
Prawdopodobnie głównym sposobem tworzenia dla systemu Windows jest użycie Microsoft Visual Studio pakiet kompilatora. To jest to, co można by uznać za najbardziej rodzime środowisko. Większość, jeśli nie wszystkie binarne dystrybucje PostgreSQL dla Windows, korzystają z tej kompilacji. Ta kompilacja nie używa normalnych plików makefile Unix, ale oddzielnego systemu kompilacji w src/tools/msvc/
. To analizuje pliki makefile i ma pewną niestandardową logikę i buduje pliki „projektu” specyficzne dla tego łańcucha narzędzi, które można następnie uruchomić, aby zbudować kod. Nazwijmy to tutaj kompilacją MSVC. Ta kompilacja jest podatna na awarie na dwa sposoby:po pierwsze, jeśli kod w rzeczywistości nie jest kompilowany ani uruchamiany w systemie Windows, i dwa, jeśli zmienisz coś w normalnym (opartym na plikach makefile) systemie kompilacji, który powoduje, że te skrypty ad-hoc złamać. Tak więc jest to zawsze świetna zabawa.
Drugim sposobem jest użycie MinGW . Wykorzystuje on łańcuch narzędzi GNU (GCC, GNU binutils, GNU ld, itp.) do budowania natywnego kodu w systemie Windows. Możesz myśleć o tym jako o „GCC w systemie Windows”, ale w rzeczywistości zawiera dodatkową podkładkę i klej do interfejsu z bibliotekami systemowymi Windows. Wykorzystuje to normalny system kompilacji w systemie Unix, używający configure i makefiles, ale kod, który tworzy, jest natywnym kodem Windows, w zasadzie równoważnym wynikowi kompilacji MSVC. Oznacza to również, że jeśli kod nie skompiluje się ani nie uruchomi z kompilacją MSVC, nie zostanie on również skompilowany ani uruchomiony tutaj. Ale system kompilacji jest taki sam jak dla Linuksa itp., więc trudniej będzie go przypadkowo zepsuć.
Trzeci sposób to Cygwin . Cygwin to podsystem, który prezentuje środowisko podobne do POSIX w systemie Windows. Na przykład Cygwin dodaje użytkowników, grupy, fork()
, pamięć współdzielona SysV i inne udogodnienia, które nie istnieją w natywnym systemie Windows, ale są standardem, powiedzmy, w systemie Linux. Pomysł polega na tym, że możesz wziąć kod źródłowy przeznaczony dla Linuksa lub BSD i zbudować go pod Cygwin bez zmian (lub przynajmniej ze zmianami, które byłyby w typowym zakresie zmian w przenoszeniu między systemami uniksopodobnymi). Z tego powodu port Cygwin dla PostgreSQL istniał na długo przed natywnym portem Windows, ponieważ był to znacznie mniejszy wysiłek. W praktyce abstrakcja załamuje się w niektórych obszarach, zwłaszcza w kodzie sieciowym oraz wokół nazewnictwa plików i dostępu, ale ogólnie kompilacja Cygwin psuje się bardzo rzadko w porównaniu z innymi celami.
Kiedyś istniał inny sposób budowania w systemie Windows. Był win32.mak
pliki, których można było używać bezpośrednio z nmake w systemie Windows, a także w pewnym momencie istniała obsługa kompilatorów Borland. Były to w zasadzie prowizoryczne środki do zbudowania tylko libpq natywnie w systemie Windows przed pojawieniem się pełnego portu natywnego. Zostały one teraz usunięte.
W tym kontekście pojawia się inny termin:MSYS . Powodem tego jest to, że sam MinGW nie jest często przydatny. To tylko łańcuch narzędzi kompilatora. Jednak do zbudowania typowego oprogramowania uniksowego potrzebne są dodatkowe narzędzia, takie jak bash, make, sed, grep i wszystkie te rzeczy, które są zwykle używane ze skryptu konfiguracyjnego lub pliku makefile. Nie wszystkie te narzędzia istnieją jako natywne porty systemu Windows. Ale możesz je uruchomić na podsystemie Cygwin. Tak więc jednym ze sposobów wykorzystania MinGW jest wejście do Cygwina. Innym jest MSYS, co oznacza „minimalny system”, który jest z grubsza stworzonym na zamówienie podzbiorem Cygwina i pewnym pakietem przeznaczonym specjalnie do używania MinGW do tworzenia oprogramowania. O ile mi wiadomo, oryginalny MSYS został porzucony, ale istnieje popularna nowa alternatywa MSYS2. Więcej na ten temat w kolejnym wpisie na blogu. Na razie po prostu zrozum związek między wszystkimi tymi różnymi pakietami oprogramowania.
Zastanówmy się teraz, jak kod źródłowy widzi te różne środowiska kompilacji.
Natywna kompilacja używająca MSVC lub MinGW definiuje _WIN32
. (O dziwo, dotyczy to zarówno kompilacji 32-bitowych, jak i 64-bitowych. Wersja 64-bitowa definiuje również _WIN64
, ale jest to rzadko używane.) Kod źródłowy PostgreSQL używa WIN32
zamiast tego, ale jest to specyficzne dla PostgreSQL, a nie kompilator.
MSVC definiuje również _MSC_VER
do jakiegoś numeru wersji. Czasami jest to przydatne do obejścia problemów z określoną wersją kompilatora (często jest to coś, do czego kompilacje uniksowe mają tendencję do używania configure). Zauważ, że MinGW nie definiuje _MSC_VER
, więc kod musi być napisany ostrożnie, aby sobie z tym poradzić. Wystąpiło kilka drobnych błędów, ponieważ kod taki jak #if _MSC_VER < NNNN
być może obejście problemu ze starszym kompilatorem uruchomiłoby się również na MinGW, co mogło nie być zamierzone. (Bardziej poprawne byłoby #if defined(_MSC_VER) && _MSC_VER < NNNN
i oczywiście zawinąć do #ifdef WIN32
.) MinGW definiuje __MINGW32__
i __MINGW64__
, ale są one bardzo rzadko używane. Ponadto MinGW oczywiście definiuje __GNUC__
ponieważ jest to GCC, więc można również użyć kodu warunkowego specyficznego dla GCC lub wersji GCC. Ogólnie rzecz biorąc, ponieważ MinGW używa Autoconf, te rzeczy powinny być zwykle sprawdzane w configure
zamiast w kodzie.
Cygwin definiuje __CYGWIN__
. Warto zauważyć, że Cygwin nie definiuje _WIN32
lub WIN32
i tak dalej — ponieważ nie uważa się za natywny system Windows. Dlatego w niektórych obszarach kodu, w których Windows zagląda przez abstrakcję Cygwin, widzisz dużo kodu z #if defined(WIN32) ||
do obsługi obu przypadków.
defined(__CYGWIN__)
(Są pewne zakurzone zakamarki w kodzie, które nie zawsze obsługują wszystkie te definicje preprocesora w rozsądny i spójny sposób. W niektórych przypadkach jest to celowe, ponieważ rzeczywistość jest dziwna, w innych to zepsuty i niepoprawny kod, który należy posprzątane.)
Każdy z tych celów istnieje zasadniczo jako wariant 32-bitowy i 64-bitowy. W 64-bitowej instalacji systemu operacyjnego Windows, która jest normalną nowoczesną instalacją, można uruchamiać zarówno oprogramowanie 32-bitowe, jak i 64-bitowe, więc można zainstalować i uruchomić oba warianty w takim systemie. Instalacja produkcyjna powinna prawdopodobnie używać kompilacji 64-bitowej, więc możesz nie zawracać sobie głowy środowiskiem 32-bitowym. W rzeczywistości 32-bitowy wariant Cygwin wydaje się być całkiem martwy i możesz nie być w stanie w ogóle go uruchomić. Jednym z problemów jest jednak to, że 64-bitowy MinGW ma pewne niejasne błędy, więc szczególnie podczas korzystania z MinGW czasami lepiej jest użyć środowiska 32-bitowego, chyba że chcesz walczyć z błędami systemu operacyjnego lub łańcucha narzędzi. Jednak 32-bitowe przetwarzanie jest oczywiście w większości na wyczerpaniu, więc nie jest to opcja przyszłościowa.
Teraz pytanie może brzmieć, które z tych środowisk jest „najlepsze”. Jeśli chodzi o rozwój, nie ma to większego znaczenia, ponieważ cały kod musi działać na nich wszystkich. Jak wspomniałem powyżej, kompilacja MSVC jest używana w większości wdrożeń produkcyjnych systemu Windows. Środowisko MinGW (a raczej MSYS2) jest przyjemniejsze do rozwijania, jeśli jesteś przyzwyczajony do środowiska uniksopodobnego, ale szczególnie 64-bitowe środowisko MinGW wydaje się być nieco wadliwe, więc trudno jest polecić to do produkcji. W tym momencie Cygwin może być uważany za historyczną ciekawostkę. Uruchamianie serwera produkcyjnego pod Cygwinem nie jest zalecane, ponieważ wydajność jest dość zła. Ale Cygwin jest rzeczywiście przydatny w niektórych sytuacjach. Na przykład Readline nie działa na żadnej z natywnych kompilacji Windows, ale działa na Cygwin, więc jeśli jesteś użytkownikiem psql, lepiej jest użyć do tego kompilacji Cygwin. Cygwin jest również przydatny w sytuacji, która jest odwrotnością tego wpisu na blogu:Jesteś głównie programistą Windows i chcesz mieć pewność, że Twój kod jest w większości kompatybilny z Uniksem. Tak więc wszystkie trzy z tych środowisk mają swoją wartość i są warte utrzymania w tej chwili.
W następnej części tej serii omówię kilka technik testowania zmian kodu w systemie Windows i dla systemu Windows, jeśli nie jest to Twoje główne środowisko programistyczne.