diff --git a/modules/FindCorrade.cmake b/modules/FindCorrade.cmake index 9af261b..9b9733c 100644 --- a/modules/FindCorrade.cmake +++ b/modules/FindCorrade.cmake @@ -374,6 +374,9 @@ set(CORRADE_LIB_SUFFIX_MODULE ${_CORRADE_MODULE_DIR}/CorradeLibSuffix.cmake) # unknown components) set(_CORRADE_LIBRARY_COMPONENTS Containers Interconnect Main PluginManager TestSuite Utility) +# These libraries are excluded from DLL detection if Corrade is built as shared +set(_CORRADE_LIBRARY_COMPONENTS_ALWAYS_STATIC + Main) set(_CORRADE_HEADER_ONLY_COMPONENTS Containers) if(NOT CORRADE_TARGET_WINDOWS) # CorradeMain is a real library only on windows, a dummy target elsewhere @@ -430,7 +433,7 @@ foreach(_component ${Corrade_FIND_COMPONENTS}) # Create imported target in case the library is found. If the project is # added as subproject to CMake, the target already exists and all the # required setup is already done from the build tree. - if(TARGET Corrade::${_component}) + if(TARGET "Corrade::${_component}") # Quotes to "fix" KDE's higlighter set(Corrade_${_component}_FOUND TRUE) else() # Default include path names to look for for library / header-only @@ -446,24 +449,30 @@ foreach(_component ${Corrade_FIND_COMPONENTS}) # Library (and not header-only) components if(_component IN_LIST _CORRADE_LIBRARY_COMPONENTS AND NOT _component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS) - add_library(Corrade::${_component} UNKNOWN IMPORTED) - # Try to find both debug and release version find_library(CORRADE_${_COMPONENT}_LIBRARY_DEBUG Corrade${_component}-d) find_library(CORRADE_${_COMPONENT}_LIBRARY_RELEASE Corrade${_component}) mark_as_advanced(CORRADE_${_COMPONENT}_LIBRARY_DEBUG CORRADE_${_COMPONENT}_LIBRARY_RELEASE) - endif() - # Header-only library components - if(_component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS) - add_library(Corrade::${_component} INTERFACE IMPORTED) - endif() + # On Windows, if we have a dynamic build of given library, find the + # DLLs as well. Abuse find_program() since the DLLs should be + # alongside usual executables. On MinGW they however have a lib + # prefix. + if(CORRADE_TARGET_WINDOWS AND NOT CORRADE_BUILD_STATIC AND NOT _component IN_LIST _CORRADE_LIBRARY_COMPONENTS_ALWAYS_STATIC) + find_program(CORRADE_${_COMPONENT}_DLL_DEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}Corrade${_component}-d.dll) + find_program(CORRADE_${_COMPONENT}_DLL_RELEASE ${CMAKE_SHARED_LIBRARY_PREFIX}Corrade${_component}.dll) + mark_as_advanced(CORRADE_${_COMPONENT}_DLL_DEBUG + CORRADE_${_COMPONENT}_DLL_RELEASE) + # If not on Windows or on a static build, unset the DLL variables + # to avoid leaks when switching shared and static builds + else() + unset(CORRADE_${_COMPONENT}_DLL_DEBUG CACHE) + unset(CORRADE_${_COMPONENT}_DLL_RELEASE CACHE) + endif() # Executable components - if(_component IN_LIST _CORRADE_EXECUTABLE_COMPONENTS) - add_executable(Corrade::${_component} IMPORTED) - + elseif(_component IN_LIST _CORRADE_EXECUTABLE_COMPONENTS) find_program(CORRADE_${_COMPONENT}_EXECUTABLE corrade-${_component}) mark_as_advanced(CORRADE_${_COMPONENT}_EXECUTABLE) @@ -492,10 +501,10 @@ foreach(_component ${Corrade_FIND_COMPONENTS}) endif() endif() - if(CORRADE_${_COMPONENT}_EXECUTABLE) - set_property(TARGET Corrade::${_component} PROPERTY - IMPORTED_LOCATION ${CORRADE_${_COMPONENT}_EXECUTABLE}) - endif() + # If not a header-only component it's something unknown, skip. FPHSA + # will take care of handling this below. + elseif(NOT _component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS) + continue() endif() # Find library includes @@ -507,30 +516,69 @@ foreach(_component ${Corrade_FIND_COMPONENTS}) endif() # Decide if the component was found. If not, skip the rest, which - # populates the target properties and finds additional dependencies. If - # found, the _FOUND variable may still get reset by something below. - if((_component IN_LIST _CORRADE_LIBRARY_COMPONENTS AND _CORRADE_${_COMPONENT}_INCLUDE_DIR AND (_component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS OR CORRADE_${_COMPONENT}_LIBRARY_RELEASE OR CORRADE_${_COMPONENT}_LIBRARY_DEBUG)) OR (_component IN_LIST _CORRADE_EXECUTABLE_COMPONENTS AND CORRADE_${_COMPONENT}_EXECUTABLE)) + # creates and populates the target and finds additional dependencies. + # If found, the _FOUND variable may still get reset by something below. + if( + # If the component is a library, it should have the include dir + (_component IN_LIST _CORRADE_LIBRARY_COMPONENTS AND _CORRADE_${_COMPONENT}_INCLUDE_DIR AND ( + # And it should be either header-only + _component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS OR + # Or have a debug library, and a DLL found if expected + (CORRADE_${_COMPONENT}_LIBRARY_DEBUG AND ( + NOT DEFINED CORRADE_${_COMPONENT}_DLL_DEBUG OR + CORRADE_${_COMPONENT}_DLL_DEBUG)) OR + # Or have a release library, and a DLL found if expected + (CORRADE_${_COMPONENT}_LIBRARY_RELEASE AND ( + NOT DEFINED CORRADE_${_COMPONENT}_DLL_RELEASE OR + CORRADE_${_COMPONENT}_DLL_RELEASE)))) OR + # If the component is an executable, it should have just the + # location + (_component IN_LIST _CORRADE_EXECUTABLE_COMPONENTS AND CORRADE_${_COMPONENT}_EXECUTABLE) + ) set(Corrade_${_component}_FOUND TRUE) else() set(Corrade_${_component}_FOUND FALSE) continue() endif() - # Library location for (non-header-only) libraries - if(_component IN_LIST _CORRADE_LIBRARY_COMPONENTS AND NOT _component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS) - if(CORRADE_${_COMPONENT}_LIBRARY_RELEASE) - set_property(TARGET Corrade::${_component} APPEND PROPERTY - IMPORTED_CONFIGURATIONS RELEASE) - set_property(TARGET Corrade::${_component} PROPERTY - IMPORTED_LOCATION_RELEASE ${CORRADE_${_COMPONENT}_LIBRARY_RELEASE}) + # Target for header-only library components + if(_component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS) + add_library(Corrade::${_component} INTERFACE IMPORTED) + + # Target and location for (non-header-only) libraries + elseif(_component IN_LIST _CORRADE_LIBRARY_COMPONENTS) + if(CORRADE_BUILD_STATIC OR _component IN_LIST _CORRADE_LIBRARY_COMPONENTS_ALWAYS_STATIC) + add_library(Corrade::${_component} STATIC IMPORTED) + else() + add_library(Corrade::${_component} SHARED IMPORTED) endif() - if(CORRADE_${_COMPONENT}_LIBRARY_DEBUG) + foreach(_CONFIG DEBUG RELEASE) + if(NOT CORRADE_${_COMPONENT}_LIBRARY_${_CONFIG}) + continue() + endif() + set_property(TARGET Corrade::${_component} APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) - set_property(TARGET Corrade::${_component} PROPERTY - IMPORTED_LOCATION_DEBUG ${CORRADE_${_COMPONENT}_LIBRARY_DEBUG}) - endif() + IMPORTED_CONFIGURATIONS ${_CONFIG}) + # Unfortunately for a DLL the two properties are swapped out, + # *.lib goes to IMPLIB, so it's duplicated like this + if(DEFINED CORRADE_${_COMPONENT}_DLL_${_CONFIG}) + # Quotes to "fix" KDE's higlighter + set_target_properties("Corrade::${_component}" PROPERTIES + IMPORTED_LOCATION_${_CONFIG} ${CORRADE_${_COMPONENT}_DLL_${_CONFIG}} + IMPORTED_IMPLIB_${_CONFIG} ${CORRADE_${_COMPONENT}_LIBRARY_${_CONFIG}}) + else() + set_property(TARGET Corrade::${_component} PROPERTY + IMPORTED_LOCATION_${_CONFIG} ${CORRADE_${_COMPONENT}_LIBRARY_${_CONFIG}}) + endif() + endforeach() + + # Target and location for executable components + elseif(_component IN_LIST _CORRADE_EXECUTABLE_COMPONENTS) + add_executable(Corrade::${_component} IMPORTED) + + set_property(TARGET Corrade::${_component} PROPERTY + IMPORTED_LOCATION ${CORRADE_${_COMPONENT}_EXECUTABLE}) endif() # No special setup for Containers library diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 1c9c521..1650482 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -412,6 +412,10 @@ set(_MAGNUM_LIBRARY_COMPONENTS Audio DebugTools GL MaterialTools MeshTools Primitives SceneGraph SceneTools Shaders ShaderTools Text TextureTools Trade WindowlessEglApplication EglContext OpenGLTester) +# These libraries are excluded from DLL detection if Magnum is built as shared. +# Additionally, all *Application and *Context libraries are excluded as well. +set(_MAGNUM_LIBRARY_COMPONENTS_ALWAYS_STATIC + OpenGLTester) set(_MAGNUM_PLUGIN_COMPONENTS AnyAudioImporter AnyImageConverter AnyImageImporter AnySceneConverter AnySceneImporter MagnumFont MagnumFontConverter ObjImporter @@ -426,6 +430,7 @@ set(_MAGNUM_IMPLICITLY_ENABLED_COMPONENTS GL Primitives) if(NOT CORRADE_TARGET_EMSCRIPTEN) list(APPEND _MAGNUM_LIBRARY_COMPONENTS Vk VulkanTester) + list(APPEND _MAGNUM_LIBRARY_COMPONENTS_ALWAYS_STATIC VulkanTester) list(APPEND _MAGNUM_EXECUTABLE_COMPONENTS vk-info) endif() if(NOT CORRADE_TARGET_ANDROID) @@ -605,13 +610,11 @@ foreach(_component ${Magnum_FIND_COMPONENTS}) # Create imported target in case the library is found. If the project is # added as subproject to CMake, the target already exists and all the # required setup is already done from the build tree. - if(TARGET Magnum::${_component}) + if(TARGET "Magnum::${_component}") # Quotes to "fix" KDE's higlighter set(Magnum_${_component}_FOUND TRUE) else() # Library components if(_component IN_LIST _MAGNUM_LIBRARY_COMPONENTS) - add_library(Magnum::${_component} UNKNOWN IMPORTED) - # Include path names to find, unless specified above already. # Application and context libraries are a special case as well. if(_component MATCHES ".+Application") @@ -633,10 +636,24 @@ foreach(_component ${Magnum_FIND_COMPONENTS}) mark_as_advanced(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG MAGNUM_${_COMPONENT}_LIBRARY_RELEASE) + # On Windows, if we have a dynamic build of given library, find the + # DLLs as well. Abuse find_program() since the DLLs should be + # alongside usual executables. On MinGW they however have a lib + # prefix. + if(CORRADE_TARGET_WINDOWS AND NOT MAGNUM_BUILD_STATIC AND NOT _component IN_LIST _MAGNUM_LIBRARY_COMPONENTS_ALWAYS_STATIC AND NOT _component MATCHES ".+Application" AND NOT _component MATCHES ".+Context") + find_program(MAGNUM_${_COMPONENT}_DLL_DEBUG ${CMAKE_SHARED_LIBRARY_PREFIX}Magnum${_component}-d.dll) + find_program(MAGNUM_${_COMPONENT}_DLL_RELEASE ${CMAKE_SHARED_LIBRARY_PREFIX}Magnum${_component}.dll) + mark_as_advanced(MAGNUM_${_COMPONENT}_DLL_DEBUG + MAGNUM_${_COMPONENT}_DLL_RELEASE) + # If not on Windows or on a static build, unset the DLL variables + # to avoid leaks when switching shared and static builds + else() + unset(MAGNUM_${_COMPONENT}_DLL_DEBUG CACHE) + unset(MAGNUM_${_COMPONENT}_DLL_RELEASE CACHE) + endif() + # Plugin components elseif(_component IN_LIST _MAGNUM_PLUGIN_COMPONENTS) - add_library(Magnum::${_component} UNKNOWN IMPORTED) - # AudioImporter plugin specific name suffixes if(_component MATCHES ".+AudioImporter$") set(_MAGNUM_${_COMPONENT}_PATH_SUFFIX audioimporters) @@ -709,16 +726,9 @@ foreach(_component ${Magnum_FIND_COMPONENTS}) # Executables elseif(_component IN_LIST _MAGNUM_EXECUTABLE_COMPONENTS) - add_executable(Magnum::${_component} IMPORTED) - find_program(MAGNUM_${_COMPONENT}_EXECUTABLE magnum-${_component}) mark_as_advanced(MAGNUM_${_COMPONENT}_EXECUTABLE) - if(MAGNUM_${_COMPONENT}_EXECUTABLE) - set_property(TARGET Magnum::${_component} PROPERTY - IMPORTED_LOCATION ${MAGNUM_${_COMPONENT}_EXECUTABLE}) - endif() - # Something unknown, skip. FPHSA will take care of handling this below. else() continue() @@ -732,33 +742,109 @@ foreach(_component ${Magnum_FIND_COMPONENTS}) mark_as_advanced(_MAGNUM_${_COMPONENT}_INCLUDE_DIR) endif() + # Determine if the plugin is static or dynamic by reading the + # per-plugin config file. Plugins use this for automatic import if + # static. + # TODO: add per-library configure.h as well, for consistency with + # extras, plugins and integration + if(_component IN_LIST _MAGNUM_PLUGIN_COMPONENTS) + find_file(_MAGNUM_${_COMPONENT}_CONFIGURE_FILE configure.h + HINTS ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}) + mark_as_advanced(_MAGNUM_${_COMPONENT}_CONFIGURE_FILE) + + # If the file wasn't found, skip this so it fails on the FPHSA + # below and not right here. + if(_MAGNUM_${_COMPONENT}_CONFIGURE_FILE) + file(READ ${_MAGNUM_${_COMPONENT}_CONFIGURE_FILE} _magnumPluginConfigure) + string(REGEX REPLACE ";" "\\\\;" _magnumPluginConfigure "${_magnumPluginConfigure}") + string(REGEX REPLACE "\n" ";" _magnumPluginConfigure "${_magnumPluginConfigure}") + list(FIND _magnumPluginConfigure "#define MAGNUM_${_COMPONENT}_BUILD_STATIC" _magnumPluginBuildStatic) + if(NOT _magnumPluginBuildStatic EQUAL -1) + # The variable is inconsistently named between C++ and + # CMake in extras, plugins and integration, keep it + # underscored / private until that's resolved + set(_MAGNUM_${_COMPONENT}_BUILD_STATIC ON) + endif() + endif() + endif() + # Decide if the library was found. If not, skip the rest, which # populates the target properties and finds additional dependencies. # This means that the rest can also rely on that e.g. FindEGL.cmake is # present in _MAGNUM_DEPENDENCY_MODULE_DIR -- given that the library # needing EGL was found, it likely also installed FindEGL for itself. - if(((_component IN_LIST _MAGNUM_LIBRARY_COMPONENTS OR _component IN_LIST _MAGNUM_PLUGIN_COMPONENTS) AND _MAGNUM_${_COMPONENT}_INCLUDE_DIR AND (MAGNUM_${_COMPONENT}_LIBRARY_DEBUG OR MAGNUM_${_COMPONENT}_LIBRARY_RELEASE)) OR (_component IN_LIST _MAGNUM_EXECUTABLE_COMPONENTS AND MAGNUM_${_COMPONENT}_EXECUTABLE)) + if( + # If the component is a library, it should have the include dir + ((_component IN_LIST _MAGNUM_LIBRARY_COMPONENTS OR _component IN_LIST _MAGNUM_PLUGIN_COMPONENTS) AND _MAGNUM_${_COMPONENT}_INCLUDE_DIR AND ( + # And it should have a debug library, and a DLL found if + # expected + (MAGNUM_${_COMPONENT}_LIBRARY_DEBUG AND ( + NOT DEFINED MAGNUM_${_COMPONENT}_DLL_DEBUG OR + MAGNUM_${_COMPONENT}_DLL_DEBUG)) OR + # Or have a release library, and a DLL found if expected + (MAGNUM_${_COMPONENT}_LIBRARY_RELEASE AND ( + NOT DEFINED MAGNUM_${_COMPONENT}_DLL_RELEASE OR + MAGNUM_${_COMPONENT}_DLL_RELEASE)))) OR + # If the component is an executable, it should have just the + # location + (_component IN_LIST _MAGNUM_EXECUTABLE_COMPONENTS AND MAGNUM_${_COMPONENT}_EXECUTABLE) + ) set(Magnum_${_component}_FOUND TRUE) else() set(Magnum_${_component}_FOUND FALSE) continue() endif() - # Library location for libraries/plugins - if(_component IN_LIST _MAGNUM_LIBRARY_COMPONENTS OR _component IN_LIST _MAGNUM_PLUGIN_COMPONENTS) - if(MAGNUM_${_COMPONENT}_LIBRARY_RELEASE) - set_property(TARGET Magnum::${_component} APPEND PROPERTY - IMPORTED_CONFIGURATIONS RELEASE) - set_property(TARGET Magnum::${_component} PROPERTY - IMPORTED_LOCATION_RELEASE ${MAGNUM_${_COMPONENT}_LIBRARY_RELEASE}) + # Target and location for libraries + if(_component IN_LIST _MAGNUM_LIBRARY_COMPONENTS) + if(MAGNUM_BUILD_STATIC OR _component IN_LIST _MAGNUM_LIBRARY_COMPONENTS_ALWAYS_STATIC OR _component MATCHES ".+Application" OR _component MATCHES ".+Context") + add_library(Magnum::${_component} STATIC IMPORTED) + else() + add_library(Magnum::${_component} SHARED IMPORTED) endif() - if(MAGNUM_${_COMPONENT}_LIBRARY_DEBUG) + foreach(_CONFIG DEBUG RELEASE) + if(NOT MAGNUM_${_COMPONENT}_LIBRARY_${_CONFIG}) + continue() + endif() + set_property(TARGET Magnum::${_component} APPEND PROPERTY - IMPORTED_CONFIGURATIONS DEBUG) + IMPORTED_CONFIGURATIONS ${_CONFIG}) + # Unfortunately for a DLL the two properties are swapped out, + # *.lib goes to IMPLIB, so it's duplicated like this + if(DEFINED MAGNUM_${_COMPONENT}_DLL_${_CONFIG}) + # Quotes to "fix" KDE's higlighter + set_target_properties("Magnum::${_component}" PROPERTIES + IMPORTED_LOCATION_${_CONFIG} ${MAGNUM_${_COMPONENT}_DLL_${_CONFIG}} + IMPORTED_IMPLIB_${_CONFIG} ${MAGNUM_${_COMPONENT}_LIBRARY_${_CONFIG}}) + else() + set_property(TARGET Magnum::${_component} PROPERTY + IMPORTED_LOCATION_${_CONFIG} ${MAGNUM_${_COMPONENT}_LIBRARY_${_CONFIG}}) + endif() + endforeach() + + # Target and location for plugins. Not dealing with DLL locations for + # those. + elseif(_component IN_LIST _MAGNUM_PLUGIN_COMPONENTS) + add_library(Magnum::${_component} UNKNOWN IMPORTED) + + foreach(_CONFIG DEBUG RELEASE) + if(NOT MAGNUM_${_COMPONENT}_LIBRARY_${_CONFIG}) + continue() + endif() + + set_property(TARGET Magnum::${_component} APPEND PROPERTY + IMPORTED_CONFIGURATIONS ${_CONFIG}) set_property(TARGET Magnum::${_component} PROPERTY - IMPORTED_LOCATION_DEBUG ${MAGNUM_${_COMPONENT}_LIBRARY_DEBUG}) - endif() + IMPORTED_LOCATION_${_CONFIG} ${MAGNUM_${_COMPONENT}_LIBRARY_${_CONFIG}}) + endforeach() + + # Target and location for executable components + elseif(_component IN_LIST _MAGNUM_EXECUTABLE_COMPONENTS) + add_executable(Magnum::${_component} IMPORTED) + + set_property(TARGET Magnum::${_component} PROPERTY + IMPORTED_LOCATION ${MAGNUM_${_COMPONENT}_EXECUTABLE}) endif() # Applications @@ -1022,21 +1108,10 @@ foreach(_component ${Magnum_FIND_COMPONENTS}) # No special setup for TgaImporter plugin # No special setup for WavAudioImporter plugin - # Automatic import of static plugins. Skip in case the include dir was - # not found -- that'll fail later with a proper message. Skip it also - # if the include dir doesn't contain the generated configure.h, which - # is the case with Magnum as a subproject and given plugin not enabled - # -- there it finds just the sources, where's just configure.h.cmake, - # and that's not useful for anything. The assumption here is that it - # will fail later anyway on the binary not being found. - if(_component IN_LIST _MAGNUM_PLUGIN_COMPONENTS AND _MAGNUM_${_COMPONENT}_INCLUDE_DIR AND EXISTS ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}/configure.h) - # Automatic import of static plugins - file(READ ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}/configure.h _magnum${_component}Configure) - string(FIND "${_magnum${_component}Configure}" "#define MAGNUM_${_COMPONENT}_BUILD_STATIC" _magnum${_component}_BUILD_STATIC) - if(NOT _magnum${_component}_BUILD_STATIC EQUAL -1) - set_property(TARGET Magnum::${_component} APPEND PROPERTY - INTERFACE_SOURCES ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}/importStaticPlugin.cpp) - endif() + # Automatic import of static plugins + if(_component IN_LIST _MAGNUM_PLUGIN_COMPONENTS AND _MAGNUM_${_COMPONENT}_BUILD_STATIC) + set_property(TARGET Magnum::${_component} APPEND PROPERTY + INTERFACE_SOURCES ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}/importStaticPlugin.cpp) endif() # Link to core Magnum library, add inter-library dependencies. If there