Merge pull request #1030 from pikajude/rsd-cc
Implement resolve-system-dependencies in C++
This commit is contained in:
		
						commit
						aa1ea0d1e4
					
				
					 7 changed files with 207 additions and 147 deletions
				
			
		
							
								
								
									
										1
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
					@ -13,6 +13,7 @@ makefiles = \
 | 
				
			||||||
  src/nix-collect-garbage/local.mk \
 | 
					  src/nix-collect-garbage/local.mk \
 | 
				
			||||||
  src/nix-prefetch-url/local.mk \
 | 
					  src/nix-prefetch-url/local.mk \
 | 
				
			||||||
  src/buildenv/local.mk \
 | 
					  src/buildenv/local.mk \
 | 
				
			||||||
 | 
					  src/resolve-system-dependencies/local.mk \
 | 
				
			||||||
  perl/local.mk \
 | 
					  perl/local.mk \
 | 
				
			||||||
  scripts/local.mk \
 | 
					  scripts/local.mk \
 | 
				
			||||||
  corepkgs/local.mk \
 | 
					  corepkgs/local.mk \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								configure.ac
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								configure.ac
									
										
									
									
									
								
							| 
						 | 
					@ -246,23 +246,6 @@ AC_MSG_RESULT(yes)
 | 
				
			||||||
AC_SUBST(perlFlags)
 | 
					AC_SUBST(perlFlags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Check for otool, an optional dependency on Darwin.
 | 
					 | 
				
			||||||
AC_PATH_PROG(otool, otool)
 | 
					 | 
				
			||||||
AC_MSG_CHECKING([that otool works])
 | 
					 | 
				
			||||||
case $host_os in
 | 
					 | 
				
			||||||
  darwin*)
 | 
					 | 
				
			||||||
    if test -z "$otool" || ! $otool --version 2>/dev/null; then
 | 
					 | 
				
			||||||
      AC_MSG_RESULT(no)
 | 
					 | 
				
			||||||
      AC_MSG_ERROR([Can't get version from otool; do you need to install developer tools?])
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    AC_MSG_RESULT(yes)
 | 
					 | 
				
			||||||
    ;;
 | 
					 | 
				
			||||||
  *)
 | 
					 | 
				
			||||||
    AC_MSG_RESULT(not needed)
 | 
					 | 
				
			||||||
    ;;
 | 
					 | 
				
			||||||
esac
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Whether to build the Perl bindings
 | 
					# Whether to build the Perl bindings
 | 
				
			||||||
AC_MSG_CHECKING([whether to build the Perl bindings])
 | 
					AC_MSG_CHECKING([whether to build the Perl bindings])
 | 
				
			||||||
AC_ARG_ENABLE(perl-bindings, AC_HELP_STRING([--enable-perl-bindings],
 | 
					AC_ARG_ENABLE(perl-bindings, AC_HELP_STRING([--enable-perl-bindings],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,19 +11,12 @@ nix_noinst_scripts := \
 | 
				
			||||||
  $(d)/nix-profile.sh \
 | 
					  $(d)/nix-profile.sh \
 | 
				
			||||||
  $(d)/nix-reduce-build
 | 
					  $(d)/nix-reduce-build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifeq ($(OS), Darwin)
 | 
					 | 
				
			||||||
  nix_noinst_scripts += $(d)/resolve-system-dependencies.pl
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
noinst-scripts += $(nix_noinst_scripts)
 | 
					noinst-scripts += $(nix_noinst_scripts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
profiledir = $(sysconfdir)/profile.d
 | 
					profiledir = $(sysconfdir)/profile.d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(eval $(call install-file-as, $(d)/nix-profile.sh, $(profiledir)/nix.sh, 0644))
 | 
					$(eval $(call install-file-as, $(d)/nix-profile.sh, $(profiledir)/nix.sh, 0644))
 | 
				
			||||||
$(eval $(call install-program-in, $(d)/build-remote.pl, $(libexecdir)/nix))
 | 
					$(eval $(call install-program-in, $(d)/build-remote.pl, $(libexecdir)/nix))
 | 
				
			||||||
ifeq ($(OS), Darwin)
 | 
					 | 
				
			||||||
  $(eval $(call install-program-in, $(d)/resolve-system-dependencies.pl, $(libexecdir)/nix))
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
$(eval $(call install-symlink, nix-build, $(bindir)/nix-shell))
 | 
					$(eval $(call install-symlink, nix-build, $(bindir)/nix-shell))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean-files += $(nix_bin_scripts) $(nix_noinst_scripts)
 | 
					clean-files += $(nix_bin_scripts) $(nix_noinst_scripts)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,122 +0,0 @@
 | 
				
			||||||
#! @perl@ -w @perlFlags@
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use utf8;
 | 
					 | 
				
			||||||
use strict;
 | 
					 | 
				
			||||||
use warnings;
 | 
					 | 
				
			||||||
use Cwd qw(realpath);
 | 
					 | 
				
			||||||
use Errno;
 | 
					 | 
				
			||||||
use File::Basename qw(dirname);
 | 
					 | 
				
			||||||
use File::Path qw(make_path);
 | 
					 | 
				
			||||||
use File::Spec::Functions qw(catfile);
 | 
					 | 
				
			||||||
use List::Util qw(reduce);
 | 
					 | 
				
			||||||
use IPC::Open3;
 | 
					 | 
				
			||||||
use Nix::Config;
 | 
					 | 
				
			||||||
use Nix::Store qw(derivationFromPath);
 | 
					 | 
				
			||||||
use POSIX qw(uname);
 | 
					 | 
				
			||||||
use Storable qw(lock_retrieve lock_store);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my ($sysname, undef, $version, undef, $machine) = uname;
 | 
					 | 
				
			||||||
$sysname =~ /Darwin/ or die "This tool is only meant to be used on Darwin systems.";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
my $cache = "$Nix::Config::stateDir/dependency-maps/$machine-$sysname-$version.map";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
make_path dirname($cache);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
our $DEPS;
 | 
					 | 
				
			||||||
eval {
 | 
					 | 
				
			||||||
  $DEPS = lock_retrieve($cache);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if($!{ENOENT}) {
 | 
					 | 
				
			||||||
  lock_store {}, $cache;
 | 
					 | 
				
			||||||
  $DEPS = {};
 | 
					 | 
				
			||||||
} elsif($@) {
 | 
					 | 
				
			||||||
  die "Unable to obtain a lock on dependency-map file $cache: $@";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sub mkset(@) {
 | 
					 | 
				
			||||||
  my %set;
 | 
					 | 
				
			||||||
  @set{@_} = ();
 | 
					 | 
				
			||||||
  \%set
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sub union($$) {
 | 
					 | 
				
			||||||
  my ($set1, $set2) = @_;
 | 
					 | 
				
			||||||
  my %new = (%$set1, %$set2);
 | 
					 | 
				
			||||||
  \%new
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sub cache_filepath($) {
 | 
					 | 
				
			||||||
  my $fp = shift;
 | 
					 | 
				
			||||||
  $fp =~ s/-/--/g;
 | 
					 | 
				
			||||||
  $fp =~ s/\//-/g;
 | 
					 | 
				
			||||||
  $fp =~ s/^-//g;
 | 
					 | 
				
			||||||
  catfile $cache, $fp
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sub resolve_tree {
 | 
					 | 
				
			||||||
  sub resolve_tree_inner {
 | 
					 | 
				
			||||||
    my ($lib, $TREE) = @_;
 | 
					 | 
				
			||||||
    return if (defined $TREE->{$lib});
 | 
					 | 
				
			||||||
    $TREE->{$lib} = mkset(@{cache_get($lib)});
 | 
					 | 
				
			||||||
    foreach my $dep (keys %{$TREE->{$lib}}) {
 | 
					 | 
				
			||||||
      resolve_tree_inner($dep, $TREE);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    values %$TREE
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  reduce { union($a, $b) } {}, resolve_tree_inner(@_)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sub cache_get {
 | 
					 | 
				
			||||||
  my $key = shift;
 | 
					 | 
				
			||||||
  if (defined $DEPS->{$key}) {
 | 
					 | 
				
			||||||
    $DEPS->{$key}
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    cache_insert($key);
 | 
					 | 
				
			||||||
    cache_get($key)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sub cache_insert($) {
 | 
					 | 
				
			||||||
  my $key = shift;
 | 
					 | 
				
			||||||
  print STDERR "Finding dependencies for $key...\n";
 | 
					 | 
				
			||||||
  my @deps = find_deps($key);
 | 
					 | 
				
			||||||
  $DEPS->{$key} = \@deps;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sub find_deps($) {
 | 
					 | 
				
			||||||
  my $lib = shift;
 | 
					 | 
				
			||||||
  my($chld_in, $chld_out, $chld_err);
 | 
					 | 
				
			||||||
  my $pid = open3($chld_in, $chld_out, $chld_err, "@otool@", "-L", "-arch", "x86_64", $lib);
 | 
					 | 
				
			||||||
  waitpid($pid, 0);
 | 
					 | 
				
			||||||
  my $line = readline $chld_out;
 | 
					 | 
				
			||||||
  if($? == 0 and $line !~ /not an object file/) {
 | 
					 | 
				
			||||||
    my @libs;
 | 
					 | 
				
			||||||
    while(<$chld_out>) {
 | 
					 | 
				
			||||||
      my $dep = (split /\s+/)[1];
 | 
					 | 
				
			||||||
      push @libs, $dep unless $dep eq $lib or $dep =~ /\@rpath/;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    @libs
 | 
					 | 
				
			||||||
  } elsif (-l $lib) {
 | 
					 | 
				
			||||||
    (realpath($lib))
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    ()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (defined $ARGV[0]) {
 | 
					 | 
				
			||||||
  my $deps = derivationFromPath($ARGV[0])->{"env"}->{"__impureHostDeps"};
 | 
					 | 
				
			||||||
  if (defined $deps) {
 | 
					 | 
				
			||||||
    my @files = split(/\s+/, $deps);
 | 
					 | 
				
			||||||
    my $depcache = {};
 | 
					 | 
				
			||||||
    my $depset = reduce { union($a, $b) } (map { resolve_tree($_, $depcache) } @files);
 | 
					 | 
				
			||||||
    print "extra-chroot-dirs\n";
 | 
					 | 
				
			||||||
    print join("\n", keys %$depset);
 | 
					 | 
				
			||||||
    print "\n";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  lock_store($DEPS, $cache);
 | 
					 | 
				
			||||||
} else {
 | 
					 | 
				
			||||||
  print STDERR "Usage: $0 path/to/derivation.drv\n";
 | 
					 | 
				
			||||||
  exit 1
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@ void Settings::processEnvironment()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // should be set with the other config options, but depends on nixLibexecDir
 | 
					    // should be set with the other config options, but depends on nixLibexecDir
 | 
				
			||||||
#ifdef __APPLE__
 | 
					#ifdef __APPLE__
 | 
				
			||||||
    preBuildHook = nixLibexecDir + "/nix/resolve-system-dependencies.pl";
 | 
					    preBuildHook = nixLibexecDir + "/nix/resolve-system-dependencies";
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/resolve-system-dependencies/local.mk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/resolve-system-dependencies/local.mk
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					ifeq ($(OS), Darwin)
 | 
				
			||||||
 | 
					  programs += resolve-system-dependencies
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resolve-system-dependencies_DIR := $(d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resolve-system-dependencies_INSTALL_DIR := $(libexecdir)/nix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resolve-system-dependencies_LIBS := libstore libmain libutil libformat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resolve-system-dependencies_SOURCES := $(d)/resolve-system-dependencies.cc
 | 
				
			||||||
							
								
								
									
										194
									
								
								src/resolve-system-dependencies/resolve-system-dependencies.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								src/resolve-system-dependencies/resolve-system-dependencies.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,194 @@
 | 
				
			||||||
 | 
					#include "derivations.hh"
 | 
				
			||||||
 | 
					#include "globals.hh"
 | 
				
			||||||
 | 
					#include "shared.hh"
 | 
				
			||||||
 | 
					#include "store-api.hh"
 | 
				
			||||||
 | 
					#include <sys/utsname.h>
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <mach-o/loader.h>
 | 
				
			||||||
 | 
					#include <mach-o/swap.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DO_SWAP(x, y) ((x) ? OSSwapInt32(y) : (y))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace nix;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static auto cacheDir = Path{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Path resolveCacheFile(Path lib) {
 | 
				
			||||||
 | 
					    std::replace(lib.begin(), lib.end(), '/', '%');
 | 
				
			||||||
 | 
					    return cacheDir + "/" + lib;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::set<string> readCacheFile(const Path & file) {
 | 
				
			||||||
 | 
					    return tokenizeString<set<string>>(readFile(file), "\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void writeCacheFile(const Path & file, std::set<string> & deps) {
 | 
				
			||||||
 | 
					    std::ofstream fp;
 | 
				
			||||||
 | 
					    fp.open(file);
 | 
				
			||||||
 | 
					    for (auto & d : deps) {
 | 
				
			||||||
 | 
					        fp << d << "\n";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fp.close();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string findDylibName(bool should_swap, ptrdiff_t dylib_command_start) {
 | 
				
			||||||
 | 
					    struct dylib_command *dylc = (struct dylib_command*)dylib_command_start;
 | 
				
			||||||
 | 
					    return std::string((char*)(dylib_command_start + DO_SWAP(should_swap, dylc->dylib.name.offset)));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::set<std::string> runResolver(const Path & filename) {
 | 
				
			||||||
 | 
					    int fd = open(filename.c_str(), O_RDONLY);
 | 
				
			||||||
 | 
					    struct stat s;
 | 
				
			||||||
 | 
					    fstat(fd, &s);
 | 
				
			||||||
 | 
					    void *obj = mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptrdiff_t mach64_offset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t magic = ((struct mach_header_64*)obj)->magic;
 | 
				
			||||||
 | 
					    if(magic == FAT_CIGAM || magic == FAT_MAGIC) {
 | 
				
			||||||
 | 
					        bool should_swap = magic == FAT_CIGAM;
 | 
				
			||||||
 | 
					        uint32_t narches = DO_SWAP(should_swap, ((struct fat_header*)obj)->nfat_arch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(uint32_t iter = 0; iter < narches; iter++) {
 | 
				
			||||||
 | 
					            ptrdiff_t header_offset = (ptrdiff_t)obj + sizeof(struct fat_header) * (iter + 1);
 | 
				
			||||||
 | 
					            struct fat_arch* arch = (struct fat_arch*)header_offset;
 | 
				
			||||||
 | 
					            if(DO_SWAP(should_swap, arch->cputype) == CPU_TYPE_X86_64) {
 | 
				
			||||||
 | 
					                mach64_offset = (ptrdiff_t)DO_SWAP(should_swap, arch->offset);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (mach64_offset == 0) {
 | 
				
			||||||
 | 
					            printMsg(lvlError, format("Could not find any mach64 blobs in file ‘%1%’, continuing...") % filename);
 | 
				
			||||||
 | 
					            return std::set<string>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) {
 | 
				
			||||||
 | 
					        mach64_offset = 0;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        printMsg(lvlError, format("Object file has unknown magic number ‘%1%’, skipping it...") % magic);
 | 
				
			||||||
 | 
					        return std::set<string>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptrdiff_t mach_header_offset = (ptrdiff_t)obj + mach64_offset;
 | 
				
			||||||
 | 
					    struct mach_header_64 *m_header = (struct mach_header_64 *)mach_header_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool should_swap = magic == MH_CIGAM_64;
 | 
				
			||||||
 | 
					    ptrdiff_t cmd_offset = mach_header_offset + sizeof(struct mach_header_64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::set<string> libs;
 | 
				
			||||||
 | 
					    for(uint32_t i = 0; i < DO_SWAP(should_swap, m_header->ncmds); i++) {
 | 
				
			||||||
 | 
					        struct load_command *cmd = (struct load_command*)cmd_offset;
 | 
				
			||||||
 | 
					        switch(DO_SWAP(should_swap, cmd->cmd)) {
 | 
				
			||||||
 | 
					            case LC_LOAD_UPWARD_DYLIB:
 | 
				
			||||||
 | 
					            case LC_LOAD_DYLIB:
 | 
				
			||||||
 | 
					            case LC_REEXPORT_DYLIB:
 | 
				
			||||||
 | 
					                libs.insert(findDylibName(should_swap, cmd_offset));
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cmd_offset += DO_SWAP(should_swap, cmd->cmdsize);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return libs;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool isSymlink(const Path & path) {
 | 
				
			||||||
 | 
					    struct stat st;
 | 
				
			||||||
 | 
					    if(lstat(path.c_str(), &st))
 | 
				
			||||||
 | 
					        throw SysError(format("getting attributes of path ‘%1%’") % path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return S_ISLNK(st.st_mode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Path resolveSymlink(const Path & path) {
 | 
				
			||||||
 | 
					    char buf[PATH_MAX];
 | 
				
			||||||
 | 
					    ssize_t len = readlink(path.c_str(), buf, sizeof(buf) - 1);
 | 
				
			||||||
 | 
					    if(len != -1) {
 | 
				
			||||||
 | 
					        buf[len] = 0;
 | 
				
			||||||
 | 
					        return Path(buf);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        throw SysError(format("readlink('%1%')") % path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::set<string> resolveTree(const Path & path, PathSet & deps) {
 | 
				
			||||||
 | 
					    std::set<string> results;
 | 
				
			||||||
 | 
					    if(deps.find(path) != deps.end()) {
 | 
				
			||||||
 | 
					        return std::set<string>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    deps.insert(path);
 | 
				
			||||||
 | 
					    for (auto & lib : runResolver(path)) {
 | 
				
			||||||
 | 
					        results.insert(lib);
 | 
				
			||||||
 | 
					        for (auto & p : resolveTree(lib, deps)) {
 | 
				
			||||||
 | 
					            results.insert(p);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return results;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::set<string> getPath(const Path & path) {
 | 
				
			||||||
 | 
					    Path cacheFile = resolveCacheFile(path);
 | 
				
			||||||
 | 
					    if(pathExists(cacheFile)) {
 | 
				
			||||||
 | 
					        return readCacheFile(cacheFile);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::set<string> deps;
 | 
				
			||||||
 | 
					    std::set<string> paths;
 | 
				
			||||||
 | 
					    paths.insert(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Path next_path = Path(path);
 | 
				
			||||||
 | 
					    while(isSymlink(next_path)) {
 | 
				
			||||||
 | 
					        next_path = resolveSymlink(next_path);
 | 
				
			||||||
 | 
					        paths.insert(next_path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(auto & t : resolveTree(next_path, deps)) {
 | 
				
			||||||
 | 
					        paths.insert(t);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    writeCacheFile(cacheFile, paths);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return paths;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char ** argv) {
 | 
				
			||||||
 | 
					    return handleExceptions(argv[0], [&]() {
 | 
				
			||||||
 | 
					        initNix();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        struct utsname _uname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uname(&_uname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto cacheParentDir = (format("%1%/dependency-maps") % settings.nixStateDir).str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cacheDir = (format("%1%/%2%-%3%-%4%")
 | 
				
			||||||
 | 
					                % cacheParentDir
 | 
				
			||||||
 | 
					                % _uname.machine
 | 
				
			||||||
 | 
					                % _uname.sysname
 | 
				
			||||||
 | 
					                % _uname.release).str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mkdir(cacheParentDir.c_str(), 0755);
 | 
				
			||||||
 | 
					        mkdir(cacheDir.c_str(), 0755);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto store = openStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto drv = store->derivationFromPath(Path(argv[1]));
 | 
				
			||||||
 | 
					        Strings impurePaths = tokenizeString<Strings>(get(drv.env, "__impureHostDeps"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::set<string> all_paths;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (auto & path : impurePaths) {
 | 
				
			||||||
 | 
					            for(auto & p : getPath(path)) {
 | 
				
			||||||
 | 
					                all_paths.insert(p);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::cout << "extra-chroot-dirs" << std::endl;
 | 
				
			||||||
 | 
					        for(auto & path : all_paths) {
 | 
				
			||||||
 | 
					            std::cout << path << std::endl;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        std::cout << std::endl;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue