4 Commits

Author SHA1 Message Date
TheAssassin b7a2e39ba2 Try to build for arm64, mk. 4 2019-12-03 02:04:02 +01:00
TheAssassin d9acb6b244 Try to build for arm64, mk. 3 2019-12-03 01:50:59 +01:00
TheAssassin 891359edf4 Try to build for arm64, mk. 2 2019-12-03 01:47:18 +01:00
TheAssassin f68f8b94e0 Try to build for arm64, mk. 1 2019-12-03 01:38:28 +01:00
46 changed files with 575 additions and 1320 deletions
+3
View File
@@ -1,3 +1,6 @@
[submodule "lib/cpp-subprocess"]
path = lib/cpp-subprocess
url = https://github.com/arun11299/cpp-subprocess.git
[submodule "lib/args"]
path = lib/args
url = https://github.com/Taywee/args.git
+39 -21
View File
@@ -1,10 +1,34 @@
language: cpp
sudo: required
matrix:
include:
- name: Ubuntu bionic x86_64 release build
env: ARCH=x86_64
- name: CentOS 6 x86_64 build
env: ARCH=x86_64 BUILD_TYPE=centos6
install: true
services:
- docker
script: travis/build-centos6-docker.sh
after_success:
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
- name: CentOS 6 i386 build
env: ARCH=i386 BUILD_TYPE=centos6
install: true
services:
- docker
script: travis/build-centos6-docker.sh
after_success:
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
- name: Ubuntu bionic arm64 build
env: ARCH=arm64 BUILD_TYPE=arm64-native
dist: bionic
arch: arm64
addons:
apt:
update: true
@@ -13,26 +37,19 @@ matrix:
- libjpeg-dev
- libpng-dev
- cimg-dev
script: travis/build.sh
after_success:
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
- bash upload.sh linuxdeploy-"$ARCH".AppImage*
- patchelf
before_script:
- git clone https://github.com/NixOS/patchelf.git && \
- pushd patchelf && \
- # cannot use -b since it's not supported in really old versions of git
- git checkout 0.8 && \
- ./bootstrap.sh && \
- ./configure --prefix=/usr && \
- make -j $(nproc) && \
- make install && \
- popd && \
- rm -r patchelf/
- name: Ubuntu bionic i386 build
env: ARCH=i386
dist: bionic
addons:
apt:
update: true
packages:
- libmagic-dev:i386
- libjpeg-dev:i386
- libpng-dev:i386
- gcc-multilib
- g++-multilib
- libfuse2:i386
- libcairo2:i386
script: travis/build.sh
after_success:
- if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ] && [ "$TRAVIS_BRANCH" != "master" ]; then export TRAVIS_EVENT_TYPE=pull_request; fi
@@ -74,6 +91,7 @@ matrix:
script: travis/test-coverage.sh
after_success: true # also, we don't intend to upload release binaries
branches:
except:
- # Do not build tags that we create when we upload to GitHub Releases
+5
View File
@@ -10,6 +10,11 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/Modules/
set(USE_SYSTEM_BOOST OFF CACHE BOOL "Set to ON to use system boost libraries instead of building up to date boost libraries from source")
set(USE_SYSTEM_CIMG ON CACHE BOOL "Set to OFF to use CImg library bundled in lib directory")
if (EXISTS "${PROJECT_SOURCE_DIR}/lib/cpp-subprocess/subprocess.hpp")
else()
message (FATAL_ERROR "Missing submodule(s), please 'git submodule update --init --recursive'...")
endif()
# support for ccache
# call CMake with -DUSE_CCACHE=ON to make use of it
set(USE_CCACHE ON CACHE BOOL "")
+1 -2
View File
@@ -16,7 +16,7 @@ linuxdeploy was greatly influenced by [linuxdeployqt](https://github.com/probono
## User guides and examples
Please see the [linuxdeploy user guide](https://docs.appimage.org/packaging-guide/from-source/linuxdeploy-user-guide.html) and the [native binaries packaging guide](https://docs.appimage.org/packaging-guide/from-source/native-binaries.html) in the [AppImage documentation](https://docs.appimage.org). There's also an [examples section](https://docs.appimage.org/packaging-guide/from-source/native-binaries.html#examples).
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
@@ -29,7 +29,6 @@ This is an incomplete list of projects using linuxdeploy. You might want to read
- [AppImageUpdate](https://github.com/AppImage/AppImageUpdate)
- [appimaged](https://github.com/AppImage/appimaged)
- [MediaElch](https://github.com/Komet/MediaElch/)
- [CPU-X](https://github.com/X0rg/CPU-X) (details available [here](https://github.com/AppImage/AppImageKit/wiki/Bundling-GTK3-apps#fully-automated-deployment-from-sources-with-github-actions-cpu-x))
## Plugins
+5 -41
View File
@@ -1,35 +1,8 @@
# required for PNG imported target
cmake_minimum_required(VERSION 3.6)
cmake_minimum_required(VERSION 3.5)
find_package(PkgConfig)
pkg_check_modules(libpng REQUIRED IMPORTED_TARGET libpng)
# build custom static version of libjpeg for static builds
if(STATIC_BUILD)
include(ExternalProject)
if($ENV{ARCH} MATCHES "i[356]86")
set(configure_command_prefix env CFLAGS=-m32 CXXFLAGS=-m32)
endif()
ExternalProject_Add(libjpeg_static_extproj
URL https://www.ijg.org/files/jpegsrc.v9d.tar.gz
URL_HASH SHA256=99cb50e48a4556bc571dadd27931955ff458aae32f68c4d9c39d624693f69c32
BUILD_IN_SOURCE ON
EXCLUDE_FROM_ALL ON
CONFIGURE_COMMAND ${configure_command_prefix} ./configure --prefix=/usr
INSTALL_COMMAND ""
)
ExternalProject_Get_property(libjpeg_static_extproj SOURCE_DIR)
add_library(libjpeg_static INTERFACE IMPORTED)
set_property(TARGET libjpeg_static PROPERTY INTERFACE_LINK_LIBRARIES ${SOURCE_DIR}/.libs/libjpeg.a)
add_dependencies(libjpeg_static libjpeg_static_extproj)
set(JPEG_LIBRARIES libjpeg_static)
else()
find_package(JPEG REQUIRED)
endif()
find_package(PNG REQUIRED)
find_package(JPEG REQUIRED)
if(NOT USE_SYSTEM_CIMG)
message(STATUS "Using bundled CImg library")
@@ -49,16 +22,7 @@ else()
endif()
endif()
set(PNG_INCLUDE_DIR ${libpng_INCLUDE_DIRS})
if(NOT STATIC_BUILD)
set(PNG_LIBRARY ${libpng_LIBRARIES})
else()
set(PNG_LIBRARY ${libpng_STATIC_LIBRARIES})
endif()
#message(FATAL_ERROR "${PNG_LIBRARY}")
add_library(CImg INTERFACE)
set_property(TARGET CImg PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${CIMG_H_DIR};${PNG_INCLUDE_DIR};${JPEG_INCLUDE_DIR}")
set_property(TARGET CImg PROPERTY INTERFACE_LINK_LIBRARIES "${PNG_LIBRARY};${JPEG_LIBRARIES}")
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")
-8
View File
@@ -57,20 +57,12 @@ namespace linuxdeploy {
// deploy executable
bool deployExecutable(const boost::filesystem::path& path, const boost::filesystem::path& destination = "");
// deploy dependencies for ELF file in AppDir, without copying it into the library dir
//
// the dependencies end up in the regular location
bool deployDependenciesOnlyForElfFile(const boost::filesystem::path& elfFilePath, bool failSilentForNonElfFile = false);
// deploy desktop file
bool deployDesktopFile(const desktopfile::DesktopFile& desktopFile);
// deploy icon
bool deployIcon(const boost::filesystem::path& path);
// deploy icon, changing its name to <target filename>.<ext>
bool deployIcon(const boost::filesystem::path& path, const std::string& targetFilename);
// deploy arbitrary file
boost::filesystem::path deployFile(const boost::filesystem::path& from, const boost::filesystem::path& to);
-2
View File
@@ -65,8 +65,6 @@ namespace linuxdeploy {
ldLog operator<<(stdEndlType strm);
ldLog operator<<(const LD_LOGLEVEL logLevel);
ldLog operator<<(const LD_STREAM_CONTROL streamControl);
void write(const char* s, const size_t n);
};
}
}
+136 -20
View File
@@ -2,19 +2,15 @@
#include <set>
#include <string>
#include <vector>
#include <fcntl.h>
#include <poll.h>
// library headers
#include <boost/filesystem.hpp>
#include <fnmatch.h>
#include <thread>
#include <subprocess.hpp>
// local headers
#include "linuxdeploy/core/log.h"
#include "linuxdeploy/util/util.h"
#include "linuxdeploy/subprocess/process.h"
#include "linuxdeploy/plugin/plugin_process_handler.h"
#pragma once
@@ -49,20 +45,13 @@ namespace linuxdeploy {
private:
int getApiLevelFromExecutable() {
const auto arg = "--plugin-api-version";
const subprocess::subprocess proc({pluginPath.string(), arg});
const auto stdoutOutput = proc.check_output();
if (stdoutOutput.empty()) {
ldLog() << LD_WARNING << "received empty response from plugin" << pluginPath << "while trying to fetch data for" << "--plugin-api-version" << std::endl;
return -1;
}
auto output = subprocess::check_output({pluginPath.c_str(), "--plugin-api-version"});
std::string stdoutOutput = output.buf.data();
try {
auto apiLevel = std::stoi(stdoutOutput);
return apiLevel;
} catch (const std::exception&) {
} catch (const std::invalid_argument&) {
return -1;
}
}
@@ -73,8 +62,9 @@ namespace linuxdeploy {
// check whether plugin implements --plugin-type
try {
const subprocess::subprocess proc({pluginPath.c_str(), "--plugin-type"});
const auto stdoutOutput = proc.check_output();
auto output = subprocess::check_output({pluginPath.c_str(), "--plugin-type"});
std::string stdoutOutput = output.buf.data();
// the specification requires a single line, but we'll silently accept more than that, too
if (std::count(stdoutOutput.begin(), stdoutOutput.end(), '\n') >= 1) {
@@ -85,7 +75,7 @@ namespace linuxdeploy {
else if (firstLine == "output")
type = OUTPUT_TYPE;
}
} catch (const std::logic_error&) {}
} catch (const subprocess::CalledProcessError&) {}
return type;
}
@@ -136,8 +126,134 @@ namespace linuxdeploy {
template<int API_LEVEL>
int PluginBase<API_LEVEL>::run(const boost::filesystem::path& appDirPath) {
plugin_process_handler handler(d->name, path());
return handler.run(appDirPath);
auto pluginPath = path();
auto args = {pluginPath.c_str(), "--appdir", appDirPath.string().c_str()};
auto log = ldLog();
log << "Running process:";
for (const auto& arg : args) {
log << "" << arg;
}
log << std::endl;
auto process = subprocess::Popen(args, subprocess::output{subprocess::PIPE}, subprocess::error{subprocess::PIPE});
std::vector<pollfd> pfds(2);
auto* opfd = &pfds[0];
auto* epfd = &pfds[1];
opfd->fd = fileno(process.output());
opfd->events = POLLIN;
epfd->fd = fileno(process.error());
epfd->events = POLLIN;
for (const auto& fd : {process.output(), process.error()}) {
auto flags = fcntl(fileno(fd), F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fileno(fd), F_SETFL, flags);
}
auto printOutput = [&pfds, opfd, epfd, this, &process]() {
poll(pfds.data(), pfds.size(), -1);
auto printUntilLastLine = [this](std::vector<char>& buf, size_t& bufSize, const std::string& streamType) {
std::ostringstream oss;
while (true) {
const auto firstLineFeed = std::find(buf.begin(), buf.end(), '\n');
const auto firstCarriageReturn = std::find(buf.begin(), buf.end(), '\r');
if (firstLineFeed == buf.end() && firstCarriageReturn == buf.end())
break;
const auto endOfLine = std::min(firstLineFeed, firstCarriageReturn);
std::string line(buf.begin(), endOfLine+1);
oss << "[" << d->name << "/" << streamType << "] " << line;
bufSize -= std::distance(buf.begin(), endOfLine+1);
buf.erase(buf.begin(), endOfLine+1);
}
auto messages = oss.str();
if (!messages.empty())
ldLog() << messages;
};
std::vector<char> stdoutBuf(16 * 1024);
std::vector<char> stderrBuf(16 * 1024);
size_t stdoutBufSize = 0;
size_t stderrBufSize = 0;
if (opfd->revents & POLLIN) {
if (stdoutBufSize >= stdoutBuf.size())
throw std::runtime_error("Buffer overflow");
while (true) {
auto bytesRead = fread(
reinterpret_cast<void*>(stdoutBuf.data() + stdoutBufSize),
sizeof(char),
static_cast<size_t>(stdoutBuf.size() - stdoutBufSize),
process.output()
);
if (bytesRead == 0)
break;
stdoutBufSize += bytesRead;
printUntilLastLine(stdoutBuf, stdoutBufSize, "stdout");
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
if (epfd->revents & POLLIN) {
if (stderrBufSize >= stderrBuf.size())
throw std::runtime_error("Buffer overflow");
while (true) {
auto bytesRead = fread(
reinterpret_cast<void*>(stderrBuf.data() + stderrBufSize),
sizeof(char),
static_cast<size_t>(stderrBuf.size() - stderrBufSize),
process.error()
);
if (bytesRead == 0)
break;
stderrBufSize += bytesRead;
printUntilLastLine(stderrBuf, stderrBufSize, "stderr");
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(50));
return true;
};
int retcode;
do {
if (!printOutput()) {
ldLog() << LD_ERROR << "Failed to communicate with process" << std::endl;
process.kill();
return -1;
}
} while ((retcode = process.poll()) < 0);
if (!printOutput()) {
ldLog() << LD_ERROR << "Failed to communicate with process" << std::endl;
process.kill();
return -1;
}
return retcode;
}
}
}
@@ -1,19 +0,0 @@
#pragma once
// library headers
#include <boost/filesystem/path.hpp>
namespace linuxdeploy {
namespace plugin {
class plugin_process_handler {
private:
std::string name_;
boost::filesystem::path path_;
public:
plugin_process_handler(std::string name, boost::filesystem::path path);
int run(const boost::filesystem::path& appDir) const;
};
}
}
@@ -1,36 +0,0 @@
#pragma once
#include <string>
#include <set>
#include <vector>
#include <poll.h>
/**
* Reads from a pipe when data is available, and hands data to registered callbacks.
*/
class pipe_reader {
private:
const int pipe_fd_;
public:
/**
* Construct new instance from pipe file descriptor.
* @param pipe_fd file descriptor for pipe we will read from (e.g., a subprocess's stdout, stderr pipes)
*/
explicit pipe_reader(int pipe_fd);
/**
* Read from pipe file descriptor and store data in buffer.
* This method is non-blocking, i.e., if there is no data to read, it returns immediately.
* Otherwise, it will read until either of the following conditions is met:
*
* - no more data left in the pipe to be read
* - buffer is completely filled
*
* On errors, a subprocess_error is thrown.
*
* @param buffer buffer to store read data into
* @returns amount of characters read from the pipe
*/
size_t read(std::vector<std::string::value_type>& buffer) const;
};
-86
View File
@@ -1,86 +0,0 @@
// system headers
#include <unordered_map>
#include <vector>
#include <signal.h>
// local headers
#include "linuxdeploy/subprocess/subprocess.h"
namespace linuxdeploy {
namespace subprocess {
class process {
private:
// child process ID
int child_pid_ = -1;
// pipes to child process's stdout/stderr
int stdout_fd_ = -1;
int stderr_fd_ = -1;
// process exited
bool exited_ = false;
// exit code -- will be initialized by close()
int exit_code_ = -1;
// these constants help make the pipe code more readable
static constexpr int READ_END_ = 0, WRITE_END_ = 1;
static std::vector<char*> make_args_vector_(const std::vector<std::string>& args);
static std::vector<char*> make_env_vector_(const subprocess_env_map_t& env);
static int check_waitpid_status_(int status);
public:
/**
* Create a child process.
* @param args parameters for process
* @param env additional environment variables (current environment will be copied)
*/
process(std::initializer_list<std::string> args, const subprocess_env_map_t& env);
/**
* Create a child process.
* @param args parameters for process
* @param env additional environment variables (current environment will be copied)
*/
process(const std::vector<std::string>& args, const subprocess_env_map_t& env);
~process();
/**
* @return child process's ID
*/
int pid() const;
/**
* @return child process's stdout file descriptor ID
*/
int stdout_fd() const;
/**
* @return child process's stderr file descriptor ID
*/
int stderr_fd() const;
/**
* Close all pipes and wait for process to exit.
* If process is not running any more, just returns exit code.
* @return child process's exit code
*/
int close();
/**
* Kill underlying process with given signal. By default, SIGTERM is used to end the process.
*/
void kill(int signal = SIGTERM) const;
/**
* Check whether process is still alive. Use close() to fetch exit code.
* @return true while process is alive, false otherwise
*/
bool is_running();
};
}
}
@@ -1,32 +0,0 @@
#pragma once
// system headers
#include <cstdio>
#include <unordered_map>
#include <string>
#include <utility>
#include <vector>
// local headers
#include "subprocess_result.h"
namespace linuxdeploy {
namespace subprocess {
typedef std::unordered_map<std::string, std::string> subprocess_env_map_t;
class subprocess {
private:
std::vector<std::string> args_{};
std::unordered_map<std::string, std::string> env_{};
public:
subprocess(std::initializer_list<std::string> args, subprocess_env_map_t env = {});
explicit subprocess(std::vector<std::string> args, subprocess_env_map_t env = {});
subprocess_result run() const;
std::string check_output() const;
};
}
}
@@ -1,37 +0,0 @@
#pragma once
// system headers
#include <cstdlib>
#include <string>
#include <utility>
#include <vector>
namespace linuxdeploy {
namespace subprocess {
typedef std::vector<std::string::value_type> subprocess_result_buffer_t;
/**
* Result of subprocess execution. Follows Value Object design pattern.
*/
class subprocess_result {
private:
int exit_code_;
subprocess_result_buffer_t stdout_contents_;
subprocess_result_buffer_t stderr_contents_;
public:
subprocess_result(int exit_code, subprocess_result_buffer_t stdout_contents,
subprocess_result_buffer_t stderr_contents);
int exit_code() const;
const subprocess_result_buffer_t& stdout_contents() const;
std::string stdout_string() const;
const subprocess_result_buffer_t& stderr_contents() const;
std::string stderr_string() const;
};
}
}
-17
View File
@@ -1,17 +0,0 @@
#pragma once
// system headers
#include <stdexcept>
namespace linuxdeploy {
namespace util {
namespace assert {
template<typename T>
void assert_not_empty(T container) {
if (container.empty()) {
throw std::invalid_argument{"container must not be empty"};
}
}
}
}
}
-31
View File
@@ -1,6 +1,5 @@
#pragma once
// system headers
#include <algorithm>
#include <climits>
#include <cstring>
@@ -9,9 +8,6 @@
#include <unistd.h>
#include <vector>
// libraries
#include <boost/filesystem.hpp>
namespace linuxdeploy {
namespace util {
namespace misc {
@@ -91,33 +87,6 @@ namespace linuxdeploy {
return buf.data();
}
// very simple but for our purposes good enough which like algorithm to find binaries in $PATH
static boost::filesystem::path which(const std::string& name) {
const auto* path = getenv("PATH");
namespace bf = boost::filesystem;
if (path == nullptr)
return "";
for (const auto& binDir : split(path, ':')) {
if (!bf::is_directory(binDir)) {
continue;
}
for (bf::directory_iterator it(binDir); it != bf::directory_iterator{}; ++it) {
const auto binary = it->path();
if (binary.filename() == name) {
// TODO: check if file is executable (skip otherwise)
return binary;
}
}
}
return {};
};
}
}
}
+19
View File
@@ -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);
}
}
}
+2 -3
View File
@@ -1,11 +1,10 @@
// local includes
#include "linuxdeploy/util/assert.h"
#include "linuxdeploy/util/misc.h"
#include "misc.h"
#include "subprocess.h"
// import functions from misc module for convenience
namespace linuxdeploy {
namespace util {
using namespace misc;
using namespace assert;
}
}
+5
View File
@@ -1,5 +1,10 @@
include(CTest)
add_library(subprocess INTERFACE)
target_sources(subprocess INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-subprocess/subprocess.hpp)
target_include_directories(subprocess INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/cpp-subprocess)
target_compile_options(subprocess INTERFACE "-Wno-deprecated")
add_library(args INTERFACE)
target_sources(args INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/args/args.hxx)
target_include_directories(args INTERFACE args)
Submodule lib/cpp-subprocess added at 6931e3d69f
+1 -9
View File
@@ -43,7 +43,6 @@ execute_process(
add_subdirectory(util)
add_subdirectory(plugin)
add_subdirectory(subprocess)
add_subdirectory(core)
add_executable(linuxdeploy main.cpp core.cpp)
@@ -55,18 +54,11 @@ 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}")
if(STATIC_BUILD)
message(WARNING "static builds enabled")
cmake_minimum_required(VERSION 3.13)
target_link_options(linuxdeploy PUBLIC -static -static-libgcc -static-libstdc++)
endif()
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")
add_executable(appdir_test appdir_test_main.cpp ../include/linuxdeploy/util/assert.h)
add_executable(appdir_test appdir_test_main.cpp)
target_link_libraries(appdir_test linuxdeploy_core args)
target_include_directories(appdir_test PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/core)
set_target_properties(appdir_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")

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