You've already forked linuxdeploy
mirror of
https://github.com/encounter/linuxdeploy.git
synced 2026-07-10 12:18:44 -07:00
Compare commits
55 Commits
arm64-builds
...
fix-145
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d57e9ae9b | |||
| 407ecc408d | |||
| 8ee0e43c23 | |||
| e9bbbc80f4 | |||
| 68f4655fc4 | |||
| 1072c6d9f0 | |||
| f33dc8dd34 | |||
| 6621f1edf7 | |||
| ee73ac6c8e | |||
| 66691ee882 | |||
| e91b459fce | |||
| 3f86f178a5 | |||
| a8975e0e50 | |||
| 6c47939fdc | |||
| 8663e5bf26 | |||
| 89493e399b | |||
| 4d999ef5c6 | |||
| b39dfa6591 | |||
| 484ff3f004 | |||
| 8b604871cc | |||
| 88dd09f2d1 | |||
| d43e8a42bf | |||
| 5feef7880e | |||
| 2b2c6a913f | |||
| aeb0bfa98b | |||
| 37aa37f5fe | |||
| 59a8ec41ba | |||
| 4a0cfe323d | |||
| c895a1dc59 | |||
| 80a5667ca7 | |||
| 2425ccc832 | |||
| 55b2d00f23 | |||
| e1f6da17b4 | |||
| 326b002ed5 | |||
| 86d4404a16 | |||
| cbfbb1ee2d | |||
| 5fde708954 | |||
| dc07fbd401 | |||
| 5b713b3bee | |||
| 5644d5ca06 | |||
| 557bad2241 | |||
| 590a746882 | |||
| a609adb4f5 | |||
| 591e21a766 | |||
| 0f3a118687 | |||
| 1c0ce6a0a5 | |||
| 2f00292756 | |||
| f24c167722 | |||
| 2af54304e2 | |||
| 4391ad24d9 | |||
| f3ae65bc57 | |||
| d086da38c4 | |||
| 652ef5a215 | |||
| 2b13c52452 | |||
| c45cd46319 |
@@ -1,6 +1,3 @@
|
||||
[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
|
||||
|
||||
+27
-13
@@ -1,25 +1,39 @@
|
||||
language: cpp
|
||||
sudo: required
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- name: CentOS 6 x86_64 build
|
||||
env: ARCH=x86_64 BUILD_TYPE=centos6
|
||||
install: true
|
||||
services:
|
||||
- docker
|
||||
script: travis/build-centos6-docker.sh
|
||||
- name: Ubuntu bionic x86_64 release build
|
||||
env: ARCH=x86_64
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev
|
||||
- libjpeg-dev
|
||||
- libpng-dev
|
||||
- cimg-dev
|
||||
script: travis/build.sh
|
||||
after_success:
|
||||
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
|
||||
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
|
||||
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
|
||||
|
||||
- name: CentOS 6 i386 build
|
||||
env: ARCH=i386 BUILD_TYPE=centos6
|
||||
install: true
|
||||
services:
|
||||
- docker
|
||||
script: travis/build-centos6-docker.sh
|
||||
- name: Ubuntu bionic i386 build
|
||||
env: ARCH=i386
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev:i386
|
||||
- libjpeg-dev:i386
|
||||
- libpng-dev:i386
|
||||
- gcc-multilib
|
||||
- g++-multilib
|
||||
- libfuse2:i386
|
||||
- libcairo2:i386
|
||||
script: travis/build.sh
|
||||
after_success:
|
||||
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
|
||||
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
|
||||
|
||||
@@ -10,11 +10,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules/
|
||||
set(USE_SYSTEM_BOOST OFF CACHE BOOL "Set to ON to use system boost libraries instead of building up to date boost libraries from source")
|
||||
set(USE_SYSTEM_CIMG ON CACHE BOOL "Set to OFF to use CImg library bundled in lib directory")
|
||||
|
||||
if (EXISTS "${PROJECT_SOURCE_DIR}/lib/cpp-subprocess/subprocess.hpp")
|
||||
else()
|
||||
message (FATAL_ERROR "Missing submodule(s), please 'git submodule update --init --recursive'...")
|
||||
endif()
|
||||
|
||||
# support for ccache
|
||||
# call CMake with -DUSE_CCACHE=ON to make use of it
|
||||
set(USE_CCACHE ON CACHE BOOL "")
|
||||
|
||||
@@ -16,7 +16,7 @@ linuxdeploy was greatly influenced by [linuxdeployqt](https://github.com/probono
|
||||
|
||||
## User guides and examples
|
||||
|
||||
Please see the [linuxdeploy user guide](https://docs.appimage.org/packaging-guide/linuxdeploy-user-guide.html) and the [native binaries packaging guide](https://docs.appimage.org/packaging-guide/native-binaries.html) in the [AppImage documentation](https://docs.appimage.org). There's also an [examples section](https://docs.appimage.org/packaging-guide/native-binaries.html#examples).
|
||||
Please see the [linuxdeploy user guide](https://docs.appimage.org/packaging-guide/from-source/linuxdeploy-user-guide.html) and the [native binaries packaging guide](https://docs.appimage.org/packaging-guide/from-source/native-binaries.html) in the [AppImage documentation](https://docs.appimage.org). There's also an [examples section](https://docs.appimage.org/packaging-guide/from-source/native-binaries.html#examples).
|
||||
|
||||
|
||||
## Projects using linuxdeploy
|
||||
@@ -29,6 +29,7 @@ This is an incomplete list of projects using linuxdeploy. You might want to read
|
||||
- [AppImageUpdate](https://github.com/AppImage/AppImageUpdate)
|
||||
- [appimaged](https://github.com/AppImage/appimaged)
|
||||
- [MediaElch](https://github.com/Komet/MediaElch/)
|
||||
- [CPU-X](https://github.com/X0rg/CPU-X) (details available [here](https://github.com/AppImage/AppImageKit/wiki/Bundling-GTK3-apps#fully-automated-deployment-from-sources-with-github-actions-cpu-x))
|
||||
|
||||
|
||||
## Plugins
|
||||
|
||||
@@ -1,8 +1,35 @@
|
||||
# required for PNG imported target
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
|
||||
find_package(PNG REQUIRED)
|
||||
find_package(JPEG REQUIRED)
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(libpng REQUIRED IMPORTED_TARGET libpng)
|
||||
|
||||
# build custom static version of libjpeg for static builds
|
||||
if(STATIC_BUILD)
|
||||
include(ExternalProject)
|
||||
|
||||
if($ENV{ARCH} MATCHES "i[356]86")
|
||||
set(configure_command_prefix env CFLAGS=-m32 CXXFLAGS=-m32)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(libjpeg_static_extproj
|
||||
URL https://www.ijg.org/files/jpegsrc.v9d.tar.gz
|
||||
URL_HASH SHA256=99cb50e48a4556bc571dadd27931955ff458aae32f68c4d9c39d624693f69c32
|
||||
BUILD_IN_SOURCE ON
|
||||
EXCLUDE_FROM_ALL ON
|
||||
CONFIGURE_COMMAND ${configure_command_prefix} ./configure --prefix=/usr
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
ExternalProject_Get_property(libjpeg_static_extproj SOURCE_DIR)
|
||||
add_library(libjpeg_static INTERFACE IMPORTED)
|
||||
set_property(TARGET libjpeg_static PROPERTY INTERFACE_LINK_LIBRARIES ${SOURCE_DIR}/.libs/libjpeg.a)
|
||||
add_dependencies(libjpeg_static libjpeg_static_extproj)
|
||||
|
||||
set(JPEG_LIBRARIES libjpeg_static)
|
||||
else()
|
||||
find_package(JPEG REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_CIMG)
|
||||
message(STATUS "Using bundled CImg library")
|
||||
@@ -22,7 +49,16 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(PNG_INCLUDE_DIR ${libpng_INCLUDE_DIRS})
|
||||
if(NOT STATIC_BUILD)
|
||||
set(PNG_LIBRARY ${libpng_LIBRARIES})
|
||||
else()
|
||||
set(PNG_LIBRARY ${libpng_STATIC_LIBRARIES})
|
||||
endif()
|
||||
|
||||
#message(FATAL_ERROR "${PNG_LIBRARY}")
|
||||
|
||||
add_library(CImg INTERFACE)
|
||||
set_property(TARGET CImg PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CIMG_H_DIR};${JPEG_INCLUDE_DIR}")
|
||||
set_property(TARGET CImg PROPERTY INTERFACE_LINK_LIBRARIES "PNG::PNG;${JPEG_LIBRARIES}")
|
||||
set_property(TARGET CImg PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CIMG_H_DIR};${PNG_INCLUDE_DIR};${JPEG_INCLUDE_DIR}")
|
||||
set_property(TARGET CImg PROPERTY INTERFACE_LINK_LIBRARIES "${PNG_LIBRARY};${JPEG_LIBRARIES}")
|
||||
set_property(TARGET CImg PROPERTY INTERFACE_COMPILE_DEFINITIONS "cimg_display=0;cimg_use_png=1;cimg_use_jpeg=1")
|
||||
|
||||
@@ -57,12 +57,20 @@ namespace linuxdeploy {
|
||||
// deploy executable
|
||||
bool deployExecutable(const boost::filesystem::path& path, const boost::filesystem::path& destination = "");
|
||||
|
||||
// deploy dependencies for ELF file in AppDir, without copying it into the library dir
|
||||
//
|
||||
// the dependencies end up in the regular location
|
||||
bool deployDependenciesOnlyForElfFile(const boost::filesystem::path& elfFilePath, bool failSilentForNonElfFile = false);
|
||||
|
||||
// deploy desktop file
|
||||
bool deployDesktopFile(const desktopfile::DesktopFile& desktopFile);
|
||||
|
||||
// deploy icon
|
||||
bool deployIcon(const boost::filesystem::path& path);
|
||||
|
||||
// deploy icon, changing its name to <target filename>.<ext>
|
||||
bool deployIcon(const boost::filesystem::path& path, const std::string& targetFilename);
|
||||
|
||||
// deploy arbitrary file
|
||||
boost::filesystem::path deployFile(const boost::filesystem::path& from, const boost::filesystem::path& to);
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ namespace linuxdeploy {
|
||||
ldLog operator<<(stdEndlType strm);
|
||||
ldLog operator<<(const LD_LOGLEVEL logLevel);
|
||||
ldLog operator<<(const LD_STREAM_CONTROL streamControl);
|
||||
|
||||
void write(const char* s, const size_t n);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,19 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
// library headers
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <fnmatch.h>
|
||||
#include <subprocess.hpp>
|
||||
#include <thread>
|
||||
|
||||
// local headers
|
||||
#include "linuxdeploy/core/log.h"
|
||||
#include "linuxdeploy/util/util.h"
|
||||
#include "linuxdeploy/subprocess/process.h"
|
||||
#include "linuxdeploy/plugin/plugin_process_handler.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -45,13 +49,20 @@ namespace linuxdeploy {
|
||||
|
||||
private:
|
||||
int getApiLevelFromExecutable() {
|
||||
auto output = subprocess::check_output({pluginPath.c_str(), "--plugin-api-version"});
|
||||
std::string stdoutOutput = output.buf.data();
|
||||
const auto arg = "--plugin-api-version";
|
||||
|
||||
const subprocess::subprocess proc({pluginPath.string(), arg});
|
||||
const auto stdoutOutput = proc.check_output();
|
||||
|
||||
if (stdoutOutput.empty()) {
|
||||
ldLog() << LD_WARNING << "received empty response from plugin" << pluginPath << "while trying to fetch data for" << "--plugin-api-version" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
auto apiLevel = std::stoi(stdoutOutput);
|
||||
return apiLevel;
|
||||
} catch (const std::invalid_argument&) {
|
||||
} catch (const std::exception&) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -62,9 +73,8 @@ namespace linuxdeploy {
|
||||
|
||||
// check whether plugin implements --plugin-type
|
||||
try {
|
||||
auto output = subprocess::check_output({pluginPath.c_str(), "--plugin-type"});
|
||||
|
||||
std::string stdoutOutput = output.buf.data();
|
||||
const subprocess::subprocess proc({pluginPath.c_str(), "--plugin-type"});
|
||||
const auto stdoutOutput = proc.check_output();
|
||||
|
||||
// the specification requires a single line, but we'll silently accept more than that, too
|
||||
if (std::count(stdoutOutput.begin(), stdoutOutput.end(), '\n') >= 1) {
|
||||
@@ -75,7 +85,7 @@ namespace linuxdeploy {
|
||||
else if (firstLine == "output")
|
||||
type = OUTPUT_TYPE;
|
||||
}
|
||||
} catch (const subprocess::CalledProcessError&) {}
|
||||
} catch (const std::logic_error&) {}
|
||||
|
||||
return type;
|
||||
}
|
||||
@@ -126,134 +136,8 @@ namespace linuxdeploy {
|
||||
|
||||
template<int API_LEVEL>
|
||||
int PluginBase<API_LEVEL>::run(const boost::filesystem::path& appDirPath) {
|
||||
auto pluginPath = path();
|
||||
auto args = {pluginPath.c_str(), "--appdir", appDirPath.string().c_str()};
|
||||
|
||||
auto log = ldLog();
|
||||
log << "Running process:";
|
||||
for (const auto& arg : args) {
|
||||
log << "" << arg;
|
||||
}
|
||||
log << std::endl;
|
||||
|
||||
auto process = subprocess::Popen(args, subprocess::output{subprocess::PIPE}, subprocess::error{subprocess::PIPE});
|
||||
|
||||
|
||||
std::vector<pollfd> pfds(2);
|
||||
auto* opfd = &pfds[0];
|
||||
auto* epfd = &pfds[1];
|
||||
|
||||
opfd->fd = fileno(process.output());
|
||||
opfd->events = POLLIN;
|
||||
|
||||
epfd->fd = fileno(process.error());
|
||||
epfd->events = POLLIN;
|
||||
|
||||
for (const auto& fd : {process.output(), process.error()}) {
|
||||
auto flags = fcntl(fileno(fd), F_GETFL, 0);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(fileno(fd), F_SETFL, flags);
|
||||
}
|
||||
|
||||
auto printOutput = [&pfds, opfd, epfd, this, &process]() {
|
||||
poll(pfds.data(), pfds.size(), -1);
|
||||
|
||||
auto printUntilLastLine = [this](std::vector<char>& buf, size_t& bufSize, const std::string& streamType) {
|
||||
std::ostringstream oss;
|
||||
|
||||
while (true) {
|
||||
const auto firstLineFeed = std::find(buf.begin(), buf.end(), '\n');
|
||||
const auto firstCarriageReturn = std::find(buf.begin(), buf.end(), '\r');
|
||||
|
||||
if (firstLineFeed == buf.end() && firstCarriageReturn == buf.end())
|
||||
break;
|
||||
|
||||
const auto endOfLine = std::min(firstLineFeed, firstCarriageReturn);
|
||||
|
||||
std::string line(buf.begin(), endOfLine+1);
|
||||
|
||||
oss << "[" << d->name << "/" << streamType << "] " << line;
|
||||
|
||||
bufSize -= std::distance(buf.begin(), endOfLine+1);
|
||||
buf.erase(buf.begin(), endOfLine+1);
|
||||
}
|
||||
|
||||
auto messages = oss.str();
|
||||
if (!messages.empty())
|
||||
ldLog() << messages;
|
||||
};
|
||||
|
||||
std::vector<char> stdoutBuf(16 * 1024);
|
||||
std::vector<char> stderrBuf(16 * 1024);
|
||||
size_t stdoutBufSize = 0;
|
||||
size_t stderrBufSize = 0;
|
||||
|
||||
if (opfd->revents & POLLIN) {
|
||||
if (stdoutBufSize >= stdoutBuf.size())
|
||||
throw std::runtime_error("Buffer overflow");
|
||||
|
||||
while (true) {
|
||||
auto bytesRead = fread(
|
||||
reinterpret_cast<void*>(stdoutBuf.data() + stdoutBufSize),
|
||||
sizeof(char),
|
||||
static_cast<size_t>(stdoutBuf.size() - stdoutBufSize),
|
||||
process.output()
|
||||
);
|
||||
|
||||
if (bytesRead == 0)
|
||||
break;
|
||||
|
||||
stdoutBufSize += bytesRead;
|
||||
|
||||
printUntilLastLine(stdoutBuf, stdoutBufSize, "stdout");
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
if (epfd->revents & POLLIN) {
|
||||
if (stderrBufSize >= stderrBuf.size())
|
||||
throw std::runtime_error("Buffer overflow");
|
||||
|
||||
while (true) {
|
||||
auto bytesRead = fread(
|
||||
reinterpret_cast<void*>(stderrBuf.data() + stderrBufSize),
|
||||
sizeof(char),
|
||||
static_cast<size_t>(stderrBuf.size() - stderrBufSize),
|
||||
process.error()
|
||||
);
|
||||
|
||||
if (bytesRead == 0)
|
||||
break;
|
||||
|
||||
stderrBufSize += bytesRead;
|
||||
|
||||
printUntilLastLine(stderrBuf, stderrBufSize, "stderr");
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
int retcode;
|
||||
|
||||
do {
|
||||
if (!printOutput()) {
|
||||
ldLog() << LD_ERROR << "Failed to communicate with process" << std::endl;
|
||||
process.kill();
|
||||
return -1;
|
||||
}
|
||||
} while ((retcode = process.poll()) < 0);
|
||||
|
||||
if (!printOutput()) {
|
||||
ldLog() << LD_ERROR << "Failed to communicate with process" << std::endl;
|
||||
process.kill();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return retcode;
|
||||
plugin_process_handler handler(d->name, path());
|
||||
return handler.run(appDirPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
// library headers
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace plugin {
|
||||
class plugin_process_handler {
|
||||
private:
|
||||
std::string name_;
|
||||
boost::filesystem::path path_;
|
||||
|
||||
public:
|
||||
plugin_process_handler(std::string name, boost::filesystem::path path);
|
||||
|
||||
int run(const boost::filesystem::path& appDir) const;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <poll.h>
|
||||
|
||||
/**
|
||||
* Reads from a pipe when data is available, and hands data to registered callbacks.
|
||||
*/
|
||||
class pipe_reader {
|
||||
private:
|
||||
const int pipe_fd_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct new instance from pipe file descriptor.
|
||||
* @param pipe_fd file descriptor for pipe we will read from (e.g., a subprocess's stdout, stderr pipes)
|
||||
*/
|
||||
explicit pipe_reader(int pipe_fd);
|
||||
|
||||
/**
|
||||
* Read from pipe file descriptor and store data in buffer.
|
||||
* This method is non-blocking, i.e., if there is no data to read, it returns immediately.
|
||||
* Otherwise, it will read until either of the following conditions is met:
|
||||
*
|
||||
* - no more data left in the pipe to be read
|
||||
* - buffer is completely filled
|
||||
*
|
||||
* On errors, a subprocess_error is thrown.
|
||||
*
|
||||
* @param buffer buffer to store read data into
|
||||
* @returns amount of characters read from the pipe
|
||||
*/
|
||||
size_t read(std::vector<std::string::value_type>& buffer) const;
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
// system headers
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <signal.h>
|
||||
|
||||
// local headers
|
||||
#include "linuxdeploy/subprocess/subprocess.h"
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace subprocess {
|
||||
class process {
|
||||
private:
|
||||
// child process ID
|
||||
int child_pid_ = -1;
|
||||
|
||||
// pipes to child process's stdout/stderr
|
||||
int stdout_fd_ = -1;
|
||||
int stderr_fd_ = -1;
|
||||
|
||||
// process exited
|
||||
bool exited_ = false;
|
||||
// exit code -- will be initialized by close()
|
||||
int exit_code_ = -1;
|
||||
|
||||
// these constants help make the pipe code more readable
|
||||
static constexpr int READ_END_ = 0, WRITE_END_ = 1;
|
||||
|
||||
static std::vector<char*> make_args_vector_(const std::vector<std::string>& args);
|
||||
|
||||
static std::vector<char*> make_env_vector_(const subprocess_env_map_t& env);
|
||||
|
||||
static int check_waitpid_status_(int status);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a child process.
|
||||
* @param args parameters for process
|
||||
* @param env additional environment variables (current environment will be copied)
|
||||
*/
|
||||
process(std::initializer_list<std::string> args, const subprocess_env_map_t& env);
|
||||
|
||||
/**
|
||||
* Create a child process.
|
||||
* @param args parameters for process
|
||||
* @param env additional environment variables (current environment will be copied)
|
||||
*/
|
||||
process(const std::vector<std::string>& args, const subprocess_env_map_t& env);
|
||||
|
||||
~process();
|
||||
|
||||
/**
|
||||
* @return child process's ID
|
||||
*/
|
||||
int pid() const;
|
||||
|
||||
/**
|
||||
* @return child process's stdout file descriptor ID
|
||||
*/
|
||||
int stdout_fd() const;
|
||||
|
||||
|
||||
/**
|
||||
* @return child process's stderr file descriptor ID
|
||||
*/
|
||||
int stderr_fd() const;
|
||||
|
||||
/**
|
||||
* Close all pipes and wait for process to exit.
|
||||
* If process is not running any more, just returns exit code.
|
||||
* @return child process's exit code
|
||||
*/
|
||||
int close();
|
||||
|
||||
/**
|
||||
* Kill underlying process with given signal. By default, SIGTERM is used to end the process.
|
||||
*/
|
||||
void kill(int signal = SIGTERM) const;
|
||||
|
||||
/**
|
||||
* Check whether process is still alive. Use close() to fetch exit code.
|
||||
* @return true while process is alive, false otherwise
|
||||
*/
|
||||
bool is_running();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
// system headers
|
||||
#include <cstdio>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// local headers
|
||||
#include "subprocess_result.h"
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace subprocess {
|
||||
typedef std::unordered_map<std::string, std::string> subprocess_env_map_t;
|
||||
|
||||
class subprocess {
|
||||
private:
|
||||
std::vector<std::string> args_{};
|
||||
std::unordered_map<std::string, std::string> env_{};
|
||||
|
||||
public:
|
||||
subprocess(std::initializer_list<std::string> args, subprocess_env_map_t env = {});
|
||||
|
||||
explicit subprocess(std::vector<std::string> args, subprocess_env_map_t env = {});
|
||||
|
||||
subprocess_result run() const;
|
||||
|
||||
std::string check_output() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
// system headers
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace subprocess {
|
||||
typedef std::vector<std::string::value_type> subprocess_result_buffer_t;
|
||||
|
||||
/**
|
||||
* Result of subprocess execution. Follows Value Object design pattern.
|
||||
*/
|
||||
class subprocess_result {
|
||||
private:
|
||||
int exit_code_;
|
||||
subprocess_result_buffer_t stdout_contents_;
|
||||
subprocess_result_buffer_t stderr_contents_;
|
||||
|
||||
public:
|
||||
subprocess_result(int exit_code, subprocess_result_buffer_t stdout_contents,
|
||||
subprocess_result_buffer_t stderr_contents);
|
||||
|
||||
int exit_code() const;
|
||||
|
||||
const subprocess_result_buffer_t& stdout_contents() const;
|
||||
|
||||
std::string stdout_string() const;
|
||||
|
||||
const subprocess_result_buffer_t& stderr_contents() const;
|
||||
|
||||
std::string stderr_string() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
// system headers
|
||||
#include <stdexcept>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace util {
|
||||
namespace assert {
|
||||
template<typename T>
|
||||
void assert_not_empty(T container) {
|
||||
if (container.empty()) {
|
||||
throw std::invalid_argument{"container must not be empty"};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// system headers
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
@@ -8,6 +9,9 @@
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
// libraries
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace util {
|
||||
namespace misc {
|
||||
@@ -87,6 +91,33 @@ namespace linuxdeploy {
|
||||
|
||||
return buf.data();
|
||||
}
|
||||
|
||||
// very simple but for our purposes good enough which like algorithm to find binaries in $PATH
|
||||
static boost::filesystem::path which(const std::string& name) {
|
||||
const auto* path = getenv("PATH");
|
||||
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
if (path == nullptr)
|
||||
return "";
|
||||
|
||||
for (const auto& binDir : split(path, ':')) {
|
||||
if (!bf::is_directory(binDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (bf::directory_iterator it(binDir); it != bf::directory_iterator{}; ++it) {
|
||||
const auto binary = it->path();
|
||||
|
||||
if (binary.filename() == name) {
|
||||
// TODO: check if file is executable (skip otherwise)
|
||||
return binary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Wrapper for cpp-subprocess. Provides additional convenience functions.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// library includes
|
||||
#include <subprocess.hpp>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace util {
|
||||
namespace subprocess {
|
||||
using namespace ::subprocess;
|
||||
|
||||
// Reads output channels of existing Popen object into buffers and returns the contents
|
||||
std::pair<std::string, std::string> check_output_error(Popen& proc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
// local includes
|
||||
#include "misc.h"
|
||||
#include "subprocess.h"
|
||||
#include "linuxdeploy/util/assert.h"
|
||||
#include "linuxdeploy/util/misc.h"
|
||||
|
||||
// import functions from misc module for convenience
|
||||
namespace linuxdeploy {
|
||||
namespace util {
|
||||
using namespace misc;
|
||||
using namespace assert;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
include(CTest)
|
||||
|
||||
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)
|
||||
target_compile_options(subprocess INTERFACE "-Wno-deprecated")
|
||||
|
||||
add_library(args INTERFACE)
|
||||
target_sources(args INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/args/args.hxx)
|
||||
target_include_directories(args INTERFACE args)
|
||||
|
||||
Submodule lib/cpp-subprocess deleted from 6931e3d69f
+9
-1
@@ -43,6 +43,7 @@ execute_process(
|
||||
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(plugin)
|
||||
add_subdirectory(subprocess)
|
||||
add_subdirectory(core)
|
||||
|
||||
add_executable(linuxdeploy main.cpp core.cpp)
|
||||
@@ -54,11 +55,18 @@ target_compile_definitions(linuxdeploy PRIVATE -DLD_VERSION="${VERSION}")
|
||||
target_compile_definitions(linuxdeploy PRIVATE -DLD_BUILD_NUMBER="${BUILD_NUMBER}")
|
||||
target_compile_definitions(linuxdeploy PRIVATE -DLD_BUILD_DATE="${DATE}")
|
||||
|
||||
if(STATIC_BUILD)
|
||||
message(WARNING "static builds enabled")
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
target_link_options(linuxdeploy PUBLIC -static -static-libgcc -static-libstdc++)
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(plugin_test plugin_test_main.cpp)
|
||||
target_link_libraries(plugin_test linuxdeploy_plugin)
|
||||
set_target_properties(plugin_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
|
||||
|
||||
add_executable(appdir_test appdir_test_main.cpp)
|
||||
add_executable(appdir_test appdir_test_main.cpp ../include/linuxdeploy/util/assert.h)
|
||||
target_link_libraries(appdir_test linuxdeploy_core args)
|
||||
target_include_directories(appdir_test PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/core)
|
||||
set_target_properties(appdir_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user