Manison Softworks

Minimalizace velikosti aplikací a DLL generovaných Visual C++
Visual C++
Zpět
Domů
E-mail

Pravděpodobně se vám to také už stalo. Napíšete malý projekt s několika málo řádky zdrojového textu a přesto po sestavení nabobtná aplikace do velikosti několika desítek či dokonce stovek kilobajtů. Optimalimazací sice lze dosáhnout zmenšení programu o několik kilobajtů, avšak hlavní příčinou nadměrné velikosti aplikace je běhová knihovna.

Běhová knihovna jazyka C

Běhová knihovna (dále jen CRT, C run-time library) je standardně staticky přilinkována ke každé aplikaci nebo dll knihovně. Obsahuje kód pro ošetření spuštění a korektní ukončení aplikace (resp. nahrání a uvolnění dll), interní kontrolní funkce (např. kontrola volného místa na zásobníku) a konečně také obsahuje funkce standardních knihoven (printf, strlen ...).

Oddělení CRT

Oddělení CRT je výhodné pro malé projekty, jako jsou např. konzolové nebo grafické utility případně malé dll knihovny. Běh aplikací postavených na MFC není bez CRT možný. Pokud se rozhodnete zmenšit výslednou velikost aplikace oddělením CRT, zde je stručný postup jak na to:
  • Nastavte linker tak, aby ignoroval CRT (Linker | Input | Ignore All Default Libraries: Yes)
  • Ujistěte se, že v projektu nepoužíváte funkce ze standardních knihoven. Pokud ano, nahraďte je jejich ekvivalenty z Windows API (př. strlen = lstrlen, fopen = CreateFile, malloc = HeapAlloc)
  • Vypněte veškeré běhové kontroly (např. kontrola přetečení buferu, Code Generation | Buffer Security Check). Vypněte podporu výjimek (Enable C++ Exceptions) a nepoužívejte je. Nepoužívejte 64 bitovou aritmetiku. Nealokujte více než 4 KB lokálních proměnných.

Vstupní body

Pokud jste ve svém projektu splnili předchozí podmínky, je dále nutné nastavit vstupní bod aplikace nebo dll.

Vstupní bod GUI aplikací

V dokumentaci se uvádí, že vstupním bodem GUI aplikací je funkce WinMain, což není tak docela pravda. Skutečným vstupním bodem je funkce s prototypem:
  EXTERN_C void __cdecl WinMainCRTStartup(void)  
Funkci můžete pojmenovat jinak, potom ale musíte linkeru sdělit její jméno (Linker | Advanced | Entry Point). Na ukončení aplikace slouží funkce ExitProcess, jejímž jediným parametrem je návratová hodnota aplikace.

Velikost jednoduché aplikace s jedním modálním dialogem je s CRT asi 21 KB, bez CRT jen 2,5 KB.
#include <windows.h>
#include "resource.h"

INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {
	case WM_INITDIALOG:
		return TRUE;
	case WM_COMMAND:
		if (LOWORD(wParam) == IDCANCEL || LOWORD(wParam) == IDOK) {
			EndDialog(hWnd, 0);
			return TRUE;
		}
	default:
		return FALSE;
	}
}

void __cdecl WinMainCRTStartup(void)
{
	ExitProcess((UINT)
		DialogBox(
			GetModuleHandle(NULL),
			MAKEINTRESOURCE(IDD_TINY),
			NULL,
			DialogProc
		)
	);
}

Vstupní bod konzolových aplikací

Podobně jako u GUI aplikací, není pravým vstupním bodem konzolových aplikací funkce main, nýbrž
  EXTERN_C void __cdecl mainCRTStartup(void)  
Velikost aplikace typu Hello World je s CRT 36 KB, bez CRT jen 2 KB.

Vstupní bod DLL knihoven

Vstupní bod dll má shodný prototyp jako DllMain, nicméně její název je _DllMainCRTStartup:
  EXTERN_C BOOL WINAPI _DllMainCRTStartup(
            HINSTANCE hinstDll,
            DWORD     fdwReason,
            LPVOID    lpvReserved
  );  
Velikost takto vytvořené výsledné dll bez CRT je s porovnáním se shodným projektem s přilinkovanou CRT asi o 35 KB menší.

C++

Pokud ve svém projektu používáte globální objekty, musíte se po oddělení CRT postarat o zavolání jejich konstruktorů a destruktorů. Postup je podrobně diskutován v článku Reduce EXE and DLL Size with LIBCTINY.LIB.

Download

Stáhnout projekt pro Visual C++ .NET (7 KB)

Odkazy

MSDN magazine: Under The Hood – Reduce EXE and DLL Size with LIBCTINY.LIB
Zdrojový kód CRT knihovny
2003 – 2021 © Manison Softworks. Všechna práva vyhrazena.
Poslední aktualizace: 16. 12. 2023