0 warnings는 아무것도 컴파일하지 않았다는 뜻일 수 있다

build가 성공했다.

warning은 0건이었다.

기분 좋게 “warning 없음”이라고 적을 뻔했다.

그런데 compiler가 대상 Swift file을 읽지 않았다.

incremental build가 모든 것을 up-to-date로 판단했다.

0은 code의 상태가 아니었다.

이번 build가 수행한 compiler work의 상태였다.

warning은 compile의 부산물이다

compiler warning을 관찰하려면 compiler가 source를 읽어야 한다.

incremental build는 바뀌지 않았다고 판단한 work를 건너뛸 수 있다.

그 경로에서는 이전 compile에서 보였던 diagnostic을 새로 출력하지 않을 수 있다.

따라서 log에 warning이 없다는 사실만으로 source가 warning-free라고 결론 내릴 수 없다.

먼저 확인할 질문이 있다.

이번 build에서 검증 대상 file이 실제로 컴파일됐는가?

이 질문의 답이 없으면 warning count의 coverage도 없다.

-quiet은 coverage를 추가하지 않는다

현재 Xcode 26.6의 xcodebuild -help는 -quiet을 이렇게 설명한다.

do not print any output except for warnings and errors

이 option은 noise를 줄인다.

compiler가 더 많은 file을 읽게 하지는 않는다.

incremental build가 compile step을 생략하고 warning도 없다면 quiet output은 완벽하게 비어 보일 수 있다.

그 빈 화면은 “모든 source를 검사했다”는 report가 아니다.

출력 filter를 통과한 diagnostic이 없었다는 관찰이다.

green build와 warning audit은 질문이 다르다

일반 build gate는 product를 만들 수 있는지 확인한다.

warning audit은 특정 scope를 compiler가 읽었고 어떤 diagnostic을 냈는지 확인한다.

build success는 첫 질문에 답할 수 있다.

두 번째 질문에는 compile coverage가 추가로 필요하다.

같은 xcodebuild를 실행했다고 두 gate가 같은 evidence를 갖는 것은 아니다.

gate 이름보다 reader가 실제로 읽은 file을 봐야 한다.

SwiftCompile entry를 먼저 찾는다

Swift source가 이번 run에서 compiler 입력이 됐다면 build log에 compile activity가 남아야 한다.

historical post-mortem에서는 touched file에 대응하는 실제 SwiftCompile entry를 확인하라는 규칙을 남겼다.

순서는 warning grep보다 compile coverage가 먼저다.

1. 대상 source scope를 정한다.
2. build log에서 그 scope의 SwiftCompile activity를 확인한다.
3. compiler diagnostic을 읽는다.
4. warning count를 기록한다.

2번이 비어 있으면 4번은 보류한다.

“0 warnings” 대신 “대상 file compile 미확인”이라고 써야 한다.

clean build가 필요한 이유

현재 xcodebuild(1) manual은 clean action을 build root의 products와 intermediate files를 제거하는 동작으로 설명한다.

clean  Remove build products and intermediate files from the build root (SYMROOT).

그래서 full warning audit에서는 clean build가 단순한 의식이 아니다.

incremental cache가 compile coverage를 비워 버리는 경로를 줄이는 방법이다.

일반적인 command 모양은 다음과 같다.

xcodebuild \
  -workspace <workspace> \
  -scheme <scheme> \
  -destination <destination> \
  clean build

project, scheme, destination은 실제 대상에 맞게 정해야 한다.

clean만 붙였다고 끝나지 않는다

clean action을 썼다는 사실도 proxy가 될 수 있다.

잘못된 scheme을 골랐을 수 있다.

검증하려던 target이 scheme build action에 없을 수 있다.

build가 중간에 실패해 warning audit scope에 도달하지 못했을 수도 있다.

그러니 clean build 뒤에도 SwiftCompile coverage를 읽는다.

command shape가 아니라 실제 activity가 property를 증명한다.

warning count에는 scope를 붙인다

“warning 0”은 너무 짧다.

다음 정보가 있어야 다른 사람이 같은 질문을 다시 만들 수 있다.

revision:       source revision
scheme:         selected scheme
configuration:  build configuration
destination:    platform and target
clean:          whether intermediates were removed
compiled_scope: files or targets observed in SwiftCompile activity
warning_reader: exact diagnostic extraction command
observed_at:    timestamp

이 중 compiled scope가 빠지면 warning count는 reader coverage를 숨긴다.

숫자가 0일수록 이 metadata가 더 중요하다.

incremental build는 개발에는 유용하다

문제는 incremental build 자체가 아니다.

빠른 iteration을 위해 필요한 최적화다.

문제는 빠른 build의 출력을 full audit의 evidence로 이름 붙이는 일이다.

목적이 “변경 후 앱이 다시 빌드되는가”라면 incremental build가 적절할 수 있다.

목적이 “이 scope의 compiler warning이 몇 개인가”라면 reader coverage가 다른 command가 필요하다.

같은 tool이라도 acceptance property에 따라 실행 조건이 달라진다.

known-warning fixture로 gate를 깨 본다

새 warning detector를 만들었다면 positive fixture가 필요하다.

throwaway target이나 통제된 fixture에 의도한 warning을 하나 둔다.

clean build에서 detector가 그것을 보고 실패하는지 확인한다.

그다음 fixture를 제거하고 통과를 확인한다.

warning이 없는 code만 보고 만든 detector는 compiler가 아무것도 읽지 않아도 통과할 수 있다.

실패를 한 번 관찰해야 pass가 무엇을 읽었는지 알 수 있다.

이 글의 근거는 현재 build 결과가 아니다

이 글은 historical post-mortem, 전역 evidence 규칙, 현재 xcodebuild -help, xcodebuild(1) manual을 근거로 썼다.

현재 어떤 project의 warning count도 evidence로 제시하거나 주장하지 않는다.

다만 warning count를 주장하기 위해 필요한 evidence boundary를 설명한다.

실전 규칙

incremental build의 warning 0건은 source warning 0건과 같지 않을 수 있다.

warning을 세기 전에 대상 file의 실제 SwiftCompile activity를 확인한다.

full warning audit에는 clean build를 사용하고, clean 뒤에도 coverage를 읽는다.

scheme, configuration, destination, revision, compiled scope를 count와 함께 기록한다.

positive warning fixture로 detector가 실제로 실패하는지 먼저 확인한다.

compile coverage가 없으면 0을 쓰지 말고 검증 보류를 기록한다.

마지막으로

warning이 없었던 것과 warning을 찾지 않은 것은 다르다.

둘 다 terminal에는 조용하게 보일 수 있다.

compiler가 무엇을 읽었는지 확인하는 순간에만 그 침묵의 이름을 정할 수 있다.