1 需求描述
- 软件能够编译c/c++源代码;
- 软件内部实现编译功能,无需安装其它开发工具。
2 设计思路
2.1 如何实现?
最开始的时候其实软件也是支持编译功能的,只是借助了Visual Studio开发工具中的编译器,这样用户在安装软件后还要安装Visual Studio才行,如此一来显得特别麻烦。后来想着把Visual Studio中的编译功能集成到软件中,但是发现可行性并不高。
那,有没有一种简单可行的办法,让软件不安装Visual Studio也能够编译代码?答案是肯定,使用MinGW编译套件即可实现集成编译功能。
MinGW,是Minimalist GNUfor Windows的缩写。它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许你在GNU/Linux和Windows平台生成本地的Windows程序而不需要第三方C运行时(C Runtime)库。
2.2 如何获取MinGW编译套件?
其实,在安装Qt的时候只要勾选了MinGW组件就能获取到套件,如下:
ok,安装完成后套件就获取到套件了。
套件路径示例:D:ProgramQtQt5.12.6Toolsmingw730_32
2.3 如何集成?
获取到套件后集成就很简单了,在Qt可执行程序目录下创建一个Tools目录(名字自拟),将mingw730_32中的内容全部复制进去即可。
3 代码实现
3.1 套件获取到了如何编译?
完成上述步骤后,接下来就是写代码了,这里使用QProcess调用脚本的方式进行编译,编译过程信息可通过信号槽获取,然后显示到界面上,是不是感觉很专业。
void CompileUtil::startCompilation(const QString &buildPath)
{
m_buildPath = buildPath;
//清空构建目录下可执行程序
clearFiles("exe");
//创建构建脚本
QFileInfo batInfo(QDir(buildPath), "build.bat");
QFile file(batInfo.absoluteFilePath());
file.open(QIODevice::WriteOnly);
QTextStream out(&file);
out << QString("set PATH=%1\Tools\bin;%PATH%").arg(QDir::toNativeSeparators(QApplication::applicationDirPath())) << endl;
out << QString(QString("cd /D %1").arg(QDir::toNativeSeparators(buildPath))) << endl;
out << QString("g++ *.cpp --verbose -o %1 -lwsock32").arg(OUTPUT_PROCESS_NAME) << endl;
file.close();
//执行构建脚本
m_process.setWorkingDirectory(buildPath);
m_process.setProcessChannelMode(QProcess::MergedChannels);
m_process.start(batInfo.absoluteFilePath());
}
3.2 编译完成后获取可执行文件
顺利的话,编译完成后会在源码路径生成exe可执行程序,这时便可获取到它了。
QString CompileUtil::getExecuteFile()
{
QDir dir(m_buildPath);
QFileInfoList infoList = dir.entryInfoList(QDir::Files);
foreach (QFileInfo info, infoList) {
if ("exe" == info.suffix().toLower()) {
return info.absoluteFilePath();
}
}
return QString();
}
3.3 复制可执行文件依赖的dll库
此时,生成的可执行程序还不能直接执行,它依赖一些动态库,现在把相关动态库复制到可执行文件目录下。
void CompileUtil::copyDependentDllFiles()
{
QDir sourceDir(QApplication::applicationDirPath() + "/Tools/bin");
QDir destDir(m_buildPath);
QStringList destList;
QStringList sourceList;
QFileInfoList infoList = sourceDir.entryInfoList(QDir::Files);
foreach (QFileInfo info, infoList) {
if ("dll" == info.suffix().toLower()) {
sourceList.append(info.absoluteFilePath());
}
}
infoList = destDir.entryInfoList(QDir::Files);
foreach (QFileInfo info, infoList) {
if ("dll" == info.suffix().toLower()) {
destList.append(info.absoluteFilePath());
}
}
foreach (QString fileName, sourceList) {
if (!destList.contains(fileName)) {
QFileInfo sourceInfo(fileName);
QFileInfo destInfo(m_buildPath, sourceInfo.fileName());
QFile file(fileName);
file.copy(destInfo.absoluteFilePath());
}
}
}
这里的处理比较简单,直接把/Tools/bin目录下所有的dll复制过来,简单且有效。
到此,通过集成的MinGW套件编译的可执行程序就可以正常执行了。
4 总结
让Qt应用程序集成编译功能步骤如下:
- 集成MinGW编译套件,其实就是一个目录;
- 编写并调用编译脚本;
- 复制依赖的dll文件。
强烈建议MinGW位数和Qt应用程序位数保持一致。