Skip to content

Commit

Permalink
Merge pull request #1 from haampie/rename
Browse files Browse the repository at this point in the history
Rename package to libtree
  • Loading branch information
haampie authored Apr 12, 2020
2 parents 7abae0d + 04858a9 commit 0b3ec3b
Show file tree
Hide file tree
Showing 18 changed files with 226 additions and 155 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/ccpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ jobs:
run: |
mkdir build
cd build
CXX=g++-8 cmake -DCMAKE_BUILD_TYPE="Release" ..
CXX=g++-8 cmake -DCMAKE_BUILD_TYPE="Release" -DCMAKE_CXX_FLAGS="-Wall -Wextra" -DCMAKE_CXX_FLAGS_RELEASE="-O2" ..
make -j$(nproc)
- name: Bundle
run: |
./build/bundler -e ./build/bundler -e $(which chrpath) -e $(which strip) -d bundler
cp src/bundler bundler/bundler
tar -zcvf bundler_x86_64.tar.gz bundler
./build/libtree -e ./build/libtree -e $(which chrpath) -e $(which strip) -d libtree
cp src/libtree libtree/libtree
tar -zcvf libtree_x86_64.tar.gz libtree
- name: Create Release
id: create_release
uses: actions/create-release@v1
Expand All @@ -44,6 +44,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./bundler_x86_64.tar.gz
asset_name: bundler_x86_64.tar.gz
asset_path: ./libtree_x86_64.tar.gz
asset_name: libtree_x86_64.tar.gz
asset_content_type: application/gzip
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
main
*.swp
build/
Dockerfile
10 changes: 5 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required (VERSION 3.0)
project (bundler)
project (libtree)

message(STATUS "Generating excludelist")
execute_process(
Expand All @@ -18,8 +18,8 @@ set(SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/src/ld.cpp
)

add_executable(bundler ${SOURCE})
target_link_libraries(bundler cxxopts termcolor cppglob ELFIO)
target_include_directories(bundler PRIVATE include deps/cppglob/include ${CMAKE_CURRENT_BINARY_DIR})
add_executable(libtree ${SOURCE})
target_link_libraries(libtree cxxopts termcolor cppglob ELFIO)
target_include_directories(libtree PRIVATE include deps/cppglob/include ${CMAKE_CURRENT_BINARY_DIR})

set_property(TARGET bundler PROPERTY CXX_STANDARD 17)
set_property(TARGET libtree PROPERTY CXX_STANDARD 17)
77 changes: 39 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# bundler
# libtree

A tool that:
- :deciduous_tree: turns `ldd` into a fancy tree
- :point_up: explains why `ldd` finds shared libraries and why not
- :package: optionally deploys relevant executables and dependencies into a single directory
- :deciduous_tree: turns `ldd` into a tree
- :point_up: explains why shared libraries are found and why not
- :package: optionally deploys executables and dependencies into a single directory

## Installation
Download the [**latest release**](https://github.com/haampie/bundler/releases) from Github:
Download the [**latest release**](https://github.com/haampie/libtree/releases) from Github:

```
- wget https://github.com/haampie/bundler/releases/download/v0.1.5/bundler_x86_64.tar.gz
- tar -xzf bundler_x86_64.tar.gz
- ./bundler/bundler -e $(which man)
```bash
$ wget https://github.com/haampie/libtree/releases/download/v1.0.0/libtree_x86_64.tar.gz
$ tar -xzf libtree_x86_64.tar.gz
$ ./libtree/libtree $(which man)
```

## Example 1: listing the dependencies of an executable
Expand All @@ -20,51 +20,52 @@ Download the [**latest release**](https://github.com/haampie/bundler/releases) f

## Example 2: deploying binaries + dependencies into a folder:
```bash
$ bundler -e $(which bundler) -d bundler.bundle
Dependency tree
bundler
├── libcppglob.so.1 [runpath]
│ ├── libstdc++.so.6 (skipped) [ld.so.conf]
│ ├── libgcc_s.so.1 (skipped) [ld.so.conf]
│ └── libc.so.6 (skipped) [ld.so.conf]
├── libstdc++.so.6 (skipped) [ld.so.conf]
├── libgcc_s.so.1 (skipped) [ld.so.conf]
└── libc.so.6 (skipped) [ld.so.conf]
$ libtree $(which libtree) -d libtree.bundle --chrpath --strip
libtree
└── libcppglob.so.1 [runpath]

Deploying to "bundler.bundle/usr"
"/home/.../Documents/projects/bundler/build/bundler" => "bundler.bundle/usr/bin/bundler"
"/home/.../Documents/projects/bundler/build/lib/libcppglob.so.1.1.0" => "bundler.bundle/usr/lib/libcppglob.so.1.1.0"
creating symlink "bundler.bundle/usr/lib/libcppglob.so.1"
Deploying to "libtree.bundle/usr"
"/bundler/build/libtree" => "libtree.bundle/usr/bin/libtree"
"/bundler/build/lib/libcppglob.so.1.1.0" => "libtree.bundle/usr/lib/libcppglob.so.1.1.0"
creating symlink "libtree.bundle/usr/lib/libcppglob.so.1"

$ tree bundler.bundle/
bundler.bundle/
$ tree libtree.bundle/
libtree.bundle/
└── usr
├── bin
   └── bundler
└── libtree
└── lib
├── libcppglob.so.1 -> libcppglob.so.1.1.0
└── libcppglob.so.1.1.0

3 directories, 3 files
```

## Verbose output
By default certain standard depenendencies are not shown. For more verbose output use
- `libtree -v $(which man)` to show skipped libraries without their children
- `libtree -a $(which apt-get)` to show the full recursive list of libraries

## Changing search paths
`libtree` follows the rules of `ld.so` to locate libraries, but does not use `ldconfig`'s
cache. Instead it parses `/etc/ld.so.conf` runtime. The location of the `ld.so` config
can be changed as well by setting `--ldconf mylibs.conf`.

Search paths can be added at runtime as well via `LD_LIBRARY_PATH=path libtree ...`.

## Build from source
```bash
git clone --recursive https://github.com/haampie/bundler.git
cd bundler
git clone --recursive https://github.com/haampie/libtree.git
cd libtree
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
```

## Current functionality
- [x] Add executables with `-e` and libraries via `-l`
- [x] Walks the dependency tree like `ld.so` (handles `RPATH`, `RUNPATH` and `LD_LIBRARY_PATH` correctly).
- [x] Uses `/etc/ld.so.conf` or any custom conf file via `-ldconf /path/to/ld.so.conf`
- [x] Skips blacklisted dependencies (and their dependencies) such as libc.so and libstdc++.so.
- [x] Deploy binaries and rewrite their `RUNPATH`s\*
- [x] Ship `chrpath` and `strip`
- [ ] i386 (currently it's hardcoded to only deploy x86_64)

\* Note: `patchelf` seems to be very broken software, so instead I'm using `chrpath`. The downside is `chrpath` will only patch rpaths _when they already exist in the binary_. Therefore you might still need to add the `yourapp/lib` folder to ld's search paths by running `echo /path/to/yourapp.bundle/lib > /etc/ld.so.conf/my_app.conf && ldconfig` or by setting `LD_LIBRARY_PATH=/path/to/yourapp.bundle/lib`.
## Known issues
- When deploying libs with `libtree app -d folder.bundle --chrpath`, the runpaths are only
changed when the binaries already have an an rpath or runpath. This is a limitation of
`chrpath`. Another option is to use `patchelf` instead, but this tool is known to break
binaries sometimes.
- There's no support yet for i386.
Binary file modified doc/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion include/bundler/deploy.hpp → include/libtree/deploy.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include <bundler/elf.hpp>
#include <libtree/elf.hpp>

#include <filesystem>
#include <vector>
Expand Down
22 changes: 19 additions & 3 deletions include/bundler/deps.hpp → include/libtree/deps.hpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
#pragma once

#include <bundler/elf.hpp>
#include <libtree/elf.hpp>

#include <vector>
#include <filesystem>
#include <optional>
#include <unordered_set>

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

class deps {

public:
deps(std::vector<Elf> &&input, std::vector<fs::path> &&ld_so_conf, std::vector<fs::path> && ld_library_paths, bool verbose);
enum class verbosity_t {NONE, VERBOSE, VERY_VERBOSE};

deps(
std::vector<Elf> &&input,
std::vector<fs::path> &&ld_so_conf,
std::vector<fs::path> &&ld_library_paths,
std::unordered_set<std::string> &&skip,
verbosity_t verbose
);

std::vector<Elf> const &get_deps() const;

private:
void explore(Elf const &elf, std::vector<fs::path> &rpaths, std::vector<bool> &done);
void explore(Elf const &elf, std::vector<fs::path> &rpaths);
void print_error(fs::path const &lib, std::vector<fs::path> const &rpaths, std::vector<fs::path> const &runpaths, std::vector<bool> const &done) const;

std::string get_indent(std::vector<bool> const &done) const;
std::string get_error_indent(std::vector<bool> const &done) const;

std::optional<Elf> locate(Elf const &parent, fs::path const &so, std::vector<fs::path> const &rpaths, std::vector<fs::path> const &runpaths);
std::optional<Elf> locate_directly(Elf const &parent, fs::path const &so);
Expand All @@ -29,8 +44,9 @@ class deps {
std::vector<fs::path> m_ld_so_conf;
std::vector<fs::path> m_default_paths{"/lib", "/usr/lib"};
std::unordered_set<fs::path, PathHash> m_visited;
std::unordered_set<std::string> m_skip;

std::vector<Elf> m_all_binaries;

bool m_verbose;
verbosity_t m_verbosity;
};
File renamed without changes.
File renamed without changes.
File renamed without changes.
22 changes: 12 additions & 10 deletions src/deploy.cpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
#include <bundler/deploy.hpp>
#include <bundler/exec.hpp>
#include <libtree/deploy.hpp>
#include <libtree/exec.hpp>

#include <termcolor/termcolor.hpp>

// Copy binaries over, change their rpath if they have it, and strip them
void deploy(std::vector<Elf> const &deps, fs::path const &bin, fs::path const &lib, fs::path const &chrpath_path, fs::path const &strip_path, bool chrpath, bool strip) {
for (auto const &elf : deps) {

// Go through all symlinks.
auto canonical = fs::canonical(elf.abs_path);

//Copy to the deploy folder
// Copy to the deploy folder
auto deploy_folder = (elf.type == deploy_t::EXECUTABLE ? bin : lib);
auto deploy_path = deploy_folder / canonical.filename();
fs::copy_file(canonical, deploy_path, fs::copy_options::overwrite_existing);

std::cout << termcolor::green << canonical << termcolor::reset << " => " << termcolor::green << deploy_path << termcolor::reset << '\n';

// Create all symlinks
for (auto link = elf.abs_path; fs::is_symlink(link); link = fs::read_symlink(link)) {
auto link_destination = deploy_folder / link.filename();
fs::remove(link_destination);
fs::create_symlink(deploy_path.filename(), link_destination);

std::cout << " " << termcolor::yellow << "creating symlink " << link_destination << '\n';
if (elf.type == deploy_t::LIBRARY) {
for (auto link = elf.abs_path; fs::is_symlink(link); link = fs::read_symlink(link)) {
auto link_destination = deploy_folder / link.filename();
fs::remove(link_destination);
fs::create_symlink(deploy_path.filename(), link_destination);

std::cout << " " << termcolor::yellow << "creating symlink " << link_destination << termcolor::reset << '\n';
}
}

auto rpath = (elf.type == deploy_t::EXECUTABLE ? "\\$ORIGIN/../lib" : "\\$ORIGIN");
Expand Down
Loading

0 comments on commit 0b3ec3b

Please sign in to comment.