K napsání tohoto článku mne inspirovaly nesčetné dotazy na fórech, které měly jedno společné: Aplikace sestavená ve Visual Studiu 2005 (nebo 2008) neběží na jiném počítači. V tomto článku naleznete vysvětlení a řešení tohoto problému.
Prakticky každý program napsaný v C nebo v C++ používá funkce z knihovny C runtime (CRT). I ten nejjednodušší program "Hello World" používá funkci printf:
#include <stdio.h> int main(void) { printf("Hello, World !\n"); }
Už od Visual Studia verze 4.0 je možné linkovat CRT funkce k programu dynamicky; kód k funkci printf není v samotném programu, ale v samostatné knihovně DLL. Je tak možné zredukovat velikost sestaveného EXE, a také sdílet kód CRT knihovny mezi více aplikacemi, což přináší určitou úsporu diskového prostoru. Aby program šel spustit, je nutné aby knihovna byla k dispozici na cílovém počítači, na kterém program poběží. Jméno knihovny závisí na verzi Visual Studia, ve kterém program sestavíte.
Verze Visual Studia | Jméno debug DLL | Jméno release DLL |
---|---|---|
Visual C++ 5.0 | msvcrtd.dll | msvcrt.dll |
Visual C++ 6.0 | msvcr60d.dll | msvcr60.dll |
Visual Studio .NET | msvcr70d.dll | msvcr70.dll |
Visual Studio .NET 2003 | msvcr71d.dll | msvcr71.dll |
Visual Studio 2005 | msvcr80d.dll | msvcr80.dll |
Visual Studio 2008 | msvcr90d.dll | msvcr90.dll |
Pokud na cílovém operačním systému není knihovna nalezena, zobrazí se pouze chybové hlášení.
Pro aplikace sestavené ve Visual Studiu starším než 2005 bylo možné nakopírovat danou knihovnu DLL do stejného adresáře jako EXE (nebo ji nakopírovat do Windows\System32), a program bez obtíží běžel. Nutnost distribuovat celou DLL s programem ale poněkud eliminuje výhodu nižší velikosti sestaveného EXE u menších projektů.
Ve Visual Studiu od verze 2005 čekalo programátory, kteří používali dynamicky linkovanou CRT knihovnu, nepříjemné překvapení. Knihovnu DLL není možné cílový počítač pouze nakopírovat, je nutné nainstalovat kompletní balíček, který je k dispozici na stránkách Microsoftu. Pokud pouze nakopírujete knihovnu msvcr80.dll s programem, dostanete toto chybové hlášení:
Runtime knihovna totiž obsahuje ve svém startovacím kódu kontrolu, zda byla nahrána z patřičného podadresáře z c:\Windows\winsxs. Pokud ne, odmítne se načíst. Toto opatření mělo zabránit tzv. "DLL hellu", kdy program může být spuštěn s jinou verzí DLL, než s jakou byl sestaven a odladěn. Toto opatření je ale problém pro programátory malých utilit, protože je nutí instalovat na cílový počítač navic C runtime. Je trochu škoda že výchozí konfigurace projektu používá dynamicky linkovanou knihovnu - program tak ve výchozím nastavení obvykle funguje jen na počítači, kde je nainstalované MS Visual Studio.
Řešení tohoto problému je jednoduché - nepoužívat dynamicky linkovanou CRT knihovnu, ale linkovat ji staticky. Tak zajistíte že program vždy na cílovém počítači poběží. V nastavení projektu "Configuration properties\C/C++\Code Generation\Runtime Library" změňte výchozí nastavení "Multithreaded Debug DLL (/MDd)" na "Multithreaded Debug (/MTd)". Pro Release verzi změňte výchozí nastavení "Multithreaded DLL (/MD)" na "Multithreaded (/MT)". Nastavení pro MFC je v "Configuration properties\General\Use of MFC", které je třeba nastavit na "Use MFC in a Static Library" ("Use Standard Windows Libraries" pro programy nepoužívající MFC). Nezapomeňte toto nastavení změnit jak u debug verze, tak i u release verze.
Dynamicky linkovanou CRT a MFC knihovnu je dobré použít jen v případě, kdy vyvíjíte větší projekt, jehož součástí je i instalátor, kde instalace extra komponenty nevadí. Jedinou nevýhodou uvedeného řešení je zvýšená velikost programu. Ale ruku na srdce - koho v době 300 gigabajtových pevných disků zajímá, že program má 1 megabajt místo např. 200 KB ?
Copyright Ladislav Zezula 14.05.2008