ti-enxame.com

Como copiar DLLs de tempo de execução Qt para a saída do projeto

Eu tenho um projeto simples criado no Qt Creator (instalado usando Qt SDK 1.1.4). Ele funciona bem no Qt Creator, mas se eu navegar até o diretório de saída no Windows e clicar duas vezes no EXE, receberei um erro como:

The program can't start because QtCored4.dll is missing from your computer.
Try reinstalling the program to fix this problem.

Isso é obviamente porque o Qt não está em meu PATH (e eu não quero que esteja, no caso de eu ter várias versões do Qt no meu computador), e o Qt Creator/qmake não copiou as DLLs do Qt para a saída do projeto .

O que eu gostaria de fazer é usar o qmake para copiar os arquivos Qt necessários para o diretório de saída do projeto - onde quer que esteja. Como eu faço isso?

(Eu tentei criar um alvo personalizado no qmake, mas não estou indo muito longe ...)

ATUALIZAÇÃO 19 de julho de 2016: Só para esclarecer, o post acima foi sobre Qt4. No Qt5, você deve tentar chamar windeployqt . Esta ferramenta Qt5 irá ler seu binário, determinar quais arquivos de tempo de execução Qt5 você precisa e copiá-los para seu diretório binário. Observe também que ele corrigirá caminhos absolutos na biblioteca Qt5 :: Core que são específicos para o seu PC - então o uso desta ferramenta é basicamente obrigatório, a menos que você queira fornecer um qt.conf arquive você mesmo.

31
James Johnston

OK, aqui está um hack feio:

# Copy required DLLs to output directory
CONFIG(debug, debug|release) {
    QtCored4.commands = copy /Y %QTDIR%\\bin\\QtCored4.dll debug
    QtCored4.target = debug/QtCored4.dll
    QtGuid4.commands = copy /Y %QTDIR%\\bin\\QtGuid4.dll debug
    QtGuid4.target = debug/QtGuid4.dll

    QMAKE_EXTRA_TARGETS += QtCored4 QtGuid4
    PRE_TARGETDEPS += debug/QtCored4.dll debug/QtGuid4.dll
} else:CONFIG(release, debug|release) {
    QtCore4.commands = copy /Y %QTDIR%\\bin\\QtCore4.dll release
    QtCore4.target = release/QtCore4.dll
    QtGui4.commands = copy /Y %QTDIR%\\bin\\QtGui4.dll release
    QtGui4.target = release/QtGui4.dll

    QMAKE_EXTRA_TARGETS += QtCore4 QtGui4
    PRE_TARGETDEPS += release/QtCore4.dll release/QtGui4.dll
} else {
    error(Unknown set of dependencies.)
}

Aqui estão algumas das coisas que eu não gosto:

  • Usa a variável de ambiente% QTDIR%; esta variável não é avaliada até que o comando de cópia seja realmente executado. Parece que algo como QMAKE_LIBS_QT_DLL seria mais apropriado, mas não consegui fazer isso funcionar por algum motivo.
  • Nomes de "depuração" e "liberação" embutidos em código; parece que deve haver algum tipo de variável a ser usada para isso.
  • Chamando o meio ambiente usando o comando "copiar".

Aceitarei outra resposta se alguém puder limpar isso um pouco, por exemplo, abreviando e/ou abordando algumas das minhas preocupações, ou apenas encontrando uma maneira melhor em geral.

8
James Johnston

Um método um pouco mais limpo, mas exigirá fazer um make install após um make. Funcionará no Windows, mas precisará de ajustes para outras plataformas.

debug { DESTDIR = debug }
release { DESTDIR = release }
debug_and_release { DESTDIR = bin }

myqtlibs.path = $$DESTDIR
myqtlibs.files = $$QMAKE_LIBDIR_QT/*.dll junk.txt fred.out
myqtlibs.CONFIG = no_check_exist

INSTALLS += myqtlibs

Se qmake for executado apenas para depuração, toda a saída irá para ./debug. Se for apenas para liberação, toda a saída irá para ./release. Se ambos, em ./bin.

Eu percebi que habilitar a construção de sombra no QtCreator fazia com que o executável não terminasse no DESTDIR. Não tenho certeza do porquê.

7
jwernerny

Copiar dependências com windeployqt

# Deployment - Automatically Detect and Copy Dependencies to Build Folder

TARGET_CUSTOM_EXT = .exe
DEPLOY_COMMAND = windeployqt

DEPLOY_OPTIONS = "--no-svg --no-system-d3d-compiler --no-opengl --no-angle --no-opengl-sw"

CONFIG( debug, debug|release ) {
    # debug
    DEPLOY_TARGET = $$Shell_quote($$Shell_path($${OUT_PWD}/debug/$${TARGET}$${TARGET_CUSTOM_EXT}))
    DEPLOY_OPTIONS += "--debug"
} else {
    # release
    DEPLOY_TARGET = $$Shell_quote($$Shell_path($${OUT_PWD}/release/$${TARGET}$${TARGET_CUSTOM_EXT}))
    DEPLOY_OPTIONS += "--release"
}

# Uncomment the following line to help debug the deploy command when running qmake
#message($${DEPLOY_COMMAND} $${DEPLOY_OPTIONS} $${DEPLOY_TARGET})

QMAKE_POST_LINK = $${DEPLOY_COMMAND} $${DEPLOY_OPTIONS} $${DEPLOY_TARGET}

ou Copiar dependências manualmente

# Deployment - Copy Dependencies to Build Folder

dlls.path  =  $${DESTDIR}
dlls.files += $$[QT_INSTALL_BINS]/icudt51.dll
dlls.files += $$[QT_INSTALL_BINS]/icuin51.dll
dlls.files += $$[QT_INSTALL_BINS]/icuuc51.dll
dlls.files += $$[QT_INSTALL_BINS]/libgcc_s_dw2-1.dll
dlls.files += $$[QT_INSTALL_BINS]/libstdc++-6.dll
dlls.files += $$[QT_INSTALL_BINS]/libwinpthread-1.dll
dlls.files += $$[QT_INSTALL_BINS]/Qt5Core.dll
dlls.files += $$[QT_INSTALL_BINS]/Qt5Network.dll
dlls.files += $$[QT_INSTALL_BINS]/Qt5Gui.dll
dlls.files += $$[QT_INSTALL_BINS]/Qt5Widgets.dll
dllA.path   += $${DESTDIR}/platforms
dllA.files  += $$[QT_INSTALL_PLUGINS]/platforms/qwindows.dll
dllB.path   += $${DESTDIR}/plugins/imageformats/
dllB.files  += $$[QT_INSTALL_PLUGINS]/imageformats/qico.dll
dllB.files  += $$[QT_INSTALL_PLUGINS]/imageformats/qwbmp.dll
INSTALLS   += dlls dllA dllB

Referência: http://doc.qt.io/qt-5/qmake-variable-reference.html#deployment


Caso você precise identificar pré-requisitos/dependências entre plataformas, dê uma olhada em getPrerequisites() do CMake. Ele usa dumpbin, objbin, ldd, otool para a identificação de dependências.

Referência: https://cmake.org/cmake/help/v3.0/module/GetPrerequisites.html

6
Jens A. Koch

Encontrei o mesmo problema e solução de jwernerny me ajudou muito. No entanto, eu estava usando o Shadow Build no Windows 7 e precisava de um pouco mais de ajustes.

Também precisei definir o DESTDIR de acordo com a configuração atual.

No meu caso, eu queria copiar *.qml arquivos, foi assim que consegui:

CONFIG(release, debug|release): DESTDIR = $$OUT_PWD/release
CONFIG(debug, debug|release): DESTDIR = $$OUT_PWD/debug

QmlFiles.path = $$DESTDIR/Qml
QmlFiles.files += $$files(Qml/*.qml)

INSTALLS += QmlFiles

EDITAR:

Como uso Shadow Build, preciso usar $$OUT_PWD para obter a pasta de saída.

4
ForceMagic