dev.log2008. 2. 1. 04:51

DLL에서 익스포트할 클래스에서 STL 클래스 멤버를 쓰는 것은 바람직하지 않지만, 세상사란 그리 만만하지 않은 법. DLL에서 STL클래스를 익스포트 해야 할 경우가 가끔 생기는데, 사실 vector같은 건 별로 문제가 되지 않는다. 컨테이너 자체가 간단하고, 연관된 할당자도 별로 없기 때문에. 사실 map이나 set같은 복잡한 컨테이너가 진짜 문제다.

 

웹에서 찾아볼 수 있는, STL map을 DLL에서 익스포트하기 위한 매크로는 대개 다음과 같다

#define EXPORT_STL_MAP( dllmacro, mapkey, mapvalue ) \
  template struct dllmacro std::pair< mapkey,mapvalue >; \
  template class dllmacro std::allocator< \
    std::pair<const mapkey,mapvalue> >; \
  template struct dllmacro std::less< mapkey >; \
  template class dllmacro std::allocator< \
    std::_Tree_ptr<std::_Tmap_traits<mapkey,mapvalue,std::less<mapkey>, \
    std::allocator<std::pair<const mapkey,mapvalue> >,false> > >; \
  template class dllmacro std::allocator< \
    std::_Tree_nod<std::_Tmap_traits<mapkey,mapvalue,std::less<mapkey>, \
    std::allocator<std::pair<const mapkey,mapvalue> >,false> > >; \
  template class dllmacro std::_Tree_nod< \
    std::_Tmap_traits<mapkey,mapvalue,std::less<mapkey>, \
    std::allocator<std::pair<const mapkey,mapvalue> >,false> >; \
  template class dllmacro std::_Tree_ptr< \

    std::_Tmap_traits<mapkey,mapvalue,std::less<mapkey>, \
    std::allocator<std::pair<const mapkey,mapvalue> >,false> >; \
  template class dllmacro std::_Tree_val< \
    std::_Tmap_traits<mapkey,mapvalue,std::less<mapkey>, \
    std::allocator<std::pair<const mapkey,mapvalue> >,false> >; \
  template class dllmacro std::map< \
    mapkey, mapvalue, std::less< mapkey >, \
    std::allocator<std::pair<const mapkey,mapvalue> > >;

(이걸보고 주눅이 안들면 비정상. 안심해라)

 

근데 이 매크로를 써서 map을 익스포트하면, VC2003에서는 아무 탈 없이 컴파일 됐는데, VC2005에서는 요상하게 다음과 같은 에러를 뱉었다.

1>c:\dev\visualstudio8\vc\include\xtree(61) : warning C4251: 'std::_Tree_nod<_Traits>::_Alnod' : class 'std::allocator<_Ty>'에서는 class 'std::_Tree_nod<_Traits>'의 클라이언트에서 DLL 인터페이스를 사용하도록 지정해야 합니다.
1>        with
1>        [
1>            _Traits=std::_Tmap_traits<int,short,std::less<int>,std::allocator<std::pair<const int,short>>,false>
1>        ]
1>        and
1>        [
1>            _Ty=std::_Tree_nod<std::_Tmap_traits<int,short,std::less<int>,std::allocator<std::pair<const int,short>>,false>>::_Node
1>        ]
1>        and
1>        [
1>            _Traits=std::_Tmap_traits<int,short,std::less<int>,std::allocator<std::pair<const int,short>>,false>
1>        ]

(보통 STL이 뱉는 에러메시지는 암호같긴 하다)

 

이걸 해석하는 것도 만만치 않긴 하지만, 해석하자면 std::allocator< ... >::_Node 가 익스포트되도록 지정되지 않았다..는 내용. 따라서 다음 두 줄을 매크로 선언에 추가하면 된다. 위의 메시지는 _Node에 대한 것이고, _Node에 대한 할당자를 익스포트하도록 지정하면 또 다른 어딘가에서 _Node*에 대한 할당자도 익스포트해야 한다는 메시지가나온다. 그래서 두줄을 더 추가해야 했다.

 

  template class dllmacro std::allocator< \

    std::_Tree_nod<std::_Tmap_traits<mapkey,mapvalue,std::less<mapkey>, \
    std::allocator<std::pair<const mapkey,mapvalue> >,false> >::_Node >; \
  template class dllmacro std::allocator< \
    std::_Tree_nod<std::_Tmap_traits<mapkey,mapvalue,std::less<mapkey>, \
    std::allocator<std::pair<const mapkey,mapvalue> >,false> >::_Node* >; \

 2003에서는 멀쩡히 잘 돌아가던 매크로가 2005에서는 안되는 이유가 뭔지는 잘 모르겠지만 -_- 여튼 저렇게 하니까 됐다. 잊어먹지 말자.


Posted by uhm
geek.log2005. 6. 4. 00:11

오늘 비주얼 스튜디오에서 흥미로운 사실을 발견.

비주얼 스튜디오에서 DLL프로젝트를 만들때 "기호 내보내기"옵션을 줘서 생성하면
다음과 같은 코드 템플릿을 만들어준다.

// dlltest.cpp : DLL 응용 프로그램에 대한 진입점을 정의합니다.
//

#include "stdafx.h"
#include "dlltest.h"
BOOL APIENTRY DllMain( HANDLE hModule,
                                       DWORD  ul_reason_for_call,
                                       LPVOID lpReserved
                                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


// 내보낸 변수의 예제입니다.
DLLTEST_API int ndlltest=0;


// 내보낸 함수의 예제입니다.
DLLTEST_API int fndlltest(void)
{
    return 42;
}


// 내보낸 클래스의 생성자입니다.
// 클래스 정의를 보려면 dlltest.h를 참조하십시오.
Cdlltest::Cdlltest()
{
    return;
}


자.. 보이는가! return 42;의 압박이!
크핫핫. 결국 MS의 개발자들도 인생, 우주와 모든 것에 대한 궁극적인 질문의 해답을 알고 있었다는 말!
(그런데 왜 제품은 그모냥으로 만드냐고..)

첨언 : 42에 대해 잘 모르는 분은 여기여기를 방문해 보시길;

Posted by uhm