/* * Copyright (C) 2018-2021 QuasarApp. * Distributed under the lgplv3 software license, see the accompanying * Everyone is permitted to copy and distribute verbatim copies * of this license document, but changing it is not allowed. */ #include "extracter.h" #include "deploycore.h" #include "pathutils.h" #include "pluginsparser.h" #include #include #include #include #include #include #include //QString DeployCore::qtDir = ""; //QStringList DeployCore::extraPaths = QStringList(); const DeployConfig* DeployCore::_config = nullptr; QtModuleEntry DeployCore::qtModuleEntries[] = { { QtBluetoothModule, "bluetooth", "QtXBluetooth", nullptr }, { QtConcurrentModule, "concurrent", "QtXConcurrent", "qtbase" }, { QtCoreModule, "core", "QtXCore", "qtbase" }, { QtDeclarativeModule, "declarative", "QtXDeclarative", "qtquick1" }, { QtDesignerModule, "designer", "QtXDesigner", nullptr }, { QtDesignerComponents, "designercomponents", "QtXDesignerComponents", nullptr }, { QtEnginioModule, "enginio", "Enginio", nullptr }, { QtGamePadModule, "gamepad", "QtXGamepad", nullptr }, { QtGuiModule, "gui", "QtXGui", "qtbase" }, { QtHelpModule, "qthelp", "QtXHelp", "qt_help" }, { QtMultimediaModule, "multimedia", "QtXMultimedia", "qtmultimedia" }, { QtMultimediaWidgetsModule, "multimediawidgets", "QtXMultimediaWidgets", "qtmultimedia" }, { QtMultimediaQuickModule, "multimediaquick", "QtXMultimediaQuick_p", "qtmultimedia" }, { QtNetworkModule, "network", "QtXNetwork", "qtbase" }, { QtNfcModule, "nfc", "QtXNfc", nullptr }, { QtOpenGLModule, "opengl", "QtXOpenGL", nullptr }, { QtOpenGLWidgetsModule, "openglwidgets", "QtXOpenGLWidgets", nullptr }, { QtPositioningModule, "positioning", "QtXPositioning", nullptr }, { QtPrintSupportModule, "printsupport", "QtXPrintSupport", nullptr }, { QtQmlModule, "qml", "QtXQml", "qtdeclarative" }, { QtQmlToolingModule, "qmltooling", "qmltooling", nullptr }, { QtQuickModule, "quick", "QtXQuick", "qtdeclarative" }, { QtQuickParticlesModule, "quickparticles", "QtXQuickParticles", nullptr }, { QtQuickWidgetsModule, "quickwidgets", "QtXQuickWidgets", nullptr }, { QtScriptModule, "script", "QtXScript", "qtscript" }, { QtScriptToolsModule, "scripttools", "QtXScriptTools", "qtscript" }, { QtSensorsModule, "sensors", "QtXSensors", nullptr }, { QtSerialPortModule, "serialport", "QtXSerialPort", "qtserialport" }, { QtSqlModule, "sql", "QtXSql", "qtbase" }, { QtSvgWidgetsModule, "svgwidgets", "QtXSvgWidgets", nullptr }, { QtSvgModule, "svg", "QtXSvg", nullptr }, { QtTestModule, "test", "QtXTest", "qtbase" }, { QtWebKitModule, "webkit", "QtXWebKit", nullptr }, { QtWebKitWidgetsModule, "webkitwidgets", "QtXWebKitWidgets", nullptr }, { QtWebSocketsModule, "websockets", "QtXWebSockets", nullptr }, { QtWidgetsModule, "widgets", "QtXWidgets", "qtbase" }, { QtWinExtrasModule, "winextras", "QtXWinExtras", nullptr }, { QtXmlModule, "xml", "QtXXml", "qtbase" }, { QtXmlPatternsModule, "xmlpatterns", "QtXXmlPatterns", "qtxmlpatterns" }, { QtWebEngineCoreModule, "webenginecore", "QtXWebEngineCore", nullptr }, { QtWebEngineModule, "webengine", "QtXWebEngine", "qtwebengine" }, { QtWebEngineWidgetsModule, "webenginewidgets", "QtXWebEngineWidgets", nullptr }, { Qt3DCoreModule, "3dcore", "QtX3DCore", nullptr }, { Qt3DRendererModule, "3drenderer", "QtX3DRender", nullptr }, { Qt3DQuickModule, "3dquick", "QtX3DQuick", nullptr }, { Qt3DQuickRendererModule, "3dquickrenderer", "QtX3DQuickRender", nullptr }, { Qt3DInputModule, "3dinput", "QtX3DInput", nullptr }, { Qt3DAnimationModule, "3danimation", "QtX3DAnimation", nullptr }, { Qt3DExtrasModule, "3dextras", "QtX3DExtras", nullptr }, { QtLocationModule, "geoservices", "QtXLocation", nullptr }, { QtWebChannelModule, "webchannel", "QtXWebChannel", nullptr }, { QtTextToSpeechModule, "texttospeech", "QtXTextToSpeech", nullptr }, { QtSerialBusModule, "serialbus", "QtXSerialBus", nullptr }, { QtWebViewModule, "webview", "QtXWebView", nullptr }, { QtVirtualKeyboard, "virtualkeyboard", "QtXVirtualKeyboard", nullptr } }; DeployCore::QtModule DeployCore::getQtModule(const QString& path) { auto Qt = DeployCore::isQtLib(path); if (!Qt) { return DeployCore::QtModule::NONE; } int modulesCount = sizeof (qtModuleEntries) / sizeof (QtModuleEntry); auto lIbName = QFileInfo(path).fileName(); for (int i = 0; i < modulesCount; ++i) { if (containsModule(qtModuleEntries[i].libraryName, lIbName)) { return static_cast(qtModuleEntries[i].module); } } return DeployCore::QtModule::NONE; } void DeployCore::addQtModule(DeployCore::QtModule &module, const QString &path) { QuasarAppUtils::Params::log("Current module " + QString::number(module), QuasarAppUtils::Debug); auto mod = getQtModule(path); QuasarAppUtils::Params::log("Add new module from path " + path + " module value " + QString::number(mod), QuasarAppUtils::Debug); module = static_cast( static_cast(module) | static_cast(mod)); } bool DeployCore::isGui(DeployCore::QtModule module) { DeployCore::QtModule guiModules = static_cast(DeployCore::QtGuiModule | DeployCore::QtOpenGLModule | DeployCore::QtQmlModule | DeployCore::QtQuickModule); return guiModules & module; } LibPriority DeployCore::getLibPriority(const QString &lib) { if (!QFileInfo(lib).isFile()) { return NotFile; } if (isQtLib(lib)) { return QtLib; } if (isExtraLib(lib)) { return ExtraLib; } if (isAlienLib(lib)) { return AlienLib; } if (isAllowedLib(lib)) { return AllowedLib; } return SystemLib; } bool DeployCore::containsModule(const QString& moduleLibrary, const QString& lib) { QRegExp erfexp(QString(moduleLibrary).replace("QtX", "Qt[4,5,6]")); return lib.contains(erfexp); } #define C(X) QuasarAppUtils::Params::isEndable(X) RunMode DeployCore::getMode() { if (C("help") || C("h") || C("v") || C("version")) { return RunMode::Info; } if (C("init")) { return RunMode::Init; } if (C("getDefaultTemplate")) { return RunMode::Template; } if (C("bin") || C("extraData")) { return RunMode::Deploy; } if (C("clear") || C("force-clear")) { return RunMode::Clear; } return RunMode::Info; } QuasarAppUtils::OptionsDataList DeployCore::avilableOptions() { QString group = "Part 1 Boolean options"; QuasarAppUtils::OptionsDataList help = {}; help.insert(group, {QuasarAppUtils::OptionData{ {"init"}, "", "will initialize cqtdeployer.json file (configuration file).", "'cqtdeployer init' - for initialize base package configuration. " "'cqtdeployer -init multi' - for initialize multi package configuration " "'cqtdeployer -init single' - for initialize singel package configuration" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"clear"}, "", "Deletes deployable files of the previous session." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"force-clear"}, "", "Deletes the destination directory before deployment." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"noStrip"}, "", "Skips strip step" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"noTranslations"}, "", "Skips the translations files. It doesn't work without qmake." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"noOverwrite"}, "", "Prevents replacing existing files." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"noCheckRPATH"}, "", "Disables automatic search of paths to qmake in executable files." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"noCheckPATH"}, "", "Disables automatic search of paths to qmake in system PATH." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"noRecursiveiIgnoreEnv"}, "", "Disables recursive ignore for ignoreEnv option." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"v", "version"}, "", "Shows compiled version" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"h", "help"}, "", "Show all help or help of the selected options." " You can add any another option to a command line for show help about using options" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"qif","-qif"}, "", "Create the QIF installer for deployment programm" " You can specify the path to your own installer template.", "Examples: cqtdeployer -qif path/to/myCustom/qif." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"qifFromSystem"}, "", "force use system binarycreator tool of qif from path or qt" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"zip"}, "", "Create the ZIP arhive for deployment programm" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"deb", "-deb"}, "", "Create the deb package for deployment programm" " You can specify the path to your own debian template.", "cqtdeployer -deb path/to/myCustom/DEBIAN." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"deploySystem"}, "", "Deploys all libraries." " Not recomendet because there may be conflicts with system libraries" " (on snap version you need to turn on permission)" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"noQt"}, "", "Ignors the error of initialize of a qmake. Use only if your application does not use the qt framework." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"allowEmptyPackages"}, "", "Allows configure the empty packages." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"getDefaultTemplate"}, "", "Extracts defaults deb or qif templates." " All templates extract into targetDirectory." " For change target directory use the targetDir option.", "cqtdeployer -bin myExecutable getDefaultTemplate qif deb." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"noHashSum"}, "", "This option disable computation of a packages hash sum" }}); group = "Part 2 Deploy options"; help.insert(group, {QuasarAppUtils::OptionData{ {"-bin"}, "{list,params}", "Files to deploy or folders that contain files to deploy.", "-bin ~/my/project/bin/,~/my/project/bin.exe,~/my/project/runtimeLinking/lib.dll." " For files: These files will be unconditional copied to the destination directory," " regardless of their format or suffix." " For folders:" " CCQtDeployer will enter these folders and non-recursively copy all executable files to the destination directory." " Then, CQtDeployer will extract all dependencies of the copied files and search dependencies in system environments and libDir paths." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-binPrefix"}, "{prefixPath}", "Sets prefix path for bin option.", "-bin path/MyExecutable is some as -bin MyExecutable -binPrefix path" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-confFile"}, "{params}", "The path to the json file with all deployment configurations. Using this file," " you can add the necessary options, thereby simplifying the command invocation in the console." " However, the parameters in Kansol have a higher priority than in the file." " For more info about this flag see https://github.com/QuasarApp/CQtDeployer/wiki/DeployConfigFileEn" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-qmlDir"}, "{params}", "Sets path to Qml data dir", "-qmlDir ~/my/project/qml" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-qmake"}, "{params}", "Sets path to the qmake executable.", "-qmake ~/Qt/bin/qmake or -qmake ~/Qt/bin/qmake.exe" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-ignore"}, "{list,params}", "Sets the list of libs to ignore.", "-ignore libicudata.so.56,libicudata2.so.56" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-ignoreEnv"}, "{list,params}", "Sets the list of the environment to ignore.", "-ignoreEnv /bad/dir,/my/bad/Dir" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-libDir"}, "{list,params}", "Sets additional paths for extra libs of an app.", "-libDir ~/myLib,~/newLibs" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-extraLibs"}, "{list,params}", "Sets the mask of the library name for forced copying.", "\"-extraLib mySql\" - forces to copy all libraries whose names contain mySql to the project folder." " This option is case-insensitive on Windows and case-sensitive on other platforms." " This option will only search libraries in system environments similar to **deploySystem**." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-customScript"}, "{scriptCode}", "Insert extra code inTo All run script.", "", " This option will be removed into next release cqtdeployer." " Please use the runScript option" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-recursiveDepth"}, "{params}", "Sets the Depth of recursive search of libs and depth for ignoreEnv option (default 0)" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-installDirQIFW"}, "{params}", "Sets install target directory for installers (by default it is /home path)" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-runScript"}, "{list,parems}", "forces cqtdeployer swap default run script to new from the arguments of option." " This option copy all content from input file and insert all code into runScript.sh or .bat", "cqtdeployer -runScript \"myTargetMame;path/to/my/myCustomLaunchScript.sh,myTargetSecondMame;path/to/my/mySecondCustomLaunchScript.sh\"" }}); group = "Part 3 Control of packages options"; help.insert(group, {QuasarAppUtils::OptionData{ {"-targetPackage"}, "{package;tar1,package;tar2}", "Creates a new package and adds 'tar1 and tar2' to it. " "If you want configure the package that do not have any targets use the allowEmptyPackages option." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-qmlOut"}, "{package;path,path}", "Sets path to qml out directory" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-libOut"}, "{package;path,path}", "Sets path to libraries out directory" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-trOut"}, "{package;path,path}", "Sets path to Sets path to translations out directory" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-pluginOut"}, "{package;path,path}", "Sets path to plugins out directory" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-binOut"}, "{package;path,path}", "Sets path to binary out directory" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-recOut"}, "{package;path,path}", "Sets path to recurses out directory" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-extraDataOut"}, "{package;path,path}", "Sets path to extra data files out directory. By Default it is root dir of the distribution." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-name"}, "{package;val,val}", "Sets name for a package." "If this if you do not specify a package, the value will be assigned to the default package ("")" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-description"}, "{package;val,val}", "Sets description for a package" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-deployVersion"}, "{package;val,val}", "Sets version for a package" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-releaseDate"}, "{package;val,val}", "Sets release date for a package" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-publisher"}, "{package;val,val}", "Sets publisher for a package" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-homePage"}, "{package;val,val}", "Sets the home page url for a package" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-prefix"}, "{package;val,val}", "Sets the prefix for the package relatively a target directory " }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-extraData"}, "{package;val,val}", "Adds the extra files or directories like a target. The selected directory will be copy to the extraDataOut location with save own structure." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-tr"}, "{package;val,val}", "Adds qm files into the translations folder." }}); group = "Part 4 Control of target options"; help.insert(group, {QuasarAppUtils::OptionData{ {"-icon"}, "{target;val,val}", "Sets path to icon for a targets" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-disableRunScript"}, "{package;val,val}", "Disables a generation of run script for selected targets" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-disableShortCut"}, "{package;val,val}", "Disables a generation of shortcut for selected targets" }}); group = "Part 5 Plugins Control Options"; help.insert(group, {QuasarAppUtils::OptionData{ {"-extraPlugin"}, "{package;val1;val2,SingeleVal}", "Sets an additional path to third-party application plug-in" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-enablePlugins"}, "{package;val1;val2,SingeleVa}", "Enables additional plugins for distribution." " By default disabled next plugins: " + PluginsParser::defaultForbidenPlugins().join(',') + " if you want enable" " it then use '-enablePlugins " + PluginsParser::defaultForbidenPlugins().join(',') + "' option" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-disablePlugins"}, "{package;val1;val2,SingeleVal}", "Disables plugins for distribution. " "You can disable any plugin of your Qt build, just see the yourQtFolder/plugins forlder for available plugins." " Example if you want disable qxcb plugin: -disablePlugins qxcb." " Note that the name of the plugin is indicated without its extension" }}); group = "Part 6 QtInstallFramework options"; help.insert(group, {QuasarAppUtils::OptionData{ {"-qifStyle"}, "{path/to/style.css}", "Sets the path to the CSS style file or sets the default style." " Available styles: quasar, quasarDark" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-qifBanner"}, "{path/to/banner.png}", "Sets path to the banner png file." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-qifLogo"}, "{path/to/logo.png}", "Sets path to the logo png file." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-qifOut"}, "{nameOfOutputInstallerFile}", "Sets name of output qifw installer. Note: on Windows, the exe suffix will be added to the installer automatically." }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-qifConfig"}, "{path/to/config.xml}", "Sets a custom path to the configure file of the qt ifw installer. By default it is qif/config/config.xml" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-qifPackages"}, "{path/to/packagesFodoler}", "Sets a custom path to the packages directories. By default it is qif/packages" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-qifResources"}, "{path/to/resources1.qrc,path/to/resources2.qrc}", "Sets a custom path to the resources files. By default this option is skipped" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-targetDir"}, "{params}", "Sets target directory(by default it is the path to the first deployable file)" }}); group = "Part 7 Deb package options"; help.insert(group, {QuasarAppUtils::OptionData{ {"-debOut"}, "{package;nameOfOutputDebFile,nameOfOutputDebFile}", "Sets name of the output debian file. This option can be work with multiple packages" }}); help.insert(group, {QuasarAppUtils::OptionData{ {"-installDirDeb"}, "{params}", "Sets install target directory fordebian package (by default it is /opt path)" }}); group = "Part 8 zip package options"; help.insert(group, {QuasarAppUtils::OptionData{ {"-zipOut"}, "{package;nameOfOutputZipFile,nameOfOutputZipFile}", "Sets name of the output zip arrhive. This option can be work with multiple packages" }}); return help; } void DeployCore::help() { auto localHelp = QuasarAppUtils::Params::getHelpOfInputOptions(); if(!localHelp.isEmpty()) { QuasarAppUtils::Help::print(localHelp); return; } // help extra data; QuasarAppUtils::Help::Charters help = { { "Part 0 General", { {"CQtDeployer version", getAppVersion()}, {"Usage", "cqtdeployer <-bin [params]> [options]"}, } }, { "Support", { {"Support for you", "If you have any questions or problems with cqtdeployer you can write to us about the problem on the GitHub page: https://github.com/QuasarApp/CQtDeployer/issues"}, {"Support for us", "If you liked cqtdeployer, then you can join any patreon plan of your choice for support us: https://www.patreon.com/QuasarApp"}, } } }; help += QuasarAppUtils::Params::getHelp(); QuasarAppUtils::Help::print(help); return; } QStringList DeployCore::extractTranslation(const QSet &libs) { QSet res; const size_t qtModulesCount = sizeof(qtModuleEntries) / sizeof(QtModuleEntry); for (const auto &lib: libs) { for (size_t i = 0; i < qtModulesCount; ++i) { if (containsModule(qtModuleEntries[i].libraryName, lib) && qtModuleEntries[i].translation) { res.insert(qtModuleEntries[i].translation); } } } return res.values(); } QString DeployCore::getAppVersion() { return APP_VERSION; } QString DeployCore::getAppVersionName() { return "*** Binary Box ***"; } QString DeployCore::getQtVersion() { #ifdef QT_VERSION_STR return QT_VERSION_STR; #else return "without qt"; #endif } void DeployCore::printVersion() { std::cout << QString{"CQtDeployer: " + getAppVersion() + " " + getAppVersionName()}.toStdString() << std::endl; std::cout << QString{"Qt: " + getQtVersion()}.toStdString() << std::endl; } bool DeployCore::isExecutable(const QFileInfo& file) { auto sufix = file.completeSuffix(); return sufix.contains("exe", Qt::CaseInsensitive) || sufix.contains("run", Qt::CaseInsensitive) || sufix.isEmpty(); } bool DeployCore::isContainsArraySeparators(const QString &val, int lastLvl) { while (lastLvl) { if (val.contains(getSeparator(--lastLvl))) return true; } return false; } QString DeployCore::findProcess(const QString &env, const QString& proc) { auto list = env.split(DeployCore::getEnvSeparator()); for (const auto& path : list) { auto files = QDir(path).entryInfoList(QDir::NoDotAndDotDot | QDir::Files); for (const auto& bin : files) { if (bin.baseName().compare(proc, DeployCore::getCaseSensitivity()) == 0) { return bin.absoluteFilePath(); } } } return ""; } QStringList DeployCore::debugExtensions() { return {".debug", "d.dll", ".pdb"}; } bool DeployCore::isDebugFile(const QString &file) { auto debug = debugExtensions(); for (const auto& debugEx: debug) { if (file.contains(debugEx, Qt::CaseInsensitive)) { return true; } } return false; } int DeployCore::find(const QString &str, const QStringList &list) { for (int i = 0 ; i < list.size(); ++i) { if (list[i].contains(str)) return i; } return -1; } bool DeployCore::isLib(const QFileInfo &file) { return file.completeSuffix().contains("so", Qt::CaseInsensitive) || file.completeSuffix().contains("dll", Qt::CaseInsensitive); } MSVCVersion DeployCore::getMSVC(const QString &_qtBin) { int res = MSVCVersion::MSVC_Unknown; QDir dir = QFileInfo(_qtBin).absoluteFilePath(); if (!dir.cdUp()) { QuasarAppUtils::Params::log("is not a standard qt repo", QuasarAppUtils::Debug); return static_cast(res); } auto msvcPath = dir.absolutePath(); if (!(dir.cdUp() && dir.cdUp())) { QuasarAppUtils::Params::log("is not a standard qt repo", QuasarAppUtils::Debug); return static_cast(res); } if (!msvcPath.contains("msvc")) { QuasarAppUtils::Params::log("vcredist not defined", QuasarAppUtils::Debug); return static_cast(res); } auto base = msvcPath.mid(msvcPath.indexOf("msvc"), 11); auto version = base.mid(4 , 4); auto type = base.right(2); if (version == "2013") { res |= MSVC_13; } else if (version == "2015") { res |= MSVC_15; } else if (version == "2017") { res |= MSVC_17; } else if (version == "2019") { res |= MSVC_19; } if (type == "32") { res |= MSVC_x32; } else if (type == "64") { res |= MSVC_x64; } return static_cast(res); } QString DeployCore::getVCredist(const QString &_qtbinDir) { auto msvc = getMSVC(_qtbinDir); QDir dir = _qtbinDir; if (!(dir.cdUp() && dir.cdUp() && dir.cdUp() && dir.cd("vcredist"))) { QuasarAppUtils::Params::log("vcredist not found!"); return ""; } auto infoList = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot); auto name = getMSVCName(msvc); auto version = getMSVCVersion(msvc); for (const auto &info: infoList) { auto file = info.fileName(); if (file.contains(name, Qt::CaseInsensitive) && file.contains(version, Qt::CaseInsensitive)) { return info.absoluteFilePath(); } } return ""; } QString DeployCore::getMSVCName(MSVCVersion msvc) { if (msvc | MSVCVersion::MSVC_13) { return "msvc2013"; } else if (msvc | MSVCVersion::MSVC_15) { return "msvc2015"; } else if (msvc | MSVCVersion::MSVC_17) { return "msvc2017"; } else if (msvc | MSVCVersion::MSVC_19) { return "msvc2019"; } return ""; } QString DeployCore::getMSVCVersion(MSVCVersion msvc) { if (msvc | MSVCVersion::MSVC_x32) { return "x86"; } else if (msvc | MSVCVersion::MSVC_x64) { return "x64"; } return ""; } QtMajorVersion DeployCore::isQtLib(const QString &lib) { QFileInfo info(lib); QtMajorVersion isQt = isQtLibName(lib); if (_config && !_config->qtDir.isQt(info.absoluteFilePath())) { return QtMajorVersion::NoQt; } return isQt; } QtMajorVersion DeployCore::isQtLibName(const QString &lib) { QFileInfo info(lib); /* * Task https://github.com/QuasarApp/CQtDeployer/issues/422 * All qt libs need to contains the Qt label. */ QtMajorVersion isQt = QtMajorVersion::NoQt; if (!isLib(info)) { return isQt; } QString fileName = info.fileName(); if (fileName.contains("Qt4", getCaseSensitivity(fileName))) { isQt = QtMajorVersion::Qt4; } else if (fileName.contains("Qt5", getCaseSensitivity(fileName))) { isQt = QtMajorVersion::Qt5; } else if (fileName.contains("Qt6", getCaseSensitivity(fileName))) { isQt = QtMajorVersion::Qt6; } if (isQt && QuasarAppUtils::Params::isEndable("noQt") && !QuasarAppUtils::Params::isEndable("qmake")) { return QtMajorVersion::NoQt; } return isQt; } bool DeployCore::isExtraLib(const QString &lib) { QFileInfo info(lib); return _config->extraPaths.contains(info.absoluteFilePath()); } bool DeployCore::isAlienLib(const QString &lib) { return lib.contains("/opt/", Qt::CaseSensitive) || lib.contains("/PROGRAM FILES", Qt::CaseInsensitive); } bool DeployCore::isAllowedLib(const QString &lib) { QFileInfo info(lib); return _config->allowedPaths.contains(info.absoluteFilePath()); } QStringList DeployCore::Qt3rdpartyLibs(Platform platform) { QStringList result; result << QStringList { // SQL LIBS // See task https://github.com/QuasarApp/CQtDeployer/issues/367 "libpq", "mysqlclient", // SLL Libs // See task https://github.com/QuasarApp/CQtDeployer/issues/620 "libcrypto", "libssl", "libeay32", "ssleay32", }; if (platform & Platform::Win) { result << QStringList { // Qml Gl driver wraper "d3dcompiler_47", "libEGL", "libGLESv2", // gcc runtime libs ow mingw "libgcc_s_seh", "libgcc_s_dw2", "libstdc++", "libwinpthread", // OpenglES libs "opengl32sw", }; } if (platform & Platform::Unix) { result << QStringList { // Begin Unicode libs "libicudata", "libicui18n", "libicuio", "libicule", "libiculx", "libicutest", "libicutu", "libicuuc", // End Unicode libs // xcb plugin "libxcb-xinerama", // qt GUI "libpng", "libjpeg" }; } return result; } QChar DeployCore::getSeparator(int lvl) { switch (lvl) { case 0: return ','; case 1: return ';'; default: return '\0'; } } char DeployCore::getEnvSeparator() { #ifdef Q_OS_UNIX return ':'; #else return ';'; #endif } bool DeployCore::isSnap() { return QProcessEnvironment::systemEnvironment().value("SNAP").size(); } QString DeployCore::snapRootFS() { return "/var/lib/snapd/hostfs"; } QString DeployCore::transportPathToSnapRoot(const QString &path) { if (isSnap() && checkSystemBakupSnapInterface()) { if(QFileInfo(path).isWritable()) { return path; } if (path.size() && path[0] != "/") { auto absalutPath = QProcessEnvironment::systemEnvironment().value("PWD") + "/" + path; if (!absalutPath.contains(DeployCore::snapRootFS())) { return snapRootFS() + "/" + absalutPath; } } if (!path.contains(DeployCore::snapRootFS())) { return snapRootFS() + "/" + path; } } return path; } bool DeployCore::checkSystemBakupSnapInterface() { return QDir(DeployCore::snapRootFS()).entryList(QDir::AllEntries | QDir::NoDotAndDotDot).size(); } void DeployCore::printInternalError(const char * function, const char* file, int line ) { QuasarAppUtils::Params::log(QString("Internal error ocurred in %0 (%1:%2).").arg(function, file).arg(line), QuasarAppUtils::Error); QuasarAppUtils::Params::log(QString("If you see this message please create a new issue" " about this problem on the official github page" " https://github.com/QuasarApp/CQtDeployer/issues/new/choose. "), QuasarAppUtils::Error); } QFileInfo DeployCore::findItem(const QString &bin) { auto prefixes = QuasarAppUtils::Params::getArg("binPrefix"). split(DeployCore::getSeparator(0), splitbehavior); for (const QString& prefix :qAsConst(prefixes)) { QFileInfo info(prefix + "/" + bin); if (info.exists()) { return info; } } return QFileInfo(bin); } Qt::CaseSensitivity DeployCore::getCaseSensitivity(const QString &checkedFile) { if (checkedFile.isEmpty()) { #ifdef Q_OS_WIN return Qt::CaseInsensitive; #else return Qt::CaseSensitive; #endif } QString sufix = QFileInfo(checkedFile).completeSuffix(); if (sufix.compare("dll", Qt::CaseInsensitive) == 0 || sufix.compare("exe", Qt::CaseInsensitive)) { return Qt::CaseInsensitive; } return Qt::CaseSensitive; }; QString DeployCore::systemLibsFolderName() { return "systemLibs"; } QString DeployCore::getLibCoreName(const QFileInfo &info) { auto baseName = info.baseName(); QString result; if (baseName.left(3) == "lib") { result = baseName.mid(3); } else { result = baseName; } return result; } uint qHash(WinAPI i) { return static_cast(i); }