gpt4 book ai didi

c++ - 如何覆盖CMake中的宏定义

转载 作者:搜寻专家 更新时间:2023-10-31 02:13:05 26 4
gpt4 key购买 nike

我在 Windows 10、Visual Studio 2015 上。假设我正在使用 CMakeLists 构建库 A,看起来像

cmake_minimum_required(VERSION 3.7)
project(A)

set(DLLIMPORT "__declspec(dllimport)")
set(DLLEXPORT "__declspec(dllexport)")

set(PROJECT_SRCS
${PROJECT_SOURCE_DIR}/src/TestA.cpp)

set(PROJECT_INCS
${PROJECT_SOURCE_DIR}/include/TestA.h)

add_library(${PROJECT_NAME} SHARED ${PROJECT_SRCS} ${PROJECT_INCS})

target_compile_definitions(${PROJECT_NAME} INTERFACE
WINDOWS_DLL_API=${DLLIMPORT})

target_compile_definitions(${PROJECT_NAME} PRIVATE
WINDOWS_DLL_API=${DLLEXPORT})

target_include_directories(${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)

我在构建库 A 时将宏 WINDOWS_DLL_API 定义为 dllexport,并将 WINDOWS_DLL_API 定义为 dllimport对于链接库 A 的外部应用程序。问题是当我有另一个库 B 也链接 A 时,我不知道如何将 WINDOWS_DLL_API 覆盖回 dllexport .下面是我对库 B 的 CMakeLists 的尝试,

cmake_minimum_required(VERSION 3.7)
project(B)

set(DLLEXPORT "__declspec(dllexport)")

set(PROJECT_SRCS
${PROJECT_SOURCE_DIR}/src/TestB.cpp)

set(PROJECT_INCS
${PROJECT_SOURCE_DIR}/include/TestB.h)

add_library(${PROJECT_NAME} SHARED ${PROJECT_SRCS} ${PROJECT_INCS})

target_include_directories(${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)

target_link_libraries(${PROJECT_NAME} A)

# does not work
target_compile_definitions(${PROJECT_NAME} PRIVATE
WINDOWS_DLL_API=${DLLEXPORT})

正确的做法是什么?

最佳答案

命令 target_compile_definitions(以及其他 target_* CMake 命令)的 INTERFACE 选项的

概念是强制执行为库的所有用户准备的东西,包括可执行文件

意图明确至少一个图书馆用户的强制执行意味着这个概念被以错误的方式使用。应该改用其他方法。

在给定的情况下,您需要为库 AB 使用不同 宏名称。最好完全删除 INTERFACE 选项,这样即使您的库的非 CMake 用户也会很高兴。

TestA.h:

#ifdef BUILD_A
#define WINDOWS_DLL_API_A __declspec(dllexport)
#else
#define WINDOWS_DLL_API_A __declspec(dllimport)
#endif

...
WINDOWS_DLL_API_A void foo(void);
...

TestB.h:

#ifdef BUILD_B
#define WINDOWS_DLL_API_B __declspec(dllexport)
#else
#define WINDOWS_DLL_API_B __declspec(dllimport)
#endif

// Assume usage of A is here.
#include <TestA.h>
...
WINDOWS_DLL_API_B void bar(void);

A/CMakeLists.txt:

cmake_minimum_required(VERSION 3.7)
project(A)

...

add_library(${PROJECT_NAME} SHARED ...)

target_compile_definitions(${PROJECT_NAME} PRIVATE "BUILD_${PROJECT_NAME}=1")

B/CMakeLists.txt:

cmake_minimum_required(VERSION 3.7)
project(B)

...

add_library(${PROJECT_NAME} SHARED ...)

target_compile_definitions(${PROJECT_NAME} PRIVATE "BUILD_${PROJECT_NAME}=1")

target_link_libraries(${PROJECT_NAME} A)

另见 this answer ,它提供了更详细的 header ,也适用于 Windows 平台。


请注意,当库 B 包含来自 A 的 header 时,它将 foo() 视为导入 ,这是正确的:该函数是在 A 中定义的,而不是在 B 中定义的。使用您的方法(即使您设法为 B 重新定义 WINDOWS_DLL_API),库 B 也会错误地对待 foo() 作为导出

这是观念的优势:克服观念的意图表明您做错了什么

关于c++ - 如何覆盖CMake中的宏定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41866614/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com