다음을 통해 공유


방법: C/C++ 응용 프로그램에 매니페스트 포함

업데이트: 2007년 11월

C/C++ 응용 프로그램 또는 라이브러리의 매니페스트를 최종 이진 파일 내에 포함시키는 것이 좋습니다. 이렇게 하면 대부분의 시나리오에서 올바른 런타임 동작이 보장됩니다. Visual Studio에서는 기본적으로 소스 파일에서 프로젝트를 빌드할 때 매니페스트를 포함시킵니다. 자세한 내용은 Visual Studio에서 매니페스트 생성을 참조하십시오. 그러나 nmake를 사용하여 응용 프로그램을 빌드하는 경우 기존의 메이크파일을 변경해야 합니다. 이 단원에서는 최종 이진 파일 안에 매니페스트를 자동으로 포함하도록 기존의 메이크파일을 변경하는 방법을 보여 줍니다.

두 가지 방법

두 가지 방법으로 매니페스트를 응용 프로그램 또는 라이브러리 내에 포함시킬 수 있습니다.

  • 증분 빌드를 수행하지 않는 경우 빌드 후 단계로 다음과 비슷한 명령줄을 사용하여 매니페스트를 직접 포함시킬 수 있습니다.

    mt.exe –manifest MyApp.exe.manifest -outputresource:MyApp.exe;1

    또는

    mt.exe –manifest MyLibrary.dll.manifest -outputresource:MyLibrary.dll;2

    (EXE의 경우 1, DLL의 경우 2)

  • 증분 빌드를 수행하는 경우 위와 같이 리소스를 직접 편집하면 증분 빌드를 사용할 수 없게 되어 전체 다시 빌드가 수행되므로 다른 방법을 사용해야 합니다.

    • 이진 파일을 링크하여 MyApp.exe.manifest 파일을 생성합니다.

    • 매니페스트를 리소스 파일로 변환합니다.

    • 다시 증분 링크하여 매니페스트 리소스를 이진 파일에 포함시킵니다.

다음 예제에서는 메이크파일을 변경하여 두 가지 기술을 통합하는 방법을 보여 줍니다.

메이크파일(이전)

먼저 한 파일로 빌드되는 간단한 응용 프로그램인 MyApp.exe의 nmake 스크립트를 살펴 봅니다.

# build MyApp.exe
!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /INCREMENTAL
!else
CPPFLAGS=$(CPPFLAGS) /MD
!endif

MyApp.exe : MyApp.obj
    link $** /out:$@ $(LFLAGS)

MyApp.obj : MyApp.cpp

clean : 
    del MyApp.obj MyApp.exe

Visual C++ 2005에서 이 스크립트를 그대로 실행하면 MyApp.exe가 작성됩니다. 또한 외부 매니페스트 파일인 MyApp.exe.manifest가 작성되며, 이 매니페스트는 운영 체제가 런타임에 종속 어셈블리를 로드하는 데 사용됩니다.

MyLibrary.dll의 nmake 스크립트도 매우 비슷합니다.

# build MyLibrary.dll
!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /DLL /INCREMENTAL

!else
CPPFLAGS=$(CPPFLAGS) /MD
LFLAGS=$(LFLAGS) /DLL

!endif

MyLibrary.dll : MyLibrary.obj
    link $** /out:$@ $(LFLAGS)

MyLibrary.obj : MyLibrary.cpp

clean : 
    del MyLibrary.obj MyLibrary.dll

메이크파일(이후)

매니페스트를 포함하여 빌드하려면 원래 메이크파일에서 네 가지 사항을 변경해야 합니다. MyApp.exe 메이크파일의 경우는 다음과 같습니다.

# build MyApp.exe
!include makefile.inc
#^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.)

!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /INCREMENTAL
!else
CPPFLAGS=$(CPPFLAGS) /MD
!endif

MyApp.exe : MyApp.obj
    link $** /out:$@ $(LFLAGS)
    $(_VC_MANIFEST_EMBED_EXE)
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2

MyApp.obj : MyApp.cpp

clean : 
    del MyApp.obj MyApp.exe
    $(_VC_MANIFEST_CLEAN)
#^^^^^^^^^^^^^^^^^^^^^^^^ Change #3

!include makefile.targ.inc
#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.)

MyLibrary.dll 메이크파일의 경우는 다음과 같습니다.

# build MyLibrary.dll
!include makefile.inc
#^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.)

!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /DLL /INCREMENTAL

!else
CPPFLAGS=$(CPPFLAGS) /MD
LFLAGS=$(LFLAGS) /DLL

!endif

MyLibrary.dll : MyLibrary.obj
    link $** /out:$@ $(LFLAGS)
    $(_VC_MANIFEST_EMBED_DLL)
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2.

MyLibrary.obj : MyLibrary.cpp

clean : 
    del MyLibrary.obj MyLibrary.dll
    $(_VC_MANIFEST_CLEAN)
#^^^^^^^^^^^^^^^^^^^^^^^^ Change #3.

!include makefile.targ.inc
#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.)

이제 실제 작업을 수행하는 makefile.inc와 makefile.targ.inc라는 두 개의 메이크파일이 포함됩니다.

makefile.inc를 만들고 다음 코드를 복사해 넣습니다.

# makefile.inc -- Include this file into existing makefile at the very top.

# _VC_MANIFEST_INC specifies whether build is incremental (1 - incremental).
# _VC_MANIFEST_BASENAME specifies name of a temporary resource file.

!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /INCREMENTAL
_VC_MANIFEST_INC=1
_VC_MANIFEST_BASENAME=__VC90.Debug

!else
CPPFLAGS=$(CPPFLAGS) /MD
_VC_MANIFEST_INC=0
_VC_MANIFEST_BASENAME=__VC90

!endif

####################################################
# Specifying name of temporary resource file used only in incremental builds:

!if "$(_VC_MANIFEST_INC)" == "1"
_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res
!else
_VC_MANIFEST_AUTO_RES=
!endif

####################################################
# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE:

!if "$(_VC_MANIFEST_INC)" == "1"

#MT_SPECIAL_RETURN=1090650113
#MT_SPECIAL_SWITCH=-notify_resource_update
MT_SPECIAL_RETURN=0
MT_SPECIAL_SWITCH=
_VC_MANIFEST_EMBED_EXE= \
if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
link $** /out:$@ $(LFLAGS)

!else

_VC_MANIFEST_EMBED_EXE= \
if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1

!endif

####################################################
# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily:

!if "$(_VC_MANIFEST_INC)" == "1"

_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \
    $(_VC_MANIFEST_BASENAME).auto.rc \
    $(_VC_MANIFEST_BASENAME).auto.manifest

!else

_VC_MANIFEST_CLEAN=

!endif

# End of makefile.inc 
####################################################

이제 makefile.targ.inc를 만들고 다음 코드를 복사해 넣습니다.

# makefile.targ.inc - include this at the very bottom of the existing makefile

####################################################
# Commands to generate initial empty manifest file and the RC file
# that references it, and for generating the .res file:

$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc

$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest
    type <<$@
#include <winuser.h>
1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest"
<< KEEP

$(_VC_MANIFEST_BASENAME).auto.manifest :
    type <<$@
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
</assembly>
<< KEEP

# end of makefile.targ.inc

참고 항목

개념

C/C++ 프로그램의 매니페스트 생성 이해