윈도우에서 맥으로 — 첫 .dmg, 그리고 '최신이 아니었다'는 한마디 (ICEPDF 맥 빌드)
윈도우로만 내던 ICEPDF를 처음으로 맥 설치파일(.dmg)로 구웠다. 코드가 아니라 '포장'의 문제였고, 정작 클론해 온 소스가 두 세대 전 버전이었다는 반전까지 — 맥 이식과 서명 없는 배포 이야기.
윈도우에서만 돌던 ICEPDF를, 처음으로 맥에서 실행되는 설치파일로 만들었다. 결론부터 말하면 코드는 거의 그대로였고, 손봐야 했던 건 '포장'이었다. 그리고 그 과정에서 예상 못 한 곳에서 한 번 넘어졌다 — 정작 클론해 온 소스가 최신이 아니었던 것.
계기 — 맥 쓰는 사람에게 줘야 했다
그동안 ICEPDF는 윈도우 설치파일(.exe)로만 냈다. 나도 그렇게 써 왔으니까. 그런데 이번엔 맥을 쓰는 사람에게 건네줄 일이 생겼다. "여기서 테스트해 보고, 잘 되면 넘겨주면 좋겠는데."
사실 코드는 이미 크로스플랫폼이었다
ICEPDF는 Electron 앱이다. Electron은 그 자체로 윈도우·맥·리눅스를 다 돈다. 열어 보니 메인 프로세스에는 이미 맥을 배려한 흔적까지 있었다. macOS의 파일 연결 열기(open-file) 처리, 창을 다 닫아도 앱은 남기는 맥 관례(platform !== 'darwin') 같은 것들.
문제는 '코드'가 아니라 '포장'이었다. 빌드 설정이 통째로 윈도우 전용이었다.
- 배포 스크립트가
electron-builder --win— 윈도우만. - 아이콘이
.ico하나. 맥은.icns를 쓴다. - 설치 방식이 NSIS(윈도우 설치 마법사)뿐.
맥으로 '포장'을 바꾸다
세 가지를 더했다.
첫째, 맥 아이콘. 기존 앱 아이콘(PNG)에서 맥용 .icns를 만들었다. 맥에 기본으로 들어 있는 sips와 iconutil로 여러 해상도를 묶으면 끝난다.
둘째, 맥 빌드 타겟. 빌드 설정에 mac 항목을 추가하고 결과물을 .dmg(맥의 드래그 설치 디스크이미지)로, 칩은 Apple Silicon(arm64)으로 잡았다.
셋째, 숨어 있던 함정 하나. 빌드가 끝나면 무거운 OCR 부속을 떼어내는 정리 스크립트가 있는데, 이게 윈도우의 폴더 구조(resources/app)만 알고 있었다. 맥은 앱 안쪽 경로가 다르다(ICEPDF.app/Contents/Resources/app). 그대로 두면 맥에서는 조용히 아무것도 안 지우고 넘어가 버린다. 플랫폼을 구분하도록 고쳤다.
여기까지 하고 .dmg를 만들어, 실제 배포처럼 마운트해서 앱을 복사하고 더블클릭으로 띄웠다. 창이 떴다. 됐다 — 싶었다.
"책갈피 드래그가 왜 안 되지?"
넘겨주기 전에 이것저것 눌러 보다가 이상한 걸 발견했다. 책갈피를 여러 개 골라 지우는 것도, 끌어서 순서를 바꾸는 것도 안 됐다. 분명 윈도우 버전에는 있는 기능인데.
소스를 뒤졌더니 그 기능 자체가 없었다. 버그가 아니라 아예 구현이 안 되어 있는 코드였다. 이상하다 — 나는 분명 만들었는데.
범인은 깃이었다. 클론해 온 기본 브랜치(main)가 v1.5.1에 멈춰 있었다. 진짜 최신 개발은 다른 브랜치(publish)에서 이어지고 있었고, 거기에 책갈피 다중선택·드래그(v1.6.0)도, 인쇄 기능(v1.7.0)도 다 있었다. 맥용으로 열심히 포장하던 물건이 사실 두 세대 전 버전이었던 것이다.
깃을 동기화하고, 내가 더한 맥 빌드 설정은 그대로 얹은 채 최신(v1.7.0)으로 다시 맞췄다. 그리고 .dmg를 다시 구웠다. 이번엔 책갈피 유틸 테스트 12개까지 전부 통과하는, 진짜 최신이었다.
마지막 함정 — 서명 없는 앱
맥에는 관문이 하나 더 있다. 애플에 돈을 내고 '공증'받지 않은 앱은, 남의 맥에서 그냥 더블클릭하면 "확인되지 않은 개발자"라며 막힌다. 유료 인증서 없이 무료로 건네려면 받는 사람이 한 번만 우클릭 → 열기를 하거나, 터미널에서 xattr -cr 한 줄을 실행하면 된다. 이 안내를 설치파일과 함께 넣어 두면 충분하다.
남은 이야기
이렇게 ICEPDF는 처음으로 맥에서 도는 물건이 됐다. 지금은 Apple Silicon 전용으로만 구웠다 — 받는 사람이 그 계열이라. 인텔 맥까지 챙기려면 한 번 더 구우면 된다.
배운 건 두 가지다. 하나, 크로스플랫폼은 생각보다 '코드'보다 '포장'의 문제였다는 것. 둘, 아무리 잘 만들어도 엉뚱한 브랜치를 붙잡고 있으면 헛일이라는 것. 물건을 옮기기 전에, 옮기는 게 진짜 최신인지부터 확인할 일이다.