Cheondi
개발 · Unity

빌드 전처리기와 기능 노출

플랫폼별 전처리 분기 때문에 특정 빌드에서만 기능이 빠진 문제를 빌드 조합별로 추적한 기록입니다.

  • #unity
  • #build
  • #preprocessor

에디터와 Android 개발 빌드에서는 보이던 메뉴가 배포용 빌드에서 사라졌다. 서버 권한과 설정을 확인했지만 값은 같았다. 코드를 더 따라가니 컴파일 전처리 조건 안에서 해당 기능 등록 자체가 제외되고 있었다. 플랫폼 조건과 개발 빌드 조건이 겹쳐 의도보다 좁은 조합에서만 코드가 들어갔다.

실행 중 if와 달리 전처리 분기는 빌드 결과에서 코드가 아예 사라질 수 있었다.

실제 빌드 조합으로 확장한 조건식

긴 전처리 식을 눈으로만 읽지 않고 표로 만들었다.

#if UNITY_ANDROID && DEVELOPMENT_BUILD || UNITY_EDITOR
RegisterFeature();
#endif

연산 우선순위와 의도를 명확히 하도록 괄호를 사용하고, 정말 플랫폼 제약인지 개발 편의 조건인지 분리했다.

Editor / Dev / Release
Android Dev / Android Release
WebGL Dev / WebGL Release

각 조합에서 기능 포함 여부를 예상하고 빌드 로그와 비교했다.

어댑터 내부의 플랫폼 차이

기능 전체를 전처리기로 감싸면 등록 누락을 발견하기 어려웠다. 공통 기능은 항상 등록하고 플랫폼에서 지원하지 않는 작은 연결 부분만 분기했다.

IShareBridge bridge = PlatformBridgeFactory.CreateShareBridge();
featureRegistry.Register(new ShareFeature(bridge));

지원하지 않는 구현은 명확한 NotSupported 결과를 반환해 UI가 상태를 설명할 수 있게 했다.

빌드 결과의 기능 포함 기록

앱 시작 로그에 공개 가능한 빌드 채널, 플랫폼, 기능 플래그 목록을 남겼다. 사용자 정보나 비밀 설정은 포함하지 않았다. 특정 빌드에서 기능이 빠졌을 때 서버와 클라이언트 설정을 빠르게 구분할 수 있었다.

릴리스에 가까운 설정의 빌드를 자동 또는 정기적으로 만들어 개발 빌드만 성공하는 상황도 줄였다.

컴파일 조건의 테스트 범위

전처리기는 편리했지만 보이지 않는 제품 변형을 만들었다. 코드 리뷰에서 한 경로를 읽는 것만으로 모든 빌드를 확신할 수 없었다.

이 경험 뒤 전처리 조건을 추가할 때 지원 조합과 제외 이유를 적고, 핵심 기능은 가능한 한 런타임 추상화로 옮긴다. 빌드 성공뿐 아니라 필요한 기능이 실제 산출물에 들어갔는지도 확인하게 됐다.

후속 확인 항목

작업 당시에는 눈앞의 오류를 먼저 고쳤지만, 이후 기술 문서와 맞춰 보며 확인 순서를 조금 더 구체화했다.

SLSA v1.0은 빌드가 성공했는가와 그 산출물이 어떤 소스·빌더·과정에서 나왔는가를 구분한다. 로컬에서 만들어진 파일과 배포 서버 산출물의 이름이 같아도 출처가 같다고 볼 수 없다.

그래서 버전 문자열만 기록하기보다 소스 커밋, 빌드 설정, 의존성 잠금 파일, 산출물 digest를 한 묶음으로 남기는 편이 재현과 장애 분석에 도움이 된다.

다음에 빌드 전처리기와 기능 노출 같은 문제를 보면 아래 순서부터 확인하려고 한다.

  • 직접·전이 의존성 전체 그래프
  • 소스 커밋과 산출물 digest
  • 깨끗한 환경의 재현 빌드
  • release 축소·서명 설정 검증

캐시가 있는 내 PC에서 한 번 성공한 결과보다 깨끗한 환경에서 같은 입력으로 같은 의존성을 해석하는지가 더 강한 증거다.

공식 참고 자료