microsoft / vcpkg

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

applocal.ps1/qtdeploy.ps1 wont deploy plugins for libraries only referenced in QML #9032

Open deanljohnson opened 4 years ago

deanljohnson commented 4 years ago

Describe the bug QtLocation depends on the Qt geoservices plugins. If a Qt plugin such as QtLocation is only used within QML it will not be picked up by dumpbin which leads to appdeploy.ps1 & qtdeploy.ps1 not deploying necessary QML plugins such as geoservices. Even if the application being built links to QtLocation, unless it actually imports a function from QtLocation, dumpbin will not report it as a dependency.

This can be worked around by including something from QtLocation and using it in some way. This will make dumpbin report QtLocation as a dependency and then geoservices will be deployed.

I've only had this happen with QtLocation because that is what I use but I imagine it can happen in other cases where a library is only referenced via QML.

To Reproduce Steps to reproduce the behavior:

  1. Create a Qt application linked to QtLocation with a QML file importing QtLocation and using it in some way. Make sure the application is not using QtLocation within c++ code.
  2. Build the application
  3. Look in the plugins folder next to the exe - there should be a geoservices folder but there is not.

Expected behavior Linking to a library such as QtLocation should deploy the required plugins.

JackBoosY commented 4 years ago

@Neumann-A Could you have a look? Thanks.

Neumann-A commented 4 years ago

@JackBoosY I think it is more of a general vcpkg problem than a Qt problem. It just materializes in Qt. vcpkg uses dumpbin to discover dependencies and deploy correspondingly. If there is no good way for vcpkg to deduce that information than we cannot deploy. (I also think port feature was actually correctly tagged)

Even if the application being built links to QtLocation, unless it actually imports a function from QtLocation, dumpbin will not report it as a dependency.

One the one hand this feels like a bug but is actually doing the sensible thing. If it is not detected as a dependency then it is probably not needed. (else we would need to guess what the user would want)

@deanljohnson Do you know of a way to ask Qt which QML dependencies it requires? If not there is no way for us to deploy (due to missing information). Did you try to use the Qt5QuickCompiler i.e. ahead of time compilation (mentioned here; Maybe it helps discovering the dependencies)?

deanljohnson commented 4 years ago

One the one hand this feels like a bug but is actually doing the sensible thing. If it is not detected as a dependency then it is probably not needed. (else we would need to guess what the user would want)

I think this is generally true, but in my CMakeLists.txt I am marking QtLocation as a dependency. Whether I use it or not shouldn't matter - vcpkg should be able to tell I am linking to it (somehow). I don't know if there is a way for vcpkg to pick up my link targets directly - perhaps by enumerating a targets link libraries with cmake.

@deanljohnson Do you know of a way to ask Qt which QML dependencies it requires? If not there is no way for us to deploy (due to missing information). Did you try to use the Qt5QuickCompiler i.e. ahead of time compilation (mentioned here; Maybe it helps discovering the dependencies)?

I don't know how but it has to be possible. I just recently converted my application to using vcpkg to manage the Qt dependency. Previously I was using Qt's own windeployqt and that worked well (correctly handled QtLocation and deployed its plugins) but it does not seem to work through vcpkg because the paths to things are different within vcpkgs Qt installation.

Ahead of time compiling the QML resources would probably work - I tried it briefly and couldn't get it to work. I already have a workaround for now (include and use QtLocation from c++).

Neumann-A commented 4 years ago

@deanljohnson What looked you windeployqt call like? I looked briefly through the source and it seems like there are additional options which can be passed.

deanljohnson commented 4 years ago

It is something like the following:

PATH=PATH_TO_QT_BIN_FOLDER windeployqt
    --dry-run
    --no-compiler-runtime
    --qmldir ${CMAKE_CURRENT_LIST_DIR}
    --list mapping
    ${TARGET_EXECUTABLE}

I'd parse the output and copy the necessary files over myself.

I've read quite a bit about using windeployqt with vcpkg and I tried various things - mostly related to specifying different paths to the Qt bin folder. I never got it working and it seems the general consensus is it is quite helplessly broken when used with vcpkg.

Neumann-A commented 4 years ago

yeah one problem could be

    const QString qtBinDir = qmakeVariables.value(QStringLiteral("QT_INSTALL_BINS"));
    const QString libraryLocation = options.platform == Unix ? qmakeVariables.value(QStringLiteral("QT_INSTALL_LIBS")) : qtBinDir;

but did you actually working qt.conf with it? You probably must do the same as vcpkg_configure_qmake (e.g. configure_file(${CURRENT_INSTALLED_DIR}/tools/qt5/qt_release.conf ${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/qt.conf)) so that qmake has the correct paths.