Search
🔑

C 동적/정적 라이브러리 헤더 설정

간단소개
동적으로도, 정적으로도 쓰일 라이브러리 헤더의 필수 설정!
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
C
Scrap
태그
9 more properties

TL; DR: 이런 설정이 필요합니다!

my_library를 만든다고 하면, 이 라이브러리를 동적 라이브러리로 쓸 때는 MY_LIBRARY_SHARED를 1로 정의해야 합니다.
우선 헤더에 이런 내용이 필요합니다. 헤더가 여러 개라면 별도의 파일로 빼는 것도 좋습니다.
// 유효성 검사 (없어도 됨) #ifndef MY_LIBRARY_SHARED # error MY_LIBRARY_SHARED must be specified #elif MY_LIBRARY_SHARED == 0 #elif MY_LIBRARY_SHARED == 1 #else # error MY_LIBRARY_SHARED must be specified as 0 or 1 #endif #undef MY_LIBRARY_API #ifdef MY_LIBRARY_EXPORT # if defined(_WIN32) && MY_LIBRARY_SHARED == 1 # define MY_LIBRARY_API __declspec(dllexport) # else # define MY_LIBRARY_API # endif #else # if defined(_WIN32) && MY_LIBRARY_SHARED == 1 # define MY_LIBRARY_API __declspec(dllimport) # else # define MY_LIBRARY_API # endif #endif
C
복사
해당 라이브러리의 헤더에서는 내보내려는 모든 심볼에 MY_LIBRARY_API를 붙여야 합니다.
#ifndef MY_LIBRARY_H #define MY_LIBRARY_H // ... includes MY_LIBRARY_API void my_library_function(void); #endif
C
복사
추가로 해당 라이브러리를 구현하는 c 파일에서는 해당 헤더를 include하기 전에 MY_LIBRARY_EXPORT를 정의해야 합니다.
#define MY_LIBRARY_EXPORT #include "my_library.h" // ... other includes MY_LIBRARY_API void my_library_function(void) { puts("Hello world!"); }
C
복사

동적 라이브러리, 정적 라이브러리

동적 라이브러리는 실행 시점에 링크되며 실행 파일에 포함되지 않는 라이브러리고,
정적 라이브러리는 빌드 타임에 링크되어 실행 파일에 포함되는 라이브러리입니다.
모종의 이유로 라이브러리를 동적으로도 배포하고 정적으로도 배포하고 싶을 수 있습니다.
이 글에서는 그럴 때 헤더에서 어떤 설정을 해야 하는지에 대해 다룹니다.

특별한 설정이 필요한 이유

헤더에 설정을 해야 될 이유가 딱히 없을 것 같긴 한데요,
실제로 macOS와 Linux에서는 헤더에 별다른 설정을 하지 않아도 문제 없습니다.
하지만 Windows에서는 동적 라이브러리에서 불러올 함수 및 동적 라이브러리로 내보낼 함수에 각각 __declspec(dllimport), __declspec(dllexport)를 불여야 합니다.
그리고 이는 Windows의 MSVC용 플래그이므로, 다른 빌드 환경에서는 붙이지 말아야 합니다.

Windows용 동적 라이브러리 함수 정의 예시

hello.dll 동적 라이브러리에 다음 함수가 있다고 합시다.
#include <stdio.h> void hello(void) { puts("Hello world!"); }
C
복사
Windows에서는 이 함수를 동적 라이브러리에서 내보내려면, 즉 외부에서 불러와서 쓸 수 있게 하려면 다음과 같은 코드가 필요합니다.
#include <stdio.h> __declspec(dllexport) void hello(void) { puts("Hello world!"); }
C
복사
그리고 사용할 때는 이런 함수 선언이 필요합니다.
__declspec(dllimport) void hello(void);
C
복사

필요한 설정

크로스 플랫폼

Windows와 POSIX 환경을 모두 지원하는 크로스 플랫폼 라이브러리라면 __declspec을 바로 사용해서는 안 됩니다.
_WIN32가 정의되어 있을 때만, 그리고 동적 라이브러리일 때만 붙이도록 해야 합니다.
#if defined(_WIN32) && MY_LIBRARY_SHARED == 1 __declspec(dllimport) #endif void my_library_function(void);
C
복사
이걸 매번 하긴 귀찮으니 MY_LIBRARY_API라는 매크로 상수로 정의해 두면 좋을 것입니다.
#if defined(_WIN32) && MY_LIBRARY_SHARED == 1 # define MY_LIBRARY_API __declspec(dllimport) #else # define MY_LIBRARY_API #endif MY_LIBRARY_API void my_library_function(void);
C
복사
물론 dllimport 부분은 라이브러리를 빌드할 떄는 dllexport로 적절히 바뀌어야 합니다.

헤더 공유

MY_LIBRARY_API의 내용이 다르다고 외부 공개용 헤더와 별개로 같은 내용의 내부용 헤더를 작성하는 것은 바람직하지 않습니다.
#ifdef MY_LIBRARY_EXPORT # if defined(_WIN32) && MY_LIBRARY_SHARED == 1 # define MY_LIBRARY_API __declspec(dllexport) # else # define MY_LIBRARY_API # endif #else # if defined(_WIN32) && MY_LIBRARY_SHARED == 1 # define MY_LIBRARY_API __declspec(dllimport) # else # define MY_LIBRARY_API # endif #endif
C
복사
MY_LIBRARY_EXPORT라는 매크로 상수가 있는지에 따라 적절히 바뀌도록 하는 것이 좋습니다.