크라우니엔진 크로스플랫폼 (맥/윈도우/리눅스)
Reconnaissance complete. Here is the full cross-platform architecture design for /Users/ef/crowny-engine.
크라우니엔진 크로스플랫폼 아키텍처 설계 (mac/win 동시 + linux 기획)
핵심 진단 (정찰 종합)
3개 레이어로 분리하면 깨끗하게 정리된다:
| 레이어 | 플랫폼 의존성 | 조치 |
|---|---|---|
| **crownyc.c / hanseonc_.c (VM·컴파일러) | 이미 #ifdef _WIN32/__APPLE__/__linux__ 완비. PE32+ exe 사전빌드 존재 | 재사용 (compositor.c 하드코딩 15곳만 별도) |
| core/.한선 (로직 SSOT) | OS 무관 — 단 체계() 호출 안에 BSD명령·/Users/ef 하드코딩 섞임 | core/플랫폼.한선 1곳으로 명령 격리 |
| 셸 레이어** (엔진.sh, shell/*.sh) | bash 전제 — flock/launchctl/shasum/sed -i ''/whoami/pgrep | lib/platform.sh + 엔진.cmd/.ps1 진입점 |
core/플랫폼.한선(한선씨 레벨)과 lib/platform.sh(셸 레벨). 나머지 26개 core 모듈과 모든 비즈니스 로직은 공통.(a) 플랫폼 추상화 계층 설계
A-1. core/플랫폼.한선 (신규 — 한선씨 레벨 명령 매핑 SSOT)
OS를 환경변수로 주입받아(한선씨는 uname 직접 못 부름) 플랫폼별 체계() 명령 문자열을 반환하는 순수 매핑 모듈. 기존 시간헬퍼.한선의 date -j||date -d 이중화 패턴을 일반화한다.
han// core/플랫폼.한선 — OS감지 + 명령매핑 SSOT
// 주입: CROWNY_PLATFORM = darwin|linux|windows (부트스트랩이 uname으로 설정)
// VM함정: 체계() stdout 캡처불가 → >/tmp 후 읽기() / 포함()=미발견 -1 / 파일존재()=-1
가져오기 "문자열.한선"
함수 플랫폼() {
변수 p = 환경변수("CROWNY_PLATFORM")
만약 (글자수(p) == 0) { p = "darwin" } // 안전 기본값(현 운영=mac)
반환 p
}
// ── 1. 해시 (앵커/체크섬/싱크) ─────────────────
함수 해시명령(경로) {
변수 p = 플랫폼()
만약 (p == "linux") { 반환 "sha256sum '" + 경로 + "' | awk '{print $1}'" }
만약 (p == "windows") { 반환 "certutil -hashfile '" + 경로 + "' SHA256 | findstr /R \"^[0-9a-f]\"" }
반환 "shasum -a 256 '" + 경로 + "' | awk '{print $1}'" // darwin
}
// ── 2. 날짜 (어제/월말 — 정산·빌드판정의 토대) ──
함수 어제날짜명령(tmp) {
변수 p = 플랫폼()
만약 (p == "windows") {
반환 "powershell -NoProfile -C \"(Get-Date).AddDays(-1).ToString('yyyy-MM-dd')\" > '" + tmp + "'"
}
// darwin(BSD) → linux(GNU) 이중 폴백 (시간헬퍼.한선 검증패턴)
반환 "date -v-1d '+%Y-%m-%d' > '" + tmp + "' 2>/dev/null || date -d 'yesterday' '+%Y-%m-%d' > '" + tmp + "' 2>/dev/null"
}
// ── 3. 파일잠금 (정산 단일라이터 / 원장 WAL) ────
// 전 플랫폼 공통: mkdir 원자성 (flock 불필요, 파이프라인.sh 검증패턴)
함수 잠금획득(락디렉토리) {
변수 결과 = 체계("mkdir '" + 락디렉토리 + "' 2>/dev/null")
반환 결과 // 0=획득 / 비0=이미잠김
}
함수 잠금해제(락디렉토리) {
체계("rm -rf '" + 락디렉토리 + "'")
반환 0
}
// ── 4. 스케줄러 (정산/빌드 크론 상태) ──────────
함수 스케줄러상태명령(작업명, tmp) {
변수 p = 플랫폼()
만약 (p == "linux") { 반환 "systemctl --user is-active " + 작업명 + " > '" + tmp + "' 2>/dev/null" }
만약 (p == "windows") { 반환 "schtasks /query /tn " + 작업명 + " > '" + tmp + "' 2>NUL" }
반환 "launchctl list | grep -q " + 작업명 + " && echo active > '" + tmp + "'" // darwin
}
// ── 5. 프로세스 생존 (서버 기동 확인) ──────────
함수 프로세스확인명령(패턴, tmp) {
변수 p = 플랫폼()
만약 (p == "windows") { 반환 "tasklist | findstr crownyc > '" + tmp + "' 2>NUL" }
반환 "pgrep -f '" + 패턴 + "' > '" + tmp + "' 2>/dev/null" // mac/linux 공통
}
// ── 6. 홈/경로 (포터빌리티.한선이 이미 처리, 래퍼만) ─
함수 홈경로() {
변수 h = 환경변수("HOME")
만약 (글자수(h) == 0) { h = 환경변수("USERPROFILE") } // windows
반환 h
}
함수 엔진루트() {
변수 r = 환경변수("ENGINE_ROOT")
만약 (글자수(r) == 0) { r = 홈경로() + "/crowny-engine" }
반환 r
}
사용 규약: 모든 core 모듈은 체계("date -v-1d ...") 직접 호출을 금지하고 가져오기 "플랫폼.한선" 후 해시명령()/어제날짜명령() 등을 거친다. 이렇게 하면 BSD/GNU/Windows 분기가 이 한 파일에만 산다.
A-2. lib/platform.sh (신규 — 셸 레벨 추상화, bash 진입점 공용)
bash#!/usr/bin/env bash
# lib/platform.sh — 셸 레벨 OS 추상화 (엔진.sh가 source)
detect_platform() {
case "$(uname -s 2>/dev/null)" in
Darwin) echo darwin ;; Linux) echo linux ;;
MINGW*|MSYS*|CYGWIN*) echo windows ;; *) echo unknown ;;
esac
}
export CROWNY_PLATFORM="${CROWNY_PLATFORM:-$(detect_platform)}" # 한선씨로 그대로 전달
get_home(){ [ -n "${HOME:-}" ] && echo "$HOME" || echo "$USERPROFILE"; }
hash_sha256(){ if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1"|awk '{print $1}';
elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1"|awk '{print $1}';
else echo "NO_SHA_TOOL" >&2; return 1; fi; }
lock_dir(){ local d="$1" to="${2:-30}" n=0; while ! mkdir "$d" 2>/dev/null; do
[ "$n" -ge "$to" ] && return 1; sleep 1; n=$((n+1)); done
echo $$ >"$d/pid"; trap "rm -rf '$d'" EXIT; }
sched_status(){ case "$CROWNY_PLATFORM" in
darwin) launchctl list 2>/dev/null|grep -q "$1" && echo active ;;
linux) systemctl --user is-active "$1" 2>/dev/null ;;
windows) schtasks /query /tn "$1" 2>NUL ;; esac; }
엔진.sh의 라인 153/213 $(whoami)는 POSIX 공통이라 유지, 라인 346/355 launchctl→sched_status, 라인 337 pgrep은 그대로(mac/linux 공통)로 두되 windows 진입은 .cmd가 담당.
(b) macOS ↔ Windows 차이 비교표
| 기능 | macOS (darwin/BSD) | Windows | Linux (기획) | 격리 위치 |
|---|---|---|---|---|
| SHA256 | shasum -a 256 f \| awk | certutil -hashfile f SHA256 | sha256sum f \| awk | 해시명령() / hash_sha256 |
| 어제날짜 | date -v-1d '+%F' | powershell (Get-Date).AddDays(-1) | date -d yesterday '+%F' | 어제날짜명령() |
| 월말날짜 | date -j -v1d -v+1m -v-1d | powershell AddMonths | date -d '+1 month -1 day' | 시간헬퍼.한선(기존) |
| 파일잠금 | mkdir 원자 (flock 없음) | mkdir 원자 | flock 또는 mkdir | 잠금획득() (mkdir 통일) |
| 스케줄러 | launchctl + plist | schtasks.exe / 작업스케줄러 | systemd --user timer | 스케줄러상태명령() |
| 프로세스확인 | pgrep -f | tasklist \| findstr | pgrep -f | 프로세스확인명령() |
| 홈 | $HOME(/Users/ef) | %USERPROFILE%/$HOME(Git Bash) | $HOME(/home/x) | 홈경로() |
| 임시 | /tmp ($TMPDIR) | %TEMP% (Git Bash /tmp 매핑) | /tmp | /tmp 유지(매핑됨) |
| in-place 편집 | sed -i '' | perl -i.bak (MSYS) | sed -i | perl로 통일 |
| 텍스트검색 | grep/awk | findstr 또는 MSYS grep | grep/awk | MSYS2 동봉 시 grep 공통 |
| 줄바꿈 | LF | CRLF 주의 (.cmd/.bat=CRLF, .한선/.sh=LF) | LF | .gitattributes/패키징 |
| 데몬화 | nohup &/launchctl | start /b/작업스케줄러 | nohup &/systemd | 진입점별 |
| C 컴파일 | cc + -framework Cocoa | mingw gcc -lws2_32 -luser32 -lgdi32 | cc -lX11 -lpthread | Makefile/빌드스크립트 |
| 셸 진입 | 엔진.sh | 엔진.cmd→MSYS bash 또는 네이티브 | 엔진.sh | (c) 레이아웃 |
dist-win/ 패키징 시 .cmd/.bat만 CRLF로 변환, .한선/.sh/.psv/.toau는 LF 유지(크라우니c가 LF 가정). 패키지 빌드 스크립트에서 강제.(c) 패키지 디렉토리 레이아웃
세 dist는 공통 core 한선씨 + 공통 libs + 플랫폼별 셸 + 플랫폼별 crownyc 바이너리로 구성. core/libs는 바이트 동일(SSOT).
/Users/ef/crowny-engine/ ← 소스 (단일 원본)
├── core/ *.한선 (26+1 플랫폼.한선) ← 공통, 무수정 복사
├── libs/ *.한선 (표준 라이브러리) ← 공통
├── lib/ platform.sh (신규) ← 셸 추상화 공통
├── shell/ *.sh + *.한선 동반 ← bash(mac/linux 공통)
├── win/ 엔진.cmd 엔진.bat *.ps1 (신규) ← windows 전용 진입
├── 엔진.sh ← mac/linux 진입
├── 매니페스트.psv
└── dist/ (빌드 산출물 — 아래 3종)
dist-mac/ dist-win/ dist-linux/ (기획)
├── core/ (동일) ├── core/ (동일) ├── core/
├── libs/ (동일) ├── libs/ (동일) ├── libs/
├── lib/platform.sh ├── lib/platform.sh ├── lib/platform.sh
├── shell/*.sh ├── shell/*.sh (MSYS bash용) ├── shell/*.sh
├── 엔진.sh ├── 엔진.cmd 엔진.bat *.ps1 ├── 엔진.sh
├── bin/crownyc (Mach-O) ├── bin/crownyc.exe (PE32+) ├── bin/crownyc (ELF)
├── bin/hanseonc_high (Mach-O) ├── bin/hanseonc_high.exe ├── bin/hanseonc_high (ELF)
└── README-mac.md └── crowny-start.cmd (5단계설치) └── crowny-install.sh + .service
윈도우 바이너리는 신규 빌드 불필요 — /Users/ef/crowny-win-pkg/bin/*.exe(검증된 PE32+) 재사용. std/ 110개도 /Users/ef/crowny-windows-package/crowny-bin/std/에서 가져와 dist-win/libs/로 병합 가능.
(d) 윈도우에서 한선씨 REPL(크라우니코드.한선) 동작 방법
REPL 진입점: crownyc.exe run core/크라우니코드.toau. 핵심은 REPL 내부 체계() 호출들이 쓰는 grep/awk/date를 윈도우에서 어떻게 충족하느냐.
3가지 경로 (권장순):
- MSYS2/Git Bash 동봉 (권장, 최소공수) —
엔진.cmd가 Git Bash 환경에서crownyc.exe를 실행. grep/awk/sed/date(GNU) 전부 제공됨 →core/*.한선의체계()명령이 거의 그대로 작동.CROWNY_PLATFORM=linux매핑 사용(GNU 명령군이므로). 실제로 정찰의 "Git Bash면 POSIX 셸 코드 대부분 작동" 결론과 일치.
- 네이티브 cmd + findstr 폴백 — Git Bash 없이 순수 cmd.
룩업.한선/학습.한선의grep -m1 -F→findstr /C:"..."로 매핑하는 분기를플랫폼.한선에 추가:
han함수 한줄검색명령(패턴, 파일, tmp) {
만약 (플랫폼() == "windows") { 반환 "findstr /C:\"" + 패턴 + "\" \"" + 파일 + "\" > \"" + tmp + "\"" }
반환 "grep -m1 -F '" + 패턴 + "' '" + 파일 + "' > '" + tmp + "'"
}
단 findstr은 -m1(첫줄만)·정규식 차이가 있어 부분()으로 첫 줄 잘라야 함.- 한선씨 네이티브화 (장기, 헌법 정합) —
읽기()로 DB 전체 로드 후포함()/부분()으로 한선씨 내부에서 검색. 외부 grep 제거 → 완전 OS독립. 단 학습DB가 16KB(STR_MAX_LEN=16384, 단일읽기()한계) 초과 시 샤딩 필요. 룩업DB가 작으면 즉시 적용 가능, 크면 페이지네이션.
chcp 65001로 UTF-8 한글 보장 — crowny-start.cmd에 이미 존재). 체계()는 cmd /c로 위임되므로 명령만 윈도우 호환이면 됨.권장: 경로 1(MSYS2 동봉) + 플랫폼.한선에 windows 분기 점진 추가. 즉시 동작 + 헌법적 한선씨 네이티브화는 룩업/학습부터 단계 이행.
(e) 리눅스 dist-linux 기획
- 빌드:
cc -O2 -DCROWNY_WINDOW -lX11 -lpthread crownyc.c crownyc_window_x11.c compositor.c ui.c theme.c -lm -o crownyc(GUI). 헤드리스 서버는cc -O2 crownyc.c -lm -o crownyc.crownyc.c에__linux__분기 40+곳 이미 존재 → 그대로 빌드. - 명령군: GNU coreutils 표준 →
CROWNY_PLATFORM=linux.sha256sum/date -d/grep/awk전부 네이티브,시간헬퍼.한선의 GNU 폴백이 이미 1차 경로가 됨. - 잠금:
flock사용 가능하나 mkdir 원자성으로 통일(mac과 동일 코드 경로 유지 → 검증 단순화). - 스케줄러:
systemd --usertimer.deploy/에org.crowny.engine-settle.service+.timer,org.crowny.engine-dailybuild.{service,timer}신규.엔진.sh status의launchctl list는플랫폼.한선 스케줄러상태명령()이systemctl --user is-active로 분기. - 경로:
$HOME=/home/x,ENGINE_ROOT=$HOME/crowny-engine— 이미 환경변수 기반(엔진.shSCRIPT_DIR자동감지)이라 무수정. - 설치:
crowny-install.sh(apt/dnf/pacman 분기로 build-essential·libx11-dev 설치 → 빌드 → systemd --user enable). - CI:
.github(또는 crowny-hub) 3-OS 매트릭스에서bash -n문법검사 + 제곱합=385 자체검사.
(f) 빌드 순서 + 이번에 만들 파일 목록 (절대경로)
신규 생성 파일
/Users/ef/crowny-engine/core/플랫폼.한선 ← (a) OS감지+명령매핑 SSOT [핵심]
/Users/ef/crowny-engine/core/플랫폼.toau ← 컴파일 산출 (hanseonc_high)
/Users/ef/crowny-engine/lib/platform.sh ← (a) 셸 추상화 (엔진.sh가 source)
/Users/ef/crowny-engine/win/엔진.cmd ← (c)(d) windows 진입(Git Bash 위임)
/Users/ef/crowny-engine/win/엔진.bat ← cmd 네이티브 폴백
/Users/ef/crowny-engine/win/엔진포트.ps1 ← netstat/Get-NetTCPConnection
/Users/ef/crowny-engine/win/crowny-start.cmd ← crowny-windows-package 패턴 재사용(5단계)
/Users/ef/crowny-engine/deploy/org.crowny.engine-settle.service ← (e) linux systemd
/Users/ef/crowny-engine/deploy/org.crowny.engine-settle.timer
/Users/ef/crowny-engine/deploy/org.crowny.engine-dailybuild.service
/Users/ef/crowny-engine/deploy/org.crowny.engine-dailybuild.timer
/Users/ef/crowny-engine/crowny-install.sh ← (e) linux 설치(apt/dnf/pacman)
/Users/ef/crowny-engine/패키지빌드.sh ← dist-{mac,win,linux} 3종 빌드 + CRLF처리
수정 파일 (플랫폼 분기 위임 — 라이브 무접촉, core SSOT만)
/Users/ef/crowny-engine/엔진.sh ← 상단에 `source lib/platform.sh`; 346/355 launchctl→sched_status
/Users/ef/crowny-engine/core/돈실행.한선 ← flock → 가져오기 플랫폼.한선; 잠금획득()
/Users/ef/crowny-engine/core/달란트서버.한선 ← flock 2곳 → 잠금획득(); /Users/ef → 환경변수("HOME")
/Users/ef/crowny-engine/core/패키지빌드판정.한선 ← sha256sum → 해시명령(); date 분기 유지
/Users/ef/crowny-engine/core/구독게이트.한선 ← date -j -f → 시간헬퍼 위임
/Users/ef/crowny-engine/core/학습.한선·룩업.한선 ← grep → 한줄검색명령()(windows findstr 분기)
/Users/ef/crowny-engine/매니페스트.psv ← 플랫폼|core/플랫폼.한선|OS감지+명령매핑 행 추가
빌드 순서 (DRYRUN 안전 — 라이브/돈/원장 무접촉)
bash# 0) 컴파일러 확인 (재사용 — 빌드 불필요)
ls /Users/ef/CrownyOS/crownyc/{crownyc,hanseonc_high} # mac Mach-O
ls /Users/ef/crowny-win-pkg/bin/{crownyc.exe,hanseonc_high.exe} # win PE32+ (검증됨)
# 1) core/플랫폼.한선 작성 → 컴파일 검증
/Users/ef/CrownyOS/crownyc/hanseonc_high /Users/ef/crowny-engine/core/플랫폼.한선 \
> /Users/ef/crowny-engine/core/플랫폼.toau 2>/dev/null
/Users/ef/CrownyOS/crownyc/crownyc run /Users/ef/crowny-engine/core/플랫폼.toau # 스모크
# 2) lib/platform.sh 작성 → 문법 검사
bash -n /Users/ef/crowny-engine/lib/platform.sh
bash -n /Users/ef/crowny-engine/엔진.sh
# 3) core 모듈에 플랫폼.한선 위임 반영 → 각 재컴파일 (2>/dev/null 필수)
for f in 돈실행 달란트서버 패키지빌드판정 학습 룩업; do
/Users/ef/CrownyOS/crownyc/hanseonc_high /Users/ef/crowny-engine/core/$f.한선 \
> /Users/ef/crowny-engine/core/$f.toau 2>/dev/null && echo "OK $f"
done
# 4) win/ 진입점 + deploy/ systemd + crowny-install.sh 작성
# 5) 패키지빌드.sh 실행 → dist-mac/ dist-win/ dist-linux/ 생성 (CRLF: .cmd/.bat만)
bash /Users/ef/crowny-engine/패키지빌드.sh # DRYRUN, 기존 dist/ 무접촉
# 6) 검증: 제곱합=385 자체검사 (3 dist 모두)
# mac: ./dist-mac/bin/crownyc run <시험.toau>
# win: crowny-win-pkg/bin/crownyc.exe run <시험.toau> (또는 mingw 크로스 재확인)
권장 착수 순서 (의존도)
core/플랫폼.한선+lib/platform.sh(다른 모든 변경의 전제) — P0/Users/ef하드코딩 → 환경변수 (돈실행/달란트서버, 포터빌리티.한선 패턴 재사용) — P0- flock/sha256/date를 플랫폼.한선 위임 — P1
win/엔진.cmd(Git Bash 경로) +crowny-start.cmd재사용 → dist-win 즉시 가동 — P1- deploy systemd + crowny-install.sh (linux 기획) — P2
패키지빌드.sh3종 산출 + CI 매트릭스 — P2
core/플랫폼.한선 + lib/platform.sh 두 파일로 격리하는 것이다. 헌법 정합(한선씨 우선)을 위해 명령 매핑은 셸이 아닌 core/플랫폼.한선을 SSOT로 둔다.