microsoft / vcpkg

C++ Library Manager for Windows, Linux, and MacOS
MIT License
23.32k stars 6.44k forks source link

[qtimageformats] 6.5.3#0 can't load jpeg and webp #40721

Open Hlongyu opened 2 months ago

Hlongyu commented 2 months ago

Describe the bug QImageReader::supportedImageFormats() not include jpeg and webp

Environment

To Reproduce Steps to reproduce the behavior:

  1. cmake -S . -B build --preset windows-x64-Release
  2. Run exe

vcpkg.json

{
    "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
    "dependencies": [
        {
            "name": "qtbase",
            "version>=": "6.5.3#0",
            "platform": "windows"
        },
        {
            "name": "qtimageformats",
            "default-features": false,
            "version>=": "6.5.3#0",
            "features": [
                "webp"
            ],
            "platform": "windows"
        }
    ],
    "builtin-baseline": "02745e0f4749d1f51d2025824209408f5a6c3614",
    "overrides": [
        {
            "name": "qtbase",
            "version": "6.5.3#0"
        },
        {
            "name": "qtimageformats",
            "version": "6.5.3#0"
        }
    ]
}

main.cpp

#include <QApplication>
#include <QImageReader>
#include <iostream>
int main(int argc, char **argv) {
  QApplication app(argc, argv);
  auto support = QImageReader::supportedImageFormats();
  for (auto &i : support) {
    qDebug() << i;
  }
  app.exec();
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.9)

project(QtImageFormatTest VERSION 0.1 LANGUAGES CXX)

find_package(Qt6 CONFIG REQUIRED)
find_package(Qt6Core CONFIG REQUIRED)
find_package(Qt6Widgets CONFIG REQUIRED)
find_package(Qt6Gui CONFIG REQUIRED)

add_executable(QtImageFormatTest main.cpp)

target_link_libraries(QtImageFormatTest PRIVATE Qt6::Widgets Qt6::Core Qt6::Gui)

if(WIN32)
    if (CMAKE_BUILD_TYPE STREQUAL "Debug")
        find_program(TOOL_WINDEPLOYQT NAMES windeployqt.debug.bat)
    else()
        find_program(TOOL_WINDEPLOYQT NAMES windeployqt)
    endif()

add_custom_command(TARGET QtImageFormatTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E echo "Run windeployqt"

    COMMAND ${TOOL_WINDEPLOYQT}
            $<TARGET_FILE:QtImageFormatTest>
    COMMAND ${CMAKE_COMMAND} -E echo "end windeployqt"
)
endif()

CMakePresets.json

{
    "version": 5,
    "configurePresets": [
        {
            "name": "windows-x64-Debug",
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "architecture": {
                "value": "x64",
                "strategy": "external"
            },
            "toolset": {
                "value": "host=x64",
                "strategy": "external"
            },
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "Debug",
                "CMAKE_CXX_COMPILER": "cl.exe",
                "CMAKE_C_COMPILER": "cl.exe",
                "CMAKE_TOOLCHAIN_FILE": "D:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake",
                "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
            }
        },
        {
            "name": "windows-x64-Release",
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "architecture": {
                "value": "x64",
                "strategy": "external"
            },
            "toolset": {
                "value": "host=x64",
                "strategy": "external"
            },
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "RelWithDebInfo",
                "CMAKE_CXX_COMPILER": "cl.exe",
                "CMAKE_C_COMPILER": "cl.exe",
                "CMAKE_TOOLCHAIN_FILE": "D:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake",
                "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
            }
        }
    ]
}

Expected behavior Support jpeg and webp.

Failure logs

Loaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qgifd.dll'. Symbols loaded.
Loaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qicnsd.dll'. Symbols loaded.
Loaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qicod.dll'. Symbols loaded.
Loaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qjpegd.dll'. Symbols loaded.
Unloaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qjpegd.dll'.
Loaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qtgad.dll'. Symbols loaded.
Loaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qwbmpd.dll'. Symbols loaded.
Loaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qwebpd.dll'. Symbols loaded.
Unloaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qwebpd.dll'.
"bmp"
"cur"
"gif"
"icns"
"ico"
"pbm"
"pgm"
"png"
"ppm"
"tga"
"wbmp"
"xbm"
"xpm"
dg0yt commented 2 months ago

Check that the DLLs for jpeg and webp libs are deployed and found, too. When it comes to plugins, deployment of transitive runtime dependencies is ... tricky.

Hlongyu commented 2 months ago

Check that the DLLs for jpeg and webp libs are deployed and found, too.

Directory: D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats

Mode LastWriteTime Length Name


-a--- 2024/8/30 10:39 130560 qgifd.dll -a--- 2024/8/30 10:49 157696 qicnsd.dll -a--- 2024/8/30 10:39 137216 qicod.dll -a--- 2024/8/30 10:39 162816 qjpegd.dll -a--- 2024/8/30 10:49 97280 qtgad.dll -a--- 2024/8/30 10:49 93184 qwbmpd.dll -a--- 2024/8/30 10:49 105984 qwebpd.dll

dg0yt commented 2 months ago

These are the Qt plugins. Some plugins need DLLs with the actual implementation.

Hlongyu commented 2 months ago

When i debug step by step. I found it will call LoadLibrary() for qjpegd.dll.

hnd = LoadLibrary(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(attempt).utf16()));

Loaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qjpegd.dll'. Symbols loaded.
Unloaded 'D:\dev\qt-bug-report\out\build\windows-x64-Debug\imageformats\qjpegd.dll'. 
dg0yt commented 2 months ago

That's just the same information as in the initial post: It fails to load the plugin. But the plugin is there. I already suggest that it might be failing because the plugin fails find runtime dependencies (DLLs), here the jpeg DLL from port libjpeg-turbo.

Harold2017 commented 2 months ago

apart from qjpeg.dll, you also need copy jpeg62.dll into your .exe folder to support jpeg

as for 'webp', you need copy libsharpyuv / libwebp / libwebpdecoder / libwebpdemux / libwebpmux.

you can find those necessary dependencies in corresponding CMakeLists.txt in https://github.com/qt/qtimageformats/blob/dev/src/plugins/imageformats

SchaichAlonso commented 1 month ago

jpeg is provided by Qt::Gui which is part of qtbase, not qtimageformats. Make sure you have the jpeg feature turned on for qtbase, and in case you're running from the build directory instead of fully deploying, either set the QT_PLUGIN_PATH to $vcpkg_installed/$triplet/debug/Qt6/plugins or $vcpkg_installed/$triplet/Qt6/plugins depending on whether you're in debug mode or not. The debug version of the plugins cannot be loaded by a release build nor can the release plugins be loaded by a debug build, so be sure they match.

In case you're using a static build, you might need to tell Qt to bundle the Qt::QJpegPlugin and Qt6::QWebpPlugin into your application target(s). If you're dynamic linking , listing Qt::QJpegPlugin and Qt6::QWebpPlugin as library dependencies will instruct vcpkg to copy the qt jpeg and webp libraries into your build directory, which is useless because you need them in a subdirectory, but it'll also copy all dependencies of the plugins into the build directory and is aware of whether you're building release or debug, which might be handy.

TLDR: adding something like

set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>$<IF:$<STREQUAL:${BUILD_SHARED_LIBS},SHARED>,DLL,>")

enable_testing()
add_test(NAME QtImageFormatTest COMMAND QtImageFormatTest -platform minimal COMMAND_EXPAND_LISTS)
set_property(TEST QtImageFormatTest PROPERTY ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}$<$<CONFIG:Debug>:/debug>/bin")
set_property(TEST QtImageFormatTest APPEND PROPERTY ENVIRONMENT_MODIFICATION "QT_PLUGIN_PATH=set:${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}$<$<CONFIG:Debug>:/debug>/Qt6/plugins")
qt_import_plugins(
  QtImageFormatTest
  INCLUDE Qt::QJpegPlugin Qt6::QWebpPlugin Qt::QMinimalIntegrationPlugin
)

should add a ctest target for your application, which configures the environment to load plugins and dlls from vcpkg's intermediate directory prior to executing the binary, bundle the jpeg and webp plugins incase of static linking, and work on either x64-windows or x64-windows-static. The _VCPKG_INSTALLED_DIR and VCPKG_TARGET_TRIPLET cmake variables are both defined in the vcpkg cmake toolchain file, and the generator expression is used to pick the debug subdirectory if required.