NSIS 사용자 설명서

본 토픽은 현재 준비중입니다. 공동공부에 참여하시면 완성 되었을 때 알려드립니다.

2.3 스크립트 구조

NSIS 스크립트는 인스톨러 속성, 페이지, 섹션, 함수를 포함합니다. 컴파일 타임에 수행되는 컴파일러 명령어 또한 사용할 수 있습니다. OutFile 명령은 필수 명령어이며, NSIS가 어느 디렉터리에 인스톨러를 작성할 지 지정합니다. 또한 최소 하나의 섹션은 반드시 작성해야 합니다.

2.3.1 인스톨러 속성

인스톨러 속성은 인스톨러의 동작, UI & UX를 설정합니다. 이러한 속성들을 사용하여 설치 도중 나타날 문자열이나 설치 유형 개수 등을 변경할 수 있습니다. 이러한 명령 대부분은 설정만 가능하며, 런타임 도중 변경할 수 없습니다.
OutFile과 같이 인스톨러 속성 중 기본적인 명령어들에는 Name과 InstallDir가 있습니다.
인스톨러 속성에 대한 더 자세한 정보는 인스톨러 속성을 참조하십시오.

2.3.2 페이지

논-사일런트(비-백그라운드) 인스톨러는 최종 사용자가 인스톨러의 구성을 설정하게 할 마법사 페이지를 내장하고 있습니다. 최종 사용자에게 보여줄 페이지를 Page 명령을 통해 설정할 수 있습니다. (고급 설정을 포함하는 PageEx 명령을 사용할 수도 있습니다.) 전형적인 페이지는 다음과 같습니다.

Page license
Page components
Page directory
Page instfiles
UninstPage uninstConfirm
UninstPage instfiles

라이선스 계약서 페이지를 보여주는 license 페이지, 설치 구성요소를 선택하는 components 페이지, 설치 디렉터리를 선택하는 directory 페이지, 마지막으로 선택된 구성요소를 설치하는 instfiles 페이지가 나타납니다. 언인스톨러의 경우 설치 제거를 확인하는 confirmation 페이지, 설치를 제거하는 instfiles 페이지가 나타납니다.

2.3.3 섹션

인스톨러는 일반적으로 최종 사용자가 선택하여 설치할 수 있는 몇가지 옵션을 가집니다. 예를 들어 NSIS 배포 인스톨러에서는 추가 도구, 플러그-인, 예제 및 기타 리소스를 선택적으로 설치할 수 있습니다.

NSIS 배포 인스톨러의 설치 옵션
<NSIS 배포 인스톨러의 설치 옵션>

각 구성요소는 몇 줄의 코드로 구성됩니다. 사용자가 구성요소를 설치하기 위해 선택하면 인스톨러는 그 구성요소를 구성하는 코드를 수행할 것입니다. 스크립트에서 그 코드는 섹션 안에 정의됩니다. 즉, 각 섹션은 구성요소 페이지에서 하나의 구성요소에 해당합니다. 섹션 이름은 구성요소 이름으로 표시됩니다. 단 하나의 섹션으로도 인스톨러를 빌드할 수 있지만 만약 구성요소 페이지를 사용하고 싶거나 최종 사용자에게 설치 옵션을 부여하려면 둘 이상의 섹션을 구현해야 합니다.

언인스톨러 또한 여러 섹션을 가질 수 있습니다. 언인스톨러 섹션 이름은 접두사 ‘un.’이 붙습니다.

Section "Installer Section"
SectionEnd

Section "un.Uninstaller Section"
SectionEnd

섹션 안에서 사용되는 명령어들은 최종 사용자의 컴퓨터에서 런타임 때 실행되기 때문에 인스톨러 속성 명령어들과는 아주 다릅니다. 파일을 압축 해제하고, 레지스트리 또는 INI 파일, 일반 파일 읽기/쓰기, 디렉토리 생성, 바로가기 생성 등 많은 작업을 합니다. 더 많은 명령어는 Instructions를 참조하십시오.

가장 기본적인 명령어는 SetOutPath입니다. 이 명령어는 인스톨러에게 타겟 시스템의 어느 디렉터리에 압축 해제 할지 알려줍니다. File 명령어는 어떠한 파일을 압축해제 할지 정합니다.

OutFile "file_name.exe"
Section "My Program" # 섹션을 하나 생성하며 이름을 인자로 주었습니다.
  SetOutPath $INSTDIR # $INSTDIR 위치를 파일이 설치될 디렉터리로 지정합니다.
  File "My Program.exe" # 압축 해제되어 설치 될 파일의 현재(컴파일 타임) 위치를 지정합니다.
  File "Readme.txt"
SectionEnd
이 예제를 컴파일할 때 인코딩 오류가 나타날 수 있습니다. UTF-8로 인코딩 된 스크립트 파일에 한글 등 비-ASCII 문자가 있는 경우 이러한 오류가 나타날 수 있습니다.
이럴 경우 비-ASCII 문자를 모두 제거하거나, 또는 스크립트 파일의 인코딩을 EUC-KR 등 해당 문자를 지원하는 인코딩으로 변경하십시오. Visual Studio Code 오른쪽 하단부에 인코딩 선택을 클릭하면 변경할 수 있습니다.

더 자세한 정보는 Sections을 참조하십시오.

2.3.4 함수

함수는 섹션과 같이 스크립트 코드를 포함할 수 있습니다. 섹션과 함수의 차이는 호출되어지는 방식입니다. 함수는 두가지 종류가 있는데 바로 사용자 함수와 콜백 함수입니다.

사용자 함수는 섹션이나 Call 명령어를 사용하는 함수 안에서 개발자에 의해 호출됩니다. 사용자 함수는 개발자가 호출하지 않는다면 실행되지 않습니다. 함수 안의 코드가 실행된 후 인스톨러는 함수 안에서 설치를 중단하지 않는 한, Call 명령어 다음에 오는 명령어를 계속해서 수행합니다. 사용자 함수는 인스톨러 안에서 여러 위치에서 수행될 명령어들을 작성할 때 유용합니다. 함수 안에 코드를 넣으면 코드의 반복을 줄이며 유지 보수를 쉽게 합니다.

콜백 함수는 인스톨러가 시작될 때와 같이 특정 이벤트가 발생했을 때 인스톨러에 의해 호출됩니다. 콜백 함수는 선택적으로 구현하면 됩니다. 예를 들어 인스톨러가 시작될 때 최종 사용자에게 환영 메시지를 띄우고 싶다면 .onInit 콜백 함수를 구현합니다. NSIS 컴파일러는 이 함수의 이름을 판단하여 콜백 함수로써 인식하게 되며, 인스톨러가 시작될 때 호출됩니다.

다음 예제에서 갑자기 MessageBox 함수가 나옵니다. 하지만 지금은 튜토리얼 단계이며, 예제에 나타나는 모든 함수에 대한 자세한 설명은 뒷 챕터에서 기술하니, 여기서는 아직 언급되지 않은 함수가 나와도 깊게 생각하지 마십시오. 또는 뒷 챕터의 해당 함수의 사용법에 대한 설명을 읽고 오는 것도 좋은 방법입니다.
예제 소스코드를 조금씩 수정해가며 컴파일 해보면 대강의 문법 구조를 추론해 익힐 수 있으며, NSIS는 절차 지향적 프로그래밍 스타일을 가지고 있음을 상기하십시오.
OutFile "file_name.exe"
Function .onInit
  MessageBox MB_YESNO "This will install My Program. Do you wish to continue?" IDYES gogogo
    Abort
  gogogo:
FunctionEnd

Section ""
SectionEnd

콜백 함수 안에서 Abort 명령어는 특별한 의미가 있습니다. 또한 각 콜백 함수는 고유한 의미를 가지므로 더 많은 정보는 Callback Functions를 참조하십시오. 위 예제에서 Abort 명령은 인스톨러에게 인스톨러 초기화를 중단하고 즉시 프로그램을 종료하라고 지시합니다.

함수에 대한 좀 더 자세한 정보는 Functions를 참조하십시오.

2.3.5 스크립트 작업
    2.3.5.1 논리적 코드 구조

조건부 실행 코드 또는 반복 실행 코드는 StrCmpIntCmpIfErrorsGoto 및 많은 명령어들을 사용할 수 있습니다. 하지만 더 쉬운 방법도 있습니다. LogicLib 라이브러리는 복잡한 논리적 구조에 대한 쉬운 구현을 도와주는 아주 간단한 매크로를 제공합니다. LogicLib.nsh 헤더 파일에서 구현된 구문은 다른 프로그래밍 언어와 유사하며 초보자와 고급 사용자 모두에게 간단합니다.

예를 들어, LogicLib 라이브러리 없이 변수의 값을 확인하려 할 때, 다음과 같이 구현될 수 있습니다.

OutFile "file_name.exe"

Section ""
StrCmp $0 'some value' 0 +3 # $0과 'some value'가 같다면 상대성 점프문(0 또는 +3)으로 분기, 자세한 문법은 뒷 챕터에서 설명.
  MessageBox MB_OK '$$0 is some value'
  Goto done
StrCmp $0 'some other value' 0 +3
  MessageBox MB_OK '$$0 is some other value'
  Goto done
# else
  MessageBox MB_OK '$$0 is "$0"'
done:
SectionEnd

하지만, LogicLib 라이브러리를 이용하여 구현하면 다음 예와 같이 좀 더 가독성이 높아집니다.

!include LogicLib.nsh

OutFile "file_name.exe"

Section ""
${If} $0 == 'some value'
  MessageBox MB_OK '$$0 is some value'
${ElseIf} $0 == 'some other value'
  MessageBox MB_OK '$$0 is some other value'
${Else}
  MessageBox MB_OK '$$0 is "$0"'
${EndIf}
SectionEnd

다음 예제와 같이 스위치 문을 사용하여 동일한 작업을 수행할 수 있습니다.

!include LogicLib.nsh

OutFile "file_name.exe"

Section ""
${Switch} $0
  ${Case} 'some value'
    MessageBox MB_OK '$$0 is some value'
    ${Break}
  ${Case} 'some other value'
    MessageBox MB_OK '$$0 is some other value'
    ${Break}
  ${Default}
    MessageBox MB_OK '$$0 is "$0"'
    ${Break}
${EndSwitch}
SectionEnd

다중 조건 또한 지원됩니다. 다음 예는 사용자에게 $0와 $1가 비어있는지 알릴 것입니다.

!include LogicLib.nsh

OutFile "file_name.exe"

Section ""
${If} $0 == ''
${AndIf} $1 == ''
  MessageBox MB_OK|MB_ICONSTOP 'both are empty!'
${EndIf}
SectionEnd

LogicLib 라이브러리는 레이블과 상대성 점프의 필요성을 제거하여 레이블 이름에 대한 충돌을 예방하고 스크립트가 수정될 때마다 상대성 점프 오프셋 값을 수동으로 수정해야하는 번거로움을 없앱니다.

또한 while, do, for 문을 지원함으로써 반복문을 단순화 시킵니다. 다음 세가지 예제들은 LogicLib 라이브러리를 활용해서 5번 카운트를 세는 예제입니다.

StrCpy $R1 0
${While} $R1 < 5
  IntOp $R1 $R1 + 1
  DetailPrint $R1
${EndWhile}
${For} $R1 1 5
  DetailPrint $R1
${Next}
StrCpy $R1 0
${Do}
  IntOp $R1 $R1 + 1
  DetailPrint $R1
${LoopUntil} $R1 >= 5

컴파일 후 인스톨러를 실행한 뒤 Show details를 클릭하면 결과를 확인할 수 있습니다.

LogicLib 라이브러리 테스트 결과
<LogicLib 라이브러리 테스트 결과>

LogicLib 라이브러리를 사용하기 위해서 스크립트 상단에 아래와 같이 헤더 파일을 추가하는 구문을 추가하십시오.

!include LogicLib.nsh

더 많은 예제들은 LogicLib.nsi를 참조하십시오.

    2.3.5.2 변수

사용자 변수($VARNAME)는 Var 명령어를 사용해 선언할 수 있습니다. 모든 변수는 전역적이며 어떠한 Section 또는 Function 블록에서도 접근할 수 있습니다.

OutFile "file_name.exe"

Var BLA ;변수 선언

Section bla
  StrCpy $BLA "123" ;이제 변수 $BLA를 사용할 수 있습니다.
SectionEnd

또한 임시 저장 공간을 위해 스택을 사용할 수 도 있습니다. 스택을 사용하기 위해 Push 및 Pop 명령어를 사용합니다. Push는 스택에 값을 추가하고, Pop은 값을 스택에서 제거하고 변수를 설정합니다.

공유 코드의 경우, 20개의 레지스터(예를 들어 $0과 $R0)들을 사용할 수 있습니다. 이 스태틱 변수들은 선언될 수 없으며, 같은 이름으로 새로운 변수를 선언할 수 없습니다. 공유 코드 안에서 이 변수들을 사용하려면, 기존 값을 스택에 저장한 뒤 사용이 끝나면 기존 값을 복원시켜야 합니다.

함수 호출 후, 변수들은 이전과 같은 값을 가집니다. 여러 변수를 사용할 때 순서에 주의하십시오. (Last-In First-Out 방식):

Function bla
  Push $R0
  Push $R1
    #...code...
  Pop $R1
  Pop $R0
FunctionEnd
    2.3.5.3 스크립트 디버깅

NSIS를 사용하여 작업할수록 스크립트는 더욱 복잡해질 것입니다. 오타나 논리적인 오류와 같은 실수는 특히 많은 변수를 다룰 때 그 가능성이 높아집니다. 코드를 디버깅할 때 도움이 되는 몇가지 방법들이 있습니다. 일반적으로 변수의 실제 값을 보기 위해 MessageBox 또는 DetailPrint 명령을 써야 합니다. 모든 변수에 대한 간단한 개요를 보기 위해서DumpState 플러그-인을 사용할 수 있습니다. 기본적으로 인스톨러의 모든 액션은 로그 창에 출력됩니다. 로그 창에 오른쪽 클릭 후 “자세한 내용을 클립보드로 복사”를 선택하면 로그를 복사할 수 있습니다. 또한 직접 파일로 로그를 출력하는 방법도 있는데, 이 방법에 대한 자세한 내용은 여기를 참조하십시오.

<설치 중 로그 복사>
<설치 중 로그 복사>
2.3.6 스크립트 실행

최종 사용자가 인스톨러 또는 언인스톨러를 실행할 때 페이지들은 스크립트에 정의된 순서대로 화면에 표시됩니다. instfiles 페이지에 도달하면, 이전 페이지에서 이미 선택되어진 구성요소에 대응되는 섹션이 스크립트에 정의된 순서대로 수행됩니다. 만약 components 페이지를 선언하지 않았거나 나타나지 않는다면 스크립트에 의해 언-체크되지 않음으로 간주되어 모든 섹션이 실행됩니다.

섹션 뿐만 아니라 콜백 함수도 정의될 경우, 섹션 코드 전에 콜백 함수 안의 코드가 수행될 수 있습니다. 예를 들어, .onInit 콜백 함수는 스크립트의 다른 어떠한 것들 보다 먼저 수행됩니다. 또한 페이지 표시 프로세스의 특정 시점에 수행되는 페이지 콜백 함수도 존재합니다.

2.3.7 컴파일러 명령어

컴파일러 명령어는 스크립트 컴파일 타임에 수행됩니다. 조건부 컴파일, 헤더 파일 포함, 응용 프로그램 실행 작업 디렉터리 변경 등에 사용될 수 있습니다. 가장 일반적인 명령어는 define 입니다. define은 컴파일 타임 상수를 선언합니다. 예를 들어, 제품의 버전을 컴파일 타임 상수로 선언하고 스크립트에서 그것을 사용할 수 있습니다.

!define VERSION "1.0.3"

Name "My Program ${VERSION}"
OutFile "My Program Installer - ${VERSION}.exe"

Section
SectionEnd

define에 대한 더 자세한 정보는 조건부 컴파일을 참조하십시오.

또 다른 일반적인 명령어는 macro 입니다. macro 명령어는 컴파일 타임에 define 명령문과 define 컴파일 상수 코드를 삽입하기 위해 사용됩니다. 매크로 명령어는 컴파일 타임에 삽입됩니다. 이것은 개발자가 일반화된 코드를 한번만 작성하면, 잦은 수정 없이 여러번 사용할 수 있도록 합니다.

!macro MyFunc UN
Function ${UN}MyFunc
  Call ${UN}DoRegStuff
  ReadRegStr $0 HKLM Software\MyProgram key
  DetailPrint $0
FunctionEnd
!macroend

!insertmacro MyFunc ""
!insertmacro MyFunc "un."

이 매크로는 인스톨러와 언인스톨러에 사용되는 중복된 코드를 줄여줍니다. 예제 끝의 두 !insertmacros 명령어는 두 함수를 삽입합니다. 인스톨러를 위한 함수는 MyFunc이며, 또 다른 하나는 언인스톨러용이며 un.MyFunc입니다. 두 함수는 정확히 같은 작업을 수행합니다.

더 많은 정보는 컴파일 타임 명령어를 참조하십시오.

댓글

댓글 본문
작성자
비밀번호
버전 관리
CraXicS
현재 버전
선택 버전
graphittie 자세히 보기