hello, robot

빌드가 실패하면 손이 먼저 코드로 가요. 그런데 로봇 쪽 작업에서 빌드가 깨지는 자리는 대개 코드가 아니에요. 무엇이 깔려 있는지, 그리고 남아 있는 상태가 최신인지, 이 둘이 훨씬 흔해요.

장치도 파일이에요

먼저 이 세계의 기본 추상화 하나를 짚고 갈게요. 모든 것이 파일이에요.

디스크에 저장된 문서만이 아니라 하드웨어도 파일이에요. 시리얼 포트에 꽂은 보드는 특정 경로의 파일로 열리고, 카메라도 그래요. 그래서 시리얼 통신이 파일 읽기·쓰기와 똑같은 순서로 처리돼요. 열고, 읽고, 쓰고, 닫아요.

이게 로봇 개발에서 중요한 이유가 있어요. 센서, 모터 드라이버, 통신 포트가 전부 같은 방식으로 열려요. 파일 다루는 법 하나만 알면 이질적인 하드웨어를 같은 관용구로 접근할 수 있죠.

여기서 파생되는 첫 번째 함정이 권한이에요. 스크립트나 실행 파일이 실행 권한이 없다고 거부되면 십중팔구 실행 비트가 빠진 거예요. 권한은 읽기·쓰기·실행 셋을 소유자, 그룹, 나머지에 각각 주는 구조인데, 파일을 복사하거나 압축을 풀면 이게 안 따라오는 경우가 있어요.

시리얼 포트도 마찬가지예요. 포트 파일에 접근 권한이 없어서 안 열리는데, 코드는 그냥 열기 실패로만 알려 주죠. 사용자를 해당 그룹에 넣는 것으로 해결하는데, 그룹 변경은 다시 로그인해야 반영돼요. 명령을 실행했는데 여전히 안 되는 이유가 이거예요.

소스는 있는데 라이브러리가 없어요

빌드 실패의 첫 번째 유형이에요.

빌드 설정 파일이 시스템에 깔린 라이브러리를 찾다가 실패하는 경우예요. 에러는 필요한 패키지를 못 찾았다고 나와요. 소스 코드는 멀쩡히 있는데, 그 코드가 의존하는 시스템 라이브러리가 안 깔린 거죠.

받아 온 소스가 이런 시스템 패키지를 요구하면 빌드 전에 깔아야 해요. 그리고 이걸 자동으로 해 주는 도구가 있어요. 소스 폴더를 훑어 선언된 의존성을 읽고 필요한 패키지를 설치해 주죠.

새 환경에서 남의 워크스페이스를 처음 빌드할 때 그 도구를 먼저 돌리는 게 순서예요. 안 돌리고 빌드하면 위 에러를 하나씩 만나며 손으로 깔게 되는데, 어차피 같은 목록이에요.

폴더를 옮겼더니 안 돼요

두 번째 유형이 더 헷갈려요.

소스 폴더의 이름을 바꾸거나 위치를 옮긴 뒤 빌드하면 존재하지 않는 디렉터리를 찾는다는 에러가 나요. 그런데 그 경로는 옛날 경로예요. 어디에도 그 경로를 적은 적이 없는데 말이죠.

범인은 남아 있는 빌드 산출물이에요. 빌드 시스템은 소스의 절대 경로를 캐시에 적어 둬요. 폴더를 옮기면 그 캐시가 낡아 버리는데, 캐시 파일이 수백 개라 눈에 잘 안 띄어요.

해법은 단순해요. 산출물 폴더 셋을 지우고 처음부터 다시 빌드해요. 이 폴더들은 어차피 버전 관리에 넣지 않는 것들이라 지워도 잃는 게 없어요.

증상이 특징적이라 한 번 겪으면 바로 알아봐요. 에러 메시지에 나오는 경로가 지금 구조와 다르면 캐시를 의심해요.

손으로 적은 목록은 조용히 낡아요

세 번째는 성격이 조금 다른데, 실전에서 자주 나와요.

빌드 대상 파일을 손으로 적은 목록으로 관리하면 파일을 새로 만들었을 때 목록에 안 들어가요. 에러가 안 나요. 그냥 그 파일이 빌드에서 조용히 빠져요.

파일 이름을 바꿨을 때는 더 나빠요. 목록에 있는 옛 이름은 이제 존재하지 않는 파일을 가리키는데, 설정에 따라 에러 없이 넘어가기도 해요. 결과물이 안 나오는데 빌드는 성공이라고 말하죠.

대안은 폴더를 훑어 자동으로 모으는 방식이에요. 다만 그냥 모으면 빌드하면 안 되는 파일까지 딸려 들어와요. 실행 진입점이 없는 파일이 섞이면 링크 단계에서 통째로 깨지죠.

그래서 규칙을 뒤집는 게 나아요. “빌드할 것을 고르는” 대신 “빌드하지 않을 것만 빼는” 거예요. 파일 앞머리에 표시를 두고 그 표시가 있으면 건너뛰는 식이면, 이름을 어떻게 바꿔도 판정이 안 흔들려요.

효과가 분명해요. 이러면 조용한 누락이 시끄러운 오검출로 바뀌어요. 실수하면 빌드가 깨지니 바로 알게 되죠. 빠진 걸 몇 주 뒤에 발견하는 것보다 훨씬 나아요.

물어볼 순서가 정해져 있어요

정리하면 빌드가 깨졌을 때 순서는 이래요.

무엇이 깔려 있는지를 먼저 봐요. 새 환경이거나 남의 소스면 이쪽이 압도적으로 흔해요. 다음으로 남아 있는 상태를 봐요. 폴더를 옮겼거나 이름을 바꿨다면 캐시예요. 그다음이 빌드 설정이고, 코드는 마지막이에요.

이 순서를 지키면 대부분 몇 분 안에 끝나요. 순서를 뒤집으면 멀쩡한 코드를 몇 시간씩 들여다보게 되고요. 에러 메시지가 코드 줄 번호를 가리켜도 원인이 거기 있다는 뜻은 아니거든요.

컴파일 단계와 링크 단계에서 각각 무엇이 깨지는지는 C++ 헤더와 소스 — 번역 단위가 만드는 에러에, 실행 중에 드러나는 문제를 잡는 도구는 C++ 도구와 디버깅 — 경고, sanitizer, gdb에 있어요.