어느 단계에서 실패했는지 먼저 구분하기

C나 C++ 프로젝트에서 undefined reference라는 메시지를 만나면 함수 구현이 잘못 동작한다고 생각하기 쉽습니다. 하지만 일반적으로 이 메시지는 실행 전에 링크 과정에서 필요한 정의를 찾지 못했다는 뜻입니다. 소스가 문법 검사를 통과해도 최종 실행 파일을 만드는 단계에서는 여러 오브젝트와 라이브러리의 기호를 연결해야 합니다. 따라서 디버거에 파일을 열기 전에 빌드가 성공했는지부터 확인해야 합니다. 이전 빌드의 실행 파일이 폴더에 남아 있으면 실패한 새 코드가 실행되는 것처럼 착각할 수 있습니다. 마지막 성공 파일과 현재 빌드 결과를 구분하세요.

선언과 정의가 모두 있는지 보기

헤더에 함수 선언이 있다고 실제 구현이 링크되는 것은 아닙니다. 구현이 들어 있는 소스 파일이 빌드 대상에 포함됐는지, 해당 파일에서 기대한 이름의 함수를 정의했는지 확인합니다. C++에서는 네임스페이스, 인수 타입, const 같은 선언의 차이가 다른 기호로 이어질 수 있습니다. 템플릿 정의를 사용하는 위치에서 볼 수 없거나 필요한 인스턴스가 만들어지지 않은 경우에도 링크 문제가 생길 수 있습니다. 오류 메시지에 나온 기호를 축약하지 말고 전체 형태로 읽으세요. 비슷한 함수가 있다는 사실보다 링크가 찾는 정확한 정의가 생성됐는지가 중요합니다.

라이브러리 파일과 링크 명령 점검하기

외부 라이브러리의 함수를 쓴다면 헤더 경로뿐 아니라 링크할 라이브러리도 필요합니다. 헤더를 찾았기 때문에 컴파일은 되지만 실제 함수 정의를 제공하는 파일이 빠질 수 있습니다. 라이브러리의 아키텍처와 도구 체인 호환성도 확인하세요. 일부 링크 방식에서는 라이브러리를 나열한 순서가 결과에 영향을 주므로 빌드 시스템이 실제로 실행한 전체 링크 명령을 보는 것이 좋습니다. 인터넷에서 찾은 옵션을 무작정 추가하기보다 어떤 파일이 어떤 기호를 제공해야 하는지 대응시켜 봅니다. 필요한 파일을 추가한 뒤에도 다른 오류가 나오면 새 오류를 이전 것과 구분해 조사합니다.

빌드 성공 후에 디버깅을 시작하기

링크 오류를 수정했다면 새 실행 파일이 생성됐는지 확인하고 DBG Desk에서 그 파일을 다시 여세요. 디버깅 세션에 이전 파일이 남아 있으면 수정 전 결과를 보게 될 수 있습니다. 최소 재현을 만들 때는 선언이 있는 파일, 정의가 있는 파일, 호출하는 파일을 작게 나누고 실제 빌드 명령도 함께 남기면 원인이 드러납니다. 같은 오류를 보고할 때는 실행 로그보다 컴파일러와 링커의 메시지, 도구 버전, 빌드 구성 정보가 더 중요합니다. 빌드 단계의 실패와 실행 중의 실패를 구분하면 조사할 도구와 자료를 빠르게 선택할 수 있습니다.

두 소스 파일로 재현해 보기

main.c에서 helper를 호출하고 helper.c에 그 구현이 있는 작은 프로젝트를 만들었다고 가정합니다. main.c만 컴파일해 링크하면 구현을 포함하지 않았기 때문에 필요한 정의를 찾지 못할 수 있습니다. 두 파일을 함께 빌드했을 때 해결되는지 보면 함수 내부 계산과 무관한 문제임을 확인할 수 있습니다. 빌드 시스템을 쓰는 프로젝트에서는 파일이 폴더에 존재하는 것과 실제 대상에 포함되는 것이 다릅니다. 설정을 수정한 뒤 출력된 명령에 helper의 오브젝트가 들어갔는지 확인하세요. 폴더를 통째로 지우고 다시 시도하기 전에 빠진 입력을 설명할 수 있는 상태로 만드는 편이 좋습니다.

두 소스 파일을 함께 빌드
gcc -g -O0 main.c helper.c -o example.exe