You've already forked linuxdeploy
mirror of
https://github.com/encounter/linuxdeploy.git
synced 2026-07-10 12:18:44 -07:00
Compare commits
257 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ee0acdb6f1 | |||
| e069f6cd22 | |||
| 74d482612a | |||
| 8f2a49daf0 | |||
| 4a9e0583d0 | |||
| d83ca617e6 | |||
| 16483c38e4 | |||
| 65ef0bd7ed | |||
| 60f2cb78cd | |||
| 9b8d7698f4 | |||
| 5b1b91da5f | |||
| 44571a4c6b | |||
| 744368868b | |||
| d476f308f8 | |||
| 232a76d1ba | |||
| b97c8b45f5 | |||
| d6e6cac6e0 | |||
| 830dc50136 | |||
| 16ed8bfa6a | |||
| dbfdc6ebe6 | |||
| a6b09ee30c | |||
| 8b8255b158 | |||
| a87fd648e0 | |||
| 574a883733 | |||
| aaaca8b321 | |||
| 22bbd04304 | |||
| 96b5c3c479 | |||
| 35e67a26bb | |||
| 74fb390e2f | |||
| 3b3f86f9a2 | |||
| e6341435bd | |||
| e388ad9eb6 | |||
| b1838315d9 | |||
| 6e525e0a65 | |||
| b540240ba5 | |||
| 5d219c99b7 | |||
| 459c5aad9a | |||
| c6a517c1f5 | |||
| 11bbe4d219 | |||
| 0d59a27905 | |||
| a4e48db545 | |||
| b56e202c40 | |||
| 8b4feb5fd5 | |||
| 156b45f819 | |||
| 3e1d340612 | |||
| 8a2d57e8d5 | |||
| be1b2c95d4 | |||
| 4bb1ef124b | |||
| 93c947b56a | |||
| 4bf295d4d6 | |||
| 2c40482bc0 | |||
| a647205226 | |||
| 73832323c8 | |||
| 169275e023 | |||
| 78e5d0858e | |||
| b4efb2bc56 | |||
| aa2e8b9105 | |||
| 793b35dc61 | |||
| 5ba8b613d6 | |||
| 75f2511437 | |||
| 9a4916fe84 | |||
| e584088656 | |||
| 8a79cfbe1d | |||
| 22ecabc51b | |||
| 81dfae892c | |||
| bedd66d161 | |||
| 62f04213ce | |||
| 4790fabc44 | |||
| 6112a6353e | |||
| 82b7ccd76a | |||
| 4e33e395de | |||
| 9d25fee1dc | |||
| 9d78e0786b | |||
| 9f20e5829d | |||
| 5055efdc05 | |||
| 19ecbb2d70 | |||
| 0e92331a12 | |||
| 4bf1948774 | |||
| f201c57177 | |||
| d7c0e94f11 | |||
| 700f6fe15f | |||
| 012e621ec5 | |||
| 6c674aa184 | |||
| 553bb9fcb0 | |||
| 906dcab283 | |||
| fc3d80c281 | |||
| f0bb1fb472 | |||
| f3f30166f2 | |||
| 2210b7e65d | |||
| cc800588d2 | |||
| 29cda3b1ac | |||
| 16b0a5948a | |||
| 41569a4f53 | |||
| 7ff05ca98e | |||
| cab57f86d6 | |||
| 93fea697e5 | |||
| bd12fefc35 | |||
| 2cdedc252c | |||
| 1fa90fbd5c | |||
| 7318d68c96 | |||
| e5f4755da7 | |||
| 31f20a398f | |||
| d9ca907da8 | |||
| 542edaf410 | |||
| e683561430 | |||
| 0de7caa8ee | |||
| f1690cc2a3 | |||
| 53e0850a2b | |||
| 3949a5fc57 | |||
| 001b8f974c | |||
| 2f5e04ec24 | |||
| 8d01c448d3 | |||
| 10df75f877 | |||
| 0c5b198e2f | |||
| 5d2984ae02 | |||
| 33829c07d0 | |||
| 90f8ed26b8 | |||
| cbaa343a82 | |||
| 9cf0663baa | |||
| e94494ea31 | |||
| 2dce34daf9 | |||
| 7260078b6c | |||
| 4bdceec7d8 | |||
| ca6c710c38 | |||
| 8a31d3d677 | |||
| 5e94977f78 | |||
| 2f96dec588 | |||
| a1308955e7 | |||
| 7e4a320f61 | |||
| 172db51186 | |||
| d09186f69f | |||
| 376eddb14d | |||
| 47ff6c8e9d | |||
| 41371c9d90 | |||
| eacc907c85 | |||
| 4c9943f0d1 | |||
| a0503a7102 | |||
| f1e752d452 | |||
| 55b6ee19e1 | |||
| 4c0d5ea891 | |||
| 83a8f52f98 | |||
| b1bf306510 | |||
| d2a021d57b | |||
| 2f7ad201f1 | |||
| 485507a2d1 | |||
| cdee469e60 | |||
| a892d066cc | |||
| 57175e0c75 | |||
| 88695de067 | |||
| 0f19458792 | |||
| c8d78eb602 | |||
| 6b8b59ee77 | |||
| 3674af54b2 | |||
| 73ecd9d318 | |||
| 1ad4e5e6a9 | |||
| f3b54236a6 | |||
| e885b47208 | |||
| 89788f5e26 | |||
| 83a9690da1 | |||
| 5fc87e1c1c | |||
| 3375de8fc4 | |||
| 906c948304 | |||
| 371343baed | |||
| 63764e2e18 | |||
| 8441dbb589 | |||
| d13814d784 | |||
| cd83c28196 | |||
| f99cac25b5 | |||
| 11a923b672 | |||
| a8aaa09a55 | |||
| 0ced1390ce | |||
| af310722df | |||
| dcf1726889 | |||
| ea12263be2 | |||
| 9a44a10173 | |||
| b550e4da21 | |||
| c4167165ad | |||
| 276c6f2d18 | |||
| 5b54db31cc | |||
| 4a098896a9 | |||
| ec051c3e0c | |||
| 0741d9441b | |||
| 9b1b214142 | |||
| db77174f24 | |||
| a0b0378d36 | |||
| 388e7d5acb | |||
| cc30bb6bd1 | |||
| 0d60f67da3 | |||
| e8dee64447 | |||
| 36c6be95d6 | |||
| 2c4fed2fad | |||
| 21849f8fbf | |||
| 4de8b6589f | |||
| 7184bcb61d | |||
| 55d524b136 | |||
| 9743988c80 | |||
| 84b614c1ea | |||
| 1035ef726d | |||
| 1c7e768b86 | |||
| a28181d98c | |||
| fcd3ad49db | |||
| cc6310cbbd | |||
| c58d9716b0 | |||
| 3e84f424e7 | |||
| a386ab19fd | |||
| 4f84082155 | |||
| 8aa1bc9d89 | |||
| 56d9d6b540 | |||
| 5165301a44 | |||
| c1452fa870 | |||
| 03cae41d55 | |||
| c10eafe823 | |||
| 4a7301eba5 | |||
| a3cc38d406 | |||
| 144fd2deb0 | |||
| b96389a064 | |||
| b156ffc0cb | |||
| bd052a5b1f | |||
| f06d5e5832 | |||
| a0ace9f75c | |||
| 2b7a5928a5 | |||
| ec862d0af9 | |||
| df61b059d3 | |||
| 5baac459b3 | |||
| c783be934b | |||
| ae6dfcfe21 | |||
| c07025ab8a | |||
| c438d5ee2b | |||
| ee15c88978 | |||
| 80fc055373 | |||
| 5d81258547 | |||
| d57e4750c2 | |||
| ddbca26b1b | |||
| 2e503362a0 | |||
| 7a2390ea95 | |||
| 312287d937 | |||
| a641ae7fac | |||
| b332dc7e7d | |||
| b16329f8ba | |||
| ee6fd2e594 | |||
| 4ee5a903ce | |||
| 852ac4d038 | |||
| eea9a5a9f9 | |||
| b046bef4c9 | |||
| e311bc9217 | |||
| 0cb0223560 | |||
| e7b3a0987a | |||
| efb59d6ea7 | |||
| 39ddfc5c79 | |||
| d5aa361eb4 | |||
| 08a1bf9b69 | |||
| eba0d70576 | |||
| 1a4d9e8130 | |||
| 2b94a4b408 | |||
| dcf4f79059 | |||
| 345fc638b6 | |||
| 8d3284c447 |
@@ -1,3 +1,5 @@
|
||||
cmake-build-*/
|
||||
*build*/
|
||||
.idea/
|
||||
squashfs-root/
|
||||
*.AppImage
|
||||
|
||||
+27
-3
@@ -4,9 +4,6 @@
|
||||
[submodule "lib/args"]
|
||||
path = lib/args
|
||||
url = https://github.com/Taywee/args.git
|
||||
[submodule "lib/cpp-feather-ini-parser"]
|
||||
path = lib/cpp-feather-ini-parser
|
||||
url = https://github.com/Turbine1991/cpp-feather-ini-parser.git
|
||||
[submodule "lib/boost-filesystem"]
|
||||
path = lib/boost-filesystem
|
||||
url = https://github.com/boostorg/filesystem.git
|
||||
@@ -73,3 +70,30 @@
|
||||
[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
|
||||
|
||||
+60
-11
@@ -1,19 +1,68 @@
|
||||
language: cpp
|
||||
sudo: required
|
||||
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libmagic-dev
|
||||
- cimg-dev
|
||||
- automake # required for patchelf
|
||||
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
|
||||
- git clone https://github.com/NixOS/patchelf.git -b 0.8
|
||||
- cd patchelf
|
||||
- ./bootstrap.sh
|
||||
- ./configure --prefix=/usr
|
||||
- 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 ..
|
||||
@@ -25,9 +74,9 @@ script:
|
||||
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" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
|
||||
- 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*.AppImage*
|
||||
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
|
||||
|
||||
branches:
|
||||
except:
|
||||
|
||||
+39
-3
@@ -5,13 +5,49 @@ project(linuxdeploy C CXX)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(LINUXDEPLOY_VERSION 0.1-alpha-1)
|
||||
add_definitions(-DLINUXDEPLOY_VERSION="${LINUXDEPLOY_VERSION}")
|
||||
|
||||
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 "")
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE ccache)
|
||||
if(CCACHE)
|
||||
message(STATUS "Using ccache")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
|
||||
else()
|
||||
message(WARNING "USE_CCACHE set, but could not find ccache")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(ENABLE_COVERAGE OFF CACHE BOOL "Enable coverage measurements")
|
||||
if(ENABLE_COVERAGE)
|
||||
include(CodeCoverage)
|
||||
message(WARNING "Enabling code coverage measurements -> disables optimizations and embeds debug information!")
|
||||
|
||||
append_coverage_compiler_flags()
|
||||
|
||||
set(COVERAGE_GCOVR_EXCLUDES ${PROJECT_SOURCE_DIR}/lib ${PROJECT_BINARY_DIR})
|
||||
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(processor_count)
|
||||
|
||||
set(command cmake --build . --target all -- -j ${processor_count} && ctest -V)
|
||||
|
||||
setup_target_for_coverage_gcovr_html(NAME coverage EXECUTABLE "${command}")
|
||||
setup_target_for_coverage_gcovr_xml(NAME coverage_xml EXECUTABLE "${command}")
|
||||
setup_target_for_coverage_gcovr_text(NAME coverage_text EXECUTABLE "${command}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(lib)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
@@ -2,4 +2,120 @@
|
||||
|
||||
AppDir creation and maintenance tool.
|
||||
|
||||
**More info will follow soon!**
|
||||
|
||||
## About
|
||||
|
||||
AppImages are a well known and quite popular format for distributing applications from developers to end users.
|
||||
|
||||
[appimagetool](https://github.com/AppImage/AppImageKit), the tool creating AppImages, expects directories in a specific format that will then be converted into the final AppImage. This format is called [AppDir](https://github.com/TheAssassin/linuxdeploy/wiki/AppDir-specification). It is not very difficult to understand, but creating AppDirs for arbitrary applications tends to be a very repetitive task. Also, bundling all the dependencies properly can be a quite difficult task. It seems like there is a need for tools which simplify these tasks.
|
||||
|
||||
linuxdeploy is designed to be an AppDir maintenance tool. It provides extensive functionalities to create and bundle AppDirs for applications. It features a plugin system that allows for easy bundling of frameworks and creating output bundles such as AppImages with little effort.
|
||||
|
||||
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
|
||||
|
||||
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).
|
||||
|
||||
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:
|
||||
|
||||
```sh
|
||||
# automake
|
||||
./configure --prefix=/usr
|
||||
make install DESTDIR=AppDir
|
||||
|
||||
# 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
|
||||
```
|
||||
|
||||
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).
|
||||
|
||||
|
||||
## Plugins
|
||||
|
||||
linuxdeploy features a plugin system. Plugins are separate executables which implement a CLI-based plugin interface ([specification](https://github.com/TheAssassin/linuxdeploy/wiki/Plugin-system)).
|
||||
|
||||
There are two types of plugins: bundling and output plugins. Bundling plugins can be used to add resources to the AppDir. Output plugins turn the AppDir in actual bundles, e.g., AppImages.
|
||||
|
||||
linuxdeploy looks for plugins in the following places:
|
||||
|
||||
- the directory containing the linuxdeploy binary
|
||||
- when using the AppImage: the directory containing the AppImage
|
||||
- the directories in the user's `$PATH`
|
||||
|
||||
You can use `./linuxdeploy*.AppImage --list-plugins` to get a list of all the plugins linuxdeploy has detected on your system.
|
||||
|
||||
linuxdeploy currently ships with some plugins. These are likely out of date. In case of issues, please download the latest version, which will take precendence over the bundled plugin.
|
||||
|
||||
If you want to use a plugin to bundle additional resources, please add `./linuxdeploy*.AppImage --plugin <name>` to your linuxdeploy command. Output plugins can be activated using `./linuxdeploy*.AppImage --output <name>`.
|
||||
|
||||
**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.
|
||||
|
||||
linuxdeploy does not change any environment variables such as `$PATH`. Your application **must** search for additional resources such as icon files or executables relative to the main binary.
|
||||
|
||||
|
||||
## Contact
|
||||
|
||||
The easiest way to get in touch with the developers is to join the IRC chatroom [#AppImage](https://webchat.freenode.net/?channels=appimage) on FreeNode. This is the preferred way for general feedback or questions how to use this application.
|
||||
|
||||
To report problems, please [create an issue](https://github.com/TheAssassin/linuxdeploy/issues/new) on GitHub.
|
||||
|
||||
Contributions welcome! Please feel free to fork this repository and send us a pull request. Even small changes, e.g., in this README, are highly appreciated!
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
# Copyright (c) 2012 - 2017, Lars Bilke
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# CHANGES:
|
||||
#
|
||||
# 2012-01-31, Lars Bilke
|
||||
# - Enable Code Coverage
|
||||
#
|
||||
# 2013-09-17, Joakim Söderberg
|
||||
# - Added support for Clang.
|
||||
# - Some additional usage instructions.
|
||||
#
|
||||
# 2016-02-03, Lars Bilke
|
||||
# - Refactored functions to use named parameters
|
||||
#
|
||||
# 2017-06-02, Lars Bilke
|
||||
# - Merged with modified version from github.com/ufz/ogs
|
||||
#
|
||||
#
|
||||
# USAGE:
|
||||
#
|
||||
# 1. Copy this file into your cmake modules path.
|
||||
#
|
||||
# 2. Add the following line to your CMakeLists.txt:
|
||||
# include(CodeCoverage)
|
||||
#
|
||||
# 3. Append necessary compiler flags:
|
||||
# APPEND_COVERAGE_COMPILER_FLAGS()
|
||||
#
|
||||
# 4. If you need to exclude additional directories from the report, specify them
|
||||
# using the COVERAGE_LCOV_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE_LCOV.
|
||||
# Example:
|
||||
# set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*')
|
||||
#
|
||||
# 5. Use the functions described below to create a custom make target which
|
||||
# runs your test executable and produces a code coverage report.
|
||||
#
|
||||
# 6. Build a Debug build:
|
||||
# cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
# make
|
||||
# make my_coverage_target
|
||||
#
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
# Check prereqs
|
||||
find_program( GCOV_PATH gcov )
|
||||
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
|
||||
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
|
||||
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
|
||||
find_program( SIMPLE_PYTHON_EXECUTABLE python )
|
||||
|
||||
if(NOT GCOV_PATH)
|
||||
message(FATAL_ERROR "gcov not found! Aborting...")
|
||||
endif() # NOT GCOV_PATH
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
|
||||
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
|
||||
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
|
||||
endif()
|
||||
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
|
||||
endif()
|
||||
|
||||
set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
|
||||
CACHE INTERNAL "")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_COVERAGE
|
||||
${COVERAGE_COMPILER_FLAGS}
|
||||
CACHE STRING "Flags used by the C++ compiler during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_C_FLAGS_COVERAGE
|
||||
${COVERAGE_COMPILER_FLAGS}
|
||||
CACHE STRING "Flags used by the C compiler during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
""
|
||||
CACHE STRING "Flags used for linking binaries during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
|
||||
""
|
||||
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
|
||||
FORCE )
|
||||
mark_as_advanced(
|
||||
CMAKE_CXX_FLAGS_COVERAGE
|
||||
CMAKE_C_FLAGS_COVERAGE
|
||||
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
|
||||
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
link_libraries(gcov)
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
|
||||
endif()
|
||||
|
||||
# Defines a target for running and collection code coverage information
|
||||
# Builds dependencies, runs the given executable and outputs reports.
|
||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||
# the coverage generation will not complete.
|
||||
#
|
||||
# SETUP_TARGET_FOR_COVERAGE_LCOV(
|
||||
# NAME testrunner_coverage # New target name
|
||||
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||
# DEPENDENCIES testrunner # Dependencies to build first
|
||||
# )
|
||||
function(SETUP_TARGET_FOR_COVERAGE_LCOV)
|
||||
|
||||
set(options NONE)
|
||||
set(oneValueArgs NAME)
|
||||
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
|
||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT LCOV_PATH)
|
||||
message(FATAL_ERROR "lcov not found! Aborting...")
|
||||
endif() # NOT LCOV_PATH
|
||||
|
||||
if(NOT GENHTML_PATH)
|
||||
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||
endif() # NOT GENHTML_PATH
|
||||
|
||||
# Setup target
|
||||
add_custom_target(${Coverage_NAME}
|
||||
|
||||
# Cleanup lcov
|
||||
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . --zerocounters
|
||||
# Create baseline to make sure untouched files show up in the report
|
||||
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base
|
||||
|
||||
# Run tests
|
||||
COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
|
||||
# Capturing lcov counters and generating report
|
||||
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info
|
||||
# add baseline counters
|
||||
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total
|
||||
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_LCOV_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
|
||||
COMMAND ${GENHTML_PATH} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
|
||||
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Coverage_DEPENDENCIES}
|
||||
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
|
||||
)
|
||||
|
||||
# Show where to find the lcov info report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ;
|
||||
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
|
||||
)
|
||||
|
||||
# Show info where to find the report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ;
|
||||
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||
)
|
||||
|
||||
endfunction() # SETUP_TARGET_FOR_COVERAGE_LCOV
|
||||
|
||||
# Defines a target for running and collection code coverage information
|
||||
# Builds dependencies, runs the given executable and outputs reports.
|
||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||
# the coverage generation will not complete.
|
||||
#
|
||||
# SETUP_TARGET_FOR_COVERAGE_GCOVR_XML(
|
||||
# NAME ctest_coverage # New target name
|
||||
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||
# DEPENDENCIES executable_target # Dependencies to build first
|
||||
# )
|
||||
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
|
||||
|
||||
set(options NONE)
|
||||
set(oneValueArgs NAME)
|
||||
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT SIMPLE_PYTHON_EXECUTABLE)
|
||||
message(FATAL_ERROR "python not found! Aborting...")
|
||||
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
|
||||
|
||||
if(NOT GCOVR_PATH)
|
||||
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||
endif() # NOT GCOVR_PATH
|
||||
|
||||
# Combine excludes to several -e arguments
|
||||
set(GCOVR_EXCLUDES "")
|
||||
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
|
||||
list(APPEND GCOVR_EXCLUDES "-e")
|
||||
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${Coverage_NAME}
|
||||
# Run tests
|
||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
|
||||
# Running gcovr
|
||||
COMMAND ${GCOVR_PATH} --xml
|
||||
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
|
||||
--object-directory=${PROJECT_BINARY_DIR}
|
||||
-o ${Coverage_NAME}.xml
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Coverage_DEPENDENCIES}
|
||||
COMMENT "Running gcovr to produce Cobertura code coverage report."
|
||||
)
|
||||
|
||||
# Show info where to find the report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ;
|
||||
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
|
||||
)
|
||||
|
||||
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_XML
|
||||
|
||||
# Defines a target for running and collection code coverage information
|
||||
# Builds dependencies, runs the given executable and outputs reports.
|
||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||
# the coverage generation will not complete.
|
||||
#
|
||||
# SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML(
|
||||
# NAME ctest_coverage # New target name
|
||||
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||
# DEPENDENCIES executable_target # Dependencies to build first
|
||||
# )
|
||||
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
|
||||
|
||||
set(options NONE)
|
||||
set(oneValueArgs NAME)
|
||||
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT SIMPLE_PYTHON_EXECUTABLE)
|
||||
message(FATAL_ERROR "python not found! Aborting...")
|
||||
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
|
||||
|
||||
if(NOT GCOVR_PATH)
|
||||
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||
endif() # NOT GCOVR_PATH
|
||||
|
||||
# Combine excludes to several -e arguments
|
||||
set(GCOVR_EXCLUDES "")
|
||||
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
|
||||
list(APPEND GCOVR_EXCLUDES "-e")
|
||||
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${Coverage_NAME}
|
||||
# Run tests
|
||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
|
||||
# Create folder
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
|
||||
|
||||
# Running gcovr
|
||||
COMMAND ${GCOVR_PATH} --html --html-details
|
||||
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
|
||||
--object-directory=${PROJECT_BINARY_DIR}
|
||||
-o ${Coverage_NAME}/index.html
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Coverage_DEPENDENCIES}
|
||||
COMMENT "Running gcovr to produce HTML code coverage report."
|
||||
)
|
||||
|
||||
# Show info where to find the report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ;
|
||||
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||
)
|
||||
|
||||
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML
|
||||
|
||||
# Defines a target for running and collection code coverage information
|
||||
# Builds dependencies, runs the given executable and outputs reports.
|
||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||
# the coverage generation will not complete.
|
||||
#
|
||||
# SETUP_TARGET_FOR_COVERAGE_GCOVR_TEXT(
|
||||
# NAME ctest_coverage # New target name
|
||||
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||
# DEPENDENCIES executable_target # Dependencies to build first
|
||||
# )
|
||||
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_TEXT)
|
||||
|
||||
set(options NONE)
|
||||
set(oneValueArgs NAME)
|
||||
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT SIMPLE_PYTHON_EXECUTABLE)
|
||||
message(FATAL_ERROR "python not found! Aborting...")
|
||||
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
|
||||
|
||||
if(NOT GCOVR_PATH)
|
||||
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||
endif() # NOT GCOVR_PATH
|
||||
|
||||
# Combine excludes to several -e arguments
|
||||
set(GCOVR_EXCLUDES "")
|
||||
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
|
||||
list(APPEND GCOVR_EXCLUDES "-e")
|
||||
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${Coverage_NAME}
|
||||
# Run tests
|
||||
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||
|
||||
# Create folder
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
|
||||
|
||||
# Running gcovr
|
||||
COMMAND ${GCOVR_PATH}
|
||||
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
|
||||
--object-directory=${PROJECT_BINARY_DIR}
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Coverage_DEPENDENCIES}
|
||||
COMMENT "Running gcovr to produce HTML code coverage report."
|
||||
)
|
||||
|
||||
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_TEXT
|
||||
|
||||
function(APPEND_COVERAGE_COMPILER_FLAGS)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
|
||||
endfunction() # APPEND_COVERAGE_COMPILER_FLAGS
|
||||
@@ -1,22 +1,28 @@
|
||||
# required for PNG imported target
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
message(STATUS "Searching for CImg")
|
||||
|
||||
find_path(CIMG_H_DIR
|
||||
NAMES CImg.h
|
||||
HINTS ${CMAKE_INSTALL_PREFIX}
|
||||
PATH_SUFFIXES include include/linux
|
||||
)
|
||||
|
||||
if(NOT CIMG_H_DIR)
|
||||
message(FATAL_ERROR "CImg.h not found")
|
||||
endif()
|
||||
|
||||
find_package(PNG REQUIRED)
|
||||
find_package(JPEG REQUIRED)
|
||||
|
||||
add_library(CImg INTERFACE IMPORTED)
|
||||
if(NOT USE_SYSTEM_CIMG)
|
||||
message(STATUS "Using bundled CImg library")
|
||||
|
||||
set(CIMG_H_DIR "${PROJECT_SOURCE_DIR}/lib/CImg/")
|
||||
else()
|
||||
message(STATUS "Searching for CImg")
|
||||
|
||||
find_path(CIMG_H_DIR
|
||||
NAMES CImg.h
|
||||
HINTS ${CMAKE_INSTALL_PREFIX}
|
||||
PATH_SUFFIXES include include/linux
|
||||
)
|
||||
|
||||
if(NOT CIMG_H_DIR)
|
||||
message(FATAL_ERROR "CImg.h not found")
|
||||
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")
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# required for zlib imported target
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
|
||||
message(STATUS "Searching for libmagic")
|
||||
|
||||
# on Debian-ish systems, libmagic depends on zlib
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
find_library(LIBMAGIC_A libmagic.a)
|
||||
|
||||
if(NOT LIBMAGIC_A)
|
||||
message(FATAL_ERROR "libmagic.a not found")
|
||||
endif()
|
||||
|
||||
find_path(LIBMAGIC_MAGIC_H_DIR
|
||||
NAMES magic.h
|
||||
HINTS ${CMAKE_INSTALL_PREFIX}
|
||||
PATH_SUFFIXES include include/linux
|
||||
)
|
||||
|
||||
if(NOT LIBMAGIC_MAGIC_H_DIR)
|
||||
message(FATAL_ERROR "magic.h not found")
|
||||
endif()
|
||||
|
||||
add_library(libmagic_static INTERFACE IMPORTED)
|
||||
set_property(TARGET libmagic_static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${LIBMAGIC_MAGIC_H_DIR})
|
||||
set_property(TARGET libmagic_static PROPERTY INTERFACE_LINK_LIBRARIES ${LIBMAGIC_A};ZLIB::ZLIB)
|
||||
@@ -0,0 +1,8 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux CACHE STRING "" FORCE)
|
||||
set(CMAKE_SYSTEM_PROCESSOR i386 CACHE STRING "" FORCE)
|
||||
|
||||
set(CMAKE_C_FLAGS "-m32" CACHE STRING "" FORCE)
|
||||
set(CMAKE_CXX_FLAGS "-m32" CACHE STRING "" FORCE)
|
||||
|
||||
# https://gitlab.kitware.com/cmake/cmake/issues/16920#note_299077
|
||||
set(THREADS_PTHREAD_ARG "2" CACHE STRING "Forcibly set by CMakeLists.txt" FORCE)
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
// local includes
|
||||
#include "linuxdeploy/core/desktopfile.h"
|
||||
#include "linuxdeploy/core/desktopfile/desktopfile.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -42,6 +42,13 @@ namespace linuxdeploy {
|
||||
// the dependencies are copied to the normal destination, though
|
||||
bool deployLibrary(const boost::filesystem::path& path, const boost::filesystem::path& destination = "");
|
||||
|
||||
// force deploy shared library
|
||||
//
|
||||
// works like deployLibrary, except that it doesn't check the excludelist
|
||||
// this is useful to deploy libraries and their dependencies that are blacklisted and would otherwise not be deployed
|
||||
// the excludelist check is only disabled for the current library, and will be enabled for the dependencies again
|
||||
bool forceDeployLibrary(const boost::filesystem::path& path, const boost::filesystem::path& destination = "");
|
||||
|
||||
// deploy executable
|
||||
bool deployExecutable(const boost::filesystem::path& path, const boost::filesystem::path& destination = "");
|
||||
|
||||
@@ -54,6 +61,9 @@ namespace linuxdeploy {
|
||||
// deploy arbitrary file
|
||||
void deployFile(const boost::filesystem::path& from, const boost::filesystem::path& to);
|
||||
|
||||
// create an <AppDir> relative symlink to <target> at <symlink>.
|
||||
bool createRelativeSymlink(const boost::filesystem::path& target, const boost::filesystem::path& symlink);
|
||||
|
||||
// execute deferred copy operations
|
||||
bool executeDeferredOperations();
|
||||
|
||||
@@ -72,12 +82,6 @@ namespace linuxdeploy {
|
||||
// create symlinks for AppRun, desktop file and icon in the AppDir root directory
|
||||
bool createLinksInAppDirRoot(const desktopfile::DesktopFile& desktopFile, boost::filesystem::path customAppRunPath = "");
|
||||
|
||||
// set application name of primary "entry point" application
|
||||
// icons and other resources will then automatically be renamed using this value in order to
|
||||
// make the deployment easier by not requiring special filenames
|
||||
// resources' filenames should be prefixed with this value (example: linuxdeploy_48x48.png)
|
||||
void setAppName(const std::string& appName);
|
||||
|
||||
// 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();
|
||||
@@ -90,6 +94,9 @@ namespace linuxdeploy {
|
||||
// calling this function can turn sure file trees created by make install commands into working
|
||||
// AppDirs
|
||||
bool deployDependenciesForExistingFiles();
|
||||
|
||||
// disable deployment of copyright files for this instance
|
||||
bool setDisableCopyrightFilesDeployment(bool disable);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
// system includes
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace core {
|
||||
namespace desktopfile {
|
||||
/*
|
||||
* Parse and read desktop files.
|
||||
*/
|
||||
class DesktopFile {
|
||||
private:
|
||||
// private data class pattern
|
||||
class PrivateData;
|
||||
PrivateData* d;
|
||||
|
||||
public:
|
||||
// default constructor
|
||||
DesktopFile();
|
||||
|
||||
// construct from existing desktop file
|
||||
// file must exist
|
||||
explicit DesktopFile(const boost::filesystem::path& path);
|
||||
|
||||
// read desktop file
|
||||
// sets path associated with this file
|
||||
bool read(const boost::filesystem::path& path);
|
||||
|
||||
// get path associated with this file
|
||||
boost::filesystem::path path() const;
|
||||
|
||||
// sets the path associated with this desktop file
|
||||
// used to e.g., save the desktop file
|
||||
void setPath(const boost::filesystem::path& path);
|
||||
|
||||
// clear contents of desktop file
|
||||
void clear();
|
||||
|
||||
// save desktop file
|
||||
bool save() const;
|
||||
|
||||
// save desktop file to path
|
||||
// does not change path associated with desktop file
|
||||
bool save(const boost::filesystem::path& path) const;
|
||||
|
||||
// check if entry exists in given section and key
|
||||
bool entryExists(const std::string& section, const std::string& key) const;
|
||||
|
||||
// get key from desktop file
|
||||
// an std::string passed as value parameter will be populated with the contents
|
||||
// returns true (and populates value) if the key exists, false otherwise
|
||||
bool getEntry(const std::string& section, const std::string& key, std::string& value) const;
|
||||
|
||||
// add key to section in desktop file
|
||||
// the section will be created if it doesn't exist already
|
||||
// returns true if an existing key was overwritten, false otherwise
|
||||
bool setEntry(const std::string& section, const std::string& key, const std::string& value);
|
||||
|
||||
// create common application entries in desktop file
|
||||
// returns false if one of the keys exists and was left unmodified
|
||||
bool addDefaultKeys(const std::string& executableFileName);
|
||||
|
||||
// validate desktop file
|
||||
bool validate() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// 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;
|
||||
|
||||
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;
|
||||
|
||||
// equality operator
|
||||
bool operator==(const DesktopFile& other);
|
||||
|
||||
// inequality operator
|
||||
bool operator!=(const DesktopFile& other);
|
||||
|
||||
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, std::string& value) 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 std::string& key, const std::string& value);
|
||||
|
||||
// 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, const 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#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:
|
||||
// allow conversion of entry to string
|
||||
// returns value
|
||||
explicit operator std::string() const;
|
||||
|
||||
// convert value to integer
|
||||
// throws boost::bad_lexical_cast in case of type errors
|
||||
int asInt() const;
|
||||
|
||||
// convert value to long
|
||||
// throws boost::bad_lexical_cast in case of type errors
|
||||
long 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,6 +1,8 @@
|
||||
// system includes
|
||||
#include <vector>
|
||||
#include <string>
|
||||
// including system elf header, which allows for interpretation of the return values of the methods
|
||||
#include <elf.h>
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -16,6 +18,12 @@ namespace linuxdeploy {
|
||||
explicit ElfFileParseError(const std::string& msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
// thrown by traceDynamicDependencies() if a dependency is missing
|
||||
class DependencyNotFoundError : public std::runtime_error {
|
||||
public:
|
||||
explicit DependencyNotFoundError(const std::string& msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
class ElfFile {
|
||||
private:
|
||||
class PrivateData;
|
||||
@@ -25,6 +33,16 @@ namespace linuxdeploy {
|
||||
explicit ElfFile(const boost::filesystem::path& path);
|
||||
~ElfFile();
|
||||
|
||||
public:
|
||||
// return system ELF OS ABI
|
||||
static uint8_t getSystemElfABI();
|
||||
|
||||
// return system ELF class (32-bit or 64-bit)
|
||||
static uint8_t getSystemElfClass();
|
||||
|
||||
// return system (ELF) endianness
|
||||
static uint8_t getSystemElfEndianness();
|
||||
|
||||
public:
|
||||
// recursively trace dynamic library dependencies of a given ELF file
|
||||
// this works for both libraries and executables
|
||||
@@ -40,6 +58,12 @@ namespace linuxdeploy {
|
||||
// set rpath in ELF file
|
||||
// returns true on success, false otherwise
|
||||
bool setRPath(const std::string& value);
|
||||
|
||||
// return ELF class
|
||||
uint8_t getElfClass();
|
||||
|
||||
// return OS ABI
|
||||
uint8_t getElfABI();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <poll.h>
|
||||
|
||||
// library headers
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -18,10 +19,13 @@
|
||||
namespace linuxdeploy {
|
||||
namespace plugin {
|
||||
namespace base {
|
||||
using namespace linuxdeploy::core::log;
|
||||
|
||||
template<int API_LEVEL>
|
||||
class PluginBase<API_LEVEL>::PrivateData {
|
||||
public:
|
||||
const boost::filesystem::path pluginPath;
|
||||
std::string name;
|
||||
int apiLevel;
|
||||
PLUGIN_TYPE pluginType;
|
||||
|
||||
@@ -33,6 +37,10 @@ namespace linuxdeploy {
|
||||
|
||||
apiLevel = getApiLevelFromExecutable();
|
||||
pluginType = getPluginTypeFromExecutable();
|
||||
|
||||
boost::cmatch res;
|
||||
boost::regex_match(path.filename().c_str(), res, PLUGIN_EXPR);
|
||||
name = res[1].str();
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -121,16 +129,130 @@ namespace linuxdeploy {
|
||||
auto pluginPath = path();
|
||||
auto args = {pluginPath.c_str(), "--appdir", appDirPath.string().c_str()};
|
||||
|
||||
auto log = linuxdeploy::core::log::ldLog();
|
||||
auto log = ldLog();
|
||||
log << "Running process:";
|
||||
for (const auto& arg : args) {
|
||||
log << "" << arg;
|
||||
}
|
||||
log << std::endl;
|
||||
|
||||
auto process = subprocess::Popen(args);
|
||||
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;
|
||||
}
|
||||
|
||||
auto retcode = process.wait();
|
||||
return retcode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
// library includes
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
// local includes
|
||||
#include "linuxdeploy/core/log.h"
|
||||
@@ -18,6 +19,11 @@ namespace linuxdeploy {
|
||||
OUTPUT_TYPE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Official regular expression to check filenames for plugins
|
||||
*/
|
||||
static const boost::regex PLUGIN_EXPR(R"(^linuxdeploy-plugin-([^\s\.-]+)(?:-[^\.]+)?(?:\..+)?$)");
|
||||
|
||||
/*
|
||||
* Plugin interface.
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
namespace linuxdeploy {
|
||||
@@ -64,6 +65,14 @@ namespace linuxdeploy {
|
||||
return strncmp(string.c_str(), prefix.c_str(), prefix.size()) == 0;
|
||||
}
|
||||
|
||||
static bool stringEndsWith(const std::string& string, const std::string& suffix) {
|
||||
// sanity check
|
||||
if (string.size() < suffix.size())
|
||||
return false;
|
||||
|
||||
return strcmp(string.c_str() + (string.size() - suffix.size()), suffix.c_str()) == 0;
|
||||
}
|
||||
|
||||
static bool stringContains(const std::string& string, const std::string& part) {
|
||||
return string.find(part) != std::string::npos;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Wrapper for cpp-subprocess. Provides additional convenience functions.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// library includes
|
||||
#include <subprocess.hpp>
|
||||
|
||||
namespace linuxdeploy {
|
||||
namespace util {
|
||||
namespace subprocess {
|
||||
using namespace ::subprocess;
|
||||
|
||||
// Reads output channels of existing Popen object into buffers and returns the contents
|
||||
std::pair<std::string, std::string> check_output_error(Popen& proc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// local includes
|
||||
#include "magicwrapper.h"
|
||||
#include "misc.h"
|
||||
#include "subprocess.h"
|
||||
|
||||
// import functions from misc module for convenience
|
||||
namespace linuxdeploy {
|
||||
Submodule
+1
Submodule lib/CImg added at 631cb96120
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user