使用qt动态链接库编译出来的可执行程序会依赖一大堆动态链接库文件,想要将本机上编写的程序发布到其他人的计算机上,就需要将依赖的动态链接库文件和可执行程序一起打包发布。打包发布的方法有很多,原理都是一样的,通过压缩程序将可执行程序和依赖文件一起打包压缩成单独的可执行文件,用户执行该可执行文件时自动解压并运行。
常见的打包方案有WinRAR、7-Zip等,通过压缩软件的自解压模块制作带脚本的自解压程序,但这些方案有一个共同的缺点,没办法传递命令行参数。本文提供新的思路,通过pyinstaller打包功能,实现qt程序打包,并且通过python实现命令行参数传递。
1. 示例程序
编写一个CGAL程序,调用qt显示面网格。下面的代码参考CGAL文档并做了一些调整,在程序启动时开启对话框接收文件输入,也可以通过命令行传入网格文件。
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/draw_surface_mesh.h>
#include <fstream>
#include <QApplication>
#include <QFileDialog>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Point> Mesh;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
const std::string filename = (argc > 1) ? argv[1] : QFileDialog::getOpenFileName(nullptr, "Open a mesh file", "", "Supported formats (*.off *.stl *.obj *.ply);;OFF format (*.off);;STL format (*.stl);;OBJ format (*.obj);;PLY format (*.ply)").toStdString();
if (filename.empty())
return EXIT_FAILURE;
Mesh sm;
if (!CGAL::IO::read_polygon_mesh(filename, sm))
{
if (filename.substr(filename.find_last_of(".") + 1) == "stl")
std::cerr << "Invalid STL file: " << filename << std::endl;
else if (filename.substr(filename.find_last_of(".") + 1) == "obj")
std::cerr << "Invalid OBJ file: " << filename << std::endl;
else if (filename.substr(filename.find_last_of(".") + 1) == "ply")
std::cerr << "Invalid PLY file: " << filename << std::endl;
else if (filename.substr(filename.find_last_of(".") + 1) == "off")
std::cerr << "Invalid OFF file: " << filename << std::endl;
else
std::cerr << "Invalid file: " << filename << "(Unknown file format.)" << std::endl;
return EXIT_FAILURE;
}
// Internal color property maps are used if they exist and are called
// "v:color", "e:color" and "f:color".
auto vcm =
sm.add_property_map<Mesh::Vertex_index, CGAL::IO::Color>("v:color").first;
auto ecm =
sm.add_property_map<Mesh::Edge_index, CGAL::IO::Color>("e:color").first;
auto fcm = sm.add_property_map<Mesh::Face_index>(
"f:color", CGAL::IO::white() /*default*/)
.first;
for (auto v : vertices(sm))
{
if (v.idx() % 2)
{
put(vcm, v, CGAL::IO::black());
}
else
{
put(vcm, v, CGAL::IO::blue());
}
}
for (auto e : edges(sm))
{
put(ecm, e, CGAL::IO::gray());
}
put(fcm, *(sm.faces().begin()), CGAL::IO::red());
// Draw!
CGAL::draw(sm);
return EXIT_SUCCESS;
}
cmake配置文件CMakeLists.txt
编写如下,输出的可执行文件名称包含文件夹名、工具链名称、编译器命名和版本等。