| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- JavaScript
- 메타버스
- https://insightbook.co.kr/
- HANBIT Academy
- C
- 데이터 통신과 컴퓨터 네트워크
- 알고리즘
- 입출력과 사칙연산
- 일기
- 백준
- unity6
- 게임 수학
- 잡생각 정리글
- C++
- 이득우의 게임수학
- The Elements of Computing Systems 2/E
- Shimon Schocken
- Noam Nisan
- 전공자를 위한 C언어 프로그래밍
- BOJ
- hanbit.co.kr
- C#
- 주우석
- 이득우
- (주)책만
- 밑바닥부터 만드는 컴퓨팅 시스템 2판
- 생능출판
- 김진홍 옮김
- booksr.co.kr
- 박기현
- Today
- Total
cyphen156
CyphenEngine 개발기 #4 엔진 구조 리팩토링 본문
지난 개발기를 쓴 이후로 꽤 많은 시간이 흘렀다.
2026년 5월 27일부터 리팩토링을 시작했으니, 어느새 한 달이 조금 넘었다.
그간의 성과를 간략하게 자랑하자면, 엔진의 모듈화 설계를 어느 정도 실제 코드 위에 올려두는 데 성공했다.
물론 앞으로도 뜯어고쳐야 할 것은 한참 남아 있다.
그 이야기는 다음 글과 다다음 글에서도 조금 더 자세히 다루게 될 것이다.
이 글을 작성하는 현재 시점은 2026년 7월 2일이다.
지금까지 총 세 번의 큰 작업 브랜치가 있었고,
이전 개발기에서 말했던 #3의 최소 목표에 도달한 상태이기 때문에,
이제는 한 번쯤 정리할 때가 되었다고 판단하여 글을 쓴다.
이번 글은 세 브랜치 중 첫 번째인 리팩토링 브랜치에 관한 글이다.
크게 다섯 가지를 개편했다.
- 문서·인코딩 규약을 먼저 정리
- Build / Core / HAL / Platform / Runtime 계층 재정립
- 플랫폼 처리 책임을 Runtime 밖으로 밀어내기
- 플랫폼 정의 계층(PlatformDefine → framework → define) 분리
- 문자열·타입 규약 확정 (using + 리터럴 매크로)
글로 써 놓으니까 상당히 짧아 보이는데, 사실 이게 엔진 바닥을 한 번 다 들어냈다 다시 까는 작업이기도 하고,
모듈 간 책임과 경계를 근본부터 나눠주는 작업이어서 스트레스를 진짜 많이 받았었다.
이 브랜치 자체는 화면에 새로 그려지는 게 없다.
지금 화면에서 두 장의 jpg가 교차로 렌더링되는 것도 사실 다음 브랜치들의 결과물이지 이 브랜치의 성과가 아니다.
대신 그 아래 구조를 거의 다 갈아엎었다.

1. 인코딩과 문서 규약
제일 먼저 정리한 건 인코딩 정책을 정하는 것이었다.
기존 프로젝트는 소스가 EUC-KR(CP-949)로 저장돼 있었고, 줄바꿈도 CRLF였다.
지금까지는 Windows에서만 작업했으니 문제가 없었지만, Linux 빌드까지 가려면 이건 반드시 먼저 걷어야 했다.
EUC-KR(CP-949) → UTF-8 (65001)
CR/LF → LF
여기서 한 번 데인 게 있다.
git이 Windows 환경에서 커밋할 때 core.autocrlf로 LF를 다시 CRLF로 바꿔 버려서, 애써 LF로 맞춘 파일이 커밋 순간 되돌아갔다.
그래서 core.autocrlf를 꺼서 문서 규약을 고정했다.
커밋 메세지 규칙과 DevLog 구조도 이때 바꿨다.
DevLog/yy.mm.dd.txt → DevLog/yyyy/yy.mm.dd.txt
사소해 보이지만, 이런 규약을 초반에 못 박아 두지 않으면 나중에 파일이 수백 개로 늘었을 때 손을 못 댄다.
리팩토링의 시작이 화려한 구조 변경이 아니라 인코딩·줄바꿈 정리였다는 게, 지금 와서 보면 오히려 순서가 맞았다.
최근에 진행한 MultiAgentCrossReview에서 이때 만든 규칙 때문에 상당 부분 자동화가 가능해져서
내가 할 건 '대화 내용 요약해서 오늘 변경한 것 커밋 메세지로 포맷 맞춰서 써와'라고 하고 오류만 잡아내는 쪽으로 확 줄었다.
2. 플랫폼 책임을 Runtime에서 빼내기
과거에 구현했던 File과 Path를 보면서, 공통 API처럼 보이는 코드 안에 플랫폼 처리가 직접 들어와 있다고 생각했고, 이번 브랜치에서 그걸 실제로 걷어냈다.
먼저 폴더부터 정리했다. 그동안 Common과 Utility로 어정쩡하게 나뉘어 있던 것들을 Core 하나로 통합했다.
그리고 File / Path / Time의 공개 API는 Core/Public에 남기고, 그중 플랫폼에 종속되거나 ABI·빌드 추상화가 필요한 부분은 HAL/Public에 공통 계약(헤더)으로만 축소해 남겼다.
실제 구현은 Platform/{TargetPlatform} 아래에 각 플랫폼별로 — 단, 동일한 이름으로 — 두어, 빌드 시스템이 타겟에 맞는 구현을 정적으로 골라 빌드하도록 개선했다.
이 결정은 실제로 #2 브랜치 후반과 #3 브랜치에서 특히 크게 빛을 봤다.
Core/Public 공개 API 선언
HAL/Public 플랫폼 종속·ABI·빌드 추상화의 공통 계약(헤더)
Platform/{TargetPlatform} 각 플랫폼별 동일 이름 구현 (빌드가 정적 선택)
계약은 헤더 한 곳에 남고, 그 계약을 각 플랫폼 구현이 채운다.
CyphenEngine 본체도 이때 Runtime 쪽으로 내렸고,
그동안 LaunchWindows / LaunchLinux로 흩어져 있던 진입점을
Platform 밑 각 플랫폼의 Launch.cpp로 통일했다.
실행 진입점(플랫폼)과 엔진 본체(공통)의 경계가 이제 폴더 구조에서 바로 보인다.
3. 플랫폼 정의를 세 계층으로 나누기
define.h가 너무 많은 일을 하고 있다고 생각했다.
플랫폼 감지, 문자열 정책, 경로 구분자, 시간 타입, 로그 매크로, 싱글톤 매크로가 전부 한 파일에 들어 있었다.
이번에 이걸 세 계층으로 쪼갰다.
PlatformDefine.h 빌드 시스템이 주입한 TARGET_PLATFORM_* 을
엔진 내부 PLATFORM_* 로 확정
framework.h 플랫폼별 시스템 헤더 포함 + 플랫폼 타입 규약
define.h 순수 공통 매크로만
핵심은 빌드 시스템과 엔진 내부의 경계다.
빌드 쪽은 TARGET_PLATFORM_WINDOWS 같은 걸 주입하고, PlatformDefine.h가 그걸 받아 PLATFORM_WINDOWS = 1 같은 엔진 내부 기준으로 바꾼다. 엔진 코드는 이제 빌드 시스템이 뭘 어떻게 주입했는지 몰라도 되고, PLATFORM_* 하나만 보면 된다.
define.h는 이 과정에서 극단적으로 가벼워졌다. 플랫폼 분기는 전부 빠지고, 남은 건 엔진 문자 인코딩 ABI 계약뿐이다.
4. 타입은 using, 리터럴은 매크로
이 리팩토링 과정 중에 가장 오래 고민한 게 문자열이었다. 그리고 그 고민은 여전히 계속된다.
Windows는 wide, Linux는 narrow를 쓰려면 코드에 박히는 리터럴까지 플랫폼에 맞춰 바뀌어야 하는데, 그러자니 전부 매크로가 되어 버린다.
이번에 원칙을 확실히 갈랐다. 자료형은 using, 리터럴만 매크로.
using CString = std::wstring; // Windows
using CString = std::string; // Linux
using CChar = wchar_t; // Windows
using CChar = char; // Linux
CTEXT("감사합니다") // Windows: L"감사합니다" / Linux: "감사합니다"
타입은 컴파일러가 이해하는 using으로 충분하다.
매크로로 만들 이유가 없다.
반대로 리터럴 앞의 L은 using으로 못 붙이니, 여기만 CTEXT 매크로가 남는다.
딱 필요한 곳에만 매크로가 있는 구조다.
이름도 바꿨다.
TString / TChar / TTEXT(T-접두)를 CString / CChar / CTEXT(C-접두)로 바꿨다.
여기서 C는 그냥 접두어가 아니라, "엔진이 플랫폼·빌드 차이를 흡수해 하나의 공통 규칙으로 확정한 타입"이라는 표시다. Windows SDK의 TCHAR와 헷갈리지 않게, 그리고 그 이름이 정책을 담도록 골랐다.
5. PCH를 얇게, 그리고 빌드가 구현을 고른다
마지막으로 두 가지를 정리했다.
하나는 PCH다.
그동안 pch.h가 표준 라이브러리를 전부 끌어안고 있었는데, 이걸 다 걷어내고
각 구현 파일이 자기가 필요한 표준 헤더를 직접 include하는 원칙으로 바꿨다.
pch.h는 이제 전처리 환경 준비만 하고, include 순서만 고정한다.
PlatformDefine.h → framework.h → define.h
이러면 빌드는 조금 느려질 수 있다.
하지만 각 파일이 무엇에 의존하는지가 파일 안에서 바로 보이고, "이게 어디서 딸려 온 헤더지?" 하는 문제가 사라진다.
다른 하나는 지난 결론이기도 했던 "어느 cpp를 빌드에 넣을지"는 빌드 시스템이 정한다.
Windows 빌드 Platform/Windows/Private/*.cpp 포함, Linux 제외
Linux 빌드 Platform/Linux/Private/*.cpp 포함, Windows 제외
둘 다 넣으면 중복 정의, 하나도 안 넣으면 링크 에러.
Runtime 코드 안에서 #if PLATFORM_WINDOWS로 갈라 두면 당장은 편하지만, 결국 플랫폼 규약이 공통 코드로 새어 나온다.
빌드 타겟이 Windows면 Windows 구현만, Linux면 Linux 구현만 컴파일하는 게 자연스럽다고 판단했다.
정리하며
이번 브랜치의 결론을 추리면 이렇다.
- 인코딩·줄바꿈·문서 규약을 먼저 고정했다 (UTF-8 / LF).
- Common·Utility를 Core로 통합하고, 계층 경계를 폴더 구조에 새겼다.
- File / Path / Time은 공개 API(Core/Public) + 공통 계약(HAL/Public) + 플랫폼별 구현(Platform/*)으로 갈랐다.
- 진입점은 플랫폼별 Launch.cpp로, 엔진 본체는 Runtime으로 내렸다.
- 플랫폼 정의를 PlatformDefine → framework → define 세 계층으로 나눴다.
- 자료형은 using, 리터럴만 CTEXT 매크로. T-접두를 C-접두로 바꿨다.
- pch를 얇게, 표준 헤더는 각 파일이 직접 포함한다.
- 플랫폼 cpp 선택은 빌드 시스템의 책임으로 넘겼다.
화면상 달라진 건 거의 없지만, 이제 엔진은 "Windows에서만 도는 코드"가 아니라 "플랫폼을 빌드 시점에 고를 수 있는 코드"가 됐다.
Linux 빌드로 넘어갈 수 있는 바닥이 이때 깔린 셈이다.
다음 글에서는 이 위에 올라간 첫 번째 실체 렌더러 모듈을 엔진에 붙인 이야기(#2 브랜치)를 정리하려 한다.
모듈을 DLL로 떼어내고, 엔진이 그걸 로드해 화면에 무언가를 그리기까지의 과정이다.
┌─────────────────────────────┐
│ Runtime │ 엔진 본체 (CyphenEngine)
└─────────────┬───────────────┘
│ 사용
┌─────────────▼───────────────┐
│ Core / Public │ File · Path · Time · Logger (공개 API)
└─────────────┬───────────────┘
│ 계약
┌─────────────▼───────────────┐
│ HAL / Public │ PlatformFile · ModuleLoader · Launch (공통 계약)
└─────────────┬───────────────┘
│ 구현
┌────────────┐ ┌─────────────▼──────┐ ┌────────────────────┐
│ Build │─▶│ Platform/Windows │ │ Platform/Linux │ 동일 이름 구현
│ 정적 선택 │ │ /Private │ │ /Private │
└────────────┘ └────────────────────┘ └────────────────────┘
PlatformDefine→framework→define
TARGET_PLATFORM_* → PLATFORM_*
→ 빌드 타겟이 고른 한 플랫폼 구현만 컴파일·링크된다. Runtime은 플랫폼 규약을 모른다.'프로젝트 > CyphenEngine' 카테고리의 다른 글
| CyphenEngine 개발기 #6 크로스플랫폼 : Linux로 포팅하기 (0) | 2026.07.03 |
|---|---|
| CyphenEngine 개발기 #5 Renderer 모듈화 : DirectX11로 이미지 렌더하기 (0) | 2026.07.03 |
| 자체엔진 개발 중간 기록 : Dx11.dll -> Vulkan.dll 렌더러 모듈 교체 테스트 (0) | 2026.07.01 |
| 저장용 리눅스 명령어 (0) | 2026.06.29 |
| 자체엔진 개발 중간 기록 : 이미지 두장 교체해서 렌더링하기 (0) | 2026.06.25 |
