Windows EXE 실행기 생성
패키징할 때 보호된 애플리케이션용 네이티브 Windows 실행기를 만들 수 있습니다. 순수한 Win32 실행 파일이라 두 번 클릭하면 바로 실행되므로, 사용자가 Java를 먼저 설치할 필요도 run.bat을 볼 필요도 없습니다.
EXE는 선택 사항이며 기본적으로는 만들어지지 않습니다. 사용하도록 설정해도 패키지에는 run.sh, run.command, run.bat이 그대로 남습니다. 두 실행 방식은 아카이브 구조, 클래스패스, 메인 클래스, JVM 시작 옵션이 완전히 같습니다.
1. 적용 범위
| 애플리케이션 유형 | Java 애플리케이션, Spring Boot (세 레이아웃 모두), Tomcat |
| 대상 플랫폼 | windows-x64, windows-x86, windows-aarch64 |
| 지원하지 않음 | 라이브러리 암호화 — 단일 .p4jx 아카이브는 실행 가능한 애플리케이션 디렉터리가 아닙니다 |
Windows 대상 플랫폼을 하나 이상 선택해야 합니다. Linux나 macOS 대상을 함께 선택해도 문제없습니다. 그쪽 패키지는 EXE 없이 정상적으로 만들어지고 기존 스크립트로 실행됩니다. Windows 대상을 하나도 선택하지 않으면 작업이 바로 실패합니다.
2. GUI에서 하는 방법
- 입력 파일과 대상 플랫폼 페이지에서 Windows 애플리케이션 EXE 생성(x64/x86/ARM64) 을 선택하고 Windows 대상 플랫폼을 하나 이상 고릅니다.
- 이 항목은 간단 모드와 고급 모드가 갈라지기 전에 있으므로 두 모드 모두 EXE를 만들 수 있습니다.
- 선택하면 Windows EXE 실행기 페이지가 추가되어 파일 이름, 실행기 모드, 아이콘, Windows 버전 정보를 입력할 수 있습니다. 선택하지 않으면 바로 최종 확인 페이지로 넘어갑니다.
- EXE를 사용하면 JVM 시작 옵션 입력란이 이 실행기 페이지에만 나타납니다. 같은 옵션의 입력 위치가 두 군데 생기지 않도록 하기 위해서입니다. 입력한 내용은 EXE와 실행 스크립트 양쪽에 기록됩니다.
- 최종 확인 페이지에는 실제로 EXE가 만들어질 플랫폼과 입력한 실행기 항목이 표시됩니다.
3. CLI 예제
가장 짧은 형태는 --windows-exe만 있으면 됩니다.
p4j --target-platform windows-x64 javaapp app.jar dist --windows-exe
파일 이름과 창 모드를 지정하는 경우:
p4j --target-platform windows-x64 javaapp app.jar dist \
--windows-exe \
--exe-name MyApp.exe \
--exe-mode gui \
--exe-icon assets/app.ico
세 가지 Windows 아키텍처를 한 번에 만들고 버전 리소스를 채우는 경우:
p4j --target-platform windows-x64,windows-x86,windows-aarch64 \
springboot app.jar dist \
--windows-exe \
--exe-name MyService \
--exe-file-version 1.4.2.0 \
--exe-product-version 1.4.2.0 \
--exe-company 'Example Inc.' \
--exe-product 'Example Service' \
--exe-description 'Example background service' \
--exe-copyright 'Copyright (C) 2026 Example Inc.'
Tomcat 패키지도 지원하며, 만들어진 EXE는 내장 Tomcat을 포그라운드로 시작합니다.
p4j --target-platform windows-x64 tomcat app.war dist --context /demo --windows-exe
4. 옵션
| 옵션 | 설명 |
|---|---|
--windows-exe | Windows 애플리케이션 EXE를 만듭니다 |
--exe-name <name> | EXE 파일 이름. 기본값은 입력 파일 이름이며 Tomcat 패키지는 tomcat |
--exe-mode <mode> | console (기본값) 또는 gui |
--exe-icon <ico> | 선택 사항인 Windows 아이콘 (.ico 형식) |
--exe-file-version <a.b.c.d> | PE 파일 버전. 10.0.0.0 |
--exe-product-version <a.b.c.d> | PE 제품 버전. 규칙은 같습니다 |
--exe-company <text> | 회사 이름 |
--exe-product <text> | 제품 이름 |
--exe-description <text> | 파일 설명. 작업 관리자와 파일 속성에 표시됩니다 |
--exe-copyright <text> | 저작권 고지 |
--exe-* 중 하나라도 지정하면 EXE 생성이 자동으로 켜지므로 --windows-exe를 따로 쓸 필요가 없습니다.
이름은 파일 이름만 가능하며 /, \, 디렉터리 부분을 포함할 수 없습니다. .exe를 빼면 자동으로 붙습니다.
두 버전 항목은 같은 규칙을 따릅니다. 마침표로 구분한 14개의 숫자이며 각 값은 065535입니다 (예: 1.0.0.1). Windows는 각 부분을 16비트 부호 없는 정수로 저장하므로 v1.0이나 1.0-beta처럼 문자나 공백이 들어간 값은 받지 않습니다. 비워 두면 0.0.0.0입니다. 이 두 항목은 패키징이 시작되기 전에 검증되므로, 잘못 입력하면 도중이 아니라 바로 알 수 있습니다.
5. 출력 구조
Java 애플리케이션을 예로 들면, EXE는 실행 스크립트와 함께 패키지 루트에 놓입니다.
dist/
├── MyApp.exe # 새로 추가된 Windows 실행기
├── app.p4jx
├── vlxjre/
├── lib/
├── run.sh
├── run.command
├── run.bat
└── README.md
패키지 안의 README.md에는 만들어진 EXE 파일 이름과 코드 서명 관련 안내가 들어 있습니다.
6. 실행기의 동작
EXE가 있는 디렉터리가 애플리케이션의 루트가 됩니다. 실행기는 그 루트 안에 있는 런타임, 아카이브, 클래스패스, 작업 디렉터리 경로만 받아들입니다. 패키지 밖의 경로나 심볼릭 링크·정션으로 바꿔치기한 경로는 거부되고 프로세스가 시작되지 않습니다. 따라서 패키지 전체를 옮기거나 이름을 바꾸는 것은 자유롭지만, EXE만 따로 복사해 쓸 수는 없습니다.
| 항목 | 동작 |
|---|---|
| 런타임 | 항상 패키지 안의 vlxjre\bin\java.exe를 씁니다. 시스템 Java를 쓰지 않고 JAVA_HOME도 읽지 않습니다. |
| 명령줄 인수 | EXE에 전달한 인수는 애플리케이션 자체 인수 뒤에 붙습니다. |
| 콘솔 모드 | 현재 콘솔의 표준 입출력을 이어받고, 애플리케이션이 끝날 때까지 기다린 뒤 그 종료 코드를 반환합니다. |
| GUI 모드 | 콘솔 창을 만들지 않아 데스크톱 애플리케이션에 적합합니다. |
| 환경 변수 | 시작 전에 JAVA_TOOL_OPTIONS, _JAVA_OPTIONS, JDK_JAVA_OPTIONS, CLASSPATH를 지워 외부에서 시작 옵션을 주입하지 못하게 합니다. |
EXE의 JVM 옵션은 패키징 시점에 고정되고 매개변수 블록과 함께 서명되어 실행 시 검증되므로, 배포한 뒤에는 바꿀 수 없습니다. APP_JAVA_OPTS는 run.bat에만 영향을 주며 EXE는 이를 읽지 않습니다. EXE의 JVM 옵션을 바꾸려면 다시 패키징하세요.
같은 이유로 -javaagent, -agentlib, -agentpath, -Xbootclasspath, --patch-module은 EXE의 시작 옵션에 넣을 수 없습니다. 이들을 --jvm-option으로 전달하면 패키징이 즉시 실패합니다.
7. 코드 서명
Protector4J는 만들어진 EXE에 게시자 서명을 넣지 않으며 Authenticode 자격 증명에도 전혀 접근하지 않습니다. 아이콘, 버전 리소스, 시작 옵션 같은 PE 수정은 모두 패키징 단계에서 끝나므로 서명은 마지막 단계여야 합니다.
- 패키징을 마치고 EXE에서 애플리케이션이 제대로 실행되는지 확인합니다.
- 자신의 인증서로 Authenticode 서명을 하고 RFC3161 타임스탬프를 붙입니다.
- Windows의
/pa정책으로 서명을 검증합니다.
서명한 뒤에는 PE 파일을 수정하지 마세요. 수정하면 서명이 무효가 됩니다. 아이콘이나 버전 번호를 바꾸려면 다시 패키징하고 다시 서명하세요.
8. 작업 파일 항목
내보낸 p4j-task.yml은 형식 버전 2를 쓰며, EXE를 사용하면 다음 항목을 저장합니다. 버전 1 작업 파일도 계속 읽을 수 있습니다.
windowsExe: true
exeName: MyApp.exe
exeMode: console
exeIcon: assets/app.ico
exeFileVersion: 1.4.2.0
exeProductVersion: 1.4.2.0
exeCompany: Example Inc.
exeProduct: Example Service
exeDescription: Example background service
exeCopyright: Copyright (C) 2026 Example Inc.
9. 문제 해결
| 증상 | 원인과 대처 |
|---|---|
| Windows 대상 플랫폼이 필요하다고 표시됨 | EXE를 사용하도록 설정했지만 windows-x64, windows-x86, windows-aarch64 중 어느 것도 선택하지 않았습니다. |
| 버전 번호 형식이 올바르지 않다고 표시됨 | 버전 항목에 문자나 공백이 있거나, 5개 이상으로 나뉘었거나, 어느 값이 0~65535 범위를 벗어났습니다. |
| EXE 이름은 파일 이름만 가능하다고 표시됨 | 이름에 경로 구분 문자가 들어 있습니다. 디렉터리 없는 파일 이름으로 바꾸세요. |
| 아이콘 파일을 찾을 수 없다고 표시됨 | --exe-icon이 존재하지 않는 .ico를 가리킵니다. 경로를 확인하세요. |
| 두 번 클릭해도 창이 없고 바로 종료됨 | GUI 모드에서 애플리케이션 시작에 실패했습니다. 콘솔 모드로 다시 패키징해 오류 출력을 확인하세요. |
| 다른 곳에 복사한 EXE가 실행되지 않음 | 실행기는 런타임과 아카이브가 같은 패키지 디렉터리에 있어야 합니다. 출력 디렉터리 전체를 복사하세요. |