target_link_libraries erroneously pulls in MODULE library at link time

Viewed 97

I have two C++ projects using CMake 3.12.2.

The first one is MODULE library (a dynamically loaded plugin). It installs a DLL, a header file and the configuration file for CMake.

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(MyPlugin LANGUAGES CXX)
set(CMAKE_DEBUG_POSTFIX "d")

# MODULE libraries are dynamically loaded at runtime and never linked against
add_library(MyPlugin MODULE
    include/a.h
    src/a.cpp
    src/b.h
    src/b.cpp
)

target_include_directories(MyPlugin
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include/MyPlugin>
    PRIVATE
        src
)

install(TARGETS MyPlugin EXPORT MyPluginConfig
    # MODULE libraries are installed as LIBRARY
    LIBRARY DESTINATION plugins COMPONENT Runtime
    RUNTIME DESTINATION bin COMPONENT Runtime
    PUBLIC_HEADER DESTINATION include/MyPlugin COMPONENT Development
)
install(FILES $<TARGET_PDB_FILE:MyPlugin> DESTINATION plugins OPTIONAL COMPONENT Runtime)
install(
    DIRECTORY include/
    DESTINATION include/MyPlugin
    FILES_MATCHING PATTERN "*.h"
)
install(EXPORT MyPluginConfig
    NAMESPACE MyPlugin::
    DESTINATION lib/cmake/MyPlugin
)

The second one is a simple executable which pulls in the header file of the plugin via target_link_libraries (the modern CMake way).

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(MyExe LANGUAGES CXX)
set(CMAKE_DEBUG_POSTFIX "d")

find_package(MyPlugin REQUIRED)

add_executable(MyExe src/main.cpp)
target_link_libraries(MyExe MyPlugin::MyPlugin)

Using the vs2015 generated solution the link fails because the plugin DLL is fed during the link of the executable...

Has anyone a solution for this or should I file a bug?

Regards.

1 Answers

A solution to this issue is to split the library in two: an interface library which only provides the headers and a module library which does not export any header.

The module library CMakeLists.txt becomes:

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(MyPlugin LANGUAGES CXX)
set(CMAKE_DEBUG_POSTFIX "d")


# Move public headers to a dedicated INTERFACE library
add_library(MyPluginInterface INTERFACE)
add_custom_target(Includes SOURCES include/a.h)
target_include_directories(MyPluginInterfacecmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(MyPlugin LANGUAGES CXX)
set(CMAKE_DEBUG_POSTFIX "d")


# Move public headers to a dedicated INTERFACE library
add_library(MyPluginInterface INTERFACE)
add_custom_target(Includes SOURCES include/a.h)
target_include_directories(MyPluginInterface
    INTERFACE
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include/MyPlugin>
)
install(TARGETS MyPluginInterface EXPORT MyPluginConfig
    PUBLIC_HEADER DESTINATION include/MyPlugin COMPONENT Development
)


# MODULE libraries are dynamically loaded at runtime and never linked against
add_library(MyPlugin MODULE
    src/a.cpp
    src/b.h
    src/b.cpp
)
target_link_libraries(MyPlugin MyPluginInterface)
install(TARGETS MyPlugin
    # MODULE libraries are installed as LIBRARY
    LIBRARY DESTINATION plugins COMPONENT Runtime
    RUNTIME DESTINATION bin COMPONENT Runtime
)
install(FILES $<TARGET_PDB_FILE:MyPlugin> DESTINATION plugins OPTIONAL COMPONENT Runtime)

install(
    DIRECTORY include/
    DESTINATION include/MyPlugin
    FILES_MATCHING PATTERN "*.h"
)
install(EXPORT MyPluginConfig
    NAMESPACE MyPlugin::
    DESTINATION lib/cmake/MyPlugin
)

    INTERFACE
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include/MyPlugin>
)
install(TARGETS MyPluginInterface EXPORT MyPluginConfig
    PUBLIC_HEADER DESTINATION include/MyPlugin COMPONENT Development
)


# MODULE libraries are dynamically loaded at runtime and never linked against
add_library(MyPlugin MODULE
    src/a.cpp
    src/b.h
    src/b.cpp
)
target_link_libraries(MyPlugin MyPluginInterface)
install(TARGETS MyPlugin
    # MODULE libraries are installed as LIBRARY
    LIBRARY DESTINATION plugins COMPONENT Runtime
    RUNTIME DESTINATION bin COMPONENT Runtime
)
install(FILES $<TARGET_PDB_FILE:MyPlugin> DESTINATION plugins OPTIONAL COMPONENT Runtime)

install(
    DIRECTORY include/
    DESTINATION include/MyPlugin
    FILES_MATCHING PATTERN "*.h"
)
install(EXPORT MyPluginConfig
    NAMESPACE MyPlugin::
    DESTINATION lib/cmake/MyPlugin
)

The executable CMakeLists.txt becomes:

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(MyExe LANGUAGES CXX)
set(CMAKE_DEBUG_POSTFIX "d")

find_package(MyPlugin REQUIRED)

add_executable(MyExe src/main.cpp)
target_link_libraries(MyExe MyPlugin::MyPluginInterface)
Related