QT打包动态库

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT打包动态库相关的知识,希望对你有一定的参考价值。

参考技术A

Qt 官方开发环境里自带了一个工具:windeployqt.exe。

  

 win+r 然后输入 cmd 打开命令提示行,切换到编译完的软件目录下,假设软件名叫 abc.exe,在命令行里输入 windeployqt abc.exe,就会把需要的动态库都复制到该软件目录下。

  

 

  

  

 封装了一个小的静态编译的exe程序

  

  链接: https://pan.baidu.com/s/1ck442q

 密码: LCQQ 

  

  

 

  

  

 warning:Cannot find Visual Studio installation directory,VCINSTALLDIR is not set.

  

  

 设置环境变量VCINSTALLDIR的值为VS目录,比如我的C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC

Qt 联合Visual Studio编译打包发布

1、qt

查找项目中使用到的qt动态链接库;

步骤如下

①打开项目使用的windeployqt工具(qt自带的工具);

②进入到文件夹所在目录;使用 cd 命令 

③使用命令:windeployqt Name.exe(在目标文件夹所在目录下执行该命令)

但是由于我的QT使用的是MSVC编译器,会用到一些VC的库,使用qt的命令行时会提示我

warning:Cannot find Visual Studio installation directory,VCINSTALLDIR is not set.

解决方案1

win+R,输入QT安装目录下windeployqt.exe的路径,然后空格,再加上项目Release的路径。
我的是:C:\\Qt\\Qt5.13.1\\5.13.1\\msvc2015_64\\bin\\windeployqt.exe D:\\GIICS\\qtReleaseDemo\\x64\\Release\\qtReleaseDemo.exe,供参考。

然后会有这个warning,这个在中间很难被发现,要注意!

找到msvcp140d.dll(我是VS2015,所以是140),复制它的路径添加到环境变量中。我的路径是C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\redist\\debug_nonredist\\x64\\Microsoft.VC140.DebugCRT\\msvcp140d.dll,添加环境变量时,到VC就可以了,后面的不要。

关闭cmd重新打开(一定要先关闭之前打开的,然后重新打开),输入第三步的路径,C:\\Qt\\Qt5.13.1\\5.13.1\\msvc2015_64\\bin\\windeployqt.exe D:\\GIICS\\qtReleaseDemo\\x64\\Release\\qtReleaseDemo.exe,回车就行了。

看到Release文件夹下多出了QT的很多dll和vcredist_x64.exe就行了。把这个文件夹放到一个全新的计算机也能跑起来,不过得在计算机上先安装图中的vcredist.exe。    

应用windeploy添加环境变量时尽量只有一个 ,当两个时你用windeployqt +可执行名时 打包可能会出错,如你使用的时msvc2019_64建立的Qt项目

你打包时可以使用的是mingw_64打包的文件。移植到其他电脑上时就会报错。

 所以你可以留有一个环境变量的路径 记得重启

方法二

  1. 首先将配置改为Release。

  2. 接下来重新生成项目。

  3. 然后从工程目录/x64/Release/中便可找到生成的exe文件。

  4. 若想运行该exe文件,需将其需要的各个dll文件与其放在同一文件夹中。

    这里主要需要qt的一些dll文件,可在qt安装目录里msvc2017_64/bin文件夹中找到。

使用windeployqt这个命令应该都知道,

将release版本exe复制拷贝到一个单独目录;

4.2打开QT下MSVC 2017控制台,切换到刚才exe所在目录;

4.3再使用 Qt 自带的 windeployqt 工具命令,其语法格式为:

windeployqt 可执行程序名

4.4可以看到windeployqt 工具已经将程序所依赖的qt环境已经复制到当前目录。

还有就是进入VS的安装路径

C:\\ProgramFiles(x86)\\MicrosoftVisualStudio14.0\\Common7\\IDE\\RemoteDebugger\\x64
你是x64开发的就选x64,要不然就选x86.

去把如下运行库拷出来放到exe路径下,要不然去遇到运行库错误,就异常尴尬了!

api-ms-win-core-console-l1-1-0.dll
api-ms-win-core-datetime-l1-1-0.dll
api-ms-win-core-debug-l1-1-0.dll
api-ms-win-core-errorhandling-l1-1-0.dll
api-ms-win-core-file-l1-1-0.dll
api-ms-win-core-file-l1-2-0.dll
api-ms-win-core-file-l2-1-0.dll
api-ms-win-core-handle-l1-1-0.dll
api-ms-win-core-heap-l1-1-0.dll
api-ms-win-core-interlocked-l1-1-0.dll
api-ms-win-core-libraryloader-l1-1-0.dll
api-ms-win-core-localization-l1-2-0.dll
api-ms-win-core-memory-l1-1-0.dll
api-ms-win-core-namedpipe-l1-1-0.dll
api-ms-win-core-processenvironment-l1-1-0.dll
api-ms-win-core-processthreads-l1-1-0.dll
api-ms-win-core-processthreads-l1-1-1.dll
api-ms-win-core-profile-l1-1-0.dll
api-ms-win-core-rtlsupport-l1-1-0.dll
api-ms-win-core-string-l1-1-0.dll
api-ms-win-core-synch-l1-1-0.dll
api-ms-win-core-synch-l1-2-0.dll
api-ms-win-core-sysinfo-l1-1-0.dll
api-ms-win-core-timezone-l1-1-0.dll
api-ms-win-core-util-l1-1-0.dll
api-ms-win-crt-conio-l1-1-0.dll
api-ms-win-crt-convert-l1-1-0.dll
api-ms-win-crt-environment-l1-1-0.dll
api-ms-win-crt-filesystem-l1-1-0.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-locale-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-multibyte-l1-1-0.dll
api-ms-win-crt-private-l1-1-0.dll
api-ms-win-crt-process-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-time-l1-1-0.dll
api-ms-win-crt-utility-l1-1-0.dll
concrt140.dll
msvcp140.dll
ucrtbase.dll
vcruntime140.dll

如遇0xc0000007b,应该是你没把上面这些库放完整。

注意concrt140.dll
msvcp140.dll
vcruntime140.dll(我是VS2015,所以是140)

查找程序所需要的dll

一、procexp

1.procexp 免费

https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer

procexp.exe查看32位程序,procexp64.exe 查看64位程序

 2.View->Lower Pane View DLLs 显示dll窗口

其他打包方式 方法一:

  1. 在exe所在目录新建文本文档(后续会改为批处理程序bat后缀),自定义命名,如AutoGetDLL.txt,并添加以下内容:

    for /r "%cd%" %%i in (*.exe) do (
    
    D:\\Qt\\6.2.4\\msvc2019_64\\bin\\windeployqt.exe "%%~nxi")
    
    pause

    注意:批处理语句中的C:\\Qt\\Qt5.7.0\\5.7\\mingw49_32\\bin\\windeployqt.exe是windeployqt.exe实际所在路径,在QT安装目录下搜索windeployqt.exe即可定位所在路径。

  2. 修改txt后缀为bat:

  3. 运行bat(批处理)程序即可将程序依赖的DLL拷贝至程序所在目录:

  4. exe依赖的dll拷贝成功,程序正常运行!

方法二:用bat自动拷贝所需动态库批处理

自动化实现依赖库拷贝

这就需要使用批处理脚本了,功能是将当前脚本所在目录的所有exe文件所依赖的QT库都拉进来,完美解决QT依赖库拷贝问题,脚本如下:


echo off
echo Setting up environment for Qt usage...
set PATH=D:\\Qt\\6.2.4\\msvc2019_64\\bin;%PATH%      rem 此行目录为QT的安装目录,需要自行调整
echo bat与exe放在同一个目录
for /f "delims=" %%A in ('dir /b *.exe') do windeployqt %%A
echo pause

方法三:

Windows下,exe文件在设计实现时可能依赖某些动态库(*.dll文件),这些在调试台调试或在本机运行因为指定了包含库文件或者指定了环境变量,使得运行时可以找到并调用这些文件。但是环境变化,很容易找不到。报错找不到dll文件。
对现成的exe文件,解决方法一般是根据报错信息,找到dll文件,设置好环境变量,或者直接复制dll文件到exe所在目录解决依赖问题。
其实主要是编译得到exe文件想要移到其他电脑上运行,解决依赖库问题。

1)思路

将依赖动态库复制到 exe 目录下,很简单的工作,用 bat 脚本自动实现。

  1.  分析依赖库
  2.  找到对应的 dll 文件目录,找不到则记录
  3.  复制到当前目录下
  4. 分析结果可能不够,提供补充工具,根据名字找到并复制到当前目录下

2)方法

  1. Vistual Studio 提供 dumpbin.exe 工具,可以分析依赖库
    该 exe 在 VS\\VC\\bin 下,可 cd 至此或者打开 VS 命令行工具。输入
    dumpbin.exe /dependents xxx\\xxx.exe
    即可得到依赖库信息。
  2. 用 findstr 工具匹配一下文本可以得到正确的 dll 依赖库文本,例如
    findstr "\\.dll$" test.txt

    即可匹配到具有“.dll”字符串的行。用通道和重定向可以很方便输出全部为dll名字的 txt 文本

  3. 用 where 工具找到本机上 dll 文件目录
    【问题】如果没有设置环境变量,自然是找不到。如果设置了,自然又不缺 dll 。
    所以这个工具也只是实现复制的作用,供移动到其他电脑方便使用。
    where xxx.dll
  4. 用 copy 工具复制文件
    copy realdir\\xxx.dll .\\dlls\\xxxxx.dll

3) bat脚本

a. get_dll.bat
需搭配add_process.bat使用,即保持同一目录
功能:

  • 复制exe到该目录下
  • 解析dll依赖
  • 复制dll到该目录下
 
  1. @echo off
    echo 应用: 利用vs的dumpbin工具解析依赖dll,并复制到.\\dll_date目录下。
    echo 原理: 用vs的dumpbin解析dll依赖,where找到dll路径,copy过来。
    echo 使用:	1. cmd下 this + exe file dir
    echo 	2. 提示输入路径。
    echo 补充: 运行时可能仍然缺少某些dll文件,运行add_dll.bat手动补充。
     
    SETLOCAL ENABLEDELAYEDEXPANSION
    set exe_path=%1
    set exe_name=%~n1%~x1
    set /p copy_exe=复制%1到 %~p0 exe_%date:~5,10% 下(y or n)?
    if %copy_exe%==y ( md .\\exe_%date:~5,10% 2>nul
    copy %1 .\\exe_%date:~5,10%\\%exe_name%)
    set dll_path=dll_%date:~5,10%
    set /p vs_root_path=visual studio 安装根目录(eg.E:\\VS2015):
    ::set vs_root_path=E:\\VS2015
    set dumpbin_path=%vs_root_path%\\VC\\bin\\
    echo Step1. set dumpbin root: %dumpbin_path%
    echo Step2. set exe file path: %exe_path%
    md .\\%dll_path%>nul
     
    echo Step3. 开始解析依赖dll
    %dumpbin_path%dumpbin.exe /dependents %exe_path% | findstr "\\.dll$" >.\\%dll_path%\\_dependent_dll_log.txt
     
    echo 解析完毕,总计
    type .\\%dll_path%\\_dependent_dll_log.txt | find /v /c ""
     
    set /p showlog=展示全部(y or n)?
    if %showlog%==y ( type .\\%dll_path%\\_dependent_dll_log.txt)
     
    echo Step4. 复制全部dll到 .\\%dll_path%\\
    set /p copyAll=确定(y or n)?
    if not %copyAll%==y ( echo 清除缓存
    del .\\%dll_path%\\*.*
    rd .\\%dll_path%
    echo 清理完毕,再见
    goto end )
     
    for /f %%i in (.\\%dll_path%\\_dependent_dll_log.txt) do ( 
    WHERE %%i 1> .\\%dll_path%\\temp.txt 2>nul
    if errorlevel 1 ( echo 找不到%%i,记录于.\\%dll_path%\\copy_error_log.txt
    echo %%i>>.\\%dll_path%\\copy_error_log.txt )
    call add_process.bat %%i -off)
     
    del %dll_path%\\temp.txt
    echo 复制工作结束
    :end
    pause
    

b. add_process.bat
附加处理工具,主要工作是获得txt文本中第一行,并复制dll文件

 
  1. @echo off
    
    set dll_name=%~n1%~x1
    
    for /f %%j in (.\\%dll_path%\\temp.txt) do ( if %2==-on echo 开始复制,复制对象:%%j
    
    copy %%j .\\dll_%date:~5,10%\\%dll_name%
    
    goto add_end )
    
    :add_end
    
    
    ::end add_process to break for loop and get only the first line.

c. add_dll.bat
补充工具
功能:

  • 根据输入dll名字,自动查找并复制到该目录下dll存放文件夹中

 使用:

  • 直接运行即可
  1. @echo off
    
    set dll_path=dll_%date:~5,10%
    
    set temp=%dll_path%\\temp.txt
    
    md .\\%dll_path% 2>nul
    
    echo 应用:复制dll文件到%dll_path%目录下
    
    :add_start
    
    set /p dll_name=输入dll文件名(eg. gflags.dll),q to quit:
    
    if %dll_name%==q ( goto add_end)
    
    where %dll_name% 2>nul 1>%temp%
    
    if errorlevel 1 ( echo 未找到%dll_name%,请重新输入
    
    goto add_start )else ( echo 找到%dll_name% 于
    
    type %temp% )
    
    
    call add_process.bat %dll_name% -on
    
    
    set /p flag=继续复制dll文件(y or n)?
    
    if %flag%==y ( goto add_start )else ( echo 再见)
    
    del .\\%temp%
    
    
    :add_end
    
    pause

 3)小结

  1. 算是完整地实现一个功能,对简单的问题有简单的解决方法。
    为了应付多种情况所以复杂了一些。调试bat的过程也感到十分地亲切。
    也对网络资源的一点点补充。
  2. 是bat的练手,bat语法奇葩但高效,以行为处理单位,对字符串直接进行运行,对空格敏感。
    小结用到的语法如下
     
      
    1. 用到的bat语法

    2. 1) 变量与赋值 set定义,%名字%调用, set /p 提示输入

    3. %加数字是批处理后面的参数,以空格间隔。0表示本身的完全路径。

    4. 利用%数字 和 其他处理手段,可以方便地处理参数和路径 https://www.jb51.net/article/52744.htm

    5. 2) 管道与重定向 | > >> >& 1> 2>

    6. |组合 >重定向 >>追加重定向

    7. 数字表示句柄,代表信息级别。1<&3 3的指向复制给1 1> 一般为标准输出级别 2为错误信息级别 0为输入。

    8. >nul 是windows下空设备。

    9. 3) if else。if [not] == if [not] exist "%filepath%" ()

    10. 需要有空格才能识别else以及括号里的命令。

    11. 4) for 循环与内部变量

    12. 一般的环境变量需延迟定义。这里失败了,用了别的方法,call第二个bat。

    13. 5) call goto

    14. call调用第二个bat 结束后返回。使for循环有效continue。

    15. goto跳转到其他代码,一旦跳出for将不再返回,为break。

    16. 对于for循环内部循环赋值变量,可见这个变量是临时性的。传入第二个for循环进行处理,并且这里不是环境变量,而是循环变量。

    17. 天然支持随循环变化。

    18. 主要用来解决:

    19. 第一个for循环得到文本内每一行,第二个循环得到由一个循环的一行字符串处理得到的一个新文本的第一行。两个for循环一样的语法,

    20. 只是第二个for循环只需得到第一行即可,故而goto,break for。

    21. goto对循环非常非常轻松地实现。

    22. 6) 字符串处理

    23. findstr + 正则表达式。其以行为处理单位。

    24. 7) 使用errorlevel

    25. 判断命令是否执行成功

  3. 还想做的
    把dumpbin独立出来

4)其他 

  1. 果然是太简单以至于网上都没有类似脚本
    用vs编译程序可以直接使用生成事件自动复制依赖库,且依赖库是原生设置的,更为准确。
    参考博客:VS编译后直接复制DLL库文件到其他目录下 VS编译后直接复制DLL库文件到其他目录下 - 94cool - 博客园

方法四 :采用liunx 的ldd命令查找所需要的依赖库并一键复制

这就需要用的Win下必备神器之Cmder

简介

cmder是一个增强型命令行工具,不仅可以使用windows下的所有命令,更爽的是可以使用linux的命令,shell命令。

下载

GitHub - cmderdev/cmder: Lovely console emulator package for Windows

Releases · cmderdev/cmder · GitHub

下载的时候,会有两个版本,分别是mini与full版;唯一的差别在于有没有内建msysgit工具,这是Git for Windows的标准配备;全安装版 cmder 自带了 msysgit, 压缩包 23M, 除了 git 本身这个命令之外, 里面可以使用大量的 linux 命令;比如 grep, curl(没有 wget); 像vim, grep, tar, unzip, ssh, ls, bash, perl 对于爱折腾的Coder更是痛点需求。

安装

直接解压到某个目录就可以了,点击Cmder.exe运行。

配置环境变量

在系统变量添加

  • 变量名: CMDER_HOME
  • 变量值: 安装绝对路径


最后在Path添加一条斜体文字
%CMDER_HOME%

添加 cmder 到右键菜单

配置环境变量后,在管理员权限的终端输入以下语句。
Win8或者Win10可以直接 win+x 再按 a 键进入。

Cmder.exe /REGISTER ALL

配置好后,任意文件夹右键

新标签打开个管理员权限终端

快捷键 Ctrl + t 后勾选

设置

快捷键:win + alt + p
或者在右下角图标,右击

设置bash作为默认开启的选项

解决中文乱码问题

之前在网找了好多方法,可是都解决不了,很多人在在Environment里添加set LANG=zh_CN.UTF-8来解决中文乱码的问题,可是我用这个方法并没有成功,可能是环境的原因吧,我的系统是win10的。
最后找到解决办法:
Settings->Startup->Environment 添加
set LANG=zh_CN.UTF-8
set LC_ALL=zh_CN.utf8

重启Cmder,发现使用ls,中文正确显示了。

解决文字重叠问题

Win + ALT + P,唤出设置界面直接去掉右边那个monospce的对勾即可

更改背景

更换主题

内置了几款不错的主题,当然如果你觉得不合适,当然也支持自己设定。

常用功能介绍

使用前需要解决的几个问题

  • ls命令不支持中文

    win+alt+p打开设置面板,找到 Startup -> Envrioment选项
    在下面的文本框里添加一行  set LANG=zh_CN.UTF-8
    然后重启cmder
    然后用ls命令查看目录下的文件,带中文的文件名都能正常显示了。
  • 添加 cmder 到右键菜单

    首先打开具有管理员权限的终端,快捷键 Ctrl + t 勾选 Run as current user和  Run as administrator这两 项,然后点start开启,然后在命令行输入 Cmder.exe /REGISTER ALL

现在在文件夹上右键点击Cmder here 就能在cmder里进入该目录

修改命令提示符号

cmder默认的命令提示符是 λ ,如果想改成常见的 $ ,具体操作如下:
打开cmder安装目录下的\\vendor\\clink.lua文件找到lambda = "λ"lambda = "("..env..") λ"把λ替换成$
然后重启cmder即可,但powerShell需要另行设置
打开cmder安装目录下的\\vendor\\profile.ps1文件找到λ <PostPrompt> <repl input>λ <PostPrompt> |Microsoft.PowerShell.UtilityWrite-Host "`nλ " -NoNewLine -ForegroundColor "DarkGray"把λ替换成$ ,然后重启cmder即可

设置默认打开目录

win+alt+p打开设置面板,找到Startup -> Tasks选项,在右侧选中cmd::Cmder 把
cmd /k "%ConEmuDir%..init.bat" 修改成 cmd /k "%ConEmuDir%..init.bat" -new_console:d:E:\\www 即可。
E:\\www就是我们指定的默认打开目录

自定义aliases

cmder还增加了alias功能,它让你用短短的指令执行一些常见但指令超长又难以记忆的语法;比如 ls cls等等
打开cmder安装目录下的\\config\\user-aliases.cmd文件
下面是我自己定义的常用的

st="D:\\Sublime Text 3\\sublime_text.exe" //输入st打开Sublime Text 3编辑器
w=cd /d E:/www  //输入w跳转到E盘下的www目录
..=cd ..  //输入..返回上一级文件夹
wp=.\\node_modules\\.bin\\webpack $* //如果webpack不是全局安装而是安装在项目下webpack命令不能直接用,
                                  //需要.\\node_modules\\.bin\\webpack调用,每次都这样写太麻烦。
                                  //现在只要输入wp就可以用webpack命令

如上图示编号的部分说明如下:

1, Cmder常用快捷键

  • 利用Tab,自动路径补全;
  • 利用Ctrl+T建立新页签;利用Ctrl+W关闭页签;
  • 利用Ctrl+Tab切换页签;
  • Alt+F4:关闭所有页签
  • Alt+Shift+1:开启cmd.exe
  • Alt+Shift+2:开启powershell.exe
  • Alt+Shift+3:开启powershell.exe (系统管理员权限)
  • Ctrl+1:快速切换到第1个页签
  • Ctrl+n:快速切换到第n个页签( n值无上限)
  • Alt + enter: 切换到全屏状态;
  • Ctr+r 历史命令搜索

2, 可在视窗内搜寻画面上出现过的任意关键字。

3, 新增页签按钮。

4, 切换页签按钮。

5, 锁定视窗,让视窗无法再输入。

6, 切换视窗是否提供卷轴功能,启动时可查询之前显示过的内容。

7, 按下滑鼠左键可开启系统选单,滑鼠右键可开启工具选项视窗。 Win+Alt+P :开启工具选项视窗。

现在讲解怎样使用

右击选择Cmder Here

验证下 ldd+ 可执行文件名

ldd untitled5.exe

 没问题开始下面操作不能使用看是否配置正确

 启动任务我用的是 bash as Admin  

准备一个.sh脚本

比如我的 untitled5.sh

#!/bin/sh
exe="untitled5" #需要发布的程序名称
pwd="C:/Users/a7357/Documents/build-untitled5-Qt_6_2_4_msvc2019_64-Debug/debug/dll" #所建文件夹的路径
files=$(ldd $exe | awk 'if (match($3,"/")) printf("%s "),$3  ')
$(mkdir $pwd)
for Variable in $files[@]
do
    cp $files $pwd
done

exe需要改为你程序的名字

pwd 改为你需要生成的路径

执行 ./ +你的.sh脚本文件名

./untitled5.sh

运行后你会发现所需要的dll会复制到该路径下,配上qt自带的windepyqt.exe 在移到其他电脑上运行基本没任何毛病

以上是关于QT打包动态库的主要内容,如果未能解决你的问题,请参考以下文章

QT程序打包

37QT程序打包

cpp文件是怎么变成可执行文件的?动态链接库又是啥呢?

Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库

如何将qt静态库代码还原动态库

qt动态库编译,是不是只要声明