C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 강좌/문서
C++Builder Programming Tutorial&Docments
[102] [KTS의 C++빌더] 최소 실행파일크기 Win32 어플 만들기.
김태선 [jsdkts] 21874 읽음    2006-06-04 17:25
//---------------------------------------------------------------------------
// 김태성의 C++빌더 강좌 : 최소 실행파일크기 Win32 어플 만들기.
//---------------------------------------------------------------------------

C++빌더로 제작할 수 있는 어플리케이션의 최소 실행파일 크기는 어느정도 일까?
처음 옵션 조정 없이 빈 폼을 컴파일하면 25KB 가 된다. 이 경우 배포를 위해 런타임용 DLL 라이브러리도
같이 배포를 해야 한다. 가끔 이런 방식의 배포도 하지만 그다지 쓰이지는 않는 방식이다.
배포를 위해 프로젝트 옵션에서 Use Dynamic RTL 와 Build with Runtime Package,
이 두 옵션을 언체크(uncheck)하면 450KB가 가장 작은 실행화일 크기가 된다.
폼을 사용하는 경우 VCL 관련 모듈을 링크하지 않을 수 없고, 450K면 지금 컴퓨팅 환경으로 볼때
매우 준수한 크기이다.
실무에 거의 문제가 되지 않으나 사실 실행화일 크기라는 것은 작으면 작을 수록 유용도가 증가하는 것이
사실이다. 특히, 메모리 제한이 있거나, 극히 적은 메모리를 사용해야 하는 환경이라면
더 말할 필요없이 컴팩트한 실행화일 크기가 요구된다.

// 참고: 폼의 실행화일 크기
// http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=550

이 경우 Console Application(콘솔용 어플) 위자드로 순수 win32 API만을 사용해서 프로그램을 제작한다면,
최소 크기의 실행화일을 만들어 낼수 있다. (새 프로젝트->Console Wizard->순수 Windows 용 프로그램)
C++빌더6에서 최소로 만들수 있는 윈도 어플 크기는 50K 이다.

빈 WinMain 함수 하나만 있는  프로그램을 컴파일해보면 50K가 나온다.
50K가 줄일 수 있는 최소한의 크기이다.
참고로, VC++에서는 최소크기 RTL 지원 옵션으로 이것보다 약간 더 작은 어플의 제작이 가능하다.

그러면 50K보다 더 작은 어플을 만들 수는 없는 것일까?
이에 대한 소개된 자료를 본적이 없으므로, 필자가 실험해서 어느정도까지 줄일 수 있는지 테스트
해 보았다.

[순수 win32 API 어플 제작의 object 파일 구성]

개발자에 의해 만들어진 소스들은 .obj 로 모두 컴파일 된다.
그리고 소스에서 사용한 lib 들이 필요한데 순수 API로만 작성하는 경우는
보통 cw32.lib 만 있어도 된다.
cw32.lib는 C++빌더가 설치된 폴더 밑에 LIB 폴더에 있다.

문제는 WinMain이 실제 프로그램 시작하는 함수이기는 하지만 이 함수로 원활하게
실행될 수 있도록 프로그램 실행환경을 만들어주는 역할이 필요하다.
먼저 OS에 의해 전체 메모리 배정과 핸들 배정이 일어나고,
startup 코드에 의해 어플 자신이 실행될 환경을 구성한다.
이 startup 코드가 (새 프로젝트에서 콘솔 어플리케이션 위자드를 선택해 순수 win32 어플을 제작하는 경우)
윈도용 win32 어플의 경우는 c0w32.obj 가 된다.
c0w32.obj는 cw32.lib와 마찬가지로 C++빌더가 설치된 폴더 밑에 LIB 폴더에 있다.

c0w32.obj 가 바로 스타트업코드로 약 4K크기를 가진다.
매우 작은 이 모듈은 거의 어셈블리로 제작되어 있다.

여기서 실행환경을 조성한 뒤 WinMain을 호출해서 프로그램을 실행될 수 있도록 하고
실행이 끝난 후의 뒷정리를 한다.

그러면 실제 실행파일 크기를 증가시키는 요인은 c0w32.obj에서 사용하는 런타임용
라이브러리 즉 cw32.lib 에 들어 있는 모듈로 인함이다. cw32.lib에서 그 모듈만
뽑아내어 링크하므로  계산해보면 크기가 대략 45K 에 이른다는 사실을 알수 있다.
그러므로, c0w32.obj 스타트업코드가 필요로 하는 cw32.lib 에 들어 있는 함수를
직접 구현해주면 크기를 줄일 수 있다는  사실을 알수 있다.

다시 정리하면 실행화일은
스타트업 코드 c0w32.obj + 자신의 만든 모듈들 .obj + cw32.lib => 링크 => 실행파일
이런 식으로 합해져 필요한 것만 링크되어 형성된다.

사실 스타트업코드에서 호출하는 여러가지 모듈들은 실행에 꼭 필요한 것들이기는 하지만,
모든 경우에 반드시 필요한 것은 아니다.
한마디로 경우에 따라 생략할 수 있기도 하다는 뜻이다.

그러면 bpr 프로젝트 파일을 외부 에디터로 열어 모든 라이브러리와 cw32.lib 를 찾아 제거한뒤
저장하고, C++빌더로 다시 열어 컴파일해보면 25개의 링크 에러가 난다.
이 25개의 링크에러만 해결해주면 되는 것이다.

[링크 에러 부분을 해결하기 위한 구성]

아래는 링크에러를 없애고 해당 함수를 직접 구현한 것이다.
아니,,, 전부 직접 구현한 것이 아니고, 링크에러를 없애기 위해 빈 함수만 선언했고
_startup 함수에서는 WinMain을 호출하도록 했다.

<windows.h> 헤더파일을 include 하면 _fmode와 _fileinfo 명칭이 이미 있어
링크에러를 해결할 수 없기 때문에,  다른 명칭으로 바꾸어주는 약간의 테크닉을 부렸다.
C++에서 명칭 중복 선언 문제를 피하는 테크닉은
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=601
에 소개한 바 있다.

cpp 파일은 obj 파일로 컴파일될 때의 네이밍 규칙(Name mangle)이 C 와는 틀려,
C 표준으로 동작하는 스타트업코드와 명칭을 동일하게 하려면 extern "C" { } 안에
링커에러 해결을 위한 함수를 두어야 한다.
extern "C" { }
문장은 순수 C 프로그래밍에서의 obj 형성때와 마찬가지로 프로그래머가 지정한 명칭을
그대로 보존하겠다는 뜻이다. 물론 앞에 언더바 _ 는 옵션에 따라 추가하거나 하지 않을 수도 있다.

//---------------------------------------------------------------------------
// 최소 크기 win32 어플리케이션 만들기.
//
// Written by 김태성
//---------------------------------------------------------------------------

#define _fmode         xxx_fmode
#define _fileinfo     xxx_fileinfo
#include <windows.h>
#pragma hdrstop
#undef _fmode
#undef _fileinfo

//---------------------------------------------------------------------------
#pragma link "c0w32.obj"
//#pragma link "cw32.lib"

//WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
// cw32.lib에 들어 있는 것을 여기서 다시 구현한다.
extern "C"
{

void    _startup()
{
    WinMain(NULL, NULL, NULL, NULL);    // 원래는 파라메터를 해석해서 보내줘야 함.
    exit(0);    // 정상종료를 위해 강제종료루틴을 부른다.
}

void    __CRTL_VCL_Init(void) { }
void _RTLENTRY __declspec(naked) __CRTL_VCLLIB_Linkage (void)
{
    __emit__(0xC3); /* asm ret */
}

void    __CRTL_MEM_UseBorMM() { }
void    _ExceptInit() { }

void    __CRTL_TLS_Alloc() { }
void    __CRTL_TLS_Free() { }
void    __CRTL_TLS_GetValue() { }
void    __CRTL_TLS_SetValue() { }
void    __CRTL_TLS_InitThread() { }
void    __CRTL_TLS_ExitThread() { }
void    _matherr() { }
void    _matherrl() { }
void    _GetExceptDLLinfoInternal() { }
void    _wargv_expand_ptr() { }
void    _argv_expand_ptr() { }
void    _handle_setargv() { }
void    _handle_exitargv() { }
void    _handle_wsetargv() { }
void    _handle_wexitargv() { }
void    _turboFloat() { }
void    _setargv__() { }
void    _setenvp__() { }
void    _fmode() { }
void    _fileinfo() { }

}
//---------------------------------------------------------------------------

#pragma argsused
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MessageBox(NULL, "C++빌더 win32 API 프로그램을 최소 실행파일 크기로 만들기\n\n"
        "불과 7KB로 간단한 프로그램이 동작합니다. 압축하면 2KB.\n\n"
        "startup코드인 c0w32.obj는 변함 없습니다. \n\n",
        "C++Builder Win32 Application", MB_OK | MB_ICONINFORMATION);
    return 0;
}
//---------------------------------------------------------------------------

소스를 컴파일하고 링크해보면 배포가능한 실행파일이 만들어 지는데,
불과 7KB에 못 미치는 작은 크기로 제작되어 진다.
놀랍지 않은가.
물론 실행에도 지장이 없다.
실행하면 메시지 창이 나오고 난 뒤 프로그램이 종료된다.
7KB 가 안되는 실행화일크기는 모든 C++컴파일러 중에 가장 작은 크기라고 할수 있다.
아니 순수 C만으로도 win32에서 이 정도의 크기는 안된다.

WinMain에 파라메터를 전달해주지 못해서 그게 아쉬운데,
이는 빌더의 Source->RTL->startup 부분을 보고 그 부분만 구현해 주어도 되나,
고수가 아니면 힘들 것이다.

위에 exit(0); 함수로 최종 종료를 하는데 이 함수가 있어야 정상종료 되므로 제거해서는 안된다.


[어디에 쓸꼬?]

그러면 이러한 시도를 왜 하는 것일까?
물론, 흥미로운 주제라 테스트해 보고픈 마음으로 시작한 것이지만,
필요하다면 매우 작은 어플리케이션의 제작을 위해
다른 컴파일러를 사용하지 않고 이미 익숙한 C++빌더를 바로 사용할 수 있다는 것을 확인하는데
더 큰 의의가 있다고 하겠다.
Borland C++ 5.5나 TC for Win 3.1이나 VC++을 사용하지 않고도
익숙한 환경으로 작은 어플을 만들 수 있다는 것은, 매우 유용할 수도  있기 때문이다.

[첨부파일]

첨부파일은 실제 실험해 제작한 테스트 프로젝트이다.
매우 작은 어플을 직접 확인 할 수 있다.

[주의]

이 프로그램은 메시지창을 표시하는 것만 실험하고, 다른 어플리케이션은 실험해보진 않았다.
그러므로 작은 실행파일 제작에 대한 가능성의 이해와 간단한 구현이 이 강좌의 목적이며,
실제 응용에 있서 프로그래밍에 따르는 문제는 스스로 해결해야 한다.

가령, 윈도 창을 생성하려면 어플의  HInstance가 필요한데, 필자의 구현에는 Hinstance를 WinMain으로
넘기는 부분이 없다. 이 부분은, 현재는 강좌 목적이므로 차후에 생각날 때  구현하겠다.


//---------------------------------------------------------------------------
// 김태성 cppbuilder@naver.com
// 이 강좌는 아무 곳에나 비상업적인 용도에 한해 내용 변경 없이 원래의 출처를 명시하여
// 배포할 수 있습니다. 단, 필자의 이메일로 게제 사실을 통보해야 합니다.
//---------------------------------------------------------------------------

+ -

관련 글 리스트
102 [KTS의 C++빌더] 최소 실행파일크기 Win32 어플 만들기. 김태선 21874 2006/06/04
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.