You've already forked linuxdeploy
mirror of
https://github.com/encounter/linuxdeploy.git
synced 2026-07-10 12:18:44 -07:00
Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56760df190 | |||
| 23dcaa5cda | |||
| 097212aa1e | |||
| 37b640fa86 | |||
| ed42a40a87 | |||
| 4c5b9c5daf | |||
| 0f5361b457 | |||
| fc27076843 | |||
| f59f8f9512 | |||
| ae8699854a | |||
| fa3e51c7db | |||
| d2e9567029 | |||
| fb5cd4d32d | |||
| 5fb5ca5a8b | |||
| ae714d69ff | |||
| 01331697d0 | |||
| d903364ffc | |||
| d77cff2adc | |||
| 5685bc575e | |||
| d621d3949d | |||
| 0c49714228 | |||
| 9aa59f3e75 | |||
| bcd9d5337e | |||
| 39ab9909cf | |||
| 03d8cb3234 | |||
| 2dfccf760b | |||
| 789222bae6 | |||
| 7e3beb4336 | |||
| 63d2fa5437 | |||
| 49f4f23776 | |||
| 1d534d2b32 | |||
| 3c6096433d | |||
| 86c99ccfb4 | |||
| d5c4124a0b | |||
| a73dbf68f4 | |||
| a7a255f9f1 | |||
| 679904ce7b | |||
| 6b96159f88 | |||
| ab49cecf09 | |||
| 49c3a57226 | |||
| 39b03f630d | |||
| 0a6a1c59b7 | |||
| 7b1c858ff5 | |||
| 0c23a481fe | |||
| b7c9785626 | |||
| 9fb2ac35d2 | |||
| f83a0e99eb | |||
| 8c848e6b26 | |||
| 58f8b6a6fd | |||
| c1bd11028c | |||
| da1bae216a | |||
| b42420e731 | |||
| 8f86082322 | |||
| fb80d6a4f4 | |||
| 575dde281d | |||
| 3e05627373 | |||
| 73f3126a59 | |||
| b6a1ba290e | |||
| 3c21d86574 | |||
| 2554b35403 | |||
| bfcde878e2 | |||
| 04d5321a5f | |||
| 76f1d8fee5 | |||
| e4fff0a5b7 | |||
| 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 |
@@ -0,0 +1,75 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# build at least once a month
|
||||
- cron: '0 0 1 * *'
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
strategy:
|
||||
matrix:
|
||||
ARCH: [x86_64, i386]
|
||||
BUILD_TYPE: [appimage, coverage]
|
||||
fail-fast: false
|
||||
|
||||
name: ${{ matrix.BUILD_TYPE }} ${{ matrix.ARCH }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
ARCH: ${{ matrix.ARCH }}
|
||||
BUILD_TYPE: ${{ matrix.BUILD_TYPE }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install dependencies (x86_64)
|
||||
if: matrix.ARCH == 'x86_64'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcovr libmagic-dev libjpeg-dev libpng-dev libboost-filesystem-dev libboost-regex-dev cimg-dev
|
||||
|
||||
- name: Install dependencies (i386)
|
||||
if: matrix.ARCH == 'i386'
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcovr libmagic-dev:i386 libjpeg-dev:i386 libpng-dev:i386 libboost-filesystem-dev:i386 libboost-regex-dev:i386 cimg-dev gcc-multilib g++-multilib libfuse2:i386
|
||||
|
||||
- name: Test coverage
|
||||
run: bash -ex ci/test-coverage.sh
|
||||
if: matrix.BUILD_TYPE == 'coverage'
|
||||
|
||||
- name: Build, test and build AppImage
|
||||
run: bash -ex ci/build.sh
|
||||
if: matrix.BUILD_TYPE != 'coverage'
|
||||
|
||||
- name: Archive artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
if: matrix.BUILD_TYPE != 'coverage'
|
||||
with:
|
||||
name: AppImage
|
||||
path: linuxdeploy*.AppImage*
|
||||
|
||||
upload:
|
||||
name: Create release and upload artifacts
|
||||
needs:
|
||||
- build-and-test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
- name: Inspect directory after downloading artifacts
|
||||
run: ls -alFR
|
||||
- name: Create release and upload artifacts
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
wget -q https://github.com/TheAssassin/pyuploadtool/releases/download/continuous/pyuploadtool-x86_64.AppImage
|
||||
chmod +x pyuploadtool-x86_64.AppImage
|
||||
./pyuploadtool-x86_64.AppImage **/linuxdeploy*.AppImage*
|
||||
@@ -3,3 +3,4 @@ cmake-build-*/
|
||||
.idea/
|
||||
squashfs-root/
|
||||
*.AppImage
|
||||
*.swp
|
||||
|
||||
+3
-75
@@ -1,84 +1,12 @@
|
||||
[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/boost-filesystem"]
|
||||
path = lib/boost-filesystem
|
||||
url = https://github.com/boostorg/filesystem.git
|
||||
[submodule "lib/boost-regex"]
|
||||
path = lib/boost-regex
|
||||
url = https://github.com/boostorg/regex.git
|
||||
[submodule "lib/boost-system"]
|
||||
path = lib/boost-system
|
||||
url = https://github.com/boostorg/system.git
|
||||
[submodule "lib/boost-config"]
|
||||
path = lib/boost-config
|
||||
url = https://github.com/boostorg/config.git
|
||||
[submodule "lib/boost-utility"]
|
||||
path = lib/boost-utility
|
||||
url = https://github.com/boostorg/utility.git
|
||||
[submodule "lib/boost-predef"]
|
||||
path = lib/boost-predef
|
||||
url = https://github.com/boostorg/predef.git
|
||||
[submodule "lib/boost-assert"]
|
||||
path = lib/boost-assert
|
||||
url = https://github.com/boostorg/assert.git
|
||||
[submodule "lib/boost-core"]
|
||||
path = lib/boost-core
|
||||
url = https://github.com/boostorg/core.git
|
||||
[submodule "lib/boost-type_traits"]
|
||||
path = lib/boost-type_traits
|
||||
url = https://github.com/boostorg/type_traits.git
|
||||
[submodule "lib/boost-iterator"]
|
||||
path = lib/boost-iterator
|
||||
url = https://github.com/boostorg/iterator.git
|
||||
[submodule "lib/boost-mpl"]
|
||||
path = lib/boost-mpl
|
||||
url = https://github.com/boostorg/mpl.git
|
||||
[submodule "lib/boost-preprocessor"]
|
||||
path = lib/boost-preprocessor
|
||||
url = https://github.com/boostorg/preprocessor.git
|
||||
[submodule "lib/boost-static_assert"]
|
||||
path = lib/boost-static_assert
|
||||
url = https://github.com/boostorg/static_assert.git
|
||||
[submodule "lib/boost-detail"]
|
||||
path = lib/boost-detail
|
||||
url = https://github.com/boostorg/detail.git
|
||||
[submodule "lib/boost-smart_ptr"]
|
||||
path = lib/boost-smart_ptr
|
||||
url = https://github.com/boostorg/smart_ptr.git
|
||||
[submodule "lib/boost-exception"]
|
||||
path = lib/boost-exception
|
||||
url = https://github.com/boostorg/exception.git
|
||||
[submodule "lib/boost-throw_exception"]
|
||||
path = lib/boost-throw_exception
|
||||
url = https://github.com/boostorg/throw_exception.git
|
||||
[submodule "lib/boost-io"]
|
||||
path = lib/boost-io
|
||||
url = https://github.com/boostorg/io.git
|
||||
[submodule "lib/boost-functional"]
|
||||
path = lib/boost-functional
|
||||
url = https://github.com/boostorg/functional.git
|
||||
[submodule "lib/boost-container_hash"]
|
||||
path = lib/boost-container_hash
|
||||
url = https://github.com/boostorg/container_hash.git
|
||||
[submodule "lib/boost-range"]
|
||||
path = lib/boost-range
|
||||
url = https://github.com/boostorg/range.git
|
||||
[submodule "lib/boost-integer"]
|
||||
path = lib/boost-integer
|
||||
url = https://github.com/boostorg/integer.git
|
||||
[submodule "lib/CImg"]
|
||||
path = lib/CImg
|
||||
url = https://github.com/dtschump/CImg.git
|
||||
[submodule "lib/googletest"]
|
||||
path = lib/googletest
|
||||
url = https://github.com/google/googletest
|
||||
[submodule "lib/boost-container"]
|
||||
path = lib/boost-container
|
||||
url = https://github.com/boostorg/container
|
||||
[submodule "lib/linuxdeploy-desktopfile"]
|
||||
path = lib/linuxdeploy-desktopfile
|
||||
url = https://github.com/linuxdeploy/linuxdeploy-desktopfile
|
||||
[submodule "lib/cmake-scripts"]
|
||||
path = lib/cmake-scripts
|
||||
url = https://github.com/linuxdeploy/cmake-scripts.git
|
||||
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
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
|
||||
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
|
||||
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: Ubuntu bionic arm64 build
|
||||
env: ARCH=arm64 BUILD_TYPE=arm64-native
|
||||
dist: bionic
|
||||
arch: arm64
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev
|
||||
- libjpeg-dev
|
||||
- libpng-dev
|
||||
- cimg-dev
|
||||
- patchelf
|
||||
before_script:
|
||||
- git clone https://github.com/NixOS/patchelf.git && \
|
||||
- pushd patchelf && \
|
||||
- # cannot use -b since it's not supported in really old versions of git
|
||||
- git checkout 0.8 && \
|
||||
- ./bootstrap.sh && \
|
||||
- ./configure --prefix=/usr && \
|
||||
- make -j $(nproc) && \
|
||||
- make install && \
|
||||
- popd && \
|
||||
- rm -r patchelf/
|
||||
|
||||
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: Ubuntu xenial x86_64 coverage build (no binaries uploaded)
|
||||
env: ARCH=x86_64 BUILD_TYPE=coverage
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev
|
||||
- libjpeg-dev
|
||||
- libpng-dev
|
||||
- cimg-dev
|
||||
before_script:
|
||||
- sudo pip install gcovr
|
||||
script: travis/test-coverage.sh
|
||||
after_success: true # also, we don't intend to upload release binaries
|
||||
|
||||
- name: Ubuntu xenial i386 coverage build (no binaries uploaded)
|
||||
env: ARCH=i386 BUILD_TYPE=coverage
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev:i386
|
||||
- libjpeg-dev:i386
|
||||
- libpng-dev:i386
|
||||
- gcc-multilib
|
||||
- g++-multilib
|
||||
- libfuse2:i386
|
||||
- libcairo2:i386
|
||||
before_script:
|
||||
- sudo pip install gcovr
|
||||
script: travis/test-coverage.sh
|
||||
after_success: true # also, we don't intend to upload release binaries
|
||||
|
||||
|
||||
branches:
|
||||
except:
|
||||
- # Do not build tags that we create when we upload to GitHub Releases
|
||||
- /^(?i:continuous)$/
|
||||
+8
-9
@@ -7,14 +7,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
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 "")
|
||||
@@ -48,11 +40,18 @@ if(ENABLE_COVERAGE)
|
||||
setup_target_for_coverage_gcovr_text(NAME coverage_text EXECUTABLE "${command}")
|
||||
endif()
|
||||
|
||||
include(CTest)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
# including this before including lib/ makes sure that the top level project's gtest is used everywhere
|
||||
include(${PROJECT_SOURCE_DIR}/lib/cmake-scripts/include-or-build-gtest.cmake)
|
||||
endif()
|
||||
|
||||
add_subdirectory(lib)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
@@ -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
|
||||
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#! /bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
INSTALL_DESTDIR="$1"
|
||||
|
||||
if [[ "$INSTALL_DESTDIR" == "" ]]; then
|
||||
echo "Error: build dir $BUILD_DIR does not exist" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# support cross-compilation for 32-bit ISAs
|
||||
case "$ARCH" in
|
||||
"x86_64"|"amd64")
|
||||
;;
|
||||
"i386"|"i586"|"i686")
|
||||
export CFLAGS="-m32"
|
||||
export CXXFLAGS="-m32"
|
||||
;;
|
||||
*)
|
||||
echo "Error: unsupported architecture: $ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# use RAM disk if possible
|
||||
if [ "$CI" == "" ] && [ -d /dev/shm ]; then
|
||||
TEMP_BASE=/dev/shm
|
||||
else
|
||||
TEMP_BASE=/tmp
|
||||
fi
|
||||
|
||||
cleanup () {
|
||||
if [ -d "$BUILD_DIR" ]; then
|
||||
rm -rf "$BUILD_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
BUILD_DIR=$(mktemp -d -p "$TEMP_BASE" linuxdeploy-build-XXXXXX)
|
||||
|
||||
pushd "$BUILD_DIR"
|
||||
|
||||
# fetch source code
|
||||
wget https://ftp.gnu.org/gnu/binutils/binutils-2.35.tar.xz -O- | tar xJ --strip-components=1
|
||||
|
||||
# configure static build
|
||||
# inspired by https://github.com/andrew-d/static-binaries/blob/master/binutils/build.sh
|
||||
./configure --prefix=/usr --disable-nls --enable-static-link --disable-shared-plugins --disable-dynamicplugin --disable-tls --disable-pie
|
||||
|
||||
# citing the script linked above: "This strange dance is required to get things to be statically linked."
|
||||
make -j "$(nproc)"
|
||||
make clean
|
||||
make -j "$(nproc)" LDFLAGS="-all-static"
|
||||
|
||||
# install into user-specified destdir
|
||||
make install DESTDIR="$(readlink -f "$INSTALL_DESTDIR")"
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#! /bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
INSTALL_DESTDIR="$1"
|
||||
|
||||
if [[ "$INSTALL_DESTDIR" == "" ]]; then
|
||||
echo "Error: build dir $BUILD_DIR does not exist" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# support cross-compilation for 32-bit ISAs
|
||||
case "$ARCH" in
|
||||
"x86_64"|"amd64")
|
||||
;;
|
||||
"i386"|"i586"|"i686")
|
||||
export CFLAGS="-m32"
|
||||
export CXXFLAGS="-m32"
|
||||
;;
|
||||
*)
|
||||
echo "Error: unsupported architecture: $ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# use RAM disk if possible
|
||||
if [ "$CI" == "" ] && [ -d /dev/shm ]; then
|
||||
TEMP_BASE=/dev/shm
|
||||
else
|
||||
TEMP_BASE=/tmp
|
||||
fi
|
||||
|
||||
cleanup () {
|
||||
if [ -d "$BUILD_DIR" ]; then
|
||||
rm -rf "$BUILD_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
BUILD_DIR=$(mktemp -d -p "$TEMP_BASE" linuxdeploy-build-XXXXXX)
|
||||
|
||||
pushd "$BUILD_DIR"
|
||||
|
||||
# fetch source code
|
||||
git clone https://github.com/NixOS/patchelf.git .
|
||||
|
||||
# cannot use -b since it's not supported in really old versions of git
|
||||
git checkout 0.8
|
||||
|
||||
# prepare configure script
|
||||
./bootstrap.sh
|
||||
|
||||
# configure static build
|
||||
env LDFLAGS="-static -static-libgcc -static-libstdc++" ./configure --prefix=/usr
|
||||
|
||||
# build binary
|
||||
make -j "$(nproc)"
|
||||
|
||||
# install into user-specified destdir
|
||||
make install DESTDIR="$INSTALL_DESTDIR"
|
||||
@@ -30,38 +30,38 @@ if [ "$ARCH" == "x86_64" ]; then
|
||||
EXTRA_CMAKE_ARGS=()
|
||||
elif [ "$ARCH" == "i386" ]; then
|
||||
EXTRA_CMAKE_ARGS=("-DCMAKE_TOOLCHAIN_FILE=$REPO_ROOT/cmake/toolchains/i386-linux-gnu.cmake" "-DUSE_SYSTEM_CIMG=OFF")
|
||||
elif [ "$ARCH" == "arm64" ] && [ "$BUILD_TYPE" == "arm64-native" ]; then
|
||||
EXTRA_CMAKE_ARGS=()
|
||||
else
|
||||
echo "Architecture not supported: $ARCH" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cmake "$REPO_ROOT" -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RelWithDebInfo "${EXTRA_CMAKE_ARGS[@]}"
|
||||
# fetch up-to-date CMake
|
||||
mkdir cmake-prefix
|
||||
wget -O- https://github.com/Kitware/CMake/releases/download/v3.18.1/cmake-3.18.1-Linux-x86_64.tar.gz | tar -xz -C cmake-prefix --strip-components=1
|
||||
export PATH="$(readlink -f cmake-prefix/bin):$PATH"
|
||||
cmake --version
|
||||
|
||||
make -j$(nproc)
|
||||
# configure build for AppImage release
|
||||
cmake "$REPO_ROOT" -DSTATIC_BUILD=On -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=RelWithDebInfo "${EXTRA_CMAKE_ARGS[@]}"
|
||||
|
||||
make -j"$(nproc)"
|
||||
|
||||
## Run Unit Tests
|
||||
ctest -V
|
||||
|
||||
strip_path=$(which strip)
|
||||
# build patchelf
|
||||
"$REPO_ROOT"/ci/build-static-patchelf.sh "$(readlink -f out/)"
|
||||
patchelf_path="$(readlink -f out/usr/bin/patchelf)"
|
||||
|
||||
if [ "$ARCH" == "i386" ]; then
|
||||
# download i386 strip for i386 AppImage
|
||||
# https://github.com/linuxdeploy/linuxdeploy/issues/59
|
||||
wget http://security.ubuntu.com/ubuntu/pool/main/b/binutils/binutils-multiarch_2.24-5ubuntu14.2_i386.deb
|
||||
echo "0106f170cebf5800e863a558cad039e4f16a76d3424ae943209c3f6b0cacd511 binutils-multiarch_2.24-5ubuntu14.2_i386.deb" | sha256sum -c
|
||||
wget http://security.ubuntu.com/ubuntu/pool/main/b/binutils/binutils-multiarch-dev_2.24-5ubuntu14.2_i386.deb
|
||||
echo "ed9ca4fbbf492233228f79fae6b349a2ed2ee3e0927bdc795425fccf5fae648e binutils-multiarch-dev_2.24-5ubuntu14.2_i386.deb" | sha256sum -c
|
||||
dpkg -x binutils-multiarch_2.24-5ubuntu14.2_i386.deb out/
|
||||
dpkg -x binutils-multiarch-dev_2.24-5ubuntu14.2_i386.deb out/
|
||||
rm binutils-multiarch*.deb
|
||||
strip_path=$(readlink -f out/usr/bin/strip)
|
||||
export LD_LIBRARY_PATH=$(readlink -f out/usr/lib)
|
||||
fi
|
||||
# build custom strip
|
||||
"$REPO_ROOT"/ci/build-static-binutils.sh "$(readlink -f out/)"
|
||||
strip_path="$(readlink -f out/usr/bin/strip)"
|
||||
|
||||
# use tools we just built for linuxdeploy run
|
||||
export PATH="$(readlink -f out/usr/bin):$PATH"
|
||||
|
||||
# args are used more than once
|
||||
LINUXDEPLOY_ARGS=("--appdir" "AppDir" "-e" "bin/linuxdeploy" "-i" "$REPO_ROOT/resources/linuxdeploy.png" "-d" "$REPO_ROOT/resources/linuxdeploy.desktop" "-e" "/usr/bin/patchelf" "-e" "$strip_path")
|
||||
LINUXDEPLOY_ARGS=("--appdir" "AppDir" "-e" "bin/linuxdeploy" "-i" "$REPO_ROOT/resources/linuxdeploy.png" "-d" "$REPO_ROOT/resources/linuxdeploy.desktop" "-e" "$patchelf_path" "-e" "$strip_path")
|
||||
|
||||
# deploy patchelf which is a dependency of linuxdeploy
|
||||
bin/linuxdeploy "${LINUXDEPLOY_ARGS[@]}"
|
||||
@@ -76,8 +76,8 @@ mv squashfs-root/ AppDir/plugins/linuxdeploy-plugin-appimage
|
||||
|
||||
ln -s ../../plugins/linuxdeploy-plugin-appimage/AppRun AppDir/usr/bin/linuxdeploy-plugin-appimage
|
||||
|
||||
export UPD_INFO="gh-releases-zsync|linuxdeploy|linuxdeploy|continuous|linuxdeploy-$ARCH.AppImage"
|
||||
export OUTPUT="linuxdeploy-devbuild-$ARCH.AppImage"
|
||||
export UPD_INFO="gh-releases-zsync|linuxdeploy|linuxdeploy|continuous|linuxdeploy-$ARCH.AppImage.zsync"
|
||||
export OUTPUT="linuxdeploy-$ARCH.AppImage"
|
||||
|
||||
# build AppImage using plugin
|
||||
AppDir/usr/bin/linuxdeploy-plugin-appimage --appdir AppDir/
|
||||
@@ -1,28 +1,97 @@
|
||||
# required for PNG imported target
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
#[=======================================================================[.rst:
|
||||
FindCImg
|
||||
-------
|
||||
|
||||
find_package(PNG REQUIRED)
|
||||
find_package(JPEG REQUIRED)
|
||||
Finds the CImg library.
|
||||
|
||||
if(NOT USE_SYSTEM_CIMG)
|
||||
message(STATUS "Using bundled CImg library")
|
||||
Imported Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
set(CIMG_H_DIR "${PROJECT_SOURCE_DIR}/lib/CImg/")
|
||||
This module provides the following imported targets, if found:
|
||||
|
||||
``CImg``
|
||||
The CImg library
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``CImg_FOUND``
|
||||
True if the system has the CImg library.
|
||||
``CImg_VERSION``
|
||||
The version of the CImg library which was found.
|
||||
``CImg_INCLUDE_DIRS``
|
||||
Include directories needed to use CImg.
|
||||
``CImg_LIBRARIES``
|
||||
Libraries needed to link to CImg.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
``CImg_INCLUDE_DIR``
|
||||
The directory containing ``CImg.h``.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
# 3.6 required for PNG imported target
|
||||
# 3.9 required for CMAKE_MATCH_<n>
|
||||
cmake_minimum_required(VERSION 3.9)
|
||||
|
||||
find_path(CIMG_H_DIR
|
||||
NAMES CImg.h
|
||||
HINTS ${CMAKE_INSTALL_PREFIX} ${CIMG_DIR}
|
||||
PATH_SUFFIXES include include/linux
|
||||
)
|
||||
|
||||
if(NOT CIMG_H_DIR)
|
||||
set(CImg_FOUND FALSE)
|
||||
else()
|
||||
message(STATUS "Searching for CImg")
|
||||
set(CImg_FOUND TRUE)
|
||||
|
||||
find_path(CIMG_H_DIR
|
||||
NAMES CImg.h
|
||||
HINTS ${CMAKE_INSTALL_PREFIX}
|
||||
PATH_SUFFIXES include include/linux
|
||||
)
|
||||
find_package(PkgConfig)
|
||||
|
||||
if(NOT CIMG_H_DIR)
|
||||
message(FATAL_ERROR "CImg.h not found")
|
||||
pkg_check_modules(libpng REQUIRED libpng)
|
||||
pkg_check_modules(libjpeg REQUIRED libjpeg)
|
||||
|
||||
set(PNG_INCLUDE_DIR ${libpng_INCLUDE_DIRS})
|
||||
set(JPEG_INCLUDE_DIR ${libjpeg_INCLUDE_DIRS})
|
||||
|
||||
if(STATIC_BUILD)
|
||||
set(PNG_LIBRARY ${libpng_STATIC_LIBRARIES})
|
||||
set(JPEG_LIBRARIES ${libjpeg_STATIC_LIBRARIES})
|
||||
else()
|
||||
set(PNG_LIBRARY ${libpng_LIBRARIES})
|
||||
set(JPEG_LIBRARIES ${libjpeg_LIBRARIES})
|
||||
endif()
|
||||
|
||||
set(CImg_INCLUDE_DIR ${CIMG_H_DIR} CACHE STRING "")
|
||||
set(CImg_INCLUDE_DIRS ${CImg_INCLUDE_DIR})
|
||||
set(CImg_LIBRARIES "${PNG_LIBRARY};${JPEG_LIBRARIES}")
|
||||
set(CImg_DEFINITIONS "cimg_display=0;cimg_use_png=1;cimg_use_jpeg=1")
|
||||
|
||||
file(READ "${CIMG_H_DIR}/CImg.h" header)
|
||||
string(REGEX MATCH "#define cimg_version ([0-9a-zA-Z\.]+)" _ "${header}")
|
||||
set(CImg_VERSION "${CMAKE_MATCH_1}")
|
||||
|
||||
# CImg_VERSION
|
||||
|
||||
if(NOT TARGET CImg)
|
||||
add_library(CImg INTERFACE)
|
||||
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 "${CImg_LIBRARIES}")
|
||||
set_property(TARGET CImg PROPERTY INTERFACE_COMPILE_DEFINITIONS "${CImg_DEFINITIONS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
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_COMPILE_DEFINITIONS "cimg_display=0;cimg_use_png=1;cimg_use_jpeg=1")
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CImg
|
||||
FOUND_VAR CImg_FOUND
|
||||
REQUIRED_VARS
|
||||
CImg_INCLUDE_DIRS
|
||||
CImg_LIBRARIES
|
||||
CImg_DEFINITIONS
|
||||
VERSION_VAR CImg_VERSION
|
||||
)
|
||||
|
||||
@@ -38,6 +38,9 @@ namespace linuxdeploy {
|
||||
// shortcut for using a normal string instead of a path
|
||||
explicit AppDir(const std::string& path);
|
||||
|
||||
// Set additional shared library name patterns to be excluded from deployment.
|
||||
void setExcludeLibraryPatterns(const std::vector<std::string> &excludeLibraryPatterns);
|
||||
|
||||
// creates basic directory structure of an AppDir in "FHS" mode
|
||||
bool createBasicStructure() const;
|
||||
|
||||
@@ -57,12 +60,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);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace elf {
|
||||
namespace elf_file {
|
||||
// thrown by constructor if file is not an ELF file
|
||||
class ElfFileParseError : public std::runtime_error {
|
||||
public:
|
||||
@@ -64,6 +64,12 @@ namespace linuxdeploy {
|
||||
|
||||
// return OS ABI
|
||||
uint8_t getElfABI();
|
||||
|
||||
// check if this file is a debug symbols file
|
||||
bool isDebugSymbolsFile();
|
||||
|
||||
// check whether the file contains a dynsym section
|
||||
bool isDynamicallyLinked();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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,88 @@
|
||||
// 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);
|
||||
|
||||
static void close_pipe_fd_(int fd);
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user