Archive for the ‘dll’ tag
C++ 라이브러리 만들기는 어려워
[옛날 블로그 글입니다. 2009.08.24]
[추가1. VC++의 예외 바이너리 호환성에 대해 내용 추가(정정)했습니다]
오랜만에 시간이 좀 나서, 요새 머리를 괴롭히는 이슈를 좀 적어 봅니다.
회사에서 C++ 라이브러리를 만들고 있습니다. 이녀석을 바이너리(dll)로 배포할 목적입니다. 컴파일러 버전별로 다 제공하기에는 무리가 있으니, 컴파일러 버전에 독립적인 바이너리가 되도록 하고 싶습니다.
이 목적을 달성하기 위해서는
- DLL에서 할당한 메모리를 EXE에서 해제하면 안됩니다.
- DLL의 인터페이스에서 STL을 쓰면 안됩니다.
- DLL에서 예외를 던지면 안됩니다.
이 규칙을 모두 만족하는 인터페이스란
- 바로 Windows API와 같은 C 함수들
- COM 인터페이스
정도가 되겠네요.
DLL에서 할당한 메모리는 DLL에서 해제
메모리를 할당해 준 CRT가 해제해야 한다는 얘기죠. 컴파일러 버전에 독립적이려면 DLL을 정적 CRT 라이브러리와 링크하는게 좋은데, 이러면 DLL과 EXE가 사용하는 CRT가 달라집니다. 그래서 DLL에서 할당한 메모리를 EXE에서 해제하면 안됩니다.
같은 컴파일러 버전으로 빌드된 DLL과 EXE이더라도 CRT가 다르면 조심해야 합니다. 같은 CRT(DLL)를 쓴다면 신경 안 써도 되구요.
그래서 DLL에서 문자열이나 메모리 블럭을 건네줄 일이 있다면, COM처럼 자기네 CRT에서 할당/해제하는 SysAlloc(), SysFree() 같은 함수를 만들어 제공하기도 합니다. DLL에서 SysAlloc()으로 메모리 블럭을 할당해서 주면 EXE에서 SysFree()로 해제하는 식이죠.
아니면 전통적인 방식으로 EXE에서 DLL에게 '메모리 블럭 크기가 몇이냐?' 물어보고 나서, EXE가 메모리를 할당해서 DLL에게 '여기에 넣어줘'라고 말하는 방법이 있습니다.
SysAlloc() 방식은 크기를 물어보는 등의 귀찮은 작업이 없는게 장점이고, 전통적인 방식은 사용자(EXE)가 자신의 메모리 풀 같은 것은 만들어 쓸 때 유리한 면이 있습니다.
DLL의 인터페이스에서 STL을 쓰면 안됨
STL의 구현이 컴파일러 버전별로 달라서 바이너리 호환성이 없는 것도 문제고, 메모리가 DLL경계를 넘어서는 경우도 있어서 안된다고 하네요.
네, 그래서 다른 언어 부럽지 않게 std::string을 반환하고 싶은 바램은 포기해야 합니다.
DLL에서 예외를 던지면 안됨
역시나 C++에 바이너리 표준이 없기 때문인데요, 예외 매커니즘을 구현하는 방식도 표준화 되어 있지 않기 때문에 컴파일러별로 다른게 현실입니다. 그래도 Visual C++이라면 같지 않을까 하는 기대감에 테스트를 해봤는데요.
VC++ 2008에서 예외를 던지는 DLL을 만듭니다. 그리고 VC++ 6.0, 2003, 2005, 2008, 2010에서 예외를 받는 EXE를 만듭니다. 결과는.. VC++ 6.0, 2003에서는 프로그램이 죽습니다. -_-;;
[추가1. 위에 테스트는 std::exception 오브젝트를 던지는 것였는데, std::exception의 구현차이 때문에 예외를 못받은 것 같습니다. 그냥 직접 만든 클래스의 포인터를 넘기니 모든 버전의 VC++에서 예외를 잘 받네요. 고민입니다. gcc도 비슷하다면 예외를 써도 되지않을까 고민중입니다.. ]
이로서 다른 언어 부럽지 않게 예외 처리를 하고 싶은 바램도 포기해야 합니다.
마무리
요즘의 언어처럼 쓰기 편한 인터페이스를 만들고 싶었는데 C++은 C++스럽게 써야만 하는 부분이 있었네요. 이래서 MS에서 닷넷 프레임웍을 만들었나 싶은 생각도 들었습니다.
참고자료
Binary-compatible C++ Interfaces, Chad Austin, 2002.02.15http://chadaustin.me/cppinterface.html