如何定义用于在CMake中切换我的dllexport和dllimport属性宏的开关宏?

huangapple go评论62阅读模式
英文:

How can I define the switch macro that switches between my dllexport and dllimport attribute macros with CMake?

问题

在我的根CMakeLists.txt文件中,我已经添加了以下内容:

set(CMAKE_CXX_VISIBILITY_PRESET hidden)

这将使默认情况下隐藏所有符号,无论是在Windows(它默认会这样做)还是Linux上。这将需要我手动导出公共API的符号。为了帮助实现这一点,我在项目的utils/目录中编写了一个名为defines.hpp的头文件,其中包含以下内容:

#ifndef __DEFINES_H_
#define __DEFINES_H_

#if defined(linux) || defined(__linux__)
	#define EXPORT __attribute__((visibility("default"))) 
#elif defined(_WIN64) || defined(__WIN32__)
	#if defined(COMPILE_LIB)
		#define EXPORT __declspec(dllexport)
	#else
		#define EXPORT __declspec(dllimport)
	#endif
#endif

#endif

然后,我可以在包含需要导出(以及随后导入)的声明的任何头文件中包含此头文件:

#include "utils/defines.hpp"

class EXPORT MyCoolClass();

EXPORT void MyCoolFunction();

(我尚未测试这个,如果我写的有任何明显问题,请告诉我!)

我的问题是,对我来说不太清楚如何定义COMPILE_LIB宏,因为库和可执行文件都是使用相同的CMake设置进行构建/链接的。我如何确保库使用dllexport构建,然后在相同的CMake构建中使用dllimport链接到可执行文件?或者我需要采取不同的方法吗?

此前的Stack Overflow帖子中接受的答案似乎表明应使用编译器参数并分别构建每个库,这并不是我要找的。另一篇回答指出,应该使用CMake定义的projectname,因为在编译DLL时它将定义宏projectname_EXPORTS。但我不确定这是否仍然适用,因为我的共享库和可执行文件都是在同一个CMake项目中构建的。(相关的CMakeLists.txt文件):

可执行文件的CMakeLists.txt

add_executable(quick-render quick_render.cpp)
target_link_libraries(quick-render ${PROJECT_NAME})
INSTALL(TARGETS quick-render DESTINATION bin)
...

库的CMakeLists.txt

...

add_library(${PROJECT_NAME} SHARED
   ...
)

target_link_libraries(${PROJECT_NAME} PUBLIC
   ...
)
...

这种方法在这里是否仍然适用,还是我的CMake设置对于以这种方式多种用途使用项目不合适?

英文:

So I have a project (meant to be supported on MacOS, Linux, and Windows) where I am building a shared library and a set of executables linked to that library. In my root CMakeLists.txt I have added:

set(CMAKE_CXX_VISIBILITY_PRESET hidden)

So that all symbols are hidden by default regardless of on Windows (which does this by default) or Linux. This will require me to manually export symbols of the public API. To help facilitate this, I've written a defines.hpp header in my project's utils/ directory which contains the following:

#ifndef __DEFINES_H_
#define __DEFINES_H_

#if defined(linux) || defined(__linux__)
	#define EXPORT __attribute__((visibility("default"))) 
#elif defined(_WIN64) || defined(__WIN32__)
	#if defined(COMPILE_LIB)
		#define EXPORT __declspec(dllexport)
	#elif
		#define EXPORT __declspec(dllimport)
	#endif
#endif

#endif

The idea being then I would include this header into any header that contains declarations that need to be exported (and subsequently imported as well) via:

#include "utils/defines.hpp"

class EXPORT MyCoolClass();

EXPORT void MyCoolFunction();

(I have not tested this yet so if there are any glaring issues with what I've written please let me know!)

My question is, it is not entirely clear to me how to define the COMPILE_LIB macro, given that the library and exectuables are built/linked with the same CMake setup. How can I ensure that the library is built using dllexport and then linked to the executables using dllimport within the same CMake build? Or would I need to take a different approach?

The accepted answer in this previous SO post seems to indicate using a compiler argument and building each separately, which isn't exactly what I am looking for. A separate answer indicates you should use the CMake defined projectname as when compiling the DLL it will define the macro projectname_EXPORTS. I'm also not sure that this will work again my shared library and the executables are all built within the same CMake project. (Relevant CMakeLists.txt files):

CMakeLists.txt for executables:

add_executable(quick-render quick_render.cpp)
target_link_libraries(quick-render ${PROJECT_NAME})
INSTALL(TARGETS quick-render DESTINATION bin)
...

CMakeLists.txt for library:

...

add_library(${PROJECT_NAME} SHARED
   ...
)

target_link_libraries(${PROJECT_NAME} PUBLIC
   ...
)
...

Would this approach still work here, or is it my CMake setup bad for using the project in multiple ways like this?

答案1

得分: 2

如Tsyvarev在评论中所说,使用target_compile_definitions命令以PRIVATE关键字定义宏。这样,宏只在库自身编译时定义。

此外,补充一下Tsyvarev的说法,如果你只是使用GenerateExportHeader模块,这部分将会自动完成。它还会负责为你配置构建系统的编译器生成C++属性。另请参阅https://stackoverflow.com/q/75432240/11107541。

英文:

As Tsyvarev said in the comments,

> Define the macro by using target_compile_definitions command with PRIVATE keyword. That way, the macro will be defined only when the library itself is compiled.

Adding to what Tsyvarev said, if you just use the GenerateExportHeader module, that part will be done for you automatically. It will also take care of generating C++ attributes for the compiler you configured the buildsystem to use. See also https://stackoverflow.com/q/75432240/11107541.

huangapple
  • 本文由 发表于 2023年2月14日 06:30:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/75441798.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定