100 Commits

Author SHA1 Message Date
Alexis Lopez Zubieta b86ccd46ee Create a symlink instead of copying the file when deployFile is requested with source and target paths inside the AppDir 2018-11-02 21:32:28 -06:00
TheAssassin 83a9690da1 Fix appending of trailing slash 2018-09-04 14:33:25 +02:00
TheAssassin 5fc87e1c1c Fix brackets 2018-09-03 23:33:26 +02:00
TheAssassin 3375de8fc4 Fix path calculation 2018-09-03 23:32:07 +02:00
TheAssassin 906c948304 Move redundant code into separate function 2018-09-03 23:30:53 +02:00
TheAssassin 371343baed Properly set rpath in existing files 2018-09-03 21:07:43 +02:00
TheAssassin 63764e2e18 Show proper version statement 2018-09-03 20:20:16 +02:00
TheAssassin 8441dbb589 Merge pull request #28 from linuxdeploy/issue-18
Deploy 32-bit and 64-bit libraries into separate directories
2018-08-31 20:05:13 +02:00
TheAssassin d13814d784 Fix syntax on 32-bit platforms 2018-08-31 19:59:15 +02:00
TheAssassin cd83c28196 Fix linker issues 2018-08-31 19:53:15 +02:00
TheAssassin f99cac25b5 Deploy 32-bit and 64-bit libraries into separate directories 2018-08-31 19:45:21 +02:00
TheAssassin 11a923b672 Properly handle parsing error 2018-08-31 19:42:40 +02:00
TheAssassin a8aaa09a55 Make sure to populate member variable 2018-08-31 19:41:12 +02:00
TheAssassin 0ced1390ce Improve ELF library, mk. 2 2018-08-31 17:35:45 +02:00
TheAssassin af310722df Make constructor more efficient 2018-08-31 16:49:17 +02:00
TheAssassin dcf1726889 Improve ELF library, mk. 1 2018-08-31 16:48:36 +02:00
TheAssassin ea12263be2 Silence warnings for cpp-subprocess 2018-08-31 15:50:19 +02:00
TheAssassin 9a44a10173 Refactor copyright files deployment 2018-08-30 22:13:01 +02:00
TheAssassin b550e4da21 Run input plugins before deploying icons and desktop files
The input plugins might even fetch these resources somewhere into the
AppDir, and this way, the user can make use of that.
2018-08-28 23:05:45 +02:00
TheAssassin c4167165ad Add note about plugin requests to README 2018-08-28 22:45:11 +02:00
TheAssassin 276c6f2d18 Improve multiplexing of subprocess output
Setting pipes to be non-blocking now, and reading using fgets() instead
of getline(), using std::getline() to read lines after non-blocking read
from pipes.

Fixes #14
2018-08-28 22:35:05 +02:00
TheAssassin 5b54db31cc Fix error message 2018-08-28 15:46:35 +02:00
TheAssassin 4a098896a9 Improve plugin related logging 2018-08-28 15:44:17 +02:00
TheAssassin ec051c3e0c Inform user about wrong usage of plugin parameters 2018-08-28 15:42:26 +02:00
TheAssassin 0741d9441b Offset error message from previous block 2018-08-28 15:41:53 +02:00
TheAssassin 9b1b214142 Install missing dependency 2018-08-27 20:00:05 +02:00
TheAssassin db77174f24 Don't deploy dependencies for existing symlinks
This might lead to unintended side effects, e.g., when bundling
additional resources in a separate prefix for which linuxdeploy is not
needed.
2018-08-27 19:52:36 +02:00
TheAssassin a0b0378d36 Improve handling of strip tool 2018-08-27 19:49:50 +02:00
TheAssassin 388e7d5acb Remove deprecated parameter from build script 2018-08-26 09:38:12 +02:00
TheAssassin cc30bb6bd1 Update README 2018-08-26 09:37:47 +02:00
TheAssassin 0d60f67da3 Always create basic AppDir structure
Fixes #20.
2018-08-25 23:51:06 +02:00
TheAssassin e8dee64447 Deprecate --app-name
It's been a useful parameter, but only in some rare edge cases. Instead,
we'll focus more on desktop files, e.g., using the Icon entry contents
for (re)naming icons, etc.
2018-08-25 23:46:13 +02:00
TheAssassin 36c6be95d6 Remove redundant parameters
CC #22
2018-08-25 23:32:14 +02:00
TheAssassin 2c4fed2fad Add links to docs.appimage.org 2018-08-25 19:08:47 +02:00
TheAssassin 21849f8fbf Fix README 2018-08-25 19:05:16 +02:00
TheAssassin 4de8b6589f Remove unused dependency libmagic
Our use of libmagic isn't very portable, and the checks aren't used
anyway. Therefore removing dependency on libmagic.

Fixes #17.
2018-08-20 23:54:35 +02:00
TheAssassin 7184bcb61d Abort if library is missing 2018-08-11 15:30:06 +02:00
TheAssassin 55d524b136 Fix argument order 2018-08-11 14:56:00 +02:00
TheAssassin 9743988c80 No longer bundle Qt plugin
It's almost always outdated, users will be better off downloading the
upstream AppImage.
2018-08-03 23:34:50 +02:00
TheAssassin 84b614c1ea Fix plugin finding 2018-08-03 23:31:25 +02:00
TheAssassin 1035ef726d Fix include path 2018-08-03 01:22:59 +02:00
TheAssassin 1c7e768b86 Provide interface to linuxdeploy_util 2018-08-03 00:56:16 +02:00
TheAssassin a28181d98c Fix CMake minimum required version 2018-07-31 21:35:06 +02:00
TheAssassin fcd3ad49db Link against shared libmagic library
This allows distro maintainers to build linuxdeploy more easily

CC @adrianschroeter
2018-07-31 16:21:46 +02:00
TheAssassin cc6310cbbd Allow icons with extension 2018-07-31 15:21:38 +02:00
TheAssassin c58d9716b0 Quick fix patchelf build 2018-07-31 15:06:19 +02:00
TheAssassin 3e84f424e7 Debug patchelf build, mk. 5 2018-07-31 14:51:22 +02:00
TheAssassin a386ab19fd Debug patchelf build, mk. 4 2018-07-31 14:35:25 +02:00
TheAssassin 4f84082155 Debug patchelf build, mk. 3 2018-07-31 14:32:01 +02:00
TheAssassin 8aa1bc9d89 Debug patchelf build, mk. 2 2018-07-31 14:25:08 +02:00
TheAssassin 56d9d6b540 Debug patchelf build 2018-07-31 14:20:42 +02:00
TheAssassin 5165301a44 Merge pull request #6 from linuxdeploy/fix_deploy_library_destinationPath
Fix deployLibrary destinationPath construction.
2018-07-18 21:52:05 +02:00
TheAssassin c1452fa870 Merge branch 'master' into fix_deploy_library_destinationPath 2018-07-18 21:46:25 +02:00
Alexis Lopez Zubieta 03cae41d55 Fix deployLibrary destinationPath construction. 2018-07-18 13:34:20 -05:00
TheAssassin c10eafe823 Bundle Qt plugin 2018-07-17 14:19:07 +02:00
TheAssassin 4a7301eba5 Use patchelf v0.8
Seems like 0.10 breaks Qt libraries which expect a symbol called
qt_version_tag in a specific section in the symbols. Patchelf breaks
this by apparently moving the symbols to another section
(section 15 vs. 13).
We found out by looking into the readelf outputs of libQt5Core.so.5.
@azubieta spotted the different numbers, and looked up their meaning.

linuxdeployqt uses the patchelf binaries Debian jessie provides, which
is 0.8. Therefore we try to build that version from source instead,
hoping that this version won't break libraries.

If that doesn't work either, we'll try with the pre-built binaries.
2018-07-13 01:01:53 +02:00
TheAssassin a3cc38d406 Show error message if dependency library cannot be found 2018-07-12 23:39:17 +02:00
TheAssassin 144fd2deb0 Deactivate strip calls if $NO_STRIP is set 2018-07-12 21:08:50 +02:00
TheAssassin b96389a064 Use -n parameter to enhance search for suitable desktop file
In case there's more than a desktop file, the user can specify the
app name using -n <app name>, and linuxdeploy will try to find a
suitable desktop file whose filename starts with the specified app
name.
2018-07-12 18:22:43 +02:00
TheAssassin b156ffc0cb Add stringEndsWith helper 2018-07-12 18:19:37 +02:00
TheAssassin bd052a5b1f Add prefix to every line in plugin output 2018-07-10 15:08:17 +02:00
TheAssassin f06d5e5832 Store plugin name in plugin class 2018-07-10 15:06:39 +02:00
TheAssassin a0ace9f75c Actually build 32-bit patchelf for 32-bit AppImage 2018-07-07 05:29:21 +02:00
TheAssassin 2b7a5928a5 Fix forceDeployLibrary, mk. 2 2018-07-01 02:28:44 +02:00
TheAssassin ec862d0af9 Fix forceDeployLibrary 2018-07-01 01:06:31 +02:00
TheAssassin df61b059d3 Force deploy libraries specified on the CLI 2018-06-30 23:27:02 +02:00
TheAssassin 5baac459b3 Don't upload AppImage plugin 2018-06-30 16:40:15 +02:00
TheAssassin c783be934b Fix build failure 2018-06-30 16:15:37 +02:00
TheAssassin ae6dfcfe21 Bundle AppImage plugin in Docker friendly way 2018-06-30 16:10:35 +02:00
TheAssassin c07025ab8a Fix missing dependency 2018-06-30 00:52:55 +02:00
TheAssassin c438d5ee2b Change build type 2018-06-30 00:52:10 +02:00
TheAssassin ee15c88978 Fix path to CImg 2018-06-30 00:22:59 +02:00
TheAssassin 80fc055373 Use bundled CImg for i386 build 2018-06-30 00:18:59 +02:00
TheAssassin 5d81258547 Bundle CImg for multiarch builds 2018-06-30 00:18:29 +02:00
TheAssassin d57e4750c2 Re-enable parallel builds 2018-06-30 00:18:02 +02:00
TheAssassin ddbca26b1b Try to resolve apt package conflict 2018-06-30 00:03:14 +02:00
TheAssassin 2e503362a0 Remove unused code 2018-06-29 23:51:02 +02:00
TheAssassin 7a2390ea95 Show held packages 2018-06-29 23:47:21 +02:00
TheAssassin 312287d937 Try to fix apt issues, mk. 8 2018-06-29 23:26:33 +02:00
TheAssassin a641ae7fac Try to fix apt issues, mk. 7 2018-06-29 23:20:06 +02:00
TheAssassin b332dc7e7d Try to fix missing header 2018-06-29 22:09:36 +02:00
TheAssassin b16329f8ba Debug missing header 2018-06-29 21:59:52 +02:00
TheAssassin ee6fd2e594 Try to fix apt issues, mk. 6 2018-06-29 21:38:59 +02:00
TheAssassin 4ee5a903ce Try to fix apt issues, mk. 5 2018-06-29 21:34:00 +02:00
TheAssassin 852ac4d038 Try to get rid of duplicate i386 builds on Travis, mk. 2 2018-06-29 21:27:35 +02:00
TheAssassin eea9a5a9f9 Try to get rid of duplicate i386 builds on Travis 2018-06-29 21:24:32 +02:00
TheAssassin b046bef4c9 Try to fix apt issues, mk. 4 2018-06-29 21:22:16 +02:00
TheAssassin e311bc9217 Try to fix apt issues, mk. 3 2018-06-29 21:19:26 +02:00
TheAssassin 0cb0223560 Try to fix apt issues, mk. 2 2018-06-29 21:16:30 +02:00
TheAssassin e7b3a0987a Try to fix apt issues 2018-06-29 21:14:22 +02:00
TheAssassin efb59d6ea7 Install cross compilers 2018-06-29 21:09:08 +02:00
TheAssassin 39ddfc5c79 Install libpng-dev 2018-06-29 21:06:27 +02:00
TheAssassin d5aa361eb4 Fix .travis.yml 2018-06-29 21:03:38 +02:00
TheAssassin 08a1bf9b69 Multiarch builds, mk. 1 2018-06-29 21:00:23 +02:00
TheAssassin eba0d70576 Improve ignores 2018-06-29 20:59:56 +02:00
TheAssassin 1a4d9e8130 Add i386 toolchain 2018-06-29 20:50:14 +02:00
TheAssassin 2b94a4b408 Improve FindLibMagic 2018-06-29 12:31:20 +02:00
TheAssassin dcf4f79059 Fix boost library types 2018-06-29 11:17:27 +02:00
TheAssassin 345fc638b6 Improve README 2018-06-29 11:08:37 +02:00
TheAssassin 8d3284c447 Merge branch 'experimental/standalone-boost'
Fixes #4.
2018-06-29 02:46:35 +02:00
30 changed files with 871 additions and 378 deletions
+3
View File
@@ -1,3 +1,6 @@
cmake-build-*/
*build*/
.idea/
squashfs-root/
tests/
*.AppImage
+3
View File
@@ -73,3 +73,6 @@
[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
+29 -10
View File
@@ -1,19 +1,38 @@
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
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 ..
@@ -27,7 +46,7 @@ after_success:
# 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
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
- bash upload.sh linuxdeploy*.AppImage*
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
branches:
except:
+1 -3
View File
@@ -5,12 +5,10 @@ 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")
add_subdirectory(lib)
+106 -1
View File
@@ -2,4 +2,109 @@
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).
## 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!
+19 -13
View File
@@ -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")
-27
View File
@@ -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)
+5
View File
@@ -0,0 +1,5 @@
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)
+7 -6
View File
@@ -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 = "");
@@ -72,12 +79,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();
+24
View File
@@ -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();
};
}
}
+82 -4
View File
@@ -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,17 +129,87 @@ 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});
auto retcode = process.wait();
return retcode;
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);
if (opfd->revents & POLLIN) {
std::vector<char> lineBuf(16384);
fgets(lineBuf.data(), static_cast<int>(lineBuf.size()), process.output());
std::stringstream ss;
ss << lineBuf.data();
lineBuf.clear();
std::string currentLine;
std::ostringstream oss;
while (std::getline(ss, currentLine)) {
oss << "[" << d->name << "/stdout] " << currentLine << std::endl;
}
linuxdeploy::core::log::ldLog() << oss.str();
}
if (epfd->revents & POLLIN) {
std::vector<char> lineBuf(16384);
fgets(lineBuf.data(), static_cast<int>(lineBuf.size()), process.error());
std::stringstream ss;
ss << lineBuf.data();
lineBuf.clear();
std::string currentLine;
std::ostringstream oss;
while (std::getline(ss, currentLine)) {
oss << "[" << d->name << "/stderr] " << currentLine << std::endl;
}
linuxdeploy::core::log::ldLog() << oss.str();
}
return true;
};
do {
if (!printOutput()) {
ldLog() << LD_ERROR << "Failed to communicate with process" << std::endl;
process.kill();
return -1;
}
} while (process.poll() < 0);
if (!printOutput()) {
ldLog() << LD_ERROR << "Failed to communicate with process" << std::endl;
process.kill();
return -1;
}
return process.retcode();
}
}
}
+6
View File
@@ -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.
*/
@@ -6,10 +6,33 @@
#include <sstream>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
namespace linuxdeploy {
namespace util {
namespace misc {
static bool path_contains_file(boost::filesystem::path dir, boost::filesystem::path file) {
// If dir ends with "/" and isn't the root directory, then the final
// component returned by iterators will include "." and will interfere
// with the std::equal check below, so we strip it before proceeding.
if (dir.filename() == ".")
dir.remove_filename();
// We're also not interested in the file's name.
assert(file.has_filename());
file.remove_filename();
// If dir has more components than file, then file can't possibly
// reside in dir.
auto dir_len = std::distance(dir.begin(), dir.end());
auto file_len = std::distance(file.begin(), file.end());
if (dir_len > file_len)
return false;
// This stops checking when it reaches dir.end(), so it's OK if file
// has more directory components afterward. They won't be checked.
return std::equal(dir.begin(), dir.end(), file.begin());
};
static inline bool ltrim(std::string& s, char to_trim = ' ') {
// TODO: find more efficient way to check whether elements have been removed
size_t initialLength = s.length();
@@ -64,6 +87,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;
}
@@ -1,5 +1,4 @@
// local includes
#include "magicwrapper.h"
#include "misc.h"
// import functions from misc module for convenience
Submodule
+1
Submodule lib/CImg added at 631cb96120
+19 -18
View File
@@ -1,6 +1,7 @@
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)
@@ -15,74 +16,74 @@ target_link_libraries(test_cpp_feather_ini_parser PRIVATE cpp-feather-ini-parser
add_test(test_cpp_feather_ini_parser test_cpp_feather_ini_parser)
if(NOT USE_SYSTEM_BOOST)
add_library(boost_config IMPORTED INTERFACE)
add_library(boost_config INTERFACE)
set_property(TARGET boost_config PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-config/include>")
add_library(boost_utility IMPORTED INTERFACE)
add_library(boost_utility INTERFACE)
set_property(TARGET boost_utility PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-utility/include>")
set_property(TARGET boost_utility PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_predef IMPORTED INTERFACE)
add_library(boost_predef INTERFACE)
set_property(TARGET boost_predef PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-predef/include>")
set_property(TARGET boost_predef PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_assert IMPORTED INTERFACE)
add_library(boost_assert INTERFACE)
set_property(TARGET boost_assert PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-assert/include>")
set_property(TARGET boost_assert PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_core IMPORTED INTERFACE)
add_library(boost_core INTERFACE)
set_property(TARGET boost_core PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-core/include>")
set_property(TARGET boost_core PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_type_traits IMPORTED INTERFACE)
add_library(boost_type_traits INTERFACE)
set_property(TARGET boost_type_traits PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-type_traits/include>")
set_property(TARGET boost_type_traits PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_iterator IMPORTED INTERFACE)
add_library(boost_iterator INTERFACE)
set_property(TARGET boost_iterator PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-iterator/include>")
set_property(TARGET boost_iterator PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_mpl IMPORTED INTERFACE)
add_library(boost_mpl INTERFACE)
set_property(TARGET boost_mpl PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-mpl/include>")
set_property(TARGET boost_mpl PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_preprocessor IMPORTED INTERFACE)
add_library(boost_preprocessor INTERFACE)
set_property(TARGET boost_preprocessor PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-preprocessor/include>")
set_property(TARGET boost_preprocessor PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_static_assert IMPORTED INTERFACE)
add_library(boost_static_assert INTERFACE)
set_property(TARGET boost_static_assert PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-static_assert/include>")
set_property(TARGET boost_static_assert PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_detail IMPORTED INTERFACE)
add_library(boost_detail INTERFACE)
set_property(TARGET boost_detail PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-detail/include>")
set_property(TARGET boost_detail PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_smart_ptr IMPORTED INTERFACE)
add_library(boost_smart_ptr INTERFACE)
set_property(TARGET boost_smart_ptr PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-smart_ptr/include>")
set_property(TARGET boost_smart_ptr PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_throw_exception IMPORTED INTERFACE)
add_library(boost_throw_exception INTERFACE)
set_property(TARGET boost_throw_exception PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-throw_exception/include>")
set_property(TARGET boost_throw_exception PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_io IMPORTED INTERFACE)
add_library(boost_io INTERFACE)
set_property(TARGET boost_io PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-io/include>")
set_property(TARGET boost_io PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_container_hash IMPORTED INTERFACE)
add_library(boost_container_hash INTERFACE)
set_property(TARGET boost_container_hash PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-container_hash/include>")
set_property(TARGET boost_container_hash PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_functional IMPORTED INTERFACE)
add_library(boost_functional INTERFACE)
set_property(TARGET boost_functional PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-functional/include>")
set_property(TARGET boost_functional PROPERTY INTERFACE_LINK_LIBRARIES "boost_config;boost_container_hash")
add_library(boost_range IMPORTED INTERFACE)
add_library(boost_range INTERFACE)
set_property(TARGET boost_range PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-range/include>")
set_property(TARGET boost_range PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
add_library(boost_integer IMPORTED INTERFACE)
add_library(boost_integer INTERFACE)
set_property(TARGET boost_integer PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/boost-integer/include>")
set_property(TARGET boost_integer PROPERTY INTERFACE_LINK_LIBRARIES "boost_config")
+36
View File
@@ -1,3 +1,6 @@
# 3.5 is required for imported boost targets
cmake_minimum_required(VERSION 3.5)
# globally include own includes
include_directories(${PROJECT_SOURCE_DIR}/include)
@@ -10,6 +13,34 @@ else()
set(BOOST_LIBS boost_system boost_filesystem boost_regex)
endif()
# read Git revision ID
# WARNING: this value will be stored in the CMake cache
# to update it, you will have to reset the CMake cache
# (doesn't matter for CI builds like Travis for instance, where there's no permanent CMake cache)
execute_process(
COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# set version and build number
set(VERSION 1-alpha)
if("$ENV{TRAVIS_BUILD_NUMBER}" STREQUAL "")
set(BUILD_NUMBER "<local dev build>")
else()
set(BUILD_NUMBER "Travis build $ENV{TRAVIS_BUILD_NUMBER}")
endif()
# get current date
execute_process(
COMMAND env LC_ALL=C date -u "+%Y-%m-%d %H:%M:%S %Z"
OUTPUT_VARIABLE DATE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_subdirectory(util)
add_subdirectory(plugin)
add_subdirectory(core)
@@ -18,6 +49,11 @@ add_executable(linuxdeploy main.cpp)
target_link_libraries(linuxdeploy linuxdeploy_core args)
set_target_properties(linuxdeploy PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
target_compile_definitions(linuxdeploy PRIVATE -DLD_GIT_COMMIT="${GIT_COMMIT}")
target_compile_definitions(linuxdeploy PRIVATE -DLD_VERSION="${VERSION}")
target_compile_definitions(linuxdeploy PRIVATE -DLD_BUILD_NUMBER="${BUILD_NUMBER}")
target_compile_definitions(linuxdeploy PRIVATE -DLD_BUILD_DATE="${DATE}")
add_executable(plugin_test plugin_test_main.cpp)
target_link_libraries(plugin_test linuxdeploy_plugin)
set_target_properties(plugin_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
+7 -7
View File
@@ -1,14 +1,10 @@
# 3.5 is required for imported boost targets
# 3.6 is required for the PkgConfig module's IMPORTED_TARGET library feature
cmake_minimum_required(VERSION 3.6)
cmake_minimum_required(VERSION 2.8)
# include headers to make CLion happy
file(GLOB HEADERS ${PROJECT_SOURCE_DIR}/include/linuxdeploy/core/*.h)
find_package(Threads)
find_package(LibMagic REQUIRED)
find_package(CImg REQUIRED)
message(STATUS "Generating excludelist")
@@ -17,8 +13,12 @@ execute_process(
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_library(linuxdeploy_core STATIC elf.cpp log.cpp appdir.cpp desktopfile.cpp ${HEADERS})
target_link_libraries(linuxdeploy_core PUBLIC linuxdeploy_plugin linuxdeploy_util ${BOOST_LIBS} subprocess cpp-feather-ini-parser CImg libmagic_static ${CMAKE_THREAD_LIBS_INIT})
add_library(linuxdeploy_core_copyright STATIC copyright.cpp copyright.h copyright_dpkgquery.cpp copyright_dpkgquery.h)
target_link_libraries(linuxdeploy_core_copyright PUBLIC subprocess ${BOOST_LIBS})
add_library(linuxdeploy_core STATIC elf.cpp log.cpp appdir.cpp desktopfile.cpp ${HEADERS})
target_link_libraries(linuxdeploy_core PUBLIC linuxdeploy_plugin linuxdeploy_util ${BOOST_LIBS} subprocess cpp-feather-ini-parser CImg ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(linuxdeploy_core PRIVATE linuxdeploy_core_copyright)
target_include_directories(linuxdeploy_core PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(linuxdeploy_core PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_compile_definitions(linuxdeploy_core PUBLIC -DBOOST_NO_CXX11_SCOPED_ENUMS)
+125 -133
View File
@@ -13,10 +13,14 @@
#include "linuxdeploy/core/appdir.h"
#include "linuxdeploy/core/elf.h"
#include "linuxdeploy/core/log.h"
#include "util.h"
#include "linuxdeploy/util/util.h"
#include "copyright.h"
// auto-generated headers
#include "excludelist.h"
using namespace linuxdeploy::core;
using namespace linuxdeploy::util::misc;
using namespace linuxdeploy::core::log;
using namespace cimg_library;
@@ -44,10 +48,31 @@ namespace linuxdeploy {
// used to automatically rename resources to improve the UX, e.g. icons
std::string appName;
public:
PrivateData() : copyOperations(), stripOperations(), setElfRPathOperations(), visitedFiles(), appDirPath(), appName() {};
std::shared_ptr<copyright::ICopyrightFilesManager> copyrightFilesManager;
public:
PrivateData() : copyOperations(), stripOperations(), setElfRPathOperations(), visitedFiles(), appDirPath(), appName() {
copyrightFilesManager = copyright::ICopyrightFilesManager::getInstance();
};
public:
// calculate library directory name for given ELF file, taking system architecture into account
static std::string getLibraryDirName(const bf::path& path) {
const auto systemElfClass = elf::ElfFile::getSystemElfClass();
const auto elfClass = elf::ElfFile(path).getElfClass();
std::string libDirName = "lib";
if (systemElfClass != elfClass) {
if (elfClass == ELFCLASS32)
libDirName += "32";
else
libDirName += "64";
}
return libDirName;
}
// actually copy file
// mimics cp command behavior
bool copyFile(const bf::path& from, bf::path to, bool overwrite = false) {
@@ -135,8 +160,10 @@ namespace linuxdeploy {
const auto& from = pair.first;
const auto& to = pair.second;
if (!copyFile(from, to))
success = false;
if (path_contains_file(appDirPath, from)) {
success = bf::exists(to) || symlinkFile(from, to, true); // create a symbolic link
} else
success = copyFile(from, to); // copy the file
copyOperations.erase(copyOperations.begin());
}
@@ -144,34 +171,42 @@ namespace linuxdeploy {
if (!success)
return false;
while (!stripOperations.empty()) {
const auto& filePath = *(stripOperations.begin());
if (getenv("NO_STRIP") != nullptr) {
ldLog() << LD_WARNING << "$NO_STRIP environment variable detected, not stripping binaries" << std::endl;
stripOperations.clear();
} else {
const auto stripPath = getStripPath();
if (util::stringStartsWith(elf::ElfFile(filePath).getRPath(), "$")) {
ldLog() << LD_WARNING << "Not calling strip on binary" << filePath << LD_NO_SPACE << ": rpath starts with $" << std::endl;
} else {
ldLog() << "Calling strip on library" << filePath << std::endl;
while (!stripOperations.empty()) {
const auto& filePath = *(stripOperations.begin());
std::map<std::string, std::string> env;
env.insert(std::make_pair(std::string("LC_ALL"), std::string("C")));
if (util::stringStartsWith(elf::ElfFile(filePath).getRPath(), "$")) {
ldLog() << LD_WARNING << "Not calling strip on binary" << filePath << LD_NO_SPACE
<< ": rpath starts with $" << std::endl;
} else {
ldLog() << "Calling strip on library" << filePath << std::endl;
subprocess::Popen proc(
{getStripPath().c_str(), filePath.c_str()},
subprocess::output(subprocess::PIPE),
subprocess::error(subprocess::PIPE),
subprocess::environment(env)
);
std::map<std::string, std::string> env;
env.insert(std::make_pair(std::string("LC_ALL"), std::string("C")));
std::string err = proc.communicate().second.buf.data();
subprocess::Popen proc(
{stripPath.c_str(), filePath.c_str()},
subprocess::output(subprocess::PIPE),
subprocess::error(subprocess::PIPE),
subprocess::environment(env)
);
if (proc.retcode() != 0 &&
!util::stringContains(err, "Not enough room for program headers")) {
ldLog() << LD_ERROR << "Strip call failed:" << err << std::endl;
success = false;
std::string err = proc.communicate().second.buf.data();
if (proc.retcode() != 0 &&
!util::stringContains(err, "Not enough room for program headers")) {
ldLog() << LD_ERROR << "Strip call failed:" << err << std::endl;
success = false;
}
}
}
stripOperations.erase(stripOperations.begin());
stripOperations.erase(stripOperations.begin());
}
}
if (!success)
@@ -194,72 +229,14 @@ namespace linuxdeploy {
return true;
}
// search for copyright file related to given file
// this function utilizes distribution tools like dpkg-query to determine the paths of copyright
// files
std::vector<bf::path> searchForCopyrightFiles(const bf::path& from) {
auto check_command = [](const std::string& command) {
auto p = subprocess::Popen(
command,
subprocess::output(subprocess::PIPE),
subprocess::error(subprocess::PIPE)
);
return p.wait();
};
// cannot deploy copyright files for files in AppDir
if (!util::stringStartsWith(bf::absolute(from).string(), bf::absolute(appDirPath).string())) {
if (check_command("which dpkg-query") == 0) {
ldLog() << LD_DEBUG << "Using dpkg-query to search for copyright files" << std::endl;
auto call = [](const std::initializer_list<const char*>& args) {
auto proc = subprocess::Popen(
args,
subprocess::output(subprocess::PIPE),
subprocess::error(subprocess::PIPE)
);
auto output = proc.communicate();
return std::make_pair(proc.retcode(), output.first);
};
auto dpkgQueryPackages = call({"dpkg-query", "-S", from.c_str()});
if (dpkgQueryPackages.first != 0
|| dpkgQueryPackages.second.buf.empty()
|| dpkgQueryPackages.second.buf.front() == '\0') {
ldLog() << LD_WARNING << "Could not find copyright files for file" << from << "using dpkg-query" << std::endl;
return {};
}
auto packageName = util::split(util::splitLines(dpkgQueryPackages.second.buf.data())[0], ':')[0];
if (!packageName.empty()) {
auto copyrightFilePath = bf::path("/usr/share/doc") / packageName / "copyright";
if (bf::is_regular_file(copyrightFilePath)) {
return {copyrightFilePath};
}
} else {
ldLog() << LD_WARNING << "Could not find copyright files for file" << from << "using dpkg-query" << std::endl;
}
}
} else {
ldLog() << LD_DEBUG << "Cannot deploy copyright files for files in AppDir:" << from << std::endl;
}
ldLog() << LD_DEBUG << "Could not find suitable tool for copyright files deployment, skipping" << from << std::endl;
return {};
}
// search for copyright file for file and deploy it to AppDir
bool deployCopyrightFiles(const bf::path& from, const std::string& logPrefix = "") {
ldLog() << logPrefix << LD_NO_SPACE << "Deploying copyright files for file" << from << std::endl;
auto copyrightFiles = searchForCopyrightFiles(from);
if (copyrightFilesManager == nullptr)
return false;
auto copyrightFiles = copyrightFilesManager->getCopyrightFilesForPath(from);
if (copyrightFiles.empty())
return false;
@@ -302,39 +279,44 @@ namespace linuxdeploy {
auto logPrefix = getLogPrefix(recursionLevel);
ldLog() << logPrefix << LD_NO_SPACE << "Deploying dependencies for ELF file" << path << std::endl;
for (const auto& dependencyPath : elf::ElfFile(path).traceDynamicDependencies()) {
if (!deployLibrary(dependencyPath, recursionLevel + 1))
return false;
try {
for (const auto &dependencyPath : elf::ElfFile(path).traceDynamicDependencies()) {
if (!deployLibrary(dependencyPath, recursionLevel + 1))
return false;
}
} catch (const elf::DependencyNotFoundError& e) {
ldLog() << LD_ERROR << e.what() << std::endl;
return false;
}
return true;
}
static std::string getStripPath() {
// by default, try to use a patchelf next to the linuxdeploy binary
// if that isn't available, fall back to searching for patchelf in the PATH
std::string patchelfPath = "strip";
// by default, try to use a strip next to the linuxdeploy binary
// if that isn't available, fall back to searching for strip in the PATH
std::string stripPath = "strip";
auto binDirPath = bf::path(util::getOwnExecutablePath());
auto localStripPath = binDirPath.parent_path() / "strip";
auto binDirPath = bf::path(util::getOwnExecutablePath()).parent_path();
auto localStripPath = binDirPath / "strip";
if (bf::exists(localStripPath))
patchelfPath = localStripPath.string();
stripPath = localStripPath.string();
ldLog() << LD_DEBUG << "Using strip:" << patchelfPath << std::endl;
ldLog() << LD_DEBUG << "Using strip:" << stripPath << std::endl;
return patchelfPath;
return stripPath;
}
bool deployLibrary(const bf::path& path, int recursionLevel = 0, const bf::path& destination = "") {
bool deployLibrary(const bf::path& path, int recursionLevel = 0, bool forceDeploy = false,const bf::path &destination = bf::path()) {
auto logPrefix = getLogPrefix(recursionLevel);
if (hasBeenVisitedAlready(path)) {
if (!forceDeploy && hasBeenVisitedAlready(path)) {
ldLog() << LD_DEBUG << logPrefix << LD_NO_SPACE << "File has been visited already:" << path << std::endl;
return true;
}
static auto isInExcludelist = [&logPrefix](const bf::path& fileName) {
for (const auto& excludePattern : generatedExcludelist) {
// simple string match is faster than using fnmatch
@@ -356,7 +338,7 @@ namespace linuxdeploy {
return false;
};
if (isInExcludelist(path.filename())) {
if (!forceDeploy && isInExcludelist(path.filename())) {
ldLog() << logPrefix << LD_NO_SPACE << "Skipping deployment of blacklisted library" << path << std::endl;
// mark file as visited
@@ -365,12 +347,21 @@ namespace linuxdeploy {
return true;
}
// note for self: make sure to have a trailing slash in libraryDir, otherwise copyFile won't
// create a directory
bf::path libraryDir = appDirPath / "usr" / (getLibraryDirName(path) + "/");
ldLog() << logPrefix << LD_NO_SPACE << "Deploying shared library" << path;
if (!destination.empty())
ldLog() << " (destination:" << destination << LD_NO_SPACE << ")";
ldLog() << std::endl;
auto destinationPath = destination.empty() ? appDirPath / "usr/lib/" : destination;
auto destinationPath = destination.empty() ? libraryDir : destination;
// not sure whether this is 100% bullet proof, but it simulates the cp command behavior
if (destinationPath.string().back() == '/' || bf::is_directory(destinationPath)) {
destinationPath /= path.filename();
}
deployFile(path, destinationPath);
deployCopyrightFiles(path, logPrefix);
@@ -389,12 +380,13 @@ namespace linuxdeploy {
rpathDestination = destination.parent_path().string();
}
auto relPath = bf::relative(bf::absolute(appDirPath) / "usr/lib", bf::absolute(rpathDestination));
auto relPath = bf::relative(bf::absolute(libraryDir), bf::absolute(rpathDestination));
rpath = "$ORIGIN/" + relPath.string() + ":$ORIGIN";
}
setElfRPathOperations[destinationPath / path.filename()] = rpath;
stripOperations.insert(destinationPath / path.filename());
setElfRPathOperations[destinationPath] = rpath;
stripOperations.insert(destinationPath);
if (!deployElfDependencies(path, recursionLevel))
return false;
@@ -417,7 +409,7 @@ namespace linuxdeploy {
deployFile(path, destinationPath);
deployCopyrightFiles(path);
std::string rpath = "$ORIGIN/../lib";
std::string rpath = "$ORIGIN/../" + getLibraryDirName(path);
if (!destination.empty()) {
std::string rpathDestination = destination.string();
@@ -431,7 +423,7 @@ namespace linuxdeploy {
rpathDestination = destination.parent_path().string();
}
auto relPath = bf::relative(bf::absolute(appDirPath) / "usr/lib", bf::absolute(rpathDestination));
auto relPath = bf::relative(bf::absolute(appDirPath) / "usr" / getLibraryDirName(path), bf::absolute(rpathDestination));
rpath = "$ORIGIN/" + relPath.string();
}
@@ -578,7 +570,11 @@ namespace linuxdeploy {
}
bool AppDir::deployLibrary(const bf::path& path, const bf::path& destination) {
return d->deployLibrary(path, 0, destination);
return d->deployLibrary(path, 0, false, destination);
}
bool AppDir::forceDeployLibrary(const bf::path& path, const bf::path& destination) {
return d->deployLibrary(path, 0, true, destination);
}
bool AppDir::deployExecutable(const bf::path& path, const boost::filesystem::path& destination) {
@@ -683,7 +679,13 @@ namespace linuxdeploy {
for (const auto& iconPath : foundIconPaths) {
ldLog() << LD_DEBUG << "Icon found:" << iconPath << std::endl;
if (iconPath.stem() == iconName) {
const bool matchesFilenameWithExtension = iconPath.filename() == iconName;
if (iconPath.stem() == iconName || matchesFilenameWithExtension) {
if (matchesFilenameWithExtension) {
ldLog() << LD_WARNING << "Icon= entry filename contains extension" << std::endl;
}
ldLog() << "Deploying icon to AppDir root:" << iconPath << std::endl;
if (!d->symlinkFile(iconPath, path())) {
@@ -768,20 +770,10 @@ namespace linuxdeploy {
return d->deployFile(from, to, true);
}
void AppDir::setAppName(const std::string& appName) {
d->appName = appName;
}
std::vector<bf::path> AppDir::listExecutables() {
util::magic::Magic magic;
std::vector<bf::path> executables;
for (const auto& file : listFilesInDirectory(path() / "usr" / "bin", false)) {
auto fileType = magic.fileType(bf::absolute(file).string());
ldLog() << LD_DEBUG << "Type of file" << file << LD_NO_SPACE << ":" << fileType << std::endl;
// make sure it's an ELF file
try {
elf::ElfFile elfFile(file);
@@ -790,23 +782,16 @@ namespace linuxdeploy {
continue;
}
// if (util::stringStartsWith(fileType, "application/x-executable"))
executables.push_back(file);
executables.push_back(file);
}
return executables;
}
std::vector<bf::path> AppDir::listSharedLibraries() {
util::magic::Magic magic;
std::vector<bf::path> sharedLibraries;
for (const auto& file : listFilesInDirectory(path() / "usr" / "lib", true)) {
auto fileType = magic.fileType(bf::absolute(file).string());
ldLog() << LD_DEBUG << "Type of file" << file << LD_NO_SPACE << ":" << fileType << std::endl;
// make sure it's an ELF file
try {
elf::ElfFile elfFile(file);
@@ -815,8 +800,7 @@ namespace linuxdeploy {
continue;
}
// if (util::stringStartsWith(fileType, "application/x-sharedlib"))
sharedLibraries.push_back(file);
sharedLibraries.push_back(file);
}
return sharedLibraries;
@@ -824,13 +808,21 @@ namespace linuxdeploy {
bool AppDir::deployDependenciesForExistingFiles() {
for (const auto& executable : listExecutables()) {
if (bf::is_symlink(executable))
continue;
if (!d->deployElfDependencies(executable))
return false;
d->setElfRPathOperations[executable] = "$ORIGIN/../lib";
std::string rpath = "$ORIGIN/../" + PrivateData::getLibraryDirName(executable);
d->setElfRPathOperations[executable] = rpath;
}
for (const auto& sharedLibrary : listSharedLibraries()) {
if (bf::is_symlink(sharedLibrary))
continue;
if (!d->deployElfDependencies(sharedLibrary))
return false;
+34
View File
@@ -0,0 +1,34 @@
// local includes
#include "linuxdeploy/core/log.h"
#include "copyright.h"
// specializations
#include "copyright_dpkgquery.h"
namespace linuxdeploy {
namespace core {
namespace copyright {
using namespace log;
std::shared_ptr<ICopyrightFilesManager> ICopyrightFilesManager::getInstance() {
auto check_command = [](const std::string& command) {
auto p = subprocess::Popen(
command,
subprocess::output(subprocess::PIPE),
subprocess::error(subprocess::PIPE)
);
return p.wait();
};
if (check_command("which dpkg-query") == 0) {
ldLog() << LD_DEBUG << "Using dpkg-query to search for copyright files" << std::endl;
return std::make_shared<DpkgQueryCopyrightFilesManager>();
}
ldLog() << LD_DEBUG << "No usable copyright files manager implementation found" << std::endl;
return nullptr;
}
}
}
}

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