Co to jest Visual C++ Redistributable i dlaczego Windows go nie zawiera?
Wiele aplikacji, do poprawnego ukończenia instalacji wymaga obecności w systemie pakietów o nazwie "Visual C++ Redistributable". Dlaczego są one potrzebne i z jakiego powodu nie są po prostu zintegrowane z Windowsem, skoro tak wiele aplikacji ich używa?
Istnieje kilka odpowiedzi na to, teoretycznie proste pytanie. Większość wytłumaczeń pomija jednak kilka kwestii, na przykład jakim cudem pakiet ten był aktualizowany przez Windows Update i dlaczego od dziesięciu lat problem ten wydaje się być rozwiązany dla nowszego oprogramowania. Zacznijmy od kanonicznego wytłumaczenia, które opisuje historyczne źródła problemu, ale oferuje lakoniczne rozwiązania. Jest nim artykuł, który w 2014 roku napisał niezastąpiony Raymond Chen.
Problem z rozwojem biblioteki C
Na swoim blogu, Chen pisze że system operacyjny nie powinien być platformą dostarczania środowiska wykonawczego dla aplikacji. Jest ona na tyle podstawowa, że - w domniemaniu - każda aplikacja powinna dostarczać swoją, bo aktualizowanie środowiska wykonawczego dostępnego globalnie w systemie jest bardzo trudne. Żadna zmiana nie może naruszać binarnej zgodności, co w efekcie niemal paraliżuje możliwości rozwoju.
Stare instalatory często dodawały i zastępowały biblioteki systemowe swoimi wersjami, ale zastąpienie biblioteki wykonawczej C (MSVCRT.DLL) byłoby szczególnie niszczące. Microsoft wprowadził kilka rozwiązań tego problemu, między innymi kreatory punktów redystrybucyjnych, magazyn Side-by-Side (niesławny WinSxS) oraz wyodrębnione instalatory dla bibliotek wykonawczych języka C. To właśnie tym są pakiety Visual C++ Redistributable.
Jeżeli aplikacja potrzebuje jakiejś funkcji systemowej, która jest w systemie operacyjnym za stara, może poprosić o jego aktualizację pakietem MSU lub przez Windows Update. Jeżeli jakaś aplikacja upiera się na bardzo konkretną wersję danej biblioteki, zostanie ona zachowana w WinSxS. A co z "pierwszą", podstawową biblioteką aplikacji, jaką jest właśnie środowisko C++? Mamy tu problem "po obu stronach równania".
Zgodność binarna
Im "dalsza" biblioteka, tym ten problem jest mniejszy, ale w przypadku C++ biblioteka musi być naprawdę niemal identyczna. Najlepiej by było, aby program dostarczał własną. Może ją albo trzymać w swoim katalogu, albo opublikować (zainstalować) w systemie - ale nie jako podmiankę systemowej, a jako nową, oddzielną.
No dobrze, ale Visual Studio, w którym tworzone są aplikacje C++, jest rozwijane przez tę samą firmę, co Windows. Dlaczego nie można po prostu wrzucić biblioteki do środka Windowsa? Jedna będzie dla systemu, a ta "Visual C++" dla aplikacji. Na tak postawione pytanie regularnie udziela się dokładnie tej samej odpowiedzi, co powyżej. Mimo, że brakuje w niej wytłumaczenia pewnych subtelności: skoro .NET Framework był tak rozprowadzany, dlaczego nie C++? I skoro są to biblioteki dla aplikacji, to po co je rejestrować jako ogólnodostępne w systemie? Albo coś jest elementem Windowsa, albo nie - prawda?
Problem w tym, że oczekiwana biblioteka może być bardzo konkretna. Na przykład musi to być wersja 12.0.30501 i już. Na innej nie zadziała. Visual Studio na którym zbudowano aplikację miał akurat takiego Service Packa i taki pakiet poprawek do runtime'u. Kolejna aplikacja może potrzebować 12.0.40664. I jeżeli ją zainstaluje, to ona nie zaktualizuje tej "niższej". Będą dostępne obie. Dlatego Windows musiałby, wraz z kalendarzem wydawniczym Visual Studio, otrzymywać kolejne 20-30 megabajtów nowych bibliotek, często niewykorzystywanych przez nic.
Aktualizacje
Skoro Visual C++ musi być "tak strasznie oddzielny", to jakim cudem aktualizowało go Windows Update? Czyżby jednak biblioteka nie musiała być dokładnie identyczna? A skoro nie musiała - to powyższe wytłumaczenie wydaje się nieadekwatne. Jest jeszcze inaczej. Windows Update istotnie umie aktualizować ten pakiet, ale nigdy nie zaktualizuje np. wersji 2008 do 2010, ale nawet wersji 12.0.x do 12.0.y!
Zmieni tylko numer podwersji "najbardziej po prawej", a więc możliwe, że nie zaktualizuje nawet wszystkich zainstalowanych wariantów 12.0. Aplikacja "powinna się przebudować na nowszą wersję". Powinna. Ale jeżeli tego nie zrobiła, aktualizacja Windows Update nie może psuć zainstalowanego oprogramowania u klienta.
Wobec tego jakim cudem ten problem zniknął? Obecnie jest dostępny tylko "jeden wielki redist", wersja zbiorcza zawierająca obsługę Visual C++ 14.x, czyli wydania 2017 (wcześniej 2015) do 2026. Microsoft, świadom problemu z mnogością wariantów zaczął zapewniać wyższą zgodność binarną korzystając z nowocześniejszych metod dostarczania oprogramowania… ale tak naprawdę, problem zmniejszono, stosując nową bibliotekę wykonawczą języka C, Microsoft Universal C Runtime Library. Zapewnia ona wyższą zgodność ze standardowym językiem C, niweluje dużo historycznych cech szczególnych środowisk CRT Microsoftu i pozwala zachować wysoką zgodność ABI.
Z powrotem w systemie
Dzięki temu, po pierwsze, nie wymaga dostarczania z aplikacją własnego pakietu CRT zbieżnego z kompilatorem w bardzo szczegółowej wersji (a więc słowa Raymonda Chena nie są już aktualne). Po drugie, będąc obecnie elementem systemu operacyjnego, zachowuje się o wiele bardziej podobnie do GNU libc, umożliwiając, ponownie po bardzo wielu latach, celowanie "w platformę", a nie w runtime Visual Studio.
UCRT okazało się tak dobrym pomysłem, że wydano je nawet, jeszcze w 2017 roku, oficjalnie na Windows XP! Istniejący dziś oddzielny "C++ Redist", również zachowujący wysoką zgodność ABI, zawiera składniki zależne od kompilatora, niewchodzące w skład zgodnej z C99 biblioteki UCRT.
Zabawnym podsumowaniem tych przemian, świadczących o ewolucji Visual C++ w stronę bardzo dojrzałego środowiska o przenośnym charakterze pozbawionym "microsoftyzmów", jest to że .NET w międzyczasie przeszedł drogę odwrotną. Przestał być elementem systemu operacyjnego (w Windows pozostaje wersja 4.8.1) i wymaga instalowania oddzielnego środowiska uruchomieniowego.
Powód jest jednak całkowicie niezwiązany ze zmianami w C++: .NET zakłada dostarczanie oprogramowania w trybie ciągłym. Aplikacje mogą dostarczać wbudowany runtime (self-contained) lub zakładać obecność (aktualizowanego przez WU) środowiska .NET.
Nowy .NET jest wydawany co roku i nawet wersje LTS, o przedłużonym wsparciu, są wydawane częściej niż Windows. Microsoft zakłada zatem, że aplikacja, dostarczając własny runtime, będzie wydawana na tyle często, że zawsze wciągnie potrzebne poprawki lub przejdzie na nowszą wersję, a gdy potrzebuje więcej czasu (choć są to tylko 3 lata…) - może użyć oddzielnej wersji LTS. Replikuje to dawny problem z C++ Redistributable, potęgując go w dodatku na tyle, że Microsoft zmuszony był wydać dedykowane narzędzie oczyszczające: .NET Uninstall Tool.
Kamil J. Dudek, współpracownik redakcji dobreprogramy.pl