C++에서 DLL 만들기

일단 새 프로젝트를 DLL(동적 연결 라이브러리)로 만든다.

Cap 2021-10-26 17-41-08-587.png

전처리기

DLL로 내보낼 —외부에서 사용될— 파일의 header 파일에 다음과 같은 전처리문을 추가한다. —cpp 파일에는 별도로 설정할 필요가 없다. cpp는 일반적인 프로젝트와 동일하게 사용하면 된다.

#ifdef (프로젝트 이름)_EXPORTS
#define (매크로 이름) __declspec(dllexport)
#else
#define (매크로 이름) __declspec(dllimport)
#endif

여기서 (프로젝트 이름)은 Visual Studio에서 프로젝트 속성 → C/C++ → 전처리기 → 전처리기 정의에 있는 이름을 의미한다.

이렇게 정의된 전처리문은 DLL로 내보낼 함수와 클래스에 동일하게 사용된다. 이를 사용하는 방법은 아래 코드와 같다. —아직 아래 코드만으로는 내보내기가 안되므로 주의

#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif

MATHLIBRARY_API void fibonacci_init(const unsigned long long a, const unsigned long long b);
MATHLIBRARY_API bool fibonacci_next();
MATHLIBRARY_API unsigned long long fibonacci_current();
MATHLIBRARY_API unsigned fibonacci_index();

함수 앞에 전처리문 MATHLIBRARY_API를 쓰지 않고 그냥 __declspec(dllexport)라고 써도 무방하다. 다만 그렇게 쓰면 코드가 지저분해 보이기 때문에 MATHLIBRARY_API와 같이 별도의 전처리문을 사용하는 것이다.

extern "C"

__declspec(dllexport) 키워드만으로 DLL export가 되면 편할텐데 추가로 한 단계가 더 필요한데, 그것이 바로 extern "C" 키워드 이다. —extern 키워드에 "C"가 붙은 것은 C 스타일로 한다는 뜻이다. C 스타일로 extern 하는 것이기 때문에 Template에 대해서는 사용할 수 없다.

extern "C" 의 의미는 C++ 컴파일러에게 네임 맹글링(Name Mangling)을 하지 말라고 선언하는 내용인데, 네임 맹글링이란 C++ 링커가 동일한 함수명을 구분하기 위해 적절한 규칙을 이용해서 함수명을 변형하는 것을 말한다.

이게 무슨 말이냐면 C++은 C와 달리 다른 네임스페이스나 클래스에 속한 함수가 같은 이름을 가질 수 있고, 또 같은 범위(scope)에 존재해도 매개변수가 다르면 같은 함수 이름을 가질 수 있는데, 링커는 이것을 모르기 때문에, 컴파일러가 함수명을 바꾸어서 링커가 헷갈리지 않게 한다는 것이다.

그런데 이렇게 네임 맹글링을 해버리면 이번에는 외부 모듈이 링크를 할 수 없기 때문에 —분명 코드에서는 finocacci_init 이라는 이름이었는데, 컴파일러가 멋대로 이름을 바꾸어 버리면 찾을 수가 없는 것이다— 이를 방지하기 위해 네임 맹글링을 하지 말라고 선언하는 것이다.

쉽게 요약하면 외부로 내보낼 함수나 클래스 등에 대해서는 extern "C" 키워드를 써줘야 외부 모듈에서 해당 함수나 클래스를 찾을 수 있게 된다는 것이다.

extern "C" 키워드는 아래와 같이 함수의 가장 앞에 사용한다.

extern "C" MATHLIBRARY_API void fibonacci_init(const unsigned long long a, const unsigned long long b);
extern "C" MATHLIBRARY_API bool fibonacci_next();
extern "C" MATHLIBRARY_API unsigned long long fibonacci_current();
extern "C" MATHLIBRARY_API unsigned fibonacci_index();