build fix

This commit is contained in:
Andrei Yankovich 2019-09-08 13:37:33 +03:00
parent f7db00d8be
commit a6c4ddadf9
18 changed files with 699 additions and 776 deletions

View File

@ -5,13 +5,14 @@
* of this license document, but changing it is not allowed.
*/
#include "deploy.h"
#include "extracter.h"
#include "quasarapp.h"
#include "deploycore.h"
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QList>
#include <deploy.h>
int main(int argc, const char *argv[]) {
@ -25,15 +26,16 @@ int main(int argc, const char *argv[]) {
qWarning() << "wrong parametrs";
DeployCore::help();
exit(0);
};
}
QuasarAppUtils::Params::setEnable("noWriteInFileLog", true);
Deploy deploy;
if (!DeployCore::parseQt(&deploy)) {
if (!deploy.prepare()) {
qCritical() << "error parse imput data";
exit(1);
}
return 0;
return deploy.deploy();
}

View File

@ -48,8 +48,8 @@ SOURCES += \
cqt.cpp \
deploy.cpp \
deploycore.cpp \
deployparams.cpp \
envirement.cpp \
extracter.cpp \
filemanager.cpp \
pe.cpp \
igetlibinfo.cpp \
@ -65,8 +65,8 @@ HEADERS += \
deploy.h \
deploy_global.h \
deploycore.h \
deployparams.h \
envirement.h \
extracter.h \
filemanager.h \
pe.h \
igetlibinfo.h \

View File

@ -4,6 +4,7 @@
#include <QFileInfo>
#include <QProcess>
#include "deploycore.h"
#include "filemanager.h"
#include "quasarapp.h"
bool CQT::parseParams() {
@ -16,6 +17,8 @@ bool CQT::parseParams() {
return false;
}
DeployCore::_config = &_config;
return true;
}
case RunMode::Clear: {
@ -26,6 +29,8 @@ bool CQT::parseParams() {
return false;
}
DeployCore::_config = &_config;
return true;
}
@ -37,6 +42,8 @@ bool CQT::parseParams() {
return false;
}
DeployCore::_config = &_config;
return true;
}
@ -45,12 +52,8 @@ bool CQT::parseParams() {
return false;
}
DeployConfig CQT::config() const {
}
void CQT::setConfig(const DeployConfig &config) {
_config = config;
const DeployConfig *CQT::config() const {
return &_config;
}
bool CQT::createFromDeploy() const {
@ -63,14 +66,88 @@ bool CQT::loadFromFile() {
bool CQT::parseQtDeployMode() {
auto bin = QuasarAppUtils::Params::getStrArg("bin").split(',');
if (!setTargets(bin)) {
auto binDir = QuasarAppUtils::Params::getStrArg("binDir");
if (!(setTargetsRecursive(binDir) || setTargets({"./"}))) {
qCritical() << "setTargetDir fail!";
return false;
}
}
initIgnoreEnvList();
initEnvirement();
initIgnoreList();
_config.depchLimit = 0;
if (QuasarAppUtils::Params::isEndable("recursiveDepth")) {
bool ok;
_config.depchLimit = QuasarAppUtils::Params::getArg("recursiveDepth").toInt(&ok);
if (!ok) {
_config.depchLimit = 0;
qWarning() << "recursiveDepth is invalid! use default value 0";
}
}
auto listLibDir = QuasarAppUtils::Params::getStrArg("libDir").split(",");
auto listExtraPlugin =
QuasarAppUtils::Params::getStrArg("extraPlugin").split(",");
setExtraPath(listLibDir);
setExtraPlugins(listExtraPlugin);
auto qmake = QuasarAppUtils::Params::getStrArg("qmake");
QString basePath = "";
QFileInfo info(qmake);
if (!info.isFile() || (info.baseName() != "qmake")) {
qInfo() << "deploy only C libs because qmake is not found";
return true;
}
basePath = info.absolutePath();
setQmake(qmake);
auto qmlDir = QuasarAppUtils::Params::getStrArg("qmlDir");
QDir dir(basePath);
if (QFileInfo::exists(qmlDir) ||
QuasarAppUtils::Params::isEndable("allQmlDependes")) {
_config.deployQml = true;
} else {
QuasarAppUtils::Params::verboseLog("qml dir not exits!",
QuasarAppUtils::VerboseLvl::Warning);
}
if (!dir.cdUp()) {
return false;
}
setQtDir(dir.absolutePath());
return true;
}
bool CQT::parseQtInfoMode() {
if ((QuasarAppUtils::Params::isEndable("v") ||
QuasarAppUtils::Params::isEndable("version"))) {
DeployCore::printVersion();
return true;
}
DeployCore::help();
return true;
}
bool CQT::parseQtClearMode() {
setTargetDir("./");
return true;
}
void CQT::setTargetDir(const QString &target) {
@ -343,8 +420,50 @@ QStringList CQT::getDirsRecursive(const QString &path) {
return res;
}
bool CQT::smartMoveTargets() {
QMap<QString, bool> temp;
bool result = true;
for (auto i = _config.targets.cbegin(); i != _config.targets.cend(); ++i) {
QFileInfo target(i.key());
auto targetPath = _config.targetDir + (DeployCore::isLib(target) ? "/lib" : "/bin");
if (target.completeSuffix().contains("dll", Qt::CaseInsensitive) ||
target.completeSuffix().contains("exe", Qt::CaseInsensitive)) {
targetPath = _config.targetDir;
}
if (!_fileManager->smartCopyFile(target.absoluteFilePath(), targetPath, _config.targetDir)) {
result = false;
}
CQT::CQT() {
temp.insert(targetPath + "/" + target.fileName(), i.value());
}
_config.targets = temp;
return result;
}
CQT::CQT(FileManager *filemanager):
_fileManager(filemanager) {
assert(_fileManager);
#ifdef Q_OS_LINUX
_config.appDir = QuasarAppUtils::Params::getStrArg("appPath");
if (_config.appDir.right(4) == "/bin") {
_config.appDir = _config.appDir.left(_config.appDir.size() - 4);
}
#else
_config.appDir = QuasarAppUtils::Params::getStrArg("appPath");
#endif
QuasarAppUtils::Params::verboseLog("appDir = " + _config.appDir);
}

View File

@ -9,6 +9,7 @@
#include <QMap>
#include <QDir>
class FileManager;
struct DeployConfig {
QString qmake = "";
@ -40,7 +41,7 @@ class CQT
private:
DeployConfig _config;
FileManager *_fileManager;
bool createFromDeploy() const;
bool loadFromFile();
bool parseQtDeployMode();
@ -68,12 +69,14 @@ private:
void initEnvirement();
QStringList getDirsRecursive(const QString &path);
bool smartMoveTargets();
public:
CQT();
CQT(FileManager *filemanager);
bool parseParams();
DeployConfig config() const;
void setConfig(const DeployConfig &config);
const DeployConfig* config() const;
};
#endif // CQT_H

View File

@ -5,560 +5,26 @@
* of this license document, but changing it is not allowed.
*/
#include "cqt.h"
#include "deploy.h"
#include "deploycore.h"
#include "pluginsparser.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QProcess>
#include <QRegularExpression>
#include "extracter.h"
#include "filemanager.h"
#include <quasarapp.h>
#include <stdio.h>
#include <fstream>
bool Deploy::getDeployQml() const { return deployQml; }
void Deploy::setDeployQml(bool value) { deployQml = value; }
QString Deploy::getQmlScaner() const { return externQmlScaner; }
QString Deploy::getQmake() const { return qmake; }
void Deploy::clear(bool force) {
_fileManager.clear(targetDir, force);
}
bool Deploy::deployMSVC() {
qInfo () << "try deploy msvc";
auto msvcInstaller = DeployCore::getVCredist(qmake);
if (msvcInstaller.isEmpty()) {
return false;
}
return _fileManager.copyFile(msvcInstaller, targetDir);
}
bool Deploy::createRunScript(const QString &target) {
QString content =
"#!/bin/sh\n"
"BASE_DIR=$(dirname \"$(readlink -f \"$0\")\")\n"
"export "
"LD_LIBRARY_PATH=\"$BASE_DIR\"/lib:\"$BASE_DIR\":$LD_LIBRARY_PATH\n"
"export QML_IMPORT_PATH=\"$BASE_DIR\"/qml:QML_IMPORT_PATH\n"
"export QML2_IMPORT_PATH=\"$BASE_DIR\"/qml:QML2_IMPORT_PATH\n"
"export QT_PLUGIN_PATH=\"$BASE_DIR\"/plugins:QT_PLUGIN_PATH\n"
"export QTDIR=\"$BASE_DIR\"\n"
"export "
"QT_QPA_PLATFORM_PLUGIN_PATH=\"$BASE_DIR\"/plugins/"
"platforms:QT_QPA_PLATFORM_PLUGIN_PATH\n"
"%2"
"\"$BASE_DIR\"/bin/%1 \"$@\"";
content = content.arg(QFileInfo(target).fileName());
int ld_index = find("ld-linux", _fileManager.getDeployedFilesStringList());
if (ld_index >= 0 && QuasarAppUtils::Params::isEndable("deploySystem") &&
!QuasarAppUtils::Params::isEndable("noLibc")) {
content = content.arg(QString("\nexport LD_PRELOAD=\"$BASE_DIR\"/lib/%0\n").
arg(QFileInfo(_fileManager.getDeployedFilesStringList()[ld_index]).fileName()));
} else {
content = content.arg("");
}
QString fname = targetDir + QDir::separator() + QFileInfo(target).baseName()+ ".sh";
QFile F(fname);
if (!F.open(QIODevice::WriteOnly)) {
return false;
}
F.write(content.toUtf8());
F.flush();
F.close();
_fileManager.addToDeployed(fname);
return F.setPermissions(QFileDevice::ExeOther | QFileDevice::WriteOther |
QFileDevice::ReadOther | QFileDevice::ExeUser |
QFileDevice::WriteUser | QFileDevice::ReadUser |
QFileDevice::ExeOwner | QFileDevice::WriteOwner |
QFileDevice::ReadOwner);
}
bool Deploy::createQConf() {
QString content =
"[Paths]\n"
"Prefix= ./\n"
"Libraries= ./\n"
"Plugins= ./plugins\n"
"Imports= ./qml\n"
"Qml2Imports= ./qml\n";
QString fname = targetDir + QDir::separator() + "qt.conf";
QFile F(fname);
if (!F.open(QIODevice::WriteOnly)) {
return false;
}
F.write(content.toUtf8());
F.flush();
F.close();
_fileManager.addToDeployed(fname);
return F.setPermissions(QFileDevice::ExeOther | QFileDevice::WriteOther |
QFileDevice::ReadOther | QFileDevice::ExeUser |
QFileDevice::WriteUser | QFileDevice::ReadUser |
QFileDevice::ExeOwner | QFileDevice::WriteOwner |
QFileDevice::ReadOwner);
}
void Deploy::deploy() {
qInfo() << "target deploy started!!";
smartMoveTargets();
for (auto i = targets.cbegin(); i != targets.cend(); ++i) {
extract(i.key());
}
if (deployQml && !extractQml()) {
qCritical() << "qml not extacted!";
}
PluginsParser pluginsParser(&scaner);
QStringList plugins;
pluginsParser.scan(DeployCore::qtDir + "/plugins", plugins);
copyPlugins(plugins);
_fileManager.copyFiles(neadedLibs, targetDir);
if (QuasarAppUtils::Params::isEndable("deploySystem")) {
_fileManager.copyFiles(systemLibs, targetDir);
}
if (!QuasarAppUtils::Params::isEndable("noStrip") && !_fileManager.strip(targetDir)) {
QuasarAppUtils::Params::verboseLog("strip failed!");
}
if (!QuasarAppUtils::Params::isEndable("noTranslations")) {
if (!copyTranslations(DeployCore::extractTranslation(neadedLibs))) {
qWarning() << " copy TR ERROR";
}
}
if (!deployMSVC()) {
QuasarAppUtils::Params::verboseLog("deploy msvc failed");
}
bool targetWindows = false;
for (auto i = targets.cbegin(); i != targets.cend(); ++i) {
if (QFileInfo(i.key()).completeSuffix() == "exe") {
targetWindows = true;
}
if (i.value() && !createRunScript(i.key())) {
qCritical() << "run script not created!";
}
}
if (targetWindows && !createQConf()) {
QuasarAppUtils::Params::verboseLog("create qt.conf failr", QuasarAppUtils::Warning);
}
_fileManager.saveDeploymendFiles(targetDir);
qInfo() << "deploy done!";
}
QString Deploy::getQtDir() const { return DeployCore::qtDir; }
void Deploy::setDepchLimit(int value) { depchLimit = value; }
int Deploy::find(const QString &str, const QStringList &list) const {
for (int i = 0 ; i < list.size(); ++i) {
if (list[i].contains(str))
return i;
}
return -1;
}
bool Deploy::copyPlugin(const QString &plugin) {
QStringList listItems;
if (!_fileManager.copyFolder(plugin, targetDir + "/plugins/" + QFileInfo(plugin).fileName(),
QStringList() << ".so.debug" << "d.dll", &listItems)) {
return false;
}
for (auto item : listItems) {
extract(item);
}
return true;
}
void Deploy::copyPlugins(const QStringList &list) {
for (auto plugin : list) {
if (!copyPlugin(plugin)) {
qWarning() << plugin << " not copied!";
}
}
QFileInfo info;
for (auto extraPlugin : extraPlugins) {
info.setFile(extraPlugin);
if (info.isDir()) {
_fileManager.copyFolder(info.absoluteFilePath(),
targetDir + "/plugins/" + info.baseName(),
QStringList() << ".so.debug" << "d.dll");
} else {
_fileManager.copyFile(info.absoluteFilePath(),
targetDir + QDir::separator() + "plugins");
extract(info.absoluteFilePath());
}
}
}
bool Deploy::copyTranslations(QStringList list) {
QDir dir(translationDir);
if (!dir.exists() || list.isEmpty()) {
return false;
}
QStringList filters;
for (auto &&i: list) {
filters.push_back("*" + i + "*");
}
auto listItems = dir.entryInfoList(filters, QDir::Files | QDir::NoDotAndDotDot);
for (auto &&i: listItems) {
_fileManager.copyFile(i.absoluteFilePath(), targetDir + "/translations");
}
return true;
}
QFileInfoList Deploy::findFilesInsideDir(const QString &name,
const QString &dirpath) {
QFileInfoList files;
QDir dir(dirpath);
auto list = dir.entryInfoList( QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
for (auto && item :list) {
if (item.isFile()) {
if (item.fileName().contains(name)) {
files += item;
}
} else {
files += findFilesInsideDir(name, item.absoluteFilePath());
}
}
return files;
}
QString Deploy::filterQmlPath(const QString &path) {
if (path.contains(qmlDir)) {
auto endIndex = path.indexOf(QDir::separator(), qmlDir.size() + 1);
QString module =
path.mid(qmlDir.size() + 1, endIndex - qmlDir.size() - 1);
return qmlDir + QDir::separator() + module;
}
return "";
}
void Deploy::extractLib(const QString &file) {
qInfo() << "extract lib :" << file;
auto data = scaner.scan(file);
for (auto &line : data) {
bool isIgnore = false;
for (auto ignore : ignoreList) {
if (line.fullPath().contains(ignore)) {
QuasarAppUtils::Params::verboseLog(line.fullPath() + " ignored by filter" + ignore);
isIgnore = true;
continue;
}
}
if (isIgnore) {
continue;
}
if (line.getPriority() != LibPriority::SystemLib && !neadedLibs.contains(line.fullPath())) {
neadedLibs << line.fullPath();
} else if (QuasarAppUtils::Params::isEndable("deploySystem") &&
line.getPriority() == LibPriority::SystemLib &&
!systemLibs.contains(line.fullPath())) {
systemLibs << line.fullPath();
}
}
}
QString Deploy::concatEnv() const {
if (deployEnvironment.isEmpty()) {
return "";
}
QString result = deployEnvironment.first();
for (auto i: deployEnvironment) {
result += (":" + i);
}
return result;
}
bool Deploy::smartMoveTargets() {
QMap<QString, bool> temp;
bool result = true;
for (auto i = targets.cbegin(); i != targets.cend(); ++i) {
QFileInfo target(i.key());
auto targetPath = targetDir + (isLib(target) ? "/lib" : "/bin");
if (target.completeSuffix().contains("dll", Qt::CaseInsensitive) ||
target.completeSuffix().contains("exe", Qt::CaseInsensitive)) {
targetPath = targetDir;
}
if (!_fileManager.smartCopyFile(target.absoluteFilePath(), targetPath, targetDir)) {
result = false;
}
temp.insert(targetPath + "/" + target.fileName(), i.value());
}
targets = temp;
scaner.setEnvironment(deployEnvironment);
return result;
}
bool Deploy::isLib(const QFileInfo &file) {
return file.completeSuffix().contains("so", Qt::CaseInsensitive)
|| file.completeSuffix().contains("dll", Qt::CaseInsensitive);
}
QStringList Deploy::extractImportsFromDir(const QString &filepath) {
QProcess p;
QProcessEnvironment env;
env.insert("LD_LIBRARY_PATH", concatEnv());
env.insert("QML_IMPORT_PATH", DeployCore::qtDir + "/qml");
env.insert("QML2_IMPORT_PATH", DeployCore::qtDir + "/qml");
env.insert("QT_PLUGIN_PATH", DeployCore::qtDir + "/plugins");
env.insert("QT_QPA_PLATFORM_PLUGIN_PATH", DeployCore::qtDir + "/plugins/platforms");
p.setProcessEnvironment(env);
p.setProgram(externQmlScaner);
p.setArguments(QStringList()
<< "-rootPath" << filepath << "-importPath" << qmlDir);
p.start();
if (!p.waitForFinished()) {
qWarning() << filepath << " not scaning!";
return QStringList();
}
auto rawData = p.readAll();
if (p.exitCode()) {
qWarning() << "scaner error " << p.errorString() << "exitCode: " << p.exitCode();
}
QuasarAppUtils::Params::verboseLog("rawData from extractImportsFromDir: " + rawData);
auto data = QJsonDocument::fromJson(rawData);
if (!data.isArray()) {
qWarning() << "wrong data from qml scaner! of " << filepath;
}
auto array = data.array();
QStringList result;
for (auto object : array) {
auto module = object.toObject().value("path").toString();
if (module.isEmpty()) {
continue;
}
if (!result.contains(module)) {
result << module;
}
}
return result;
}
bool Deploy::extractQmlAll() {
if (!QFileInfo::exists(qmlDir)) {
qWarning() << "qml dir wrong!";
return false;
}
QStringList listItems;
if (!_fileManager.copyFolder(qmlDir, targetDir + "/qml",
QStringList() << ".so.debug" << "d.dll",
&listItems)) {
return false;
}
for (auto item : listItems) {
extract(item);
}
return true;
}
bool Deploy::extractQmlFromSource(const QString& sourceDir) {
QFileInfo info(sourceDir);
if (!info.isDir()) {
qCritical() << "extract qml fail! qml source dir not exits or is not dir " << sourceDir;
return false;
}
QuasarAppUtils::Params::verboseLog("extractQmlFromSource " + info.absoluteFilePath());
if (!QFileInfo::exists(qmlDir)) {
qWarning() << "qml dir wrong!";
return false;
}
QStringList plugins;
QStringList listItems;
QStringList filter;
filter << ".so.debug" << "d.dll" << ".pdb";
if (QuasarAppUtils::Params::isEndable("qmlExtern")) {
/// @todo remove in verison 1.3
qInfo() << "use extern qml scaner!";
plugins = extractImportsFromDir(info.absoluteFilePath());
} else {
qInfo() << "use own qml scaner!";
QML ownQmlScaner(qmlDir);
if (!ownQmlScaner.scan(plugins, info.absoluteFilePath())) {
QuasarAppUtils::Params::verboseLog("qml scaner run failed!");
return false;
}
}
if (!_fileManager.copyFolder(qmlDir, targetDir + "/qml",
filter , &listItems, &plugins)) {
return false;
}
for (auto item : listItems) {
extract(item);
}
return true;
}
bool Deploy::extractQml() {
if (QuasarAppUtils::Params::isEndable("qmlDir")) {
return extractQmlFromSource(
QuasarAppUtils::Params::getStrArg("qmlDir"));
} else if (QuasarAppUtils::Params::isEndable("allQmlDependes")) {
return extractQmlAll();
} else {
return false;
}
}
void Deploy::extract(const QString &file) {
QFileInfo info(file);
auto sufix = info.completeSuffix();
if (sufix.contains("dll", Qt::CaseSensitive) ||
sufix.contains("exe", Qt::CaseSensitive) ||
sufix.isEmpty() || sufix.contains("so", Qt::CaseSensitive)) {
extractLib(file);
} else {
QuasarAppUtils::Params::verboseLog("file with sufix " + sufix + " not supported!");
}
}
Deploy::Deploy() {
_fileManager.loadDeployemendFiles(targetDir);
#ifdef Q_OS_LINUX
appDir = QuasarAppUtils::Params::getStrArg("appPath");
if (appDir.right(4) == "/bin") {
appDir = appDir.left(appDir.size() - 4);
}
#else
appDir = QuasarAppUtils::Params::getStrArg("appPath");
#endif
QuasarAppUtils::Params::verboseLog("appDir = " + appDir);
_fileManager = new FileManager();
_paramsParser = new CQT(_fileManager);
_extracter = new Extracter(_fileManager);
}
bool Deploy::prepare() {
return _paramsParser->parseParams();
}
int Deploy::deploy() {
_fileManager->loadDeployemendFiles(_paramsParser->config()->targetDir);
_extracter->deploy();
_fileManager->saveDeploymendFiles(_paramsParser->config()->targetDir);
return 0;
}

View File

@ -7,66 +7,27 @@
#ifndef DEPLOY_H
#define DEPLOY_H
#include <QDir>
#include <QString>
#include <QStringList>
#include <dependenciesscanner.h>
#include "deploy_global.h"
#include "filemanager.h"
#include "qml.h"
class DEPLOYSHARED_EXPORT Deploy {
private:
class CQT;
class Extracter;
class FileManager;
QStringList neadedLibs;
QStringList systemLibs;
class DEPLOYSHARED_EXPORT Deploy
{
private:
DependenciesScanner scaner;
FileManager _fileManager;
int find(const QString& str, const QStringList& list) const;
void extract(const QString &file);
bool copyPlugin(const QString &plugin);
void copyPlugins(const QStringList &list);
bool copyTranslations(QStringList list);
bool createQConf();
bool extractQml();
QStringList extractImportsFromDir(const QString &dirpath);
QFileInfoList findFilesInsideDir(const QString &name, const QString &dirpath);
bool extractQmlAll();
bool extractQmlFromSource(const QString &sourceDir);
QString filterQmlPath(const QString &path);
void extractLib(const QString & file);
void addEnv(const QString& dir);
QString concatEnv() const;
bool smartMoveTargets();
bool isLib(const QFileInfo &file);
bool setBinDir(const QString& dir, bool recursive = false);
bool deployMSVC();
CQT * _paramsParser;
Extracter *_extracter;
FileManager *_fileManager;
public:
Deploy();
bool prepare();
int deploy();
bool getDeployQml() const;
void setDeployQml(bool value);
bool createRunScript(const QString &target);
void deploy();
void clear(bool force);
friend class deploytest;
};
#endif // DEPLOY_H

View File

@ -5,7 +5,7 @@
* of this license document, but changing it is not allowed.
*/
#include "deploy.h"
#include "extracter.h"
#include "deploycore.h"
#include "quasarapp.h"
@ -13,11 +13,14 @@
#include <QDir>
#include <QFileInfo>
#include <QLibraryInfo>
#include <cqt.h>
//QString DeployCore::qtDir = "";
//QStringList DeployCore::extraPaths = QStringList();
const DeployConfig* DeployCore::_config = nullptr;
QtModuleEntry DeployCore::qtModuleEntries[] = {
{ QtBluetoothModule, "bluetooth", "Qt5Bluetooth", nullptr },
{ QtConcurrentModule, "concurrent", "Qt5Concurrent", "qtbase" },
@ -184,7 +187,6 @@ void DeployCore::help() {
{ " -targetDir [params] : Sets target directory(by default it is the path to the first deployable file)" },
{ " noStrip : Skips strip step" },
{ " noTranslations : Skips the translations files." },
{ " qmlExtern : Use the qml external scanner (qmlimportscaner)" },
{ " | It doesn't work without qmake and inside a snap package" },
{ " v / version : Shows compiled version" },
{ " verbose [1-3] : Shows debug log" },
@ -195,124 +197,6 @@ void DeployCore::help() {
{ "Example (only C libs): cqtdeployer -bin myApp clear" }};
QuasarAppUtils::Params::showHelp(help);
}
bool DeployCore::parseQtClearMode(Deploy *deploy) {
deploy->clear(QuasarAppUtils::Params::isEndable("force-clear"));
return true;
}
bool DeployCore::parseQtInfoMode() {
if ((QuasarAppUtils::Params::isEndable("v") ||
QuasarAppUtils::Params::isEndable("version"))) {
DeployCore::printVersion();
return true;
}
DeployCore::help();
return true;
}
bool DeployCore::parseQtDeployMode(Deploy *deploy) {
auto bin = QuasarAppUtils::Params::getStrArg("bin").split(',');
if (!deploy->setTargets(bin)) {
auto binDir = QuasarAppUtils::Params::getStrArg("binDir");
if (!(deploy->setTargetsRecursive(binDir) || deploy->setTargets({"./"}))) {
qCritical() << "setTargetDir fail!";
return false;
}
}
deploy->initIgnoreEnvList();
deploy->initEnvirement();
deploy->initIgnoreList();
if (QuasarAppUtils::Params::isEndable("clear") ||
QuasarAppUtils::Params::isEndable("force-clear")) {
qInfo() << "clear old data";
deploy->clear(QuasarAppUtils::Params::isEndable("force-clear"));
}
int limit = 0;
if (QuasarAppUtils::Params::isEndable("recursiveDepth")) {
bool ok;
limit = QuasarAppUtils::Params::getArg("recursiveDepth").toInt(&ok);
if (!ok) {
limit = 0;
qWarning() << "recursiveDepth is invalid! use default value 0";
}
}
deploy->setDepchLimit(limit);
auto listLibDir = QuasarAppUtils::Params::getStrArg("libDir").split(",");
auto listExtraPlugin =
QuasarAppUtils::Params::getStrArg("extraPlugin").split(",");
deploy->setExtraPath(listLibDir);
deploy->setExtraPlugins(listExtraPlugin);
auto qmake = QuasarAppUtils::Params::getStrArg("qmake");
QString basePath = "";
QFileInfo info(qmake);
if (!info.isFile() || (info.baseName() != "qmake")) {
qInfo() << "deploy only C libs because qmake is not found";
return true;
}
basePath = info.absolutePath();
deploy->setQmake(qmake);
auto qmlDir = QuasarAppUtils::Params::getStrArg("qmlDir");
QDir dir(basePath);
if (QuasarAppUtils::Params::isEndable("qmlExtern")) {
#ifdef Q_OS_WIN
auto scaner = basePath + QDir::separator() + "qmlimportscanner.exe";
#else
auto scaner = basePath + QDir::separator() + "qmlimportscanner";
#endif
if ( !QFileInfo::exists(scaner)) {
QuasarAppUtils::Params::verboseLog("qml scaner not defined, using own scaner!",
QuasarAppUtils::VerboseLvl::Warning);
QuasarAppUtils::Params::setEnable("qmlExtern", false);
} else {
deploy->setQmlScaner(scaner);
}
}
if (QFileInfo::exists(qmlDir) ||
QuasarAppUtils::Params::isEndable("allQmlDependes")) {
deploy->setDeployQml(true);
} else {
QuasarAppUtils::Params::verboseLog("qml dir not exits!",
QuasarAppUtils::VerboseLvl::Warning);
}
if (!dir.cdUp()) {
return false;
}
deploy->setQtDir(dir.absolutePath());
return true;
}
bool DeployCore::parseQt(Deploy *deploy) {
}
QStringList DeployCore::extractTranslation(const QStringList &libs) {
@ -347,6 +231,19 @@ void DeployCore::printVersion() {
qInfo() << "Qt: " + getQtVersion();
}
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 &_qmake) {
QFileInfo qmake(_qmake);
@ -456,14 +353,14 @@ QString DeployCore::getMSVCVersion(MSVCVersion msvc) {
bool DeployCore::isQtLib(const QString &lib) {
QFileInfo info(lib);
return !qtDir.isEmpty() && info.absoluteFilePath().contains(qtDir);
return !_config->qtDir.isEmpty() && info.absoluteFilePath().contains(_config->qtDir);
}
bool DeployCore::isExtraLib(const QString &lib) {
QFileInfo info(lib);
for (auto i : extraPaths) {
for (auto i : _config->extraPaths) {
if (info.absoluteFilePath().contains(i)) {
return true;
}

View File

@ -10,6 +10,7 @@
#include <QStringList>
#include <QDebug>
#include <QFileInfo>
#include "deploy_global.h"
enum MSVCVersion: int {
@ -51,7 +52,8 @@ enum class RunMode: int {
Clear
};
class Deploy;
class Extracter;
class DeployConfig;
class DEPLOYSHARED_EXPORT DeployCore
{
@ -122,6 +124,7 @@ public:
static QtModuleEntry qtModuleEntries[];
static const DeployConfig * _config;
static MSVCVersion getMSVC(const QString & _qmake);
static QString getVCredist(const QString & _qmake);
@ -135,11 +138,13 @@ public:
static void verboseLog(const QString &str);
static RunMode getMode();
static void help();
static bool parseQt(Deploy *deploy);
static QStringList extractTranslation(const QStringList& libs);
static QString getAppVersion();
static QString getQtVersion();
static void printVersion();
static int find(const QString &str, const QStringList &list);
static bool isLib(const QFileInfo &file);
};

View File

@ -1,6 +0,0 @@
#include "deployparams.h"
DeployParams::DeployParams()
{
}

View File

@ -1,12 +0,0 @@
#ifndef DEPLOYPARAMS_H
#define DEPLOYPARAMS_H
#include "deploy_global.h"
class DEPLOYSHARED_EXPORT DeployParams
{
public:
DeployParams();
};
#endif // DEPLOYPARAMS_H

View File

@ -75,6 +75,24 @@ int Envirement::size() const {
return _deployEnvironment.size();
}
QString Envirement::concatEnv() const {
if (_deployEnvironment.isEmpty()) {
return "";
}
QString result = _deployEnvironment.first();
for (auto i: _deployEnvironment) {
#ifdef Q_OS_UNIX
result += (":" + i);
#else
result += (";" + i);
#endif
}
return result;
}
Envirement::Envirement()
{

View File

@ -21,6 +21,7 @@ public:
void addEnv(const QString &dir, const QString &appDir, const QString &targetDir);
int size() const;
QString concatEnv() const;
};
#endif // ENVIREMENT_H

415
Deploy/extracter.cpp Normal file
View File

@ -0,0 +1,415 @@
/*
* Copyright (C) 2018-2019 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 "pluginsparser.h"
#include "cqt.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QProcess>
#include <QRegularExpression>
#include <quasarapp.h>
#include <stdio.h>
#include <fstream>
bool Extracter::deployMSVC() {
qInfo () << "try deploy msvc";
auto msvcInstaller = DeployCore::getVCredist(DeployCore::_config->qmake);
if (msvcInstaller.isEmpty()) {
return false;
}
return _fileManager->copyFile(msvcInstaller, DeployCore::_config->targetDir);
}
bool Extracter::copyPlugin(const QString &plugin) {
QStringList listItems;
if (!_fileManager->copyFolder(plugin, DeployCore::_config->targetDir + "/plugins/" + QFileInfo(plugin).fileName(),
QStringList() << ".so.debug" << "d.dll", &listItems)) {
return false;
}
for (auto item : listItems) {
extract(item);
}
return true;
}
void Extracter::copyPlugins(const QStringList &list) {
for (auto plugin : list) {
if (!copyPlugin(plugin)) {
qWarning() << plugin << " not copied!";
}
}
QFileInfo info;
for (auto extraPlugin : DeployCore::_config->extraPlugins) {
info.setFile(extraPlugin);
if (info.isDir()) {
_fileManager->copyFolder(info.absoluteFilePath(),
DeployCore::_config->targetDir + "/plugins/" + info.baseName(),
QStringList() << ".so.debug" << "d.dll");
} else {
_fileManager->copyFile(info.absoluteFilePath(),
DeployCore::_config->targetDir + QDir::separator() + "plugins");
extract(info.absoluteFilePath());
}
}
}
bool Extracter::createRunScript(const QString &target) {
QString content =
"#!/bin/sh\n"
"BASE_DIR=$(dirname \"$(readlink -f \"$0\")\")\n"
"export "
"LD_LIBRARY_PATH=\"$BASE_DIR\"/lib:\"$BASE_DIR\":$LD_LIBRARY_PATH\n"
"export QML_IMPORT_PATH=\"$BASE_DIR\"/qml:QML_IMPORT_PATH\n"
"export QML2_IMPORT_PATH=\"$BASE_DIR\"/qml:QML2_IMPORT_PATH\n"
"export QT_PLUGIN_PATH=\"$BASE_DIR\"/plugins:QT_PLUGIN_PATH\n"
"export QTDIR=\"$BASE_DIR\"\n"
"export "
"QT_QPA_PLATFORM_PLUGIN_PATH=\"$BASE_DIR\"/plugins/"
"platforms:QT_QPA_PLATFORM_PLUGIN_PATH\n"
"%2"
"\"$BASE_DIR\"/bin/%1 \"$@\"";
content = content.arg(QFileInfo(target).fileName());
int ld_index = DeployCore::find("ld-linux", _fileManager->getDeployedFilesStringList());
if (ld_index >= 0 && QuasarAppUtils::Params::isEndable("deploySystem") &&
!QuasarAppUtils::Params::isEndable("noLibc")) {
content = content.arg(QString("\nexport LD_PRELOAD=\"$BASE_DIR\"/lib/%0\n").
arg(QFileInfo(_fileManager->getDeployedFilesStringList()[ld_index]).fileName()));
} else {
content = content.arg("");
}
QString fname = DeployCore::_config->targetDir + QDir::separator() + QFileInfo(target).baseName()+ ".sh";
QFile F(fname);
if (!F.open(QIODevice::WriteOnly)) {
return false;
}
F.write(content.toUtf8());
F.flush();
F.close();
_fileManager->addToDeployed(fname);
return F.setPermissions(QFileDevice::ExeOther | QFileDevice::WriteOther |
QFileDevice::ReadOther | QFileDevice::ExeUser |
QFileDevice::WriteUser | QFileDevice::ReadUser |
QFileDevice::ExeOwner | QFileDevice::WriteOwner |
QFileDevice::ReadOwner);
}
bool Extracter::createQConf() {
QString content =
"[Paths]\n"
"Prefix= ./\n"
"Libraries= ./\n"
"Plugins= ./plugins\n"
"Imports= ./qml\n"
"Qml2Imports= ./qml\n";
QString fname = DeployCore::_config->targetDir + QDir::separator() + "qt.conf";
QFile F(fname);
if (!F.open(QIODevice::WriteOnly)) {
return false;
}
F.write(content.toUtf8());
F.flush();
F.close();
_fileManager->addToDeployed(fname);
return F.setPermissions(QFileDevice::ExeOther | QFileDevice::WriteOther |
QFileDevice::ReadOther | QFileDevice::ExeUser |
QFileDevice::WriteUser | QFileDevice::ReadUser |
QFileDevice::ExeOwner | QFileDevice::WriteOwner |
QFileDevice::ReadOwner);
}
void Extracter::deploy() {
qInfo() << "target deploy started!!";
if (QuasarAppUtils::Params::isEndable("clear") ||
QuasarAppUtils::Params::isEndable("force-clear")) {
qInfo() << "clear old data";
_fileManager->clear(DeployCore::_config->targetDir,
QuasarAppUtils::Params::isEndable("force-clear"));
}
scaner.setEnvironment(DeployCore::_config->envirement.deployEnvironment());
for (auto i = DeployCore::_config->targets.cbegin(); i != DeployCore::_config->targets.cend(); ++i) {
extract(i.key());
}
if (DeployCore::_config->deployQml && !extractQml()) {
qCritical() << "qml not extacted!";
}
PluginsParser pluginsParser(&scaner);
QStringList plugins;
pluginsParser.scan(DeployCore::_config->qtDir + "/plugins", plugins);
copyPlugins(plugins);
_fileManager->copyFiles(neadedLibs, DeployCore::_config->targetDir);
if (QuasarAppUtils::Params::isEndable("deploySystem")) {
_fileManager->copyFiles(systemLibs, DeployCore::_config->targetDir);
}
if (!QuasarAppUtils::Params::isEndable("noStrip") && !_fileManager->strip(DeployCore::_config->targetDir)) {
QuasarAppUtils::Params::verboseLog("strip failed!");
}
if (!QuasarAppUtils::Params::isEndable("noTranslations")) {
if (!copyTranslations(DeployCore::extractTranslation(neadedLibs))) {
qWarning() << " copy TR ERROR";
}
}
if (!deployMSVC()) {
QuasarAppUtils::Params::verboseLog("deploy msvc failed");
}
bool targetWindows = false;
for (auto i = DeployCore::_config->targets.cbegin(); i != DeployCore::_config->targets.cend(); ++i) {
if (QFileInfo(i.key()).completeSuffix() == "exe") {
targetWindows = true;
}
if (i.value() && !createRunScript(i.key())) {
qCritical() << "run script not created!";
}
}
if (targetWindows && !createQConf()) {
QuasarAppUtils::Params::verboseLog("create qt.conf failr", QuasarAppUtils::Warning);
}
_fileManager->saveDeploymendFiles(DeployCore::_config->targetDir);
qInfo() << "deploy done!";
}
bool Extracter::copyTranslations(QStringList list) {
QDir dir(DeployCore::_config->translationDir);
if (!dir.exists() || list.isEmpty()) {
return false;
}
QStringList filters;
for (auto &&i: list) {
filters.push_back("*" + i + "*");
}
auto listItems = dir.entryInfoList(filters, QDir::Files | QDir::NoDotAndDotDot);
for (auto &&i: listItems) {
_fileManager->copyFile(i.absoluteFilePath(), DeployCore::_config->targetDir + "/translations");
}
return true;
}
QFileInfoList Extracter::findFilesInsideDir(const QString &name,
const QString &dirpath) {
QFileInfoList files;
QDir dir(dirpath);
auto list = dir.entryInfoList( QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
for (auto && item :list) {
if (item.isFile()) {
if (item.fileName().contains(name)) {
files += item;
}
} else {
files += findFilesInsideDir(name, item.absoluteFilePath());
}
}
return files;
}
QString Extracter::filterQmlPath(const QString &path) {
if (path.contains(DeployCore::_config->qmlDir)) {
auto endIndex = path.indexOf(QDir::separator(), DeployCore::_config->qmlDir.size() + 1);
QString module =
path.mid(DeployCore::_config->qmlDir.size() + 1, endIndex - DeployCore::_config->qmlDir.size() - 1);
return DeployCore::_config->qmlDir + QDir::separator() + module;
}
return "";
}
void Extracter::extractLib(const QString &file) {
qInfo() << "extract lib :" << file;
auto data = scaner.scan(file);
for (auto &line : data) {
bool isIgnore = false;
for (auto ignore : DeployCore::_config->ignoreList) {
if (line.fullPath().contains(ignore)) {
QuasarAppUtils::Params::verboseLog(line.fullPath() + " ignored by filter" + ignore);
isIgnore = true;
continue;
}
}
if (isIgnore) {
continue;
}
if (line.getPriority() != LibPriority::SystemLib && !neadedLibs.contains(line.fullPath())) {
neadedLibs << line.fullPath();
} else if (QuasarAppUtils::Params::isEndable("deploySystem") &&
line.getPriority() == LibPriority::SystemLib &&
!systemLibs.contains(line.fullPath())) {
systemLibs << line.fullPath();
}
}
}
bool Extracter::extractQmlAll() {
if (!QFileInfo::exists(DeployCore::_config->qmlDir)) {
qWarning() << "qml dir wrong!";
return false;
}
QStringList listItems;
if (!_fileManager->copyFolder(DeployCore::_config->qmlDir, DeployCore::_config->targetDir + "/qml",
QStringList() << ".so.debug" << "d.dll",
&listItems)) {
return false;
}
for (auto item : listItems) {
extract(item);
}
return true;
}
bool Extracter::extractQmlFromSource(const QString& sourceDir) {
QFileInfo info(sourceDir);
if (!info.isDir()) {
qCritical() << "extract qml fail! qml source dir not exits or is not dir " << sourceDir;
return false;
}
QuasarAppUtils::Params::verboseLog("extractQmlFromSource " + info.absoluteFilePath());
if (!QFileInfo::exists(DeployCore::_config->qmlDir)) {
qWarning() << "qml dir wrong!";
return false;
}
QStringList plugins;
QStringList listItems;
QStringList filter;
filter << ".so.debug" << "d.dll" << ".pdb";
QML ownQmlScaner(DeployCore::_config->qmlDir);
if (!ownQmlScaner.scan(plugins, info.absoluteFilePath())) {
QuasarAppUtils::Params::verboseLog("qml scaner run failed!");
return false;
}
if (!_fileManager->copyFolder(DeployCore::_config->qmlDir, DeployCore::_config->targetDir + "/qml",
filter , &listItems, &plugins)) {
return false;
}
for (auto item : listItems) {
extract(item);
}
return true;
}
bool Extracter::extractQml() {
if (QuasarAppUtils::Params::isEndable("qmlDir")) {
return extractQmlFromSource(
QuasarAppUtils::Params::getStrArg("qmlDir"));
} else if (QuasarAppUtils::Params::isEndable("allQmlDependes")) {
return extractQmlAll();
} else {
return false;
}
}
void Extracter::extract(const QString &file) {
QFileInfo info(file);
auto sufix = info.completeSuffix();
if (sufix.contains("dll", Qt::CaseSensitive) ||
sufix.contains("exe", Qt::CaseSensitive) ||
sufix.isEmpty() || sufix.contains("so", Qt::CaseSensitive)) {
extractLib(file);
} else {
QuasarAppUtils::Params::verboseLog("file with sufix " + sufix + " not supported!");
}
}
Extracter::Extracter(FileManager *fileManager):
_fileManager(fileManager) {
assert(_fileManager);
assert(DeployCore::_config);
}

55
Deploy/extracter.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2018-2019 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.
*/
#ifndef EXTRACTER_H
#define EXTRACTER_H
#include <QDir>
#include <QString>
#include <QStringList>
#include <dependenciesscanner.h>
#include "deploy_global.h"
#include "filemanager.h"
#include "qml.h"
class DEPLOYSHARED_EXPORT Extracter {
private:
QStringList neadedLibs;
QStringList systemLibs;
DependenciesScanner scaner;
FileManager *_fileManager;
void extract(const QString &file);
bool copyTranslations(QStringList list);
bool createQConf();
bool extractQml();
QFileInfoList findFilesInsideDir(const QString &name, const QString &dirpath);
bool extractQmlAll();
bool extractQmlFromSource(const QString &sourceDir);
QString filterQmlPath(const QString &path);
void extractLib(const QString & file);
bool deployMSVC();
bool copyPlugin(const QString &plugin);
void copyPlugins(const QStringList &list);
public:
explicit Extracter(FileManager *fileManager);
bool createRunScript(const QString &target);
void deploy();
friend class deploytest;
};
#endif // EXTRACTER_H_H

View File

@ -6,7 +6,6 @@
#include <deploy_global.h>
class DeployedFiles;
class DEPLOYSHARED_EXPORT FileManager
{

View File

@ -20,6 +20,8 @@ private:
public:
PluginsParser(DependenciesScanner *scaner);
bool scan(const QString &pluginPath, QStringList& resDependencies);
};
#endif // QTMODULES_H

View File

@ -43,7 +43,6 @@ Key differences of this program:
| -targetDir [params] | Sets target directory(by default it is the path to the first deployable file)|
| noStrip | Skips strip step |
| noTranslations | Skips the translations files. |
| qmlExtern | Use qml external scanner (qmlimportscaner) |
| | It doesn't work without qmake and inside a snap package |
| -verbose [0-3] | Shows debug log |
| v / version | Shows compiled version |
@ -114,7 +113,6 @@ Console QtDeployer является консольной реализацией
| -targetDir [params] | Устанавливает целевой каталог (по умолчанию это путь к первому развертываемому файлу)|
| noStrip | Пропускает шаг strip |
| noTranslations | Пропускает файлы переводов |
| qmlExtern | Использует внешний сканер qml (qmlimportscaner) |
| | не работает без qmake и в snap |
| -verbose [0-3] | Показывает дебаг лога |
| v / version | Показывает версию приложения |

View File

@ -8,7 +8,7 @@
#include <QtTest>
#include <quasarapp.h>
#include <deploycore.h>
#include <deploy.h>
#include <extracter.h>
#include <dependenciesscanner.h>
#include <qml.h>
@ -334,38 +334,38 @@ void deploytest::testDeployCore() {
void deploytest::testDeployTarget() {
Deploy *deploy = new Deploy();
Extracter *deploy = new Extracter();
QStringList targets;
targets << "./test/bins/execTarget.exe";
QVERIFY(deploy->setTargets(targets));
delete deploy;
targets.clear();
deploy = new Deploy();
deploy = new Extracter();
targets << "./test/bins/execTarget";
QVERIFY(deploy->setTargets(targets));
delete deploy;
targets.clear();
deploy = new Deploy();
deploy = new Extracter();
targets << "./test/bins/execTarget.exe" << "./test/bins/execTarget";
QVERIFY(deploy->setTargets(targets));
delete deploy;
targets.clear();
deploy = new Deploy();
deploy = new Extracter();
targets << "./test/bns/execTarget.exe";
QVERIFY(!deploy->setTargets(targets));
delete deploy;
targets.clear();
deploy = new Deploy();
deploy = new Extracter();
targets << "./test/bins/";
QVERIFY(deploy->setTargets(targets));
delete deploy;
targets.clear();
deploy = new Deploy();
deploy = new Extracter();
targets << "./test/bins/" << "./test/warning/";
QVERIFY(deploy->setTargets(targets));
@ -444,7 +444,7 @@ void deploytest::testStrip() {
void deploytest::testDeploy() {
QuasarAppUtils::Params::parseParams(0, nullptr);
Deploy *deploy = new Deploy();
Extracter *deploy = new Extracter();
QVERIFY(!deploy->appDir.isEmpty());
delete deploy;
}
@ -476,7 +476,7 @@ void deploytest::testExtractLib() {
}
void deploytest::testDeployLdLinux() {
auto deploy = new Deploy();
auto deploy = new Extracter();
int argc = 3;
deploy->targetDir = "./test/bins/sh";
QVERIFY(QDir("./").mkpath("./test/bins/sh/"));
@ -615,7 +615,7 @@ void deploytest::testQmlExtrct() {
void deploytest::testSetTargetDir() {
Deploy dep;
Extracter dep;
dep.setTargetDir();
@ -884,7 +884,7 @@ void deploytest::testTranslations() {
DeployCore::qtDir = QFileInfo("./test/QtDir/").absoluteFilePath();
Deploy *deploy = new Deploy();
Extracter *deploy = new Extracter();
for (auto &&i: trList) {
generateLib(i);