programing

Linux 및 Windows에서 모두 실행할 휴대용 라이브러리 만들기

cafebook 2023. 10. 10. 20:56
반응형

Linux 및 Windows에서 모두 실행할 휴대용 라이브러리 만들기

gcc (GCC) 4.7.2

안녕하세요.

저는 리눅스 상에서 컴파일 할 공유 라이브러리와 윈도우 상에서 동일한 소스 코드를 사용하여 컴파일 할 dll을 만들고 있습니다.그래서 저는 리눅스와 윈도우 모두를 위한 휴대용 라이브러리를 만들고 있습니다.

라이브러리에 대한 내 헤더 파일에는 이 module.h가 있습니다.

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#define LIB_INTERFACE(type) EXTERN_C __declspec(dllexport) type
#else
#define LIB_INTERFACE(type) type
#endif

LIB_INTERFACE(int) module_init();

#ifdef __cplusplus
}
#endif

나는 소스에 다음과 같은 module.c

#include "module.h"

LIB_INTERFACE(int) module_init()
{
    /* do something useful
    return 0;
}

그리고 이 module.so 를 링크하여 사용할 수 있는 테스트 애플리케이션에는 다음과 같은 내용이 있습니다.

#include "module.h"

int main(void)
{
    if(module_init() != 0) {
    return -1;
    }
    return 0;
}

1) 위에서 한 것이 리눅스와 윈도우용 휴대용 라이브러리를 만드는 올바른 구현입니까?

을 2) 뿐입니다.extern "C"C++로 컴파일된 프로그램에서 이 라이브러리를 호출할 수 있도록 합니다.요가 도 필요한가요?EXTERN_C다음의 경우에

#define LIB_INTERFACE(type) EXTERN_C __declspec(dllexport) type

) 입니까의 입니까?EXTERN_C?

미리 감사 드려요,

Windows용 DLL API를 내보내고 Linux를 지원하는 일반적인 방법입니다.

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#  ifdef MODULE_API_EXPORTS
#    define MODULE_API __declspec(dllexport)
#  else
#    define MODULE_API __declspec(dllimport)
#  endif
#else
#  define MODULE_API
#endif

MODULE_API int module_init();

#ifdef __cplusplus
}
#endif

DLL 소스에서:

#define MODULE_API_EXPORTS
#include "module.h"

MODULE_API int module_init()
{
    /* do something useful */
    return 0;
}

응용프로그램 소스가 정확합니다.

위 모델을 사용하면 윈도우에서 DLL은 API를 내보내고 응용프로그램은 API를 가져옵니다.면.__declspec장식이 제거됩니다.

가 전체 를 에 extern "C", 를 합니다.EXTERN_C각 인터페이스의 매크로는 필요하지 않습니다.extern "C"링커에게 사용할 것을 지시하는 데 사용됩니다.C 대신 C++는 않기 때문에을 동일한 응용 C 링크는 컴파일러 간에 표준이지만 C++는 그렇지 않기 때문에 DLL 사용이 동일한 컴파일러로 작성된 응용 프로그램으로 제한됩니다.

반환 유형을 API 매크로에 통합할 필요가 없습니다.

외부 "C"는 기본적으로 컴파일러에게 함수 이름을 망가지지 말라고 말하는 것을 의미합니다.망글링은 나중에 실행하기 위해 함수 이름을 "인코딩"하는 과정이며 C++가 동일한 이름을 가진 다른 함수를 가질 수 있기 때문에 C와 C++에서는 상당히 다릅니다.

C++ 소스에서 외부 "C"의 효과는 무엇입니까?

컴파일이 완료되면 이러한 함수를 어디에서나 호출할 수 있지만 시작하기 전에 어떤 종류의 라이브러리(정적 또는 동적)를 작성하는지 확인해야 할 수 있습니다.

또한 개발 후반부에 발생할 수 있는 유지보수나 가독성 문제 때문에 동일한 파일에서 사용하는 것처럼 DEFINES를 휴대용으로 사용하지 않는 것이 좋습니다.WIN과 UNIX가 완전히 휴대할 수 있는 인터페이스를 정의하는 기본 파일을 만든 다음 인터페이스를 구현하는 두 개의 다른 라이브러리를 만들지만 다른 플랫폼을 위해 만들 것입니다.

예를 들어 다음을 가질 수 있습니다: 초록Interface.h, WinInterface.h, UnixInterface.h

그럼 플랫폼에 따라 필요한 것만 컴파일해주세요.

Linux의 경우 -fvisibility=hidden이 없는 gcc는 정적 함수를 제외하고 기본적으로 내보냅니다.

-fvisibility=숨김으로 gcc는 기본적으로 다음으로 장식된 기능을 제외하고 내보내지 않습니다.

__attribute__ ((visibility ("default")))

Windows의 경우 다음으로 장식된 내보내기 기능

__attribute__ ((dllexport))

내보낸 함수를 사용할 때는 다음과 같이 장식해야 합니다.

__attribute__ ((dllimport))

게시물의 매크로가

__declspec(dllexport)

는 MSVC 에 의해 지원되지만 위의 __attribute_ 구문을 사용하는 대신 윈도우를 대상으로 하는 GCC의해서도 지원됩니다.

따라서 교차된 리눅스 및 윈도우 매크로는 다음과 같습니다.

#if defined _WIN32 || defined __CYGWIN__ || defined __MINGW32__
  #ifdef BUILDING_DLL
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllexport))
    #else
      #define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
    #endif
  #else
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllimport))
    #else
      #define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
    #endif
  #endif
  #define DLL_LOCAL
#else
  #if __GNUC__ >= 4
    #define DLL_PUBLIC __attribute__ ((visibility ("default")))
    #define DLL_LOCAL  __attribute__ ((visibility ("hidden")))
  #else
    #define DLL_PUBLIC
    #define DLL_LOCAL
  #endif
#endif
  • 공유 개체 또는 DLL 프로젝트를 -DBUILDING_DLL로 컴파일해야 합니다.
  • 공유 개체 또는 DLL에 의존하는 프로젝트는 -DB 없이 컴파일해야 합니다.UILDING_DLL

가시성에 대한 자세한 내용은 http://gcc.gnu.org/wiki/Visibility 을 참조하십시오.

c++ 언어에 고유한 다형성의 개념으로 인해 c++에 정의된 모든 함수들이 망가지게 됩니다. 즉, "컴파일러"는 재정의된 각 함수에 대해 고유한 이름을 만들기 위해 함수 이름을 장식합니다.

이름 망글링은 "컴파일러"에 의해 처리되고 이름 망글링 규칙을 엄격하게 정의하는 사양이 없기 때문에, 각각의 컴파일러는 다른 방식으로 이름을 장식합니다.간단히 말해서, gcc와 msvc 컴파일러는 동일한 코드에 대해 다른 기능 시그니처를 만듭니다.이름 망글링에 대해서는 여기 위키 기사에서 자세히 보실 수 있습니다.

당신의 module.h 파일은 단순히 컴파일러에게 c 스타일 이름 맹글링을 사용하거나 아예 맹글링을 사용하지 말라고 지시합니다. 이 지시사항 때문에 gcc에 의해 컴파일된 라이브러리는 비주얼 스튜디오에서 작성된 바이너리에 연결하는 데 사용될 수 있습니다.이렇게 하면 소스 코드 대신 라이브러리의 이진 파일을 배포하는 데 도움이 됩니다.

반면 EXTERN_C 디렉티브를 사용하지 않는 경우 라이브러리와 라이브러리에 연결되는 프로젝트는 동일한 컴파일러를 사용하여 컴파일해야 합니다.예를 들어, 당신은 라이브러리와 해당 라이브러리에 연결된 프로젝트 둘다에 대해 리눅스 컴파일을 위해 gcc를 사용하고 윈도우 컴파일을 위해 msvc를 사용해야 합니다.

헤더 파일을 직접 작성하는 대신 CMake가 다음과 같이 CMake의 generate_export_header를 사용하여 빌드 컴파일러용 파일을 생성하도록 할 수도 있습니다(링크된 페이지에서 가져온 예제).

add_library(libfoo foo.cpp)
generate_export_header(libfoo)
#include "libfoo_export.h"
class LIBFOO_EXPORT FooClass {
    int bar;
};

언급URL : https://stackoverflow.com/questions/19418908/creating-a-portable-library-to-run-on-both-linux-and-windows

반응형