114 Commits

Author SHA1 Message Date
TheAssassin 0d57e9ae9b Log error when pipe creation fails 2020-10-05 22:31:16 +02:00
TheAssassin 407ecc408d Read subprocesses' pipes until they're empty 2020-09-22 13:04:23 +02:00
TheAssassin 8ee0e43c23 Switch to new subprocess lib in type 0 plugins, mk. 3
This commit fixes the remaining buffer issues by introducing a little more complexity. It shall be refactored in the future to decrease complexity again, but for now, it works well and function is more important than form at this point.

CC #143
2020-09-04 18:02:40 +02:00
TheAssassin e9bbbc80f4 Switch to new subprocess lib in type 0 plugins, mk. 2
Apparently fixes all buffer-related crashes, but there's a few minor bugs left.

CC #143
2020-08-31 08:39:43 +02:00
TheAssassin 68f4655fc4 Add method to write from buffers to ldLog streams 2020-08-31 06:30:06 +02:00
TheAssassin 1072c6d9f0 Improve check_output performance 2020-08-31 05:08:24 +02:00
TheAssassin f33dc8dd34 Switch to new subprocess lib in type 0 plugins, mk. 1 2020-08-31 04:41:01 +02:00
TheAssassin 6621f1edf7 Forgot to add pipe reader to CMake 2020-08-31 04:20:40 +02:00
TheAssassin ee73ac6c8e Use new pipe_reader in subprocess's check_output
The class will read until the process quits (or until memory's up).

TODO: reduce load on CPU with some sleep (right now, it's pretty much some busy waiting)
2020-08-31 04:20:03 +02:00
TheAssassin 66691ee882 Add new helper class pipe reader
Implements synchronous, non-block reading from pipes.
2020-08-28 17:36:56 +02:00
TheAssassin e91b459fce Use std::distance instead of pointer arithmetics 2020-08-08 11:54:58 +02:00
TheAssassin 3f86f178a5 Use classic C string handling
That way, we don't have to allocate memory, and it's also shorter.
2020-08-08 11:49:17 +02:00
TheAssassin a8975e0e50 Clean up memory in case exec* fails
Prevents memory leaks.
2020-08-08 11:44:21 +02:00
TheAssassin 6c47939fdc Fix initialization bug 2020-08-08 11:34:02 +02:00
TheAssassin 8663e5bf26 Update license information in help text 2020-08-08 01:06:51 +02:00
TheAssassin 89493e399b Build fully static strip binary 2020-08-08 00:47:54 +02:00
TheAssassin 4d999ef5c6 Build somewhat static strip ourselves 2020-08-08 00:30:28 +02:00
TheAssassin b39dfa6591 Fix static binaries handling 2020-08-08 00:30:28 +02:00
TheAssassin 484ff3f004 Fix C string processing bug
Well, makes sense now that I look at it... but caused a couple of hours worrying why my child processes were crashing until I noticed it'd only happen if I specified custom environment variables...
2020-08-08 00:30:28 +02:00
TheAssassin 8b604871cc Refactor duplicate code into static method 2020-08-08 00:30:28 +02:00
TheAssassin 88dd09f2d1 Set all variables to defaults in header 2020-08-08 00:30:28 +02:00
TheAssassin d43e8a42bf Fix whitespace 2020-08-08 00:30:28 +02:00
TheAssassin 5feef7880e Try to fix waitpid issues 2020-08-08 00:30:28 +02:00
TheAssassin 2b2c6a913f Set default value 2020-08-07 21:22:58 +02:00
TheAssassin aeb0bfa98b Use consistent error message for all plugins 2020-08-07 21:22:58 +02:00
TheAssassin 37aa37f5fe Fix behavior of close()
The implementation was obviously wrong/incomplete.
2020-08-07 21:22:58 +02:00
TheAssassin 59a8ec41ba Replace cpp-subprocess with own linuxdeploy-subprocess 2020-08-07 21:22:58 +02:00
TheAssassin 4a0cfe323d Require newer CMake version only for static builds 2020-08-07 21:22:58 +02:00
TheAssassin c895a1dc59 Add kill and poll features for processes 2020-08-07 21:22:58 +02:00
TheAssassin 80a5667ca7 Check waitpid() for errors 2020-08-07 21:22:58 +02:00
TheAssassin 2425ccc832 Extract process handling into separate class
Needed for plugins' subprocess handling.
2020-08-07 21:22:58 +02:00
TheAssassin 55b2d00f23 Add reusable assert template 2020-08-07 21:22:58 +02:00
TheAssassin e1f6da17b4 Add basic subprocess micro library
cpp-subprocess does not work when linked statically for some weird reason. Therefore, we're going to ship our own.
2020-08-07 21:22:58 +02:00
TheAssassin 326b002ed5 Fetch up-to-date CMake for AppImage builds 2020-08-07 21:22:58 +02:00
TheAssassin 86d4404a16 Try to use target_link_options again 2020-08-07 21:22:58 +02:00
TheAssassin cbfbb1ee2d Debug CI build issues mk. 1 2020-08-07 21:22:58 +02:00
TheAssassin 5fde708954 Improve CMake check 2020-08-06 14:44:00 +02:00
TheAssassin dc07fbd401 Build static binaries for releases on Travis 2020-08-06 14:10:57 +02:00
TheAssassin 5b713b3bee Add support for fully static builds 2020-08-06 02:07:31 +02:00
TheAssassin 5644d5ca06 Add license notices to binary for dependencies
Was long overdue.
2020-08-06 01:19:29 +02:00
TheAssassin 557bad2241 Add --deploy-deps-only 2020-07-15 03:17:37 +02:00
TheAssassin 590a746882 Replace std::cerr messages with ldLog
Was long overdue now. Makes for a consistent logging, and helps communicate that the messages are errors to the user.
2020-07-15 03:10:12 +02:00
TheAssassin a609adb4f5 Merge pull request #135 from komputerwiz/master
Fix update information used by Travis builds
2020-07-05 20:41:00 +02:00
Matthew Barry 591e21a766 fix update information used by Travis builds
Seems like this was overlooked by commit 2af5430 when fixing #126
2020-07-05 12:50:47 -05:00
TheAssassin 0f3a118687 Add param to automatically rename deployed icons
Useful e.g., when passing multiple icons with different resolutions via -i, if they have the resolution in the filename.

Also removes all traces of that appName concept that has been abandoned.
2020-06-11 21:04:33 +02:00
TheAssassin 1c0ce6a0a5 Merge pull request #132 from X0rg/patch-1
Update README.md with CPU-X project
2020-05-24 01:50:12 +02:00
Xorg 2f00292756 Update README.md with CPU-X project 2020-05-24 01:00:32 +02:00
TheAssassin f24c167722 Add $LINUXDEPLOY for input plugins
The input plugins can use this environment variable to call linuxdeploy themselves. This can be very handy to have it deploy additional dependencies on libraries they copy themselves.

An alternative approach is to simply use liblinuxdeploy inside the plugin, like the Qt plugin does.
2020-05-03 18:32:55 +02:00
TheAssassin 2af54304e2 Fix update information
Closes #126.
2020-04-08 23:41:58 +02:00
TheAssassin 4391ad24d9 Merge pull request #125 from d1vanov/master
Fix links in README.md
2020-04-04 16:19:13 +02:00
Dmitry Ivanov f3ae65bc57 Fix links in README.md 2020-04-04 17:17:41 +03:00
TheAssassin d086da38c4 Allow users to use custom patchelf
Fixes #120.
2020-02-06 02:34:37 +01:00
TheAssassin 652ef5a215 Use the right method to resolve symlinks
Just checked with absolute, it doesn't always resolve symlinks. canonical is supposed to do that according to https://www.boost.org/doc/libs/1_48_0/libs/filesystem/v3/doc/reference.html#Canonical-path.
2019-12-13 17:53:28 +01:00
TheAssassin 2b13c52452 Workaround for ldd bug
Closes #110.

See https://sourceware.org/bugzilla/show_bug.cgi?id=25263 for more information.
2019-12-13 17:49:22 +01:00
TheAssassin c45cd46319 Move which to utils module
Also uses the native split functionality provided by the utils module
instead of some external dependency's.

Preparation for using this method in plugins such as the Qt plugin.
2019-11-19 11:28:24 +01:00
TheAssassin 1bd5453c61 Fix detection of copyright tools
CC #104
2019-11-18 23:13:44 +01:00
TheAssassin 9783db602e Quick fix unavailability of which command
CC #104
2019-11-18 20:44:53 +01:00
TheAssassin 6cfa741f40 Add missing newline (fixes #102) 2019-11-13 15:31:52 +01:00
TheAssassin 1be3327a11 Use own prebuilt CMake 2019-09-28 15:25:13 +02:00
TheAssassin cca5ad2e07 Merge pull request #96 from linuxdeploy/completely-switch-to-centos6
Build all binaries on CentOS 6
2019-09-28 04:22:40 +02:00
TheAssassin 058832615c Fix binaries upload 2019-09-28 04:02:00 +02:00
TheAssassin cf5927c521 Make sure old build script artifacts carry different name 2019-09-28 03:49:57 +02:00
TheAssassin 103b637944 Make CentOS 6 build script equivalent to old one 2019-09-28 03:49:15 +02:00
TheAssassin 58189efba6 Build binaries on CentOS 6 2019-09-28 03:48:53 +02:00
TheAssassin 019f902b17 Fix Docker build artifacts handling 2019-09-28 03:48:18 +02:00
TheAssassin f97d1e9a01 Improve shell use of Docker images 2019-09-28 03:47:24 +02:00
TheAssassin 543078c11e Clean up Dockerfile 2019-09-28 03:47:05 +02:00
TheAssassin 9ddb0d7650 Remove old debug code 2019-09-28 01:33:45 +02:00
TheAssassin 8252503d97 Merge pull request #95 from linuxdeploy/centos6-builds
Centos6 builds
2019-09-27 21:59:30 +02:00
TheAssassin d312ba07d0 No need to run install step for Docker builds 2019-09-27 21:34:06 +02:00
TheAssassin d3853e961b Clean up Dockerfile 2019-09-27 21:32:44 +02:00
TheAssassin ef7b397d4a Use devtoolset to compile dependencies in CentOS 6 builds 2019-09-27 21:32:27 +02:00
TheAssassin 330f8a393f Use devtoolset 7 for 64-bit CentOS builds 2019-09-27 21:32:09 +02:00
TheAssassin 77ad746c5d Build i386 CentOS 6 binaries on Travis 2019-09-27 21:15:52 +02:00
TheAssassin cd04cc260e 32-bit CentOS 6 builds 2019-09-27 21:09:10 +02:00
TheAssassin 3c4580a325 Allow bundling of additional binaries without moving them
Required to bundle e.g., applications' plugins together with their
dependencies without moving them out of position so they can still
be found by the original apps.
2019-09-22 19:06:00 +02:00
TheAssassin f20af7dc67 Refactor and improve relative directory calculation
Also makes variable names less ambiguous and adds some documenting
comments.
2019-09-22 18:58:21 +02:00
TheAssassin 0ba33879b0 Fix argument forwarding in generated AppRun script 2019-09-12 16:35:09 +02:00
TheAssassin f3b7c5ab73 Never ask to integrate linuxdeploy AppImages 2019-09-06 15:47:45 +02:00
TheAssassin 6bc354bacb Update linuxdeploy-desktopfile 2019-09-06 03:13:21 +02:00
TheAssassin d26947985d Add tests only if they are built and can therefore be run 2019-09-06 03:13:05 +02:00
TheAssassin 2cc962a344 Update README.md 2019-08-22 15:08:04 +02:00
TheAssassin 612bf962a3 Another missing return statement 2019-08-15 01:10:02 +02:00
TheAssassin 19d958d30f There should at least be debug messages for potential errors 2019-08-15 00:00:19 +02:00
TheAssassin fc82028af4 More forgotten return statements in bool methods 2019-08-14 23:57:50 +02:00
TheAssassin 2d45ef4c72 Fix missing return statement in static bool method
Looks like devtoolset compiler behaves differently on bool methods
without an explicit return statement. Kind of strange.

Undefined behavior?
2019-08-14 23:42:57 +02:00
TheAssassin 470caa3db1 Replace ln based subprocess symlinking with boost functionality 2019-08-14 23:25:21 +02:00
TheAssassin d24e6dac56 Clean up symlink helper 2019-08-14 22:47:59 +02:00
TheAssassin 913f5bc6cc Mirror package was hosted on disappeared 2019-08-14 16:12:19 +02:00
TheAssassin 4746fd0e87 Merge pull request #87 from linuxdeploy/apprun-hooks
AppRun hooks for plugins
2019-08-14 16:10:45 +02:00
TheAssassin de363bc90b Merge branch 'master' into apprun-hooks 2019-08-14 15:14:02 +02:00
TheAssassin 8e9114b7c5 Improve generated AppRun script 2019-08-14 14:36:06 +02:00
TheAssassin 72e4fb49e0 Don't try to move if there's no need to do so 2019-08-14 14:35:53 +02:00
TheAssassin abdefbc0ff Use a custom variable to support test runs from IDE better
When your IDE is running as an AppImage, the $APPRUN variable is
already set in the built-in terminal. Now of course you could just
calculate the path of $APPRUN yourself and force-overwrite it in that
script; however that's more effort and more likely to break.

Therefore it's easier to just introduce and use a custom variable.
2019-08-14 14:33:25 +02:00
TheAssassin 58845cee8f Support for AppRun hooks installed by plugins, mk. 1 2019-08-14 04:13:30 +02:00
TheAssassin 5bc8840003 Mark methods const where possible 2019-08-14 04:11:36 +02:00
TheAssassin 1cb5a742db Break up deployment algorithm into independent methods
That makes maintenance easier.
2019-08-14 02:28:21 +02:00
TheAssassin 142facd986 Improve method 2019-08-14 01:35:31 +02:00
TheAssassin aced62378a Move AppDir root deployment into separate class
Makes adding more features easier, as there's a clear defined interface
to the class and the mechanism can be split into more methods more
easily without bloating the AppDir class further.
2019-08-14 01:35:23 +02:00
TheAssassin 3fd595a63b Expose file copying helper in public interface 2019-08-14 01:33:09 +02:00
TheAssassin 9dc10fc0fc Method can be static 2019-08-14 01:08:20 +02:00
TheAssassin 3183ee2f4f Mark methods const where possible 2019-07-27 16:37:16 +02:00
TheAssassin 374e17b5e3 Merge pull request #85 from linuxdeploy/update_cpp_subprocess
Update cpp-subprocess to ensure that the bug in util::read_all() is fixed
2019-07-25 20:32:12 +02:00
TheAssassin d9681ccf5c Merge branch 'master' into update_cpp_subprocess 2019-07-25 20:10:35 +02:00
Alexis Lopez Zubieta 57dbdc6933 Update cpp-subprocess to ensure that the bug in util::read_all() is fixed 2019-07-25 13:08:21 -05:00
TheAssassin 3d766446d9 Improve log message 2019-07-25 17:47:34 +02:00
TheAssassin e24b46d291 Change method name to something more meaningful 2019-07-25 17:44:50 +02:00
TheAssassin 47b8370751 Method can be static 2019-07-25 17:43:45 +02:00
TheAssassin 0d055ebb81 Merge pull request #84 from darealshinji/patch-1
remove all comments
2019-07-07 16:06:52 +02:00
darealshinji ce5aecead5 remove all comments
Otherwise the generated header contains entries like this:
``` c
    "libxcb-dri2.so.0",
    "#",
    "https://github.com/probonopd/linuxdeployqt/issues/331#issuecomment-442276277",
    "libxcb-dri3.so.0",
    "#",
    "https://github.com/AppImage/AppImages/issues/348",
```
2019-07-06 20:21:16 +02:00
TheAssassin f01ae51f58 Merge pull request #79 from haampie/fix-deployment-of-dependencies
Fix an issue where dependencies are not deployed when calling deployLibrary only
2019-06-10 20:31:12 +02:00
Harmen Stoppels 0e95f19a75 Make deployLibrary deploy its dependencies by default, and avoid unnecessary recursion by making deployElfDependencies not deploy its deps of deps 2019-06-10 20:12:30 +02:00
TheAssassin 94bb814d69 Merge pull request #78 from haampie/fix-remove-recursion-elf-deployment
Remove recursion of ELF deployment since ldd already does that for us
2019-06-09 21:08:37 +02:00
Harmen Stoppels 159b082658 Remove recursion of ELF deployment since ldd already does that for us 2019-06-09 14:43:59 +02:00
55 changed files with 1852 additions and 738 deletions
-3
View File
@@ -1,6 +1,3 @@
[submodule "lib/cpp-subprocess"]
path = lib/cpp-subprocess
url = https://github.com/arun11299/cpp-subprocess.git
[submodule "lib/args"]
path = lib/args
url = https://github.com/Taywee/args.git
+57 -68
View File
@@ -1,9 +1,10 @@
language: cpp
sudo: required
matrix:
include:
- env: ARCH=x86_64
- name: Ubuntu bionic x86_64 release build
env: ARCH=x86_64
dist: bionic
addons:
apt:
update: true
@@ -12,78 +13,66 @@ matrix:
- 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
- env: ARCH=x86_64 BUILD_TYPE=centos6
services:
- docker
script: travis/build-centos6-docker.sh
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-centos6-"$ARCH".AppImage*
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
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
- name: Ubuntu bionic i386 build
env: ARCH=i386
dist: bionic
addons:
apt:
update: true
packages:
- libmagic-dev:i386
- libjpeg-dev:i386
- libpng-dev:i386
- gcc-multilib
- g++-multilib
- libfuse2:i386
- libcairo2:i386
script: travis/build.sh
after_success:
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
script:
- travis/build.sh
- 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
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*
- 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:
-5
View File
@@ -10,11 +10,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules/
set(USE_SYSTEM_BOOST OFF CACHE BOOL "Set to ON to use system boost libraries instead of building up to date boost libraries from source")
set(USE_SYSTEM_CIMG ON CACHE BOOL "Set to OFF to use CImg library bundled in lib directory")
if (EXISTS "${PROJECT_SOURCE_DIR}/lib/cpp-subprocess/subprocess.hpp")
else()
message (FATAL_ERROR "Missing submodule(s), please 'git submodule update --init --recursive'...")
endif()
# support for ccache
# call CMake with -DUSE_CCACHE=ON to make use of it
set(USE_CCACHE ON CACHE BOOL "")
+3 -1
View File
@@ -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
@@ -28,6 +28,8 @@ This is an incomplete list of projects using linuxdeploy. You might want to read
- [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
+41 -5
View File
@@ -1,8 +1,35 @@
# required for PNG imported target
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.6)
find_package(PNG REQUIRED)
find_package(JPEG REQUIRED)
find_package(PkgConfig)
pkg_check_modules(libpng REQUIRED IMPORTED_TARGET libpng)
# build custom static version of libjpeg for static builds
if(STATIC_BUILD)
include(ExternalProject)
if($ENV{ARCH} MATCHES "i[356]86")
set(configure_command_prefix env CFLAGS=-m32 CXXFLAGS=-m32)
endif()
ExternalProject_Add(libjpeg_static_extproj
URL https://www.ijg.org/files/jpegsrc.v9d.tar.gz
URL_HASH SHA256=99cb50e48a4556bc571dadd27931955ff458aae32f68c4d9c39d624693f69c32
BUILD_IN_SOURCE ON
EXCLUDE_FROM_ALL ON
CONFIGURE_COMMAND ${configure_command_prefix} ./configure --prefix=/usr
INSTALL_COMMAND ""
)
ExternalProject_Get_property(libjpeg_static_extproj SOURCE_DIR)
add_library(libjpeg_static INTERFACE IMPORTED)
set_property(TARGET libjpeg_static PROPERTY INTERFACE_LINK_LIBRARIES ${SOURCE_DIR}/.libs/libjpeg.a)
add_dependencies(libjpeg_static libjpeg_static_extproj)
set(JPEG_LIBRARIES libjpeg_static)
else()
find_package(JPEG REQUIRED)
endif()
if(NOT USE_SYSTEM_CIMG)
message(STATUS "Using bundled CImg library")
@@ -22,7 +49,16 @@ else()
endif()
endif()
set(PNG_INCLUDE_DIR ${libpng_INCLUDE_DIRS})
if(NOT STATIC_BUILD)
set(PNG_LIBRARY ${libpng_LIBRARIES})
else()
set(PNG_LIBRARY ${libpng_STATIC_LIBRARIES})
endif()
#message(FATAL_ERROR "${PNG_LIBRARY}")
add_library(CImg INTERFACE)
set_property(TARGET CImg PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CIMG_H_DIR};${JPEG_INCLUDE_DIR}")
set_property(TARGET CImg PROPERTY INTERFACE_LINK_LIBRARIES "PNG::PNG;${JPEG_LIBRARIES}")
set_property(TARGET CImg PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CIMG_H_DIR};${PNG_INCLUDE_DIR};${JPEG_INCLUDE_DIR}")
set_property(TARGET CImg PROPERTY INTERFACE_LINK_LIBRARIES "${PNG_LIBRARY};${JPEG_LIBRARIES}")
set_property(TARGET CImg PROPERTY INTERFACE_COMPILE_DEFINITIONS "cimg_display=0;cimg_use_png=1;cimg_use_jpeg=1")
+21 -10
View File
@@ -39,7 +39,7 @@ namespace linuxdeploy {
explicit AppDir(const std::string& path);
// creates basic directory structure of an AppDir in "FHS" mode
bool createBasicStructure();
bool createBasicStructure() const;
// deploy shared library
//
@@ -57,48 +57,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
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);
+2
View File
@@ -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);
};
}
}
+21 -149
View File
@@ -2,16 +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
@@ -46,19 +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";
// only interpret last line (fixes issues with --appimage-extract-and-run, where the runtime
// prints all the paths it extracts out to stdout)
const auto& lines = util::splitLines(stdoutOutput);
const auto& lastLine = lines.back();
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 {
const auto pluginApiLevel = std::stoi(lastLine);
return pluginApiLevel;
} catch (const std::invalid_argument&) {
ldLog() << LD_DEBUG << "Failed to understand plugin response:" << lastLine << std::endl;
auto apiLevel = std::stoi(stdoutOutput);
return apiLevel;
} catch (const std::exception&) {
return -1;
}
}
@@ -69,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) {
@@ -82,7 +85,7 @@ namespace linuxdeploy {
else if (firstLine == "output")
type = OUTPUT_TYPE;
}
} catch (const subprocess::CalledProcessError&) {}
} catch (const std::logic_error&) {}
return type;
}
@@ -94,12 +97,7 @@ namespace linuxdeploy {
if (d->apiLevel != API_LEVEL) {
std::stringstream msg;
if (d->apiLevel < 0) {
msg << "Could not read plugin API level";
} else {
msg << "This class only supports API level " << API_LEVEL << ", not " << d->apiLevel;
}
msg << "This class only supports API level " << API_LEVEL << ", not " << d->apiLevel;
throw WrongApiLevelError(msg.str());
}
}
@@ -138,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;
};
+86
View File
@@ -0,0 +1,86 @@
// system headers
#include <unordered_map>
#include <vector>
#include <signal.h>
// local headers
#include "linuxdeploy/subprocess/subprocess.h"
namespace linuxdeploy {
namespace subprocess {
class process {
private:
// child process ID
int child_pid_ = -1;
// pipes to child process's stdout/stderr
int stdout_fd_ = -1;
int stderr_fd_ = -1;
// process exited
bool exited_ = false;
// exit code -- will be initialized by close()
int exit_code_ = -1;
// these constants help make the pipe code more readable
static constexpr int READ_END_ = 0, WRITE_END_ = 1;
static std::vector<char*> make_args_vector_(const std::vector<std::string>& args);
static std::vector<char*> make_env_vector_(const subprocess_env_map_t& env);
static int check_waitpid_status_(int status);
public:
/**
* Create a child process.
* @param args parameters for process
* @param env additional environment variables (current environment will be copied)
*/
process(std::initializer_list<std::string> args, const subprocess_env_map_t& env);
/**
* Create a child process.
* @param args parameters for process
* @param env additional environment variables (current environment will be copied)
*/
process(const std::vector<std::string>& args, const subprocess_env_map_t& env);
~process();
/**
* @return child process's ID
*/
int pid() const;
/**
* @return child process's stdout file descriptor ID
*/
int stdout_fd() const;
/**
* @return child process's stderr file descriptor ID
*/
int stderr_fd() const;
/**
* Close all pipes and wait for process to exit.
* If process is not running any more, just returns exit code.
* @return child process's exit code
*/
int close();
/**
* Kill underlying process with given signal. By default, SIGTERM is used to end the process.
*/
void kill(int signal = SIGTERM) const;
/**
* Check whether process is still alive. Use close() to fetch exit code.
* @return true while process is alive, false otherwise
*/
bool is_running();
};
}
}
@@ -0,0 +1,32 @@
#pragma once
// system headers
#include <cstdio>
#include <unordered_map>
#include <string>
#include <utility>
#include <vector>
// local headers
#include "subprocess_result.h"
namespace linuxdeploy {
namespace subprocess {
typedef std::unordered_map<std::string, std::string> subprocess_env_map_t;
class subprocess {
private:
std::vector<std::string> args_{};
std::unordered_map<std::string, std::string> env_{};
public:
subprocess(std::initializer_list<std::string> args, subprocess_env_map_t env = {});
explicit subprocess(std::vector<std::string> args, subprocess_env_map_t env = {});
subprocess_result run() const;
std::string check_output() const;
};
}
}
@@ -0,0 +1,37 @@
#pragma once
// system headers
#include <cstdlib>
#include <string>
#include <utility>
#include <vector>
namespace linuxdeploy {
namespace subprocess {
typedef std::vector<std::string::value_type> subprocess_result_buffer_t;
/**
* Result of subprocess execution. Follows Value Object design pattern.
*/
class subprocess_result {
private:
int exit_code_;
subprocess_result_buffer_t stdout_contents_;
subprocess_result_buffer_t stderr_contents_;
public:
subprocess_result(int exit_code, subprocess_result_buffer_t stdout_contents,
subprocess_result_buffer_t stderr_contents);
int exit_code() const;
const subprocess_result_buffer_t& stdout_contents() const;
std::string stdout_string() const;
const subprocess_result_buffer_t& stderr_contents() const;
std::string stderr_string() const;
};
}
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
// system headers
#include <stdexcept>
namespace linuxdeploy {
namespace util {
namespace assert {
template<typename T>
void assert_not_empty(T container) {
if (container.empty()) {
throw std::invalid_argument{"container must not be empty"};
}
}
}
}
}
+31
View File
@@ -1,5 +1,6 @@
#pragma once
// system headers
#include <algorithm>
#include <climits>
#include <cstring>
@@ -8,6 +9,9 @@
#include <unistd.h>
#include <vector>
// libraries
#include <boost/filesystem.hpp>
namespace linuxdeploy {
namespace util {
namespace misc {
@@ -87,6 +91,33 @@ namespace linuxdeploy {
return buf.data();
}
// very simple but for our purposes good enough which like algorithm to find binaries in $PATH
static boost::filesystem::path which(const std::string& name) {
const auto* path = getenv("PATH");
namespace bf = boost::filesystem;
if (path == nullptr)
return "";
for (const auto& binDir : split(path, ':')) {
if (!bf::is_directory(binDir)) {
continue;
}
for (bf::directory_iterator it(binDir); it != bf::directory_iterator{}; ++it) {
const auto binary = it->path();
if (binary.filename() == name) {
// TODO: check if file is executable (skip otherwise)
return binary;
}
}
}
return {};
};
}
}
}
-19
View File
@@ -1,19 +0,0 @@
/**
* Wrapper for cpp-subprocess. Provides additional convenience functions.
*/
#pragma once
// library includes
#include <subprocess.hpp>
namespace linuxdeploy {
namespace util {
namespace subprocess {
using namespace ::subprocess;
// Reads output channels of existing Popen object into buffers and returns the contents
std::pair<std::string, std::string> check_output_error(Popen& proc);
}
}
}
+3 -2
View File
@@ -1,10 +1,11 @@
// local includes
#include "misc.h"
#include "subprocess.h"
#include "linuxdeploy/util/assert.h"
#include "linuxdeploy/util/misc.h"
// import functions from misc module for convenience
namespace linuxdeploy {
namespace util {
using namespace misc;
using namespace assert;
}
}
-5
View File
@@ -1,10 +1,5 @@
include(CTest)
add_library(subprocess INTERFACE)
target_sources(subprocess INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-subprocess/subprocess.hpp)
target_include_directories(subprocess INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-subprocess)
target_compile_options(subprocess INTERFACE "-Wno-deprecated")
add_library(args INTERFACE)
target_sources(args INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/args/args.hxx)
target_include_directories(args INTERFACE args)

Some files were not shown because too many files have changed in this diff Show More