You've already forked linuxdeploy
mirror of
https://github.com/encounter/linuxdeploy.git
synced 2026-07-10 12:18:44 -07:00
Compare commits
220 Commits
use-std-regex
...
arm
| Author | SHA1 | Date | |
|---|---|---|---|
| 01311f1ce3 | |||
| 87e377cb3c | |||
| a56aac5ecf | |||
| 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 | |||
| 1bd5453c61 | |||
| 9783db602e | |||
| 6cfa741f40 | |||
| 1be3327a11 | |||
| cca5ad2e07 | |||
| 058832615c | |||
| cf5927c521 | |||
| 103b637944 | |||
| 58189efba6 | |||
| 019f902b17 | |||
| f97d1e9a01 | |||
| 543078c11e | |||
| 9ddb0d7650 | |||
| 8252503d97 | |||
| d312ba07d0 | |||
| d3853e961b | |||
| ef7b397d4a | |||
| 330f8a393f | |||
| 77ad746c5d | |||
| cd04cc260e | |||
| 3c4580a325 | |||
| f20af7dc67 | |||
| 0ba33879b0 | |||
| f3b7c5ab73 | |||
| 6bc354bacb | |||
| d26947985d | |||
| 2cc962a344 | |||
| 612bf962a3 | |||
| 19d958d30f | |||
| fc82028af4 | |||
| 2d45ef4c72 | |||
| 470caa3db1 | |||
| d24e6dac56 | |||
| 913f5bc6cc | |||
| 4746fd0e87 | |||
| de363bc90b | |||
| 8e9114b7c5 | |||
| 72e4fb49e0 | |||
| abdefbc0ff | |||
| 58845cee8f | |||
| 5bc8840003 | |||
| 1cb5a742db | |||
| 142facd986 | |||
| aced62378a | |||
| 3fd595a63b | |||
| 9dc10fc0fc | |||
| 3183ee2f4f | |||
| 374e17b5e3 | |||
| d9681ccf5c | |||
| 57dbdc6933 | |||
| 3d766446d9 | |||
| e24b46d291 | |||
| 47b8370751 | |||
| 0d055ebb81 | |||
| ce5aecead5 | |||
| f01ae51f58 | |||
| 0e95f19a75 | |||
| 94bb814d69 | |||
| 159b082658 | |||
| 2a1127d7e8 | |||
| 3f81577b04 | |||
| 834b467a41 | |||
| 46ccb8965d | |||
| 5c3a51fd48 | |||
| 44cb9466b3 | |||
| 1dfcab8556 | |||
| e62e8d8396 | |||
| 875842ee3b | |||
| a4fe77305d | |||
| 4f44dcf954 | |||
| 44b234734b | |||
| 871f1d6e99 | |||
| f06643ea5f | |||
| 6baa443fd7 | |||
| 77c52883f1 | |||
| 157861d236 | |||
| 32dca18eee | |||
| 1f498772b4 | |||
| f9fc51a832 | |||
| a3e06e0024 | |||
| 956a253428 | |||
| ce6597fb9d | |||
| 028d85a070 | |||
| 8df605cb19 | |||
| 3a0870842c | |||
| 1510d0c333 | |||
| 7c8ab1c773 | |||
| 5374e7ece9 | |||
| 6b715c691a | |||
| 78f33a7190 | |||
| 3df27ba175 | |||
| 2ea9a367b5 | |||
| 673ccf5691 | |||
| d743e11486 | |||
| cddefc3806 | |||
| 1f5315926d | |||
| a12f3ac0fe | |||
| 640b756a7f | |||
| d486f936e2 |
@@ -0,0 +1,107 @@
|
||||
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, aarch64]
|
||||
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 (native)
|
||||
run: bash -ex ci/test-coverage.sh
|
||||
if: matrix.ARCH != 'aarch64' && matrix.BUILD_TYPE == 'coverage'
|
||||
|
||||
- name: Test coverage (VM)
|
||||
if: matrix.ARCH != 'x86_64' && matrix.ARCH != 'i386' && matrix.BUILD_TYPE == 'coverage'
|
||||
uses: uraimo/run-on-arch-action@v2.2.0
|
||||
with:
|
||||
arch: ${{ matrix.ARCH }}
|
||||
distro: ubuntu20.04
|
||||
githubToken: ${{ github.token }}
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/build"
|
||||
install: |
|
||||
apt-get update
|
||||
apt-get install -y build-essential wget git pkg-config autoconf libmagic-dev libjpeg-dev libpng-dev cimg-dev libboost-filesystem-dev libboost-regex-dev gcovr
|
||||
run: |
|
||||
cd /build
|
||||
ARCH=$(uname -m) ci/test-coverage.sh
|
||||
|
||||
- name: Build, test and build AppImage (native)
|
||||
if: matrix.ARCH != 'aarch64' && matrix.BUILD_TYPE != 'coverage'
|
||||
run: bash -ex ci/build.sh
|
||||
|
||||
- name: Build, test and build AppImage (VM)
|
||||
if: matrix.ARCH != 'x86_64' && matrix.ARCH != 'i386' && matrix.BUILD_TYPE != 'coverage'
|
||||
uses: uraimo/run-on-arch-action@v2.2.0
|
||||
with:
|
||||
arch: ${{ matrix.ARCH }}
|
||||
distro: ubuntu20.04
|
||||
githubToken: ${{ github.token }}
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/build"
|
||||
install: |
|
||||
apt-get update
|
||||
apt-get install -y build-essential wget git pkg-config autoconf libmagic-dev libjpeg-dev libpng-dev cimg-dev libboost-filesystem-dev libboost-regex-dev gcovr
|
||||
run: |
|
||||
cd /build
|
||||
ARCH=$(uname -m) ci/build.sh
|
||||
|
||||
- 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
|
||||
|
||||
+6
-93
@@ -1,99 +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-lexical_cast"]
|
||||
path = lib/boost-lexical_cast
|
||||
url = https://github.com/boostorg/lexical_cast
|
||||
[submodule "lib/boost-concept_check"]
|
||||
path = lib/boost-concept_check
|
||||
url = https://github.com/boostorg/concept_check
|
||||
[submodule "lib/boost-numeric_conversion"]
|
||||
path = lib/boost-numeric_conversion
|
||||
url = https://github.com/boostorg/numeric_conversion
|
||||
[submodule "lib/boost-array"]
|
||||
path = lib/boost-array
|
||||
url = https://github.com/boostorg/array
|
||||
[submodule "lib/boost-container"]
|
||||
path = lib/boost-container
|
||||
url = https://github.com/boostorg/container
|
||||
[submodule "lib/boost-move"]
|
||||
path = lib/boost-move
|
||||
url = https://github.com/boostorg/move
|
||||
[submodule "lib/boost-math"]
|
||||
path = lib/boost-math
|
||||
url = https://github.com/boostorg/math
|
||||
[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
|
||||
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
language: cpp
|
||||
sudo: required
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: ARCH=x86_64
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev
|
||||
- libjpeg-dev
|
||||
- libpng-dev
|
||||
- cimg-dev
|
||||
- automake # required for patchelf
|
||||
- env: ARCH=i386
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev:i386
|
||||
- libjpeg-dev:i386
|
||||
- libpng-dev:i386
|
||||
- gcc-multilib
|
||||
- g++-multilib
|
||||
- automake # required for patchelf
|
||||
- libfuse2:i386
|
||||
- libcairo2:i386
|
||||
- env: ARCH=x86_64 BUILD_TYPE=coverage
|
||||
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
|
||||
- env: ARCH=i386 BUILD_TYPE=coverage
|
||||
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
|
||||
|
||||
|
||||
install:
|
||||
- git clone https://github.com/NixOS/patchelf.git -b 0.8
|
||||
- cd patchelf
|
||||
- ./bootstrap.sh
|
||||
- if [ "$ARCH" == "i386" ]; then ./configure --prefix=/usr --build=i686-pc-linux-gnu CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32; fi
|
||||
- if [ "$ARCH" == "x86_64" ]; then ./configure --prefix=/usr; fi
|
||||
- make -j$(nproc)
|
||||
- sudo make install
|
||||
- cd ..
|
||||
- rm -rf patchelf
|
||||
|
||||
script:
|
||||
- travis/build.sh
|
||||
|
||||
after_success:
|
||||
- ls -lh
|
||||
# make sure only pushes to rewrite create a new release, otherwise pretend PR and upload to transfer.sh
|
||||
- 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*
|
||||
|
||||
branches:
|
||||
except:
|
||||
- # Do not build tags that we create when we upload to GitHub Releases
|
||||
- /^(?i:continuous)$/
|
||||
+8
-4
@@ -7,9 +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")
|
||||
|
||||
# support for ccache
|
||||
# call CMake with -DUSE_CCACHE=ON to make use of it
|
||||
set(USE_CCACHE ON CACHE BOOL "")
|
||||
@@ -43,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()
|
||||
|
||||
@@ -14,60 +14,22 @@ linuxdeploy is designed to be an AppDir maintenance tool. It provides extensive
|
||||
linuxdeploy was greatly influenced by [linuxdeployqt](https://github.com/probonopd/linuxdeployqt), and while it employs stricter rules on AppDirs, it's more flexible in use. If you use linuxdeployqt at the moment, consider switching to linuxdeploy today!
|
||||
|
||||
|
||||
## Usage
|
||||
## User guides and examples
|
||||
|
||||
linuxdeploy, being a tool for creating AppDirs and eventually AppImages, is released as an AppImage itself. Please download and use the AppImage for normal use. If you encounter errors, e.g., when building the tool from source, please try with the AppImage first before [creating an issue](https://github.com/TheAssassin/linuxdeploy/issues/new).
|
||||
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).
|
||||
|
||||
There are two main ways to use linuxdeploy: Provide the paths to all files you want to bundle manually, or create an FHS-like directory and run linuxdeploy on it.
|
||||
|
||||
Most build systems provide some kind of `make install` functionality that is capable of producing FHS-like directory trees that can be turned into AppDirs:
|
||||
## Projects using linuxdeploy
|
||||
|
||||
```sh
|
||||
# automake
|
||||
./configure --prefix=/usr
|
||||
make install DESTDIR=AppDir
|
||||
This is an incomplete list of projects using linuxdeploy. You might want to read their build scripts to see how they use linuxdeploy.
|
||||
|
||||
# cmake
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
make install DESTDIR=AppDir
|
||||
|
||||
# qmake
|
||||
qmake CONFIG+=release PREFIX=/usr .
|
||||
make install INSTALL_ROOT=AppDir
|
||||
```
|
||||
|
||||
Next, download the latest linuxdeploy AppImage. It's available on the [release page](https://github.com/linuxdeploy/linuxdeploy/releases). Make sure to pick the right one for your (target) architecture.
|
||||
|
||||
Now, simply run linuxdeploy like `./linuxdeploy*.AppImage --appdir AppDir`.
|
||||
|
||||
Please use `./linuxdeploy*.AppImage --help` to get a list of options supported by linuxdeploy.
|
||||
|
||||
If your build system cannot produce such install trees or you prefer to bundle everything manually, you can also specify the paths to the resources yourself. linuxdeploy provides the following options for this use case:
|
||||
|
||||
```
|
||||
-l[library...],
|
||||
--lib=[library...],
|
||||
--library=[library...] Shared library to deploy
|
||||
-e[executable...],
|
||||
--executable=[executable...] Executable to deploy
|
||||
-d[desktop file...],
|
||||
--desktop-file=[desktop file...] Desktop file to deploy
|
||||
enough for some tests
|
||||
-i[icon file...],
|
||||
--icon-file=[icon file...] Icon to deploy
|
||||
```
|
||||
|
||||
An example run could look like this:
|
||||
|
||||
```bash
|
||||
./linuxdeploy*.AppImage --appdir AppDir -e myapp -d myapp.desktop -i myapp_64x64.png
|
||||
```
|
||||
|
||||
Of course both approaches can be combined, e.g., you can bundle additional executables with your main app.
|
||||
|
||||
linuxdeploy doesn't mind being run on an AppDir more than once, as it recognize previous runs, and should not break files within the AppDir. This is called an "iterative workflow". In case of errors, you can simply fix them, and re-run linuxdeploy afterwards.
|
||||
If you ever encounter issues when running linuxdeploy on an existing AppDir, please let us know by [creating an issue](https://github.com/TheAssassin/linuxdeploy/issues/new).
|
||||
- [Pext](https://github.com/Pext/Pext)
|
||||
- [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher)
|
||||
- [OpenRCT2](https://github.com/OpenRCT2/OpenRCT2)
|
||||
- [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
|
||||
@@ -93,22 +55,6 @@ If you want to use a plugin to bundle additional resources, please add `./linuxd
|
||||
**Note:** If you want to suggest a plugin for a specific framework, language etc., please feel free to [create a new issue](https://github.com/linuxdeploy/linuxdeploy/issues/new). Current plugin requests can be found [here](https://github.com/linuxdeploy/linuxdeploy/issues?utf8=%E2%9C%93&q=label%3A%22plugin+request%22).
|
||||
|
||||
|
||||
## 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).
|
||||
|
||||
|
||||
## Projects using linuxdeploy
|
||||
|
||||
This is an incomplete list of projects using linuxdeploy. You might want to read their build scripts to see how they use linuxdeploy.
|
||||
|
||||
- [Pext](https://github.com/Pext/Pext)
|
||||
- [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher)
|
||||
- [OpenRCT2](https://github.com/OpenRCT2/OpenRCT2)
|
||||
- [AppImageUpdate](https://github.com/AppImage/AppImageUpdate)
|
||||
- [appimaged](https://github.com/AppImage/appimaged)
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
> I bundled additional resources, but when I try to run them, either the system binary is called or the file is not found.
|
||||
|
||||
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"|"armhf"|"aarch64")
|
||||
;;
|
||||
"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 http://mirrors.kernel.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"|"armhf"|"aarch64")
|
||||
;;
|
||||
"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,36 +30,42 @@ 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" == "armhf" ]; then
|
||||
EXTRA_CMAKE_ARGS=()
|
||||
elif [ "$ARCH" == "aarch64" ]; 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.19.6/cmake-3.19.6-Linux-$(uname -m).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" "--create-desktop-file" "-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[@]}"
|
||||
@@ -67,20 +73,21 @@ bin/linuxdeploy "${LINUXDEPLOY_ARGS[@]}"
|
||||
# bundle AppImage plugin
|
||||
mkdir -p AppDir/plugins
|
||||
|
||||
wget https://github.com/TheAssassin/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-"$ARCH".AppImage
|
||||
wget https://github.com/encounter/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-"$ARCH".AppImage
|
||||
chmod +x linuxdeploy-plugin-appimage-"$ARCH".AppImage
|
||||
./linuxdeploy-plugin-appimage-"$ARCH".AppImage --appimage-extract
|
||||
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 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/
|
||||
|
||||
# rename AppImage to avoid "Text file busy" issues when using it to create another one
|
||||
mv ./linuxdeploy-"$ARCH".AppImage test.AppImage
|
||||
mv "$OUTPUT" test.AppImage
|
||||
|
||||
# verify that the resulting AppImage works
|
||||
./test.AppImage "${LINUXDEPLOY_ARGS[@]}"
|
||||
@@ -88,4 +95,4 @@ mv ./linuxdeploy-"$ARCH".AppImage test.AppImage
|
||||
# check whether AppImage plugin is found and works
|
||||
./test.AppImage "${LINUXDEPLOY_ARGS[@]}" --output appimage
|
||||
|
||||
mv linuxdeploy-"$ARCH".AppImage* "$OLD_CWD"
|
||||
mv "$OUTPUT"* "$OLD_CWD"/
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#! /bin/bash
|
||||
|
||||
# get a compiler that allows for using modern-ish C++ (>= 11) on a distro that doesn't normally support it
|
||||
# before you ask: yes, the binaries will work on CentOS 6 even without devtoolset (they somehow partially link C++
|
||||
# things statically while using others from the system...)
|
||||
# so, basically, it's magic!
|
||||
source /opt/rh/devtoolset-*/enable
|
||||
|
||||
exec "$@"
|
||||
@@ -30,6 +30,10 @@ 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" == "armhf" ]; then
|
||||
EXTRA_CMAKE_ARGS=()
|
||||
elif [ "$ARCH" == "aarch64" ]; then
|
||||
EXTRA_CMAKE_ARGS=()
|
||||
else
|
||||
echo "Architecture not supported: $ARCH" 1>&2
|
||||
exit 1
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// system includes
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
// local includes
|
||||
#include "linuxdeploy/core/desktopfile/desktopfile.h"
|
||||
#include "linuxdeploy/desktopfile/desktopfile.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -19,7 +20,7 @@ namespace linuxdeploy {
|
||||
private:
|
||||
// private data class pattern
|
||||
class PrivateData;
|
||||
PrivateData* d;
|
||||
std::shared_ptr<PrivateData> d;
|
||||
|
||||
public:
|
||||
// default constructor
|
||||
@@ -27,14 +28,21 @@ namespace linuxdeploy {
|
||||
// the directory will be created if it doesn't exist
|
||||
explicit AppDir(const boost::filesystem::path& path);
|
||||
|
||||
~AppDir();
|
||||
// we don't want any copy/move(-assignment) behavior, therefore we delete those operators/constructors
|
||||
AppDir(const AppDir&) = delete;
|
||||
AppDir(AppDir&&) = delete;
|
||||
void operator=(const AppDir&) = delete;
|
||||
void operator=(AppDir&&) = delete;
|
||||
|
||||
// alternative constructor
|
||||
// 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();
|
||||
bool createBasicStructure() const;
|
||||
|
||||
// deploy shared library
|
||||
//
|
||||
@@ -52,48 +60,59 @@ 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
|
||||
void deployFile(const boost::filesystem::path& from, const boost::filesystem::path& to);
|
||||
boost::filesystem::path deployFile(const boost::filesystem::path& from, const boost::filesystem::path& to);
|
||||
|
||||
// copy arbitrary file (immediately)
|
||||
bool copyFile(const boost::filesystem::path& from, const boost::filesystem::path& to, bool overwrite = false) const;
|
||||
|
||||
// create an <AppDir> relative symlink to <target> at <symlink>.
|
||||
bool createRelativeSymlink(const boost::filesystem::path& target, const boost::filesystem::path& symlink);
|
||||
bool createRelativeSymlink(const boost::filesystem::path& target, const boost::filesystem::path& symlink) const;
|
||||
|
||||
// execute deferred copy operations
|
||||
bool executeDeferredOperations();
|
||||
|
||||
// return path to AppDir
|
||||
boost::filesystem::path path();
|
||||
boost::filesystem::path path() const;
|
||||
|
||||
// create a list of all icon paths in the AppDir
|
||||
std::vector<boost::filesystem::path> deployedIconPaths();
|
||||
std::vector<boost::filesystem::path> deployedIconPaths() const;
|
||||
|
||||
// create a list of all executable paths in the AppDir
|
||||
std::vector<boost::filesystem::path> deployedExecutablePaths();
|
||||
std::vector<boost::filesystem::path> deployedExecutablePaths() const;
|
||||
|
||||
// create a list of all desktop file paths in the AppDir
|
||||
std::vector<desktopfile::DesktopFile> deployedDesktopFiles();
|
||||
std::vector<desktopfile::DesktopFile> deployedDesktopFiles() const;
|
||||
|
||||
// create symlinks for AppRun, desktop file and icon in the AppDir root directory
|
||||
bool createLinksInAppDirRoot(const desktopfile::DesktopFile& desktopFile, boost::filesystem::path customAppRunPath = "");
|
||||
bool setUpAppDirRoot(const desktopfile::DesktopFile& desktopFile, boost::filesystem::path customAppRunPath = "");
|
||||
|
||||
// list all executables in <AppDir>/usr/bin
|
||||
// this function does not perform a recursive search, but only searches the bin directory
|
||||
std::vector<boost::filesystem::path> listExecutables();
|
||||
std::vector<boost::filesystem::path> listExecutables() const;
|
||||
|
||||
// list all shared libraries in <AppDir>/usr/lib
|
||||
// this function recursively searches the entire lib directory for shared libraries
|
||||
std::vector<boost::filesystem::path> listSharedLibraries();
|
||||
std::vector<boost::filesystem::path> listSharedLibraries() const;
|
||||
|
||||
// search for executables and libraries and deploy their dependencies
|
||||
// calling this function can turn sure file trees created by make install commands into working
|
||||
// AppDirs
|
||||
bool deployDependenciesForExistingFiles();
|
||||
bool deployDependenciesForExistingFiles() const;
|
||||
|
||||
// disable deployment of copyright files for this instance
|
||||
void setDisableCopyrightFilesDeployment(bool disable);
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
// system includes
|
||||
#include <unordered_map>
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
// local includes
|
||||
#include "desktopfileentry.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace desktopfile {
|
||||
/*
|
||||
* Parse and read desktop files.
|
||||
*/
|
||||
class DesktopFile {
|
||||
public:
|
||||
// describes a single section
|
||||
typedef std::unordered_map<std::string, DesktopFileEntry> section_t;
|
||||
|
||||
// describes all sections in the desktop file
|
||||
typedef std::unordered_map<std::string, section_t> sections_t;
|
||||
|
||||
private:
|
||||
// private data class pattern
|
||||
class PrivateData;
|
||||
std::shared_ptr<PrivateData> d;
|
||||
|
||||
// (in)equality operators are implemented outside this class
|
||||
friend bool operator==(const DesktopFile& first, const DesktopFile& second);
|
||||
friend bool operator!=(const DesktopFile& first, const DesktopFile& second);
|
||||
|
||||
public:
|
||||
// default constructor
|
||||
DesktopFile();
|
||||
|
||||
// construct from existing desktop file
|
||||
// if the file exists, it will be read using DesktopFileReader
|
||||
// if reading fails, exceptions will be thrown (see DesktopFileReader for more information)
|
||||
explicit DesktopFile(const boost::filesystem::path& path);
|
||||
|
||||
// construct by reading an existing stream
|
||||
// file must exist, otherwise std::runtime_error is thrown
|
||||
explicit DesktopFile(std::istream& is);
|
||||
|
||||
// copy constructor
|
||||
DesktopFile(const DesktopFile& other);
|
||||
|
||||
// copy assignment constructor
|
||||
DesktopFile& operator=(const DesktopFile& other);
|
||||
|
||||
// move assignment operator
|
||||
DesktopFile& operator=(DesktopFile&& other) noexcept;
|
||||
|
||||
public:
|
||||
// returns true if a file has been loaded, false otherwise
|
||||
bool isEmpty() const;
|
||||
|
||||
// read desktop file
|
||||
// sets path associated with this file
|
||||
// throws exceptions in case of issues, see DesktopFileReader for more information
|
||||
void read(const boost::filesystem::path& path);
|
||||
|
||||
// read desktop file from existing stream
|
||||
// throws exceptions in case of issues, see DesktopFileReader for more information
|
||||
void read(std::istream& is);
|
||||
|
||||
// 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
|
||||
// throws exceptions in case of errors, see DesktopFileWriter::save(...) for more information
|
||||
bool save(const boost::filesystem::path& path) const;
|
||||
|
||||
// save desktop file to ostream
|
||||
// does not change path associated with desktop file
|
||||
// throws exceptions in case of errors, see DesktopFileWriter::save(...) for more information
|
||||
bool save(std::ostream& os) 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, DesktopFileEntry& 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 DesktopFileEntry& entry);
|
||||
|
||||
// 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, DesktopFileEntry&& entry);
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
// DesktopFile equality operator
|
||||
bool operator==(const DesktopFile& first, const DesktopFile& second);
|
||||
|
||||
// DesktopFile inequality operator
|
||||
bool operator!=(const DesktopFile& first, const DesktopFile& second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// system headers
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// library headers
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace desktopfile {
|
||||
class DesktopFileEntry {
|
||||
private:
|
||||
// opaque data class pattern
|
||||
class PrivateData;
|
||||
|
||||
std::shared_ptr<PrivateData> d;
|
||||
|
||||
public:
|
||||
// default constructor
|
||||
DesktopFileEntry();
|
||||
|
||||
// construct from key and value
|
||||
explicit DesktopFileEntry(std::string key, std::string value);
|
||||
|
||||
// copy constructor
|
||||
DesktopFileEntry(const DesktopFileEntry& other);
|
||||
|
||||
// copy assignment constructor
|
||||
DesktopFileEntry& operator=(const DesktopFileEntry& other);
|
||||
|
||||
// move assignment operator
|
||||
DesktopFileEntry& operator=(DesktopFileEntry&& other) noexcept;
|
||||
|
||||
// equality operator
|
||||
bool operator==(const DesktopFileEntry& other) const;
|
||||
|
||||
// inequality operator
|
||||
bool operator!=(const DesktopFileEntry& other) const;
|
||||
|
||||
public:
|
||||
// checks whether a key and value have been set
|
||||
bool isEmpty() const;
|
||||
|
||||
// return entry's key
|
||||
const std::string& key() const;
|
||||
|
||||
// return entry's value
|
||||
const std::string& value() const;
|
||||
|
||||
public:
|
||||
// convert value to integer
|
||||
// throws boost::bad_lexical_cast in case of type errors
|
||||
int32_t asInt() const;
|
||||
|
||||
// convert value to long
|
||||
// throws boost::bad_lexical_cast in case of type errors
|
||||
int64_t asLong() const;
|
||||
|
||||
// convert value to double
|
||||
// throws boost::bad_lexical_cast in case of type errors
|
||||
double asDouble() const;
|
||||
|
||||
// split CSV list value into vector
|
||||
// the separator used to split the string is a semicolon as per desktop file spec
|
||||
std::vector<std::string> parseStringList() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace desktopfile {
|
||||
/**
|
||||
* Desktop file library's base exception.
|
||||
*/
|
||||
class DesktopFileError : public std::runtime_error {
|
||||
public:
|
||||
explicit DesktopFileError(const std::string& message = "unknown desktop file error") : runtime_error(message) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Exception thrown by DesktopFileReader on parsing errors.
|
||||
*/
|
||||
class ParseError : public DesktopFileError {
|
||||
public:
|
||||
explicit ParseError(const std::string& message = "unknown parse error") : DesktopFileError(message) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* I/O exception, thrown if files cannot be opened, reading or writing fails etc.
|
||||
*/
|
||||
class IOError : public DesktopFileError {
|
||||
public:
|
||||
explicit IOError(const std::string& message = "unknown I/O error") : DesktopFileError(message) {};
|
||||
};
|
||||
|
||||
class UnknownSectionError : public DesktopFileError {
|
||||
public:
|
||||
explicit UnknownSectionError(const std::string& section) : DesktopFileError("unknown section: " + section) {};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user