git-svn-id: svn://db.shs.com.ru/libs@778 a8b55f48-bf90-11e4-a774-851b48703e85

This commit is contained in:
2020-03-12 19:35:47 +00:00
parent 8f0e086562
commit 31a7460fc2
3 changed files with 350 additions and 1 deletions

View File

@@ -148,7 +148,7 @@ if (SomeQtFound)
else() else()
message(STATUS "None of Qt found, skip Qt-derived targets") message(STATUS "None of Qt found, skip Qt-derived targets")
endif() endif()
list(INSERT _DIRS 0 cd_utils) list(INSERT _DIRS 0 cd_utils deploy_tool)
foreach(_D ${_DIRS}) foreach(_D ${_DIRS})
include_directories(${_D}) include_directories(${_D})
add_subdirectory(${_D}) add_subdirectory(${_D})

View File

@@ -0,0 +1,58 @@
cmake_minimum_required(VERSION 3.0)
project(deploy_tool)
if (POLICY CMP0017)
cmake_policy(SET CMP0017 NEW)
endif()
if (NOT LIBPROJECT)
find_package(PIP REQUIRED)
option(LIB "System install" 1)
option(DEBUG "Build with -g3" 0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
if (DEBUG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3")
endif()
endif()
if (MINGW)
find_package(MinGW REQUIRED)
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${PIP_INCLUDES})
file(GLOB SRC "*.h" "*.cpp")
add_executable(${PROJECT_NAME} ${SRC})
target_link_libraries(${PROJECT_NAME} ${PIP_LIBRARY})
if(NOT LIBPROJECT)
if(LIB)
if(WIN32)
if(MINGW)
set(CMAKE_INSTALL_PREFIX ${MINGW_DIR})
endif()
else()
if (DEFINED ANDROID_PLATFORM)
set(CMAKE_INSTALL_PREFIX ${ANDROID_SYSTEM_LIBRARY_PATH}/usr)
else()
if(CMAKE_CROSSCOMPILING)
set(CMAKE_INSTALL_PREFIX ${CMAKE_STAGING_PREFIX})
else()
set(CMAKE_INSTALL_PREFIX ${INSTALL_PREFIX}/usr/local)
endif()
endif()
endif()
message(STATUS "Install ${PROJECT_NAME} to system \"${CMAKE_INSTALL_PREFIX}\"")
else()
message(STATUS "Install ${PROJECT_NAME} to local \"bin\", \"lib\" and \"include\"")
endif()
endif()
if(LIB)
list(APPEND _ALL_TARGETS ${PROJECT_NAME})
set(_ALL_TARGETS ${_ALL_TARGETS} PARENT_SCOPE)
if(WIN32)
install(TARGETS ${PROJECT_NAME} DESTINATION ${MINGW_BIN})
else()
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
endif()
#message(STATUS "Install ${PROJECT_NAME} to system \"${CMAKE_INSTALL_PREFIX}\"")
else()
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
#message(STATUS "Install ${PROJECT_NAME} to local \"bin\"")
endif()

291
deploy_tool/main.cpp Normal file
View File

@@ -0,0 +1,291 @@
#include <picli.h>
#include <pidir.h>
#include <piprocess.h>
using namespace PICoutManipulators;
PIString cmd_copy;
PIString qplatform;
void setCommands() {
#ifdef WINDOWS
cmd_copy = "copy /y ";
qplatform = "*windows*";
#else
cmd_copy = "cp -f ";
# ifdef MAC_OS
qplatform = "*cocoa*";
# else
qplatform = "*xcb*";
# endif
#endif
}
void usage() {
piCout << Bold << "Deploy tool";
piCout << Cyan << "Version PIP" << Bold << PIPVersion();
piCout << Green << Bold << "Usage:" << Default << "\"deploy_tool [-hv] -o <out_path> [-s <search_path>] [-S <styles>] [-l <ldd>] [-L <readelf> | -O <objdump>] [-d <depth>] [-q <qtdir>] [-a <add_libs>] [-S <styles>] [-P <Platforms>] <file>\"" << NewLine;
piCout << Green << Bold << "Details:";
piCout << Bold << "Debug control";
piCout << "-h " << Green << "- display this message and exit";
piCout << "-v " << Green << "- be verbose";
piCout << "";
piCout << Bold << "Processing control";
piCout << "-s <search_path> " << Green << "- set search pathes for system libraries, may be separated by \";\", default \"/usr/lib\"";
piCout << "-l <ldd> " << Green << "- \"ldd\" path, default \"/usr/bin/ldd\"";
piCout << "-L <readelf> " << Green << "- \"*-readelf\" path, overrides \"ldd\"";
piCout << "-O <objdump> " << Green << "- \"*-objdump\" path, overrides \"ldd\"";
piCout << "-d <depth> " << Green << "- dependepcies depth, default 1";
piCout << "-q <qtdir> " << Green << "- path where Qt root dir, default takes from \"qmake -v\"";
piCout << "-S <styles> " << Green << "- add Qt styles (e.g. \"oxygen,breeze\"), default \"\"";
piCout << "-P <Platforms> " << Green << "- add Qt platform (e.g. \"windows\"), default by host system";
piCout << "";
piCout << Bold << "Output control";
piCout << "-o <out_path> " << Green << "- path for libraries copy to";
piCout << "";
piCout << Bold << "Input control";
piCout << "<file> " << Green << "- executable to process";
piCout << "-a <add_libs> " << Green << "- additional libs, may be separated by \";\"";
}
int depth = 1;
PIString ldd, readelf, objdump, out_dir, qt_dir;
PIStringList styles, lib_dirs, add_libs, platforms;
PISet<PIString> all_libs, miss_libs;
PIString findLib(const PIString & l) {
if (PIFile::isExists(l)) return l;
piForeachC (PIString & s, lib_dirs) {
if (PIFile::isExists(s + l)) {
return s + l;
}
}
return "";
}
void procLdd(PIString file, bool ext_lib = false, int cur_depth = 0) {
++cur_depth;
if (cur_depth > depth) return;
PISet<PIString> cur_libs;
if (ext_lib) {
if (!all_libs[file]) {
cur_libs << file;
all_libs << file;
}
}
PIStringList lines;
if (readelf.isEmpty() && objdump.isEmpty()) {
PIProcess proc;
proc.setGrabOutput(true);
piCout << "scan" << file << "...";
proc.exec(ldd, file);
proc.waitForFinish(5000);
lines = PIString(proc.readOutput()).split("\n");
} else {
PIString cmd;
if (!readelf.isEmpty()) {
cmd = readelf + " -a " + file;
cmd += " | grep \"Shared library:\" | grep -oG \"\\[.*\\]\"";
} else {
cmd = objdump + " -p " + file;
cmd += " | grep \"DLL Name:\"";
}
//piCout << cmd;
FILE * fp = popen(cmd.dataAscii(), "r");
PIString vs;
if (fp) {
const int sz = 256;
char in[sz];
memset(in, 0, sz);
while (true) {
int r = fread(in, 1, sz, fp);
if (r <= 0) break;
vs += PIString(in, r);
}
pclose(fp);
}
lines = vs.split("\n");
if (!objdump.isEmpty()) {
piForeach (PIString & l, lines) {
l.trim().cutLeft(9).trim();
l.append('.').prepend('.');
}
}
//piCout << "readelf:" << vs;
}
piForeachC (PIString & sl, lines) {
PIString l = sl.trimmed();
if (readelf.isEmpty() && objdump.isEmpty()) {
if (!l.contains("=>")) continue;
l.cutLeft(l.find("=>") + 2);
if (l.contains("("))
l.cutRight(l.length() - l.find("("));
l.trim();
if (l.toLowerCase() == "not found") {
miss_libs << sl.left(sl.find("=>")).trim();
continue;
}
} else {
l.cutLeft(1).cutRight(1);
if (l.isEmpty()) continue;
PIString flp = findLib(l);
if (flp.isEmpty()) {
piCout << "Can`t find" << l;
continue;
}
l = flp;
}
if (all_libs[l]) continue;
cur_libs << l;
all_libs << l;
}
PIVector<PIString> clibs = cur_libs.toVector();
piForeachC (PIString & l, clibs) {
procLdd(l, cur_depth);
}
}
void copyWildcard(const PIString & from, const PIString & to) {
piCout << "copy" << from;
PIDir(to).make();
#ifdef WINDOWS
PIFile::FileInfo fi; fi.path = from;
system("robocopy \"" + fi.dir() + "\" \"" + to + "\" \"" + fi.name() + "\" /NJH /NJS /NP /NDL /NS /NC /NFL");
#else
system(cmd_copy + from + " \"" + to + "/\"");
#endif
}
void procQt() {
piCout << "qmake ...";
PIString vs;
if (qt_dir.isEmpty()) {
FILE * fp = popen("qmake -v", "r");
if (fp) {
char in[1024];
memset(in, 0, 1024);
if (fread(in, 1, 1024, fp))
vs = in;
pclose(fp);
}
if (vs.isEmpty()) {
piCout << "Can`t exec \"qmake -v\"!";
return;
}
} else
vs = "QMake version ?.?\nUsing Qt version ?.?.? in " + qt_dir;
PIStringList vsl = vs.split("\n");
PIStringList pdirs;
PIString out_plugins_dir = out_dir + "plugins/";
pdirs << "imageformats" << "sqldrivers";
piForeach (PIString l, vsl) {
if (l.trim().contains("Qt version")) {
l.cutLeft(l.find("Qt version") + 10).trim();
PIString qv = l.takeWord();
l.takeWord();
PIString qloc = l.trim();
piCout << "Qt" << qv << "in" << qloc;
PIString qdir = qloc;
#ifdef WINDOWS
if (qt_dir.isEmpty())
qdir += "/../plugins/";
else
qdir += "/plugins/";
#else
if (qt_dir.isEmpty())
qdir += "/qt5/plugins/";
else
qdir += "/plugins/";
#endif
piForeachC (PIString & p, pdirs) {
copyWildcard(qdir + p + "/*", out_plugins_dir + p);
}
copyWildcard(qdir + "platforms/" + qplatform, out_plugins_dir + "platforms");
piForeachC (PIString & s, styles) {
copyWildcard(qdir + "styles/*" + s + "*", out_plugins_dir + "styles");
}
}
}
pdirs << "platforms" << "styles";
piForeachC (PIString & p, pdirs) {
PIVector<PIFile::FileInfo> fil = PIDir(out_plugins_dir + p).entries();
piForeachC (PIFile::FileInfo & f, fil) {
if (f.isFile())
procLdd(f.path);
}
}
}
int main(int argc, char * argv[]) {
PICLI cli(argc, argv);
//piCout << cli.rawArguments();
cli.setOptionalArgumentsCount(-1);
cli.addArgument("help");
cli.addArgument("verbose");
cli.addArgument("output", true);
cli.addArgument("search_path", true);
cli.addArgument("Styles", true);
cli.addArgument("Platforms", true);
cli.addArgument("ldd", true);
cli.addArgument("Ldd", true);
cli.addArgument("Objdump", true);
cli.addArgument("depth", true);
cli.addArgument("qtdir", true);
cli.addArgument("add_libs", true);
if (cli.hasArgument("help") || cli.argumentValue("output").isEmpty() || (cli.optionalArguments().size_s() != 1)) {
usage();
return 0;
}
setCommands();
piDebug = cli.hasArgument("verbose");
PIString bin = cli.optionalArguments()[0];
out_dir = cli.argumentValue("output");
lib_dirs = cli.argumentValue("search_path").split(";");
add_libs = cli.argumentValue("add_libs").split(";");
qt_dir = cli.argumentValue("qtdir");
ldd = cli.argumentValue("ldd");
readelf = cli.argumentValue("Ldd");
objdump = cli.argumentValue("Objdump");
if (!readelf.isEmpty() && !objdump.isEmpty()) {
piCout << "Can`t you both \"readelf\" and \"objdump\"!";
return 1;
}
if (!cli.argumentValue("Platforms").isEmpty())
qplatform = cli.argumentValue("Platforms");
piForeach (PIString & s, lib_dirs) {
if (!s.endsWith("/")) s += "/";
}
if (out_dir.isEmpty()) out_dir = ".";
if (!out_dir.endsWith("/")) out_dir += "/";
if (ldd.isEmpty()) ldd = "/usr/bin/ldd";
styles = cli.argumentValue("Styles").split(",");
PIDir(out_dir).make();
if (!cli.argumentValue("depth").isEmpty())
depth = cli.argumentValue("depth").toInt();
if (depth > 0)
procLdd(bin);
piForeach (PIString & s, add_libs) {
piCout << s << "->" << findLib(s);
procLdd(findLib(s), true);
}
procQt();
PIVector<PIString> clibs = all_libs.toVector();
piForeachC (PIString & l, clibs) {
piCout << "copy" << l;
system(cmd_copy + "\"" + l + "\" \"" + out_dir + "\"");
}
piCout << "copied" << clibs.size_s() << "files";
if (!miss_libs.isEmpty()) {
piCout << "Missing libraries:\n - " << PIStringList(miss_libs.toVector()).join("\n - ");
}
return 0;
}