You've already forked linuxdeploy
mirror of
https://github.com/encounter/linuxdeploy.git
synced 2026-03-30 11:18:58 -07:00
Initial commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
cmake-build-*/
|
||||
*build*/
|
||||
.idea/
|
||||
@@ -0,0 +1,9 @@
|
||||
[submodule "lib/cpp-subprocess"]
|
||||
path = lib/cpp-subprocess
|
||||
url = https://github.com/arun11299/cpp-subprocess.git
|
||||
[submodule "lib/args"]
|
||||
path = lib/args
|
||||
url = https://github.com/Taywee/args.git
|
||||
[submodule "lib/cpp-feather-ini-parser"]
|
||||
path = lib/cpp-feather-ini-parser
|
||||
url = https://github.com/Turbine1991/cpp-feather-ini-parser.git
|
||||
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
project(linuxdeploy C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(LINUXDEPLOY_VERSION 0.1-alpha-1)
|
||||
add_definitions(-DLINUXDEPLOY_VERSION="${LINUXDEPLOY_VERSION}")
|
||||
|
||||
add_subdirectory(lib)
|
||||
|
||||
add_subdirectory(src)
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
Copyright 2018 TheAssassin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,5 @@
|
||||
# linuxdeploy
|
||||
|
||||
AppDir creation and maintenance tool.
|
||||
|
||||
**More info will follow soon!**
|
||||
@@ -0,0 +1,71 @@
|
||||
// system includes
|
||||
#include <string>
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
// local includes
|
||||
#include "linuxdeploy/core/desktopfile.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace appdir {
|
||||
/*
|
||||
* Base class for AppDirs.
|
||||
*/
|
||||
class AppDir {
|
||||
private:
|
||||
// private data class pattern
|
||||
class PrivateData;
|
||||
PrivateData* d;
|
||||
|
||||
public:
|
||||
// default constructor
|
||||
// construct AppDir from given path
|
||||
// the directory will be created if it doesn't exist
|
||||
explicit AppDir(const boost::filesystem::path& path);
|
||||
|
||||
~AppDir();
|
||||
|
||||
// alternative constructor
|
||||
// shortcut for using a normal string instead of a path
|
||||
explicit AppDir(const std::string& path);
|
||||
|
||||
// creates basic directory structure of an AppDir in "FHS" mode
|
||||
bool createBasicStructure();
|
||||
|
||||
// deploy shared library
|
||||
bool deployLibrary(const boost::filesystem::path& path);
|
||||
|
||||
// deploy executable
|
||||
bool deployExecutable(const boost::filesystem::path& path);
|
||||
|
||||
// deploy desktop file
|
||||
bool deployDesktopFile(const desktopfile::DesktopFile& desktopFile);
|
||||
|
||||
// deploy icon
|
||||
bool deployIcon(const boost::filesystem::path& path);
|
||||
|
||||
// execute deferred copy operations
|
||||
bool executeDeferredOperations();
|
||||
|
||||
// return path to AppDir
|
||||
boost::filesystem::path path();
|
||||
|
||||
// create a list of all icon paths in the AppDir
|
||||
std::vector<boost::filesystem::path> deployedIconPaths();
|
||||
|
||||
// create a list of all executable paths in the AppDir
|
||||
std::vector<boost::filesystem::path> deployedExecutablePaths();
|
||||
|
||||
// create a list of all desktop file paths in the AppDir
|
||||
std::vector<desktopfile::DesktopFile> deployedDesktopFiles();
|
||||
|
||||
// create symlinks for AppRun, desktop file and icon in the AppDir root directory
|
||||
bool createLinksInAppDirRoot(const desktopfile::DesktopFile& desktopFile);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// system includes
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace desktopfile {
|
||||
/*
|
||||
* Parse and read desktop files.
|
||||
*/
|
||||
class DesktopFile {
|
||||
private:
|
||||
// private data class pattern
|
||||
class PrivateData;
|
||||
PrivateData* d;
|
||||
|
||||
public:
|
||||
// default constructor
|
||||
DesktopFile();
|
||||
|
||||
// construct from existing desktop file
|
||||
// file must exist
|
||||
explicit DesktopFile(const boost::filesystem::path& path);
|
||||
|
||||
// read desktop file
|
||||
// sets path associated with this file
|
||||
bool read(const boost::filesystem::path& path);
|
||||
|
||||
// get path associated with this file
|
||||
boost::filesystem::path path() const;
|
||||
|
||||
// sets the path associated with this desktop file
|
||||
// used to e.g., save the desktop file
|
||||
void setPath(const boost::filesystem::path& path);
|
||||
|
||||
// clear contents of desktop file
|
||||
void clear();
|
||||
|
||||
// save desktop file
|
||||
bool save() const;
|
||||
|
||||
// save desktop file to path
|
||||
// does not change path associated with desktop file
|
||||
bool save(const boost::filesystem::path& path) const;
|
||||
|
||||
// check if entry exists in given section and key
|
||||
bool entryExists(const std::string& section, const std::string& key) const;
|
||||
|
||||
// get key from desktop file
|
||||
// an std::string passed as value parameter will be populated with the contents
|
||||
// returns true (and populates value) if the key exists, false otherwise
|
||||
bool getEntry(const std::string& section, const std::string& key, std::string& value) const;
|
||||
|
||||
// add key to section in desktop file
|
||||
// the section will be created if it doesn't exist already
|
||||
// returns true if an existing key was overwritten, false otherwise
|
||||
bool setEntry(const std::string& section, const std::string& key, const std::string& value);
|
||||
|
||||
// create common application entries in desktop file
|
||||
// returns false if one of the keys exists and was left unmodified
|
||||
bool addDefaultKeys(const std::string& executableFileName);
|
||||
|
||||
// validate desktop file
|
||||
bool validate() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// system includes
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace elf {
|
||||
class ElfFile {
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData* d;
|
||||
|
||||
public:
|
||||
explicit ElfFile(const boost::filesystem::path& path);
|
||||
~ElfFile();
|
||||
|
||||
public:
|
||||
// recursively trace dynamic library dependencies of a given ELF file
|
||||
// this works for both libraries and executables
|
||||
// the resulting vector consists of absolute paths to the libraries determined by the same methods a system's
|
||||
// linker would use
|
||||
std::vector<boost::filesystem::path> traceDynamicDependencies();
|
||||
|
||||
// fetch rpath stored in binary
|
||||
// it appears that according to the ELF standard, the rpath is ignored in libraries, therefore if the path
|
||||
// points to an executable, an empty string is returned
|
||||
std::string getRPath();
|
||||
|
||||
// set rpath in ELF file
|
||||
// returns true on success, false otherwise
|
||||
bool setRPath(const std::string& value);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// system includes
|
||||
#include <iostream>
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace log {
|
||||
enum LD_LOGLEVEL {
|
||||
LD_DEBUG = 0,
|
||||
LD_INFO,
|
||||
LD_WARNING,
|
||||
LD_ERROR
|
||||
};
|
||||
|
||||
enum LD_STREAM_CONTROL {
|
||||
LD_NOOP = 0,
|
||||
LD_NO_SPACE,
|
||||
};
|
||||
|
||||
class ldLog {
|
||||
private:
|
||||
// this is the type of std::cout
|
||||
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
|
||||
|
||||
// this is the function signature of std::endl
|
||||
typedef CoutType& (* stdEndlType)(CoutType&);
|
||||
|
||||
private:
|
||||
static LD_LOGLEVEL verbosity;
|
||||
|
||||
private:
|
||||
bool prependSpace;
|
||||
bool logLevelSet;
|
||||
CoutType& stream = std::cout;
|
||||
|
||||
LD_LOGLEVEL currentLogLevel;
|
||||
|
||||
private:
|
||||
// advanced behavior
|
||||
ldLog(bool prependSpace, bool logLevelSet, LD_LOGLEVEL logLevel);
|
||||
|
||||
void checkPrependSpace();
|
||||
|
||||
bool checkVerbosity();
|
||||
|
||||
public:
|
||||
static void setVerbosity(LD_LOGLEVEL verbosity);
|
||||
|
||||
public:
|
||||
// public constructor
|
||||
// does not implement the advanced behavior -- see private constructors for that
|
||||
ldLog();
|
||||
|
||||
public:
|
||||
ldLog operator<<(const std::string& message);
|
||||
ldLog operator<<(const char* message);
|
||||
ldLog operator<<(const boost::filesystem::path& path);
|
||||
ldLog operator<<(const double val);
|
||||
ldLog operator<<(stdEndlType strm);
|
||||
ldLog operator<<(const LD_LOGLEVEL logLevel);
|
||||
ldLog operator<<(const LD_STREAM_CONTROL streamControl);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace util {
|
||||
static inline bool ltrim(std::string& s, char to_trim = ' ') {
|
||||
// TODO: find more efficient way to check whether elements have been removed
|
||||
size_t initialLength = s.length();
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [to_trim](int ch) {
|
||||
return ch != to_trim;
|
||||
}));
|
||||
return s.length() < initialLength;
|
||||
}
|
||||
|
||||
static inline bool rtrim(std::string& s, char to_trim = ' ') {
|
||||
// TODO: find more efficient way to check whether elements have been removed
|
||||
auto initialLength = s.length();
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), [to_trim](int ch) {
|
||||
return ch != to_trim;
|
||||
}).base(), s.end());
|
||||
return s.length() < initialLength;
|
||||
}
|
||||
|
||||
static inline bool trim(std::string& s, char to_trim = ' ') {
|
||||
// returns true if either modifies s
|
||||
auto ltrim_result = ltrim(s, to_trim);
|
||||
return rtrim(s, to_trim) && ltrim_result;
|
||||
}
|
||||
|
||||
static std::vector<std::string> split(const std::string& s, char delim = ' ') {
|
||||
std::vector<std::string> result;
|
||||
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
|
||||
while (std::getline(ss, item, delim)) {
|
||||
result.push_back(item);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::vector<std::string> splitLines(const std::string& s) {
|
||||
return split(s, '\n');
|
||||
}
|
||||
|
||||
static inline std::string strLower(std::string s) {
|
||||
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
add_library(subprocess INTERFACE)
|
||||
target_sources(subprocess INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-subprocess/subprocess.hpp)
|
||||
target_include_directories(subprocess INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-subprocess)
|
||||
|
||||
add_library(args INTERFACE)
|
||||
target_sources(args INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/args/args.hxx)
|
||||
target_include_directories(args INTERFACE args)
|
||||
|
||||
add_library(cpp-feather-ini-parser INTERFACE)
|
||||
target_sources(cpp-feather-ini-parser INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-feather-ini-parser/INI.h)
|
||||
target_include_directories(cpp-feather-ini-parser INTERFACE cpp-feather-ini-parser)
|
||||
|
||||
add_executable(test_cpp_feather_ini_parser EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/cpp-feather-ini-parser/example/example.cpp)
|
||||
target_link_libraries(test_cpp_feather_ini_parser PRIVATE cpp-feather-ini-parser)
|
||||
add_test(test_cpp_feather_ini_parser test_cpp_feather_ini_parser)
|
||||
Submodule
+1
Submodule lib/args added at bd0429e91f
Submodule
+1
Submodule lib/cpp-feather-ini-parser added at 2dff628f92
Submodule
+1
Submodule lib/cpp-subprocess added at 05c76a5311
@@ -0,0 +1,4 @@
|
||||
# globally include own includes
|
||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
|
||||
add_subdirectory(core)
|
||||
@@ -0,0 +1,27 @@
|
||||
# 3.5 is required for imported boost targets
|
||||
# 3.6 is required for the PkgConfig module's IMPORTED_TARGET library feature
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
|
||||
# include headers to make CLion happy
|
||||
file(GLOB HEADERS ${PROJECT_SOURCE_DIR}/include/linuxdeploy/core/*.h)
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS filesystem regex)
|
||||
find_package(Threads)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(magick++ REQUIRED IMPORTED_TARGET Magick++)
|
||||
|
||||
message(STATUS "Generating excludelist")
|
||||
execute_process(
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/generate-excludelist.sh
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
add_library(core elf.cpp log.cpp appdir.cpp desktopfile.cpp ${HEADERS})
|
||||
target_link_libraries(core Boost::filesystem Boost::regex subprocess cpp-feather-ini-parser PkgConfig::magick++ ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_include_directories(core PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_executable(linuxdeploy main.cpp)
|
||||
target_link_libraries(linuxdeploy core args)
|
||||
|
||||
set_target_properties(linuxdeploy PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
// library headers
|
||||
#include <INI.h>
|
||||
|
||||
// local headers
|
||||
#include "linuxdeploy/core/desktopfile.h"
|
||||
#include "linuxdeploy/core/log.h"
|
||||
|
||||
using namespace linuxdeploy::core;
|
||||
using namespace linuxdeploy::core::log;
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace desktopfile {
|
||||
class DesktopFile::PrivateData {
|
||||
public:
|
||||
bf::path path;
|
||||
INI<> ini;
|
||||
|
||||
public:
|
||||
PrivateData() : path(), ini("", false) {};
|
||||
};
|
||||
|
||||
DesktopFile::DesktopFile() {
|
||||
d = new PrivateData();
|
||||
}
|
||||
|
||||
DesktopFile::DesktopFile(const bf::path& path) : DesktopFile() {
|
||||
if (!read(path))
|
||||
throw std::runtime_error("Failed to read desktop file");
|
||||
};
|
||||
|
||||
bool DesktopFile::read(const boost::filesystem::path& path) {
|
||||
setPath(path);
|
||||
|
||||
clear();
|
||||
|
||||
// nothing to do
|
||||
if (!bf::exists(path))
|
||||
return true;
|
||||
|
||||
std::ifstream ifs(path.string());
|
||||
if (!ifs)
|
||||
return false;
|
||||
|
||||
d->ini.parse(ifs);
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::filesystem::path DesktopFile::path() const {
|
||||
return d->path;
|
||||
}
|
||||
|
||||
void DesktopFile::setPath(const boost::filesystem::path& path) {
|
||||
d->path = path;
|
||||
}
|
||||
|
||||
void DesktopFile::clear() {
|
||||
d->ini.clear();
|
||||
}
|
||||
|
||||
bool DesktopFile::save() const {
|
||||
return save(d->path);
|
||||
}
|
||||
|
||||
bool DesktopFile::save(const boost::filesystem::path& path) const {
|
||||
return d->ini.save(path.string());
|
||||
}
|
||||
|
||||
bool DesktopFile::entryExists(const std::string& section, const std::string& key) const {
|
||||
if (!d->ini.select(section))
|
||||
return false;
|
||||
|
||||
std::string absolutelyUnlikeValue = "<>!§$%&/()=?+'#-.,_:;'*¹²³½¬{[]}^°|";
|
||||
|
||||
auto value = d->ini.get<std::string, std::string, std::string>(section, key, absolutelyUnlikeValue);
|
||||
|
||||
return value != absolutelyUnlikeValue;
|
||||
}
|
||||
|
||||
bool DesktopFile::setEntry(const std::string& section, const std::string& key, const std::string& value) {
|
||||
// check if value exists -- used for return value
|
||||
auto rv = entryExists(section, key);
|
||||
|
||||
// set key
|
||||
d->ini[section][key] = value;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool DesktopFile::getEntry(const std::string& section, const std::string& key, std::string& value) const {
|
||||
if (!entryExists(section, key))
|
||||
return false;
|
||||
|
||||
if (!d->ini.select(section))
|
||||
return false;
|
||||
|
||||
value = d->ini.get(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DesktopFile::addDefaultKeys(const std::string& executableFileName) {
|
||||
auto rv = true;
|
||||
|
||||
auto setDefault = [&rv, this](const std::string& section, const std::string& key, const std::string& value) {
|
||||
if (setEntry(section, key, value)) {
|
||||
rv = false;
|
||||
}
|
||||
};
|
||||
|
||||
setDefault("Desktop Entry", "Name", executableFileName);
|
||||
setDefault("Desktop Entry", "Exec", executableFileName);
|
||||
setDefault("Desktop Entry", "Icon", executableFileName);
|
||||
setDefault("Desktop Entry", "Type", "Application");
|
||||
setDefault("Desktop Entry", "Categories", "Utility;");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool DesktopFile::validate() const {
|
||||
// FIXME: call desktop-file-validate
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
// library includes
|
||||
#include <boost/regex.hpp>
|
||||
#include <subprocess.hpp>
|
||||
|
||||
// local headers
|
||||
#include "linuxdeploy/core/elf.h"
|
||||
#include "linuxdeploy/core/log.h"
|
||||
#include "linuxdeploy/core/util.h"
|
||||
|
||||
using namespace linuxdeploy::core::log;
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace elf {
|
||||
class ElfFile::PrivateData {
|
||||
public:
|
||||
const bf::path path;
|
||||
|
||||
public:
|
||||
explicit PrivateData(const bf::path& path) : path(path) {}
|
||||
};
|
||||
|
||||
ElfFile::ElfFile(const boost::filesystem::path& path) {
|
||||
d = new PrivateData(path);
|
||||
}
|
||||
|
||||
ElfFile::~ElfFile() {
|
||||
delete d;
|
||||
}
|
||||
|
||||
std::vector<bf::path> ElfFile::traceDynamicDependencies() {
|
||||
// this method's purpose is to abstract this process
|
||||
// the caller doesn't care _how_ it's done, after all
|
||||
|
||||
// for now, we use the same ldd based method linuxdeployqt uses
|
||||
|
||||
std::vector<bf::path> paths;
|
||||
|
||||
subprocess::Popen lddProc(
|
||||
{"ldd", d->path.string().c_str()},
|
||||
subprocess::output{subprocess::PIPE},
|
||||
subprocess::error{subprocess::PIPE}
|
||||
);
|
||||
|
||||
auto lddOutput = lddProc.communicate();
|
||||
auto& lddStdout = lddOutput.first;
|
||||
auto& lddStderr = lddOutput.second;
|
||||
|
||||
if (lddProc.retcode() != 0) {
|
||||
ldLog() << LD_ERROR << "Call to ldd failed:" << std::endl << lddStderr.buf.data() << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string lddStdoutContents(lddStdout.buf.data());
|
||||
|
||||
const boost::regex expr(R"(\s*(.+)\s+\=>\s+(.+)\s+\((.+)\)\s*)");
|
||||
boost::smatch what;
|
||||
|
||||
for (const auto& line : util::splitLines(lddStdoutContents)) {
|
||||
if (boost::regex_search(line, what, expr)) {
|
||||
auto libraryPath = what[2].str();
|
||||
util::trim(libraryPath);
|
||||
paths.push_back(bf::absolute(libraryPath));
|
||||
} else {
|
||||
ldLog() << LD_DEBUG << "Invalid ldd output: " << line << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
std::string ElfFile::getRPath() {
|
||||
subprocess::Popen patchelfProc(
|
||||
{"patchelf", "--print-rpath", d->path.c_str()},
|
||||
subprocess::output(subprocess::PIPE),
|
||||
subprocess::error(subprocess::PIPE)
|
||||
);
|
||||
|
||||
auto patchelfOutput = patchelfProc.communicate();
|
||||
auto& patchelfStdout = patchelfOutput.first;
|
||||
auto& patchelfStderr = patchelfOutput.second;
|
||||
|
||||
if (patchelfProc.retcode() != 0) {
|
||||
std::string errStr(patchelfStderr.buf.data());
|
||||
|
||||
// if file is not an ELF executable, there is no need for a detailed error message
|
||||
if (patchelfProc.retcode() == 1 && errStr.find("not an ELF executable")) {
|
||||
return "";
|
||||
} else {
|
||||
ldLog() << LD_ERROR << "Call to patchelf failed:" << std::endl << errStr;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string retval = patchelfStdout.buf.data();
|
||||
util::trim(retval, '\n');
|
||||
util::trim(retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool ElfFile::setRPath(const std::string& value) {
|
||||
subprocess::Popen patchelfProc(
|
||||
{"patchelf", "--set-rpath", value.c_str(), d->path.c_str()},
|
||||
subprocess::output(subprocess::PIPE),
|
||||
subprocess::error(subprocess::PIPE)
|
||||
);
|
||||
|
||||
auto patchelfOutput = patchelfProc.communicate();
|
||||
auto& patchelfStdout = patchelfOutput.first;
|
||||
auto& patchelfStderr = patchelfOutput.second;
|
||||
|
||||
if (patchelfProc.retcode() != 0) {
|
||||
ldLog() << LD_ERROR << "Call to patchelf failed:" << std::endl << patchelfStderr.buf;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2018 Alexander Gottwald (https://github.com/ago1024)
|
||||
# Copyright 2018 TheAssassin (https://github.com/TheAssassin)
|
||||
#
|
||||
# Dual-licensed under the terms of the GPLv3 and LGPL v3 licenses as part of
|
||||
# linuxdeployqt (https://github.com/probonopd/linuxdeployqt).
|
||||
#
|
||||
# Changed to use C++ standard library containers instead of Qt ones.
|
||||
|
||||
set -e
|
||||
|
||||
# download excludelist
|
||||
blacklisted=($(wget --quiet https://raw.githubusercontent.com/probonopd/AppImages/master/excludelist -O - | sort | uniq | grep -v "^#.*" | grep "[^-\s]"))
|
||||
|
||||
# sanity check
|
||||
if [ "$blacklisted" == "" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
filename=excludelist.h
|
||||
|
||||
# overwrite existing source file
|
||||
cat > "$filename" <<EOF
|
||||
/*
|
||||
* List of libraries to exclude for different reasons.
|
||||
*
|
||||
* Automatically generated from
|
||||
* https://raw.githubusercontent.com/probonopd/AppImages/master/excludelist
|
||||
*
|
||||
* This file shall be committed by the developers occassionally,
|
||||
* otherwise systems without access to the internet won't be able to build
|
||||
* fully working versions of linuxdeployqt.
|
||||
*
|
||||
* See https://github.com/probonopd/linuxdeployqt/issues/274 for more
|
||||
* information.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
static const std::vector<std::string> generatedExcludelist = {
|
||||
EOF
|
||||
|
||||
# Create array
|
||||
for item in ${blacklisted[@]:0:${#blacklisted[@]}-1}; do
|
||||
echo -e ' "'"$item"'",' >> "$filename"
|
||||
done
|
||||
echo -e ' "'"${blacklisted[$((${#blacklisted[@]}-1))]}"'"' >> "$filename"
|
||||
|
||||
echo "};" >> "$filename"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user