Qt產生的exe發布方式

本篇將介紹如何在 Windows 下使用 Qt 提供的工具來佈署 exe,
你可能會問,我不是已經編譯出 exe 了嗎?為什麼還需要佈署呢?
佈署就是將這個 exe 執行時所需要的依賴檔全部都複製到指定目錄內,
最後這個目錄內的東西拿到任一台電腦上都可以執行了!

那接下來就來介紹怎麼使用吧!

使用 windeployqt 工具

假設編譯出來的執行檔名為 hello.exe, 使用 windeployqt 來佈署(會自動找出相依的dll複製到此目錄下)

1
windeployqt hello.exe

設定 VCINSTALLDIR 環境變數

使用 windeployqt 可能出現下列訊息

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

設置環境變量 VCINSTALLDIR 的值為 VS 目錄,
比如我的 C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC

加完以後 windeployqt 會多複製一個 vcredist_x86.exe / vcredist_x64.exe 到資料夾下

參考
Qt官方開發環境生成的exe發布方式–使用windeployqt
如何將QT 5.5.1程式佈署在Windows
Tutorial Qt Creator - Installer Framework (Instalar aplicaciones de Qt en Windows) - 如何打包成安裝檔教學
QT編譯好的檔案無法執行的一種解決方案

其它相關文章推薦
[Qt] 讀檔,讀取 txt 文字檔
[Qt] 寫檔,寫入 txt 文字檔
安裝 Qt 在 Windows 7 (使用MSVC)
Qt產生的exe發布方式
Qt 新增多國語言.ts翻譯檔案
Qt5的中文亂碼問題如何解決

Qt5的中文亂碼問題如何解決

Qt5的中文亂碼問題如何解決

Qt5的中文亂碼問題如何解決

如果使用msvc2005/2008/2010,那麼需要將包含中文的源文件保存為帶BOM的UTF8格式,並且使用QStringLiteral;如果要處理本地文件路徑,那麼需要使用QFile::encodeName和QFile::decodeName

參考:http://blog.csdn.net/dbzhang800/article/details/7325698

其它相關文章推薦
[Qt] 讀檔,讀取 txt 文字檔
[Qt] 寫檔,寫入 txt 文字檔
安裝 Qt 在 Windows 7 (使用MSVC)
Qt產生的exe發布方式
Qt 新增多國語言.ts翻譯檔案

Linux md5sum 指令用法

md5sum 是個可以將檔案透過某種特定的函式或演算法產生出一組雜湊值,
而這個檔案生成組雜湊值將會是獨一無二的唯一碼,不會有別的檔案生成的雜湊值跟它一樣,
所以我們可以透過這個方式來比對這幾個檔案是不是同一個檔案,
也可以比對這個檔案有沒有被竄改過。

接下來就介紹 Linux md5sum 指令怎麼使用吧!

單一檔案產生 md5sum

以下示範對單一檔案產生 md5sum,假設我目錄下有 msvcp140.dll、msvcp140d.dll、vcruntime140.dll、vcruntime140d.dll 這 4 個 dll,但我想知道 msvcp140.dll 的 md5sum 是多少的話,我可以透過以下指令來計算 msvcp140.dll 的 md5sum,

1
2
3
4
$ ls
msvcp140.dll msvcp140d.dll vcruntime140.dll vcruntime140d.dll

$ md5sum msvcp140.dll

多個檔案產生 md5sum

如果我一次想要對多個檔案產生 md5sum 的話,可以用 * 的方式,用法如下,

1
2
3
4
$ ls
msvcp140.dll msvcp140d.dll vcruntime140.dll vcruntime140d.dll

$ md5sum * > md5sum.txt

根據 md5sum 校驗碼來檢查檔案

承上述例子,我可以將產生好的 md5sum 檔案反過來檢查這些檔案的 md5sum 是不是跟 md5sum.txt 裡紀錄的校驗碼一樣,用法是在執行 md5sum 時加上 -c 的參數後面接 md5sum 校驗碼的檔名,md5sum 檢查結果相同的話會顯示 OK,不同的話會顯示 FAILED

1
2
3
4
5
$ md5sum -c md5sum.txt
msvcp140.dll: OK
msvcp140d.dll: OK
vcruntime140.dll: OK
vcruntime140d.dll: OK

旋轉矩陣 轉 尤拉角 (Conversion Euler To Matrix)

我寫出了屬於我自己的兩種版本, 如下

版本一

參考來源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/** this conversion uses conventions as described on page:
* https://www.euclideanspace.com/maths/geometry/rotations/euler/index.htm
* Coordinate System: right hand
* Positive angle: right hand
* Order of euler angles: heading first, then attitude, then bank
* matrix row column ordering:
* [m00 m01 m02]
* [m10 m11 m12]
* [m20 m21 m22]*/
public final void rotate(matrix m) {
// Assuming the angles are in radians.
if (m.m10 > 0.998) { // singularity at north pole
heading = Math.atan2(m.m02,m.m22);
attitude = Math.PI/2;
bank = 0;
return;
}
if (m.m10 < -0.998) { // singularity at south pole
heading = Math.atan2(m.m02,m.m22);
attitude = -Math.PI/2;
bank = 0;
return;
}
heading = Math.atan2(-m.m20,m.m00);
bank = Math.atan2(-m.m12,m.m11);
attitude = Math.asin(m.m10);
}

轉成 opencv 的版本, 且對應到我的座標系 (x, z 對調), 最後 x y 軸還加上負號.
bank(x) -> attitude(x)
heading(y) -> heading(y)
attitude(z) -> bank(z)
euclideanspace -> 我的座標系(OpennGL)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Vec3f matrix2Euler(const Mat &R) {
// Assuming the angles are in radians.
float heading, attitude, bank;
if (R.at<double>(1,0) > 0.998) { // singularity at north pole
heading = atan2(R.at<double>(0,2),R.at<double>(2,2));
attitude = M_PI/2;
bank = 0;
return Vec3f(bank, heading, attitude);
}
if (R.at<double>(1,0) < -0.998) { // singularity at south pole
heading = atan2(R.at<double>(0,2),R.at<double>(2,2));
attitude = -M_PI/2;
bank = 0;
return Vec3f(bank, heading, attitude);
}
heading = atan2(-R.at<double>(2,0),R.at<double>(0,0));
bank = atan2(-R.at<double>(1,2),R.at<double>(1,1));
attitude = asin(R.at<double>(1,0));

return Vec3f(-bank, -heading, attitude);
}

版本二

參考來源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Checks if a matrix is a valid rotation matrix.
static bool isRotationMatrix(const Mat &R)
{
Mat Rt;
transpose(R, Rt);
Mat shouldBeIdentity = Rt * R;
Mat I = Mat::eye(3,3, shouldBeIdentity.type());

return norm(I, shouldBeIdentity) < 1e-6;
}

/** rotation matrix to euler angles
* Coordinate System: right hand
* Positive angle: right hand
* Order of euler angles: heading first, then attitude, then bank
* matrix row column ordering:
* [m00 m01 m02]
* [m10 m11 m12]
* [m20 m21 m22]*/
Vec3f matrix2Euler(const Mat &R)
{
assert(isRotationMatrix(R));
float sy = sqrt(R.at<double>(0,0) * R.at<double>(0,0) + R.at<double>(1,0) * R.at<double>(1,0) );
bool singular = sy < 1e-6; // If

float x, y, z;
if (!singular)
{
x = atan2(R.at<double>(2,1) , R.at<double>(2,2));
y = atan2(-R.at<double>(2,0), sy);
z = atan2(R.at<double>(1,0), R.at<double>(0,0));
}
else
{
x = atan2(-R.at<double>(1,2), R.at<double>(1,1));
y = atan2(-R.at<double>(2,0), sy);
z = 0;
}
return Vec3f(x, y, z);
}

轉成 我的座標系 (z 軸加上負號).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Vec3f matrix2Euler(const Mat &R)
{
assert(isRotationMatrix(R));
float sy = sqrt(R.at<double>(0,0) * R.at<double>(0,0) + R.at<double>(1,0) * R.at<double>(1,0) );
bool singular = sy < 1e-6; // If

float x, y, z;
if (!singular)
{
x = atan2(R.at<double>(2,1) , R.at<double>(2,2));
y = atan2(-R.at<double>(2,0), sy);
z = atan2(R.at<double>(1,0), R.at<double>(0,0));
}
else
{
x = atan2(-R.at<double>(1,2), R.at<double>(1,1));
y = atan2(-R.at<double>(2,0), sy);
z = 0;
}
return Vec3f(x, y, -z);
}

Git submodule 子模組

本篇將介紹怎麼使用 Git 的 submodule 的功能,
通常在開發時有使用到外部第三方的函式庫時(例如:sub.git),
就可以使用 Git submodule 這個功能,
將外部的 Git (sub.git)加入進來,
此時我們自己的 Git (mainrepo.git) 會去記住目前是使用 sub.git 的哪一筆 commit,
而不是去追蹤紀錄整包 sub.git 的程式碼。
這樣 mainrepo.git 就會省很多硬碟空間。

新增 submodule

1
2
cd mainrepo
git submodule add git@github.com:aaa/sub.git sub

再推上 server

抓子模組 submodule

方法1. 一次抓下來

1
git clone --recursive git@github.com:aaa/mainrepo.git

方法二. 先抓完, 再抓submodule

1
2
3
4
git clone git@github.com:aaa/mainrepo.git
cd mainrepo
git submodule init
git submodule update --recursive

移除抓下來的 submodule (清空而已)

1
git submodule deinit .

Git tag 標籤使用

新增 tag

1
2
git tag -a v0.9.0 -m '0.9.0'
git tag -a v1.0.0 -m '1.0.0'

針對很久以前 commit 的進行 tag

1
git tag -a v0.9.0 -m '0.9.0' a1b2c3456

上傳指定的 tag 到遠端

1
git push origin v0.9.0

一次上傳多個 tag 到遠端

1
git push origin --tags

刪除遠端 tag

1
git push origin :refs/tags/v1.1.0

刪除本地 tag

1
git tag -d v1.0.0