링커 도구 오류 LNK2001
해결되지 않은 외부 기호 "symbol"
컴파일된 코드는 기호를 참조하거나 호출합니다. 기호는 링커에서 검색한 라이브러리 또는 개체 파일에 정의되지 않습니다.
이 오류 메시지 뒤에는 치명적인 오류 LNK1120이 표시됩니다. 오류 LNK1120 해결하려면 먼저 모든 LNK2001 수정하고 오류를 LNK2019.
LNK2001 오류를 가져오는 방법에는 여러 가지가 있습니다. 모두 링커가 확인할 수 없는 함수 또는 변수에 대한 참조를 포함하거나 정의를 찾습니다. 컴파일러는 코드가 기호를 선언하지 않는 경우를 식별할 수 있지만, 기호를 정의하지 않을 때는 식별할 수 없습니다. 정의가 다른 원본 파일 또는 라이브러리에 있을 수 있기 때문입니다. 코드가 기호를 참조하지만 정의되지 않은 경우 링커는 오류를 생성합니다.
해결되지 않은 외부 기호란?
기호는 함수 또는 전역 변수의 내부 이름입니다. 컴파일된 개체 파일 또는 라이브러리에 사용되거나 정의된 이름의 형식입니다. 전역 변수는 스토리지가 할당된 개체 파일에 정의됩니다. 함수는 함수 본문에 대해 컴파일된 코드가 배치되는 개체 파일에 정의됩니다. 외부 기호는 하나의 개체 파일에서 참조되지만 다른 라이브러리 또는 개체 파일에 정의됩니다. 내보낸 기호는 개체 파일 또는 이를 정의하는 라이브러리에서 공개적으로 사용할 수 있게 하는 기호입니다.
애플리케이션 또는 DLL을 만들려면 사용되는 모든 기호에 정의가 있어야 합니다. 링커는 각 개체 파일에서 참조하는 모든 외부 기호에 대해 일치하는 정의를 확인하거나 찾아야 합니다. 링커는 외부 기호를 확인할 수 없을 때 오류를 생성합니다. 즉, 링커가 연결된 파일에서 일치하는 내보낸 기호 정의를 찾을 수 없습니다.
컴파일 및 링크 문제
이 오류는 다음과 같이 발생할 수 있습니다.
프로젝트에 라이브러리에 대한 참조가 누락된 경우(. LIB) 또는 개체(. OBJ) 파일. 이 문제를 해결하려면 필요한 라이브러리 또는 개체 파일에 대한 참조를 프로젝트에 추가합니다. 자세한 내용은 lib Files를 링커 입력으로 참조하세요.
프로젝트에 라이브러리에 대한 참조가 있는 경우(. LIB) 또는 개체(. OBJ) 다른 라이브러리의 기호가 필요한 파일입니다. 종속성을 유발하는 함수를 호출하지 않는 경우에도 발생할 수 있습니다. 이 문제를 해결하려면 프로젝트에 다른 라이브러리에 대한 참조를 추가합니다. 자세한 내용은 링크에 대한 클래식 모델 이해: 타고 함께 기호를 복용을 참조하세요.
/NODEFAULTLIB 또는 /Zl 옵션을 사용하는 경우 이러한 옵션을 지정하면 필요한 코드가 포함된 라이브러리는 명시적으로 포함하지 않는 한 프로젝트에 연결되지 않습니다. 이 문제를 해결하려면 링크 명령줄에 사용하는 모든 라이브러리를 명시적으로 포함합니다. 이러한 옵션을 사용할 때 누락된 CRT 또는 표준 라이브러리 함수 이름이 많이 표시되는 경우 링크에 CRT 및 표준 라이브러리 DLL 또는 라이브러리 파일을 명시적으로 포함합니다.
/clr 옵션을 사용하여 컴파일하는 경우 에 대한 참조
.cctor
가 누락되었을 수 있습니다. 이 문제를 해결하는 방법에 대한 자세한 내용은 혼합 어셈블리 초기화를 참조 하세요.애플리케이션의 디버그 버전을 빌드할 때 릴리스 모드 라이브러리에 연결하는 경우 마찬가지로 /MTd 또는 /MDd 옵션을 사용하거나 릴리스 라이브러리를 정의
_DEBUG
한 다음 릴리스 라이브러리에 연결하는 경우 다른 문제 중에서도 해결되지 않은 외부가 많이 발생할 수 있습니다. 릴리스 모드 빌드를 디버그 라이브러리와 연결하면 비슷한 문제가 발생합니다. 이 문제를 해결하려면 디버그 빌드의 디버그 라이브러리와 소매 빌드의 소매 라이브러리를 사용해야 합니다.코드가 한 라이브러리 버전의 기호를 참조하지만 다른 버전의 라이브러리를 연결하는 경우 일반적으로 다른 버전의 컴파일러용으로 빌드된 개체 파일이나 라이브러리를 혼합할 수 없습니다. 한 버전으로 제공되는 라이브러리에는 다른 버전에 포함된 라이브러리에서 찾을 수 없는 기호가 포함될 수 있습니다. 이 문제를 해결하려면 함께 연결하기 전에 동일한 버전의 컴파일러를 사용하여 모든 개체 파일 및 라이브러리를 빌드합니다. 자세한 내용은 Visual Studio 버전 간의 C++ 이진 호환성을 참조하세요.
라이브러리 경로가 만료된 경우 도구 > 옵션 > 프로젝트 > VC++ 디렉터리 대화 상자의 라이브러리 파일 선택에서 라이브러리 검색 순서를 변경할 수 있습니다. 프로젝트의 속성 페이지 대화 상자의 링커 폴더에는 만료될 수 있는 경로도 포함될 수 있습니다.
새 Windows SDK가 설치된 경우(아마도 다른 위치로) 새 위치를 가리키도록 라이브러리 검색 순서를 업데이트해야 합니다. 일반적으로 새 SDK 포함 및 lib 디렉터리에 대한 경로를 기본 Visual C++ 위치 앞에 배치해야 합니다. 또한 포함된 경로가 포함된 프로젝트는 여전히 유효하지만 오래된 경로를 가리킬 수 있습니다. 다른 위치에 설치된 새 버전에서 추가된 새 기능에 대한 경로를 업데이트합니다.
명령줄에서 빌드하고 사용자 고유의 환경 변수를 만든 경우 도구, 라이브러리 및 헤더 파일의 경로가 일관된 버전으로 이동했는지 확인합니다. 자세한 내용은 명령줄에서 MSVC 도구 집합 사용을 참조하세요.
코딩 문제
이 오류는 다음과 같은 이유로 인해 발생할 수 있습니다.
소스 코드 또는 모듈 정의(.def) 파일의 대/소문자를 일치하지 않습니다. 예를 들어 한 C++ 원본 파일에서 변수
var1
의 이름을 지정하고 다른 파일에서와 같이VAR1
액세스하려고 하면 이 오류가 생성됩니다. 이 문제를 해결하려면 일관되게 맞춤법 및 대/소문자 이름을 사용합니다.함수 인라인을 사용하는 프로젝트입니다. 헤더 파일이 아닌 소스 파일에서와 같이
inline
함수를 정의할 때 발생할 수 있습니다. 인라인 함수를 정의하는 소스 파일 외부에서는 인라인 함수를 볼 수 없습니다. 이 문제를 해결하려면 선언된 헤더에서 인라인 함수를 정의합니다.C 함수에 대한 선언을 사용하지 않고 C++ 프로그램에서 C 함수를
extern "C"
호출합니다. 컴파일러는 C 및 C++ 코드에 대해 서로 다른 내부 기호 명명 규칙을 사용합니다. 내부 기호 이름은 기호를 확인할 때 링커가 찾는 이름입니다. 이 문제를 해결하려면 C++ 코드에 사용되는 모든 C 함수 선언에 래퍼를 사용하여extern "C"
컴파일러가 해당 기호에 대해 C 내부 명명 규칙을 사용하도록 합니다. 컴파일러 옵션 /Tp 및 /Tc 를 사용하면 파일 이름 확장명과 관계없이 컴파일러가 각각 C++ 또는 C로 파일을 컴파일합니다. 이러한 옵션을 사용하면 내부 함수 이름이 예상과 다를 수 있습니다.외부 링크가 없는 함수 또는 데이터를 참조하려는 시도입니다. C++에서는 명시적으로 .로 지정하지 않는 한 인라인 함수와
const
데이터에 내부 링크가extern
있습니다. 이 문제를 해결하려면 정의 소스 파일 외부에서 참조되는 기호에 명시적extern
선언을 사용합니다.누락된 함수 본문 또는 변수 정의입니다. 이 오류는 코드에서 변수, 함수 또는 클래스를 선언하지만 정의하지 않는 경우에 일반적입니다. 컴파일러는 오류 없이 개체 파일을 생성하기 위해 함수 프로토타입 또는
extern
변수 선언만 필요하지만, 함수 코드나 변수 공간이 예약되어 있지 않기 때문에 링커는 함수 호출 또는 변수에 대한 참조를 확인할 수 없습니다. 이 문제를 해결하려면 연결하는 원본 파일 또는 라이브러리에서 참조된 모든 함수와 변수를 정의해야 합니다.함수 정의에 있는 것과 일치하지 않는 반환 및 매개 변수 형식 또는 호출 규칙을 사용하는 함수 호출입니다. C++ 개체 파일 에서 이름 장식 은 함수의 호출 규칙, 클래스 또는 네임스페이스 범위 및 반환 및 매개 변수 형식을 인코딩합니다. 인코딩된 문자열은 마지막으로 데코레이팅된 함수 이름의 일부가 됩니다. 이 이름은 링커가 다른 개체 파일에서 함수 호출을 확인하거나 일치시킬 때 사용됩니다. 이 문제를 해결하려면 함수 선언, 정의 및 호출이 모두 동일한 범위, 형식 및 호출 규칙을 사용하는지 확인합니다.
클래스 정의에 함수 프로토타입을 포함하지만 함수 구현을 포함하지 않는 경우 호출하는 C++ 코드입니다. 이 문제를 해결하려면 호출하는 모든 클래스 멤버에 대한 정의를 제공해야 합니다.
추상 기본 클래스에서 순수 가상 함수를 호출하려는 시도입니다. 순수 가상 함수에는 기본 클래스 구현이 없습니다. 이 문제를 해결하려면 호출된 모든 가상 함수가 구현되었는지 확인합니다.
해당 함수 범위 외부의 함수(지역 변수) 내에서 선언된 변수를 사용하려고 합니다. 이 문제를 해결하려면 범위에 없는 변수에 대한 참조를 제거하거나 변수를 더 높은 범위로 이동합니다.
ATL 프로젝트의 릴리스 버전을 빌드할 때 CRT 시작 코드가 필요하다는 메시지를 생성합니다. 이 문제를 해결하려면 다음 중 하나를 수행합니다.
CRT 시작 코드를 포함할 수 있도록 전처리기 정의 목록에서 제거
_ATL_MIN_CRT
합니다. 자세한 내용은 일반 속성 페이지(프로젝트)를 참조하세요.가능하면 CRT 시작 코드가 필요한 CRT 함수에 대한 호출을 제거합니다. 대신 Win32 등가를 사용합니다. 예를 들어
strcmp
대신lstrcmp
을 사용합니다. CRT 시작 코드가 필요한 알려진 함수는 문자열 및 부동 소수점 함수 중 일부입니다.
일관성 문제
현재 컴파일러 공급업체 간 또는 동일한 컴파일러의 다른 버전 간에 C++ 이름 장식에 대한 표준이 없습니다. 다른 컴파일러로 컴파일된 개체 파일은 동일한 명명 체계를 사용하지 않을 수 있습니다. 연결하면 오류 LNK2001 발생할 수 있습니다.
다른 모듈에서 인라인 및 비인라인 컴파일 옵션을 혼합하면 LNK2001 발생할 수 있습니다. 함수 인라인이 켜져 있지만(/Ob1 또는 /Ob2) 함수를 설명하는 해당 헤더 파일에 인라인이 꺼져 있는 C++ 라이브러리가 만들어지면(키워드 없음 inline
) 이 오류가 발생합니다. 이 문제를 해결하려면 다른 소스 파일에 포함하는 헤더 파일의 함수 inline
를 정의합니다.
컴파일러 지시문을 사용하는 #pragma inline_depth
경우 2 이상의 값을 설정했는지 확인하고 /Ob1 또는 /Ob2 컴파일러 옵션도 사용해야 합니다.
리소스 전용 DLL을 만들 때 LINK 옵션 /NOENTRY를 생략하면 이 오류가 발생할 수 있습니다. 이 문제를 해결하려면 링크 명령에 /NOENTRY 옵션을 추가합니다.
이 오류는 프로젝트에서 잘못된 /SUBSYSTEM 또는 /ENTRY 설정을 사용하는 경우에 발생할 수 있습니다. 예를 들어 콘솔 애플리케이션을 작성하고 /SUBSYSTEM:WINDOWS를 지정하면 해결되지 않은 외부 오류가 발생 WinMain
합니다. 이 문제를 해결하려면 옵션과 프로젝트 형식을 일치해야 합니다. 이러한 옵션 및 진입점에 대한 자세한 내용은 /SUBSYSTEM 및 /ENTRY 링커 옵션을 참조하세요.
내보낸 .def 파일 기호 문제
이 오류는 .def 파일에 나열된 내보내기를 찾을 수 없는 경우에 발생합니다. 내보내기가 없거나, 철자가 잘못되었거나, C++ 데코레이팅된 이름을 사용하기 때문일 수 있습니다. .def 파일은 데코레이팅된 이름을 포함하지 않습니다. 이 문제를 해결하려면 불필요한 내보내기를 제거하고 내보낸 기호에 선언을 사용합니다 extern "C"
.
데코레이팅된 이름을 사용하여 오류 찾기
C++ 컴파일러 및 링커는 name-mangling이라고도 하는 이름 장식을 사용합니다. 이름 장식은 기호 이름의 변수 형식에 대한 추가 정보를 인코딩합니다. 함수의 기호 이름은 반환 형식, 매개 변수 형식, 범위 및 호출 규칙을 인코딩합니다. 이 데코레이팅된 이름은 링커가 외부 기호를 확인하기 위해 검색하는 기호 이름입니다.
함수 또는 변수의 선언이 함수 또는 변수의 정의와 정확히 일치하지 않으면 링크 오류가 발생할 수 있습니다. 그 이유는 어떤 차이가 일치시킬 기호 이름의 일부가 되기 때문입니다. 호출 코드와 정의 코드 모두에서 동일한 헤더 파일을 사용하는 경우에도 오류가 발생할 수 있습니다. 발생할 수 있는 한 가지 방법은 다른 컴파일러 플래그를 사용하여 소스 파일을 컴파일하는 경우입니다. 예를 들어 코드가 호출 규칙을 사용하도록 __vectorcall
컴파일되지만 클라이언트가 기본 __cdecl
또는 __fastcall
호출 규칙을 사용하여 호출할 것으로 예상되는 라이브러리에 연결합니다. 이 경우 호출 규칙이 다르기 때문에 기호가 일치하지 않습니다.
원인을 찾는 데 도움이 되도록 오류 메시지에는 두 가지 버전의 이름이 표시됩니다. 소스 코드에 사용되는 이름인 "친숙한 이름"과 데코레이팅된 이름(괄호)을 모두 표시합니다. 데코레이트된 이름을 해석하는 방법을 알 필요가 없습니다. 여전히 다른 데코레이팅된 이름을 검색하여 비교할 수 있습니다. 명령줄 도구는 필요한 기호 이름과 실제 기호 이름을 찾아 비교하는 데 도움이 될 수 있습니다.
DUMPBIN 명령줄 도구의 /EXPORTS 및 /SYMBOLS 옵션은 여기에서 유용합니다. .dll 및 개체 또는 라이브러리 파일에 정의된 기호를 검색하는 데 도움이 될 수 있습니다. 기호 목록을 사용하여 내보낸 데코레이트된 이름이 링커가 검색하는 데코레이팅된 이름과 일치하는지 확인할 수 있습니다.
경우에 따라 링커는 기호의 데코레이팅된 이름만 보고할 수 있습니다. UNDNAME 명령줄 도구를 사용하여 데코레이팅된 이름의 디코레이트되지 않은 형식을 가져올 수 있습니다.
추가 리소스
자세한 내용은 Stack Overflow 질문 "정의되지 않은 참조/확인되지 않은 외부 기호 오류란 무엇이며 어떻게 해결합니까?"를 참조하세요.