다음을 통해 공유


메타데이터 API 및 토큰 사용

업데이트: 2007년 11월

메타데이터 API는 C++에서 호출할 수 있습니다. 메타데이터 API가 사용되는 방식은 해당 API를 사용하는 클라이언트의 종류에 따라 부분적으로 달라집니다. 대부분의 메타데이터 API 클라이언트는 다음 두 범주 중 하나에 속합니다.

  • Visual C++ 2005의 컴파일러와 같이 중간 .obj 파일을 빌드한 다음 별도의 링커 단계를 수행하여 개별 컴파일 단위를 하나의 대상 이식 가능(PE) 파일로 병합하는 컴파일러

  • 빌드 전까지 모든 코드 및 데이터 구조를 도구 환경에서 관리하고, 빌드할 때는 PE 파일을 빌드하고 내보내는 작업을 한 단계로 수행하는 RAD(신속한 응용 프로그램 개발) 도구

다른 클라이언트에서는 이 두 가지 스타일의 중간에 해당하는 방식으로 메타데이터 API를 사용할 수 있습니다. 일부 도구에서는 메타데이터 엔진이 최적화를 수행할 수 있도록 하지만 토큰 재매핑 정보는 필요로 하지 않을 수 있습니다. 또는일부 토큰 형식에 대한 재매핑 정보만 필요로 할 수도 있습니다. 실제로 .obj 파일을 내보낼 때도 컴파일러에서 최적화를 수행하지 않는 경우가 있습니다.

컴파일 후 링크 스타일

컴파일 후 링크 스타일의 상호 작용에서 컴파일러 프런트 엔드는 IMetaDataDispenserEx API를 사용하여 메모리 내 메타데이터 범위를 설정한 다음 IMetaDataEmit API를 사용하여 메타데이터 토큰 개요에 설명된 메타데이터 추상화와 함께 사용할 수 있는 형식 및 멤버를 선언합니다. 그러나 구현 방식이 관리 코드인지 비관리 코드인지, MSIL 코드인지 네이티브 코드인지와 같은 메서드 구현 정보나 RVA(상대 가상 주소) 정보는 컴파일할 때 확인할 수 없으므로 프런트 엔드에서 이러한 정보를 제공할 수 없습니다. 대신 나중에 코드를 컴파일하여 PE 파일로 내보낼 때 백 엔드나 링커에서 이러한 정보를 제공해야 합니다.

그러나 백 엔드 도구에서는 메타데이터 바이너리의 대상 저장 크기에 대한 정보를 알고 있어야 PE 파일을 저장하는 데 필요한 공간을 남겨 둘 수 있으므로 여기에서 복잡한 문제가 발생합니다. 이 도구는 메서드 RVA 및 모듈 수준 정적 데이터 멤버 RVA가 알려지고 메타데이터로 내보내지기 전까지는 메타데이터 바이너리를 파일에 저장할 수 없습니다. 대상 저장 크기를 올바르게 계산하려면 메타데이터 엔진에서 먼저 저장 전 최적화를 수행해야 합니다. 이러한 최적화를 통해 대상 바이너리를 보다 작게 만들 수 있기 때문입니다. 해당 참조가 현재 범위에 선언된 형식 또는 멤버에 대한 참조일 경우, 최적화 작업에는 빠른 검색을 위한 데이터 구조 정렬이나 mdTypeRefmdMemberRef 토큰에 대한 최적화(초기 바인딩)가 포함될 수 있습니다. 이러한 종류의 최적화를 수행하면 도구에서 구현 및 RVA 정보를 내보내기 위해 다시 사용할 수 있어야 하는 메타데이터 토큰이 다시 매핑됩니다. 결과적으로 토큰 재매핑을 추적하려면 도구와 메타데이터 엔진이 상호 작용해야 합니다.

따라서 컴파일 중에 메타데이터를 유지하기 위한 호출 순서는 다음과 같습니다.

  1. IMetaDataEmit::SetHandler - 메타데이터 엔진에서 IID_IMapToken을 쿼리하는 데 사용할 수 있는 IUnknown 인터페이스를 제공합니다. IID_IMapToken은 토큰 재매핑을 클라이언트에 알리는 데 사용됩니다. SetHandler는 메타데이터 범위가 만들어진 후 IMetaDataEmit::GetSaveSize를 호출하기 전에 호출할 수 있습니다.

  2. IMetaDataEmit::GetSaveSize - 메타데이터 바이너리의 대상 저장 크기를 가져옵니다. GetSaveSizeIMetaDataEmit::SetHandler에 제공된 IMapToken 인터페이스를 사용하여 토큰 재매핑을 클라이언트에 알립니다. SetHandler를 사용하여 IMapToken 인터페이스를 제공하지 않은 경우에는 최적화가 수행되지 않습니다. 이 경우 중간 .obj 파일을 내보내는 컴파일러에서는 링크 및 병합 단계 후에 다시 수행해야 할 수 있는 불필요한 최적화 작업을 건너뛸 수 있습니다.

  3. IMetaDataEmit::Save - IMetaDataEmit::SetRVA 및 다른 IMetaDataEmit 메서드를 사용하여 최종 구현 메타데이터를 내보낸 후 메타데이터 바이너리를 저장합니다.

다음으로 복잡한 문제는 링커 단계에서 여러 컴파일 단위를 하나의 통합된 PE 파일로 병합할 때 나타납니다. 이 경우 메타데이터 범위를 병합해야 할 뿐 아니라 새 PE 파일이 내보내질 때 RVA도 다시 변경됩니다. 병합 단계에서 IMetaDataEmit::Merge 메서드는 가져오기 범위의 메타데이터 토큰을 내보내기 범위에 다시 매핑합니다. 이때 각 호출에서 가져오기 범위와 내보내기 범위가 각각 하나씩 사용됩니다. 또한 병합 프로세스에서는 연속적 오류가 발생할 수 있으며 이러한 오류는 클라이언트에 보낼 수 있어야 합니다. 병합이 완료된 후 최종 PE 파일을 내보내려면 IMetaDataEmit::GetSaveSize를 호출하고 토큰 재매핑을 다시 수행해야 합니다.

링커에서 메타데이터를 내보내고 저장하기 위한 호출 순서는 다음과 같습니다.

  1. IMetaDataEmit::SetHandler - 메타데이터 엔진에서 앞의 경우와 마찬가지로 IID_IMapToken을 쿼리할 뿐 아니라 IID_IMetaDataError도 쿼리하는 데 사용할 수 있는 IUnknown 인터페이스를 제공합니다. IID_IMetaDataError 인터페이스는 병합 과정에서 발생한 연속적 오류를 클라이언트에 알리는 데 사용됩니다.

  2. IMetaDataEmit::Merge - 지정된 메타데이터 범위를 현재 내보내기 범위에 병합합니다. MergeIMapToken 인터페이스를 사용하여 토큰 재매핑을 클라이언트에 알리고 IMetaDataError를 사용하여 연속적 오류를 클라이언트에 알립니다.

  3. IMetaDataEmit::GetSaveSize - 메타데이터 바이너리의 대상 저장 크기를 가져옵니다. GetSaveSizeIMetaDataEmit::SetHandler에 제공된 IMapToken 인터페이스를 사용하여 토큰 재매핑을 클라이언트에 알립니다. 형식 최적화가 수행된 후 도구에서는 토큰 재매핑을 Merge에서 처리한 다음 GetSaveSize에서 처리할 수 있도록 준비해야 합니다. 토큰에 대한 마지막 알림은 도구에서 사용해야 하는 최종 매핑을 나타냅니다.

  4. IMetaDataEmit::Save - IMetaDataEmit::SetRVA 및 다른 IMetaDataEmit 메서드를 사용하여 최종 구현 메타데이터를 내보낸 후에 메타데이터 바이너리를 저장합니다.

RAD 도구 스타일

RAD 도구에서는 컴파일 후 링크 스타일의 상호 작용에서와 마찬가지로 IMetaDataDispenserEx 인터페이스를 사용하여 메모리 내 메타데이터 범위를 설정한 다음 IMetaDataEmit 인터페이스를 사용하여 메타데이터 토큰 개요에 설명된 메타데이터 추상화와 함께 사용할 수 있는 형식 및 멤버를 선언합니다.

컴파일 후 링크 스타일과 달리 RAD 도구는 일반적으로 PE 파일을 한 단계로 내보냅니다. 선언 및 구현 정보를 한 번에 내보낼 수 있으므로 IMetaDataEmit::Merge를 호출할 필요가 없을 수 있습니다. 따라서 RAD 도구에서 복잡한 토큰 재매핑을 처리해야 하는 유일한 이유는 IMetaDataEmit::GetSaveSize에서 현재 수행된 저장 전 최적화를 활용하기 위해서 입니다.

일반적으로 완전하게 최적화된 메타데이터를 내보낼 수 있는 도구에서는 메타데이터 엔진이 없어도 적절하게 최적화된 파일을 내보낼 수 있습니다. 그러나 이후에 구현되는 메타데이터 엔진과 파일 형식에서는 일부 최적화 전략이 사용되지 않을 수도 있으므로 최적화된 메타데이터를 내보내는 방식에 대한 명확한 규칙이 있습니다.

메타데이터 선언 및 구현 정보를 내보낸 후의 호출 순서는 다음과 같습니다.

  1. IMetaDataEmit::SetRVA 및 다른 IMetaDataEmit 메서드 - 최종 구현 메타데이터를 내보냅니다.

  2. IMetaDataEmit::Save - 메타데이터 바이너리를 저장합니다.

참고 항목

기타 리소스

메타데이터 개요