From ff6953cb031c0d2a625bbb2df985a7a3bb17bc46 Mon Sep 17 00:00:00 2001 From: Jude Taylor Date: Wed, 21 Oct 2015 12:38:45 -0700 Subject: [PATCH] Add resolve-system-dependencies.pl --- configure.ac | 17 +++ scripts/local.mk | 2 + scripts/resolve-system-dependencies.pl.in | 123 ++++++++++++++++++++++ src/libstore/build.cc | 7 ++ src/libstore/local.mk | 2 +- 5 files changed, 150 insertions(+), 1 deletion(-) create mode 100755 scripts/resolve-system-dependencies.pl.in diff --git a/configure.ac b/configure.ac index 1d4b7d3b8..a30e0c3b2 100644 --- a/configure.ac +++ b/configure.ac @@ -261,6 +261,23 @@ AC_MSG_RESULT(yes) 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 AC_MSG_CHECKING([whether to build the Perl bindings]) AC_ARG_ENABLE(perl-bindings, AC_HELP_STRING([--enable-perl-bindings], diff --git a/scripts/local.mk b/scripts/local.mk index 3fb47676f..cdac56bf1 100644 --- a/scripts/local.mk +++ b/scripts/local.mk @@ -17,6 +17,7 @@ nix_substituters := \ nix_noinst_scripts := \ $(d)/build-remote.pl \ $(d)/find-runtime-roots.pl \ + $(d)/resolve-system-dependencies.pl \ $(d)/nix-http-export.cgi \ $(d)/nix-profile.sh \ $(d)/nix-reduce-build \ @@ -29,6 +30,7 @@ profiledir = $(sysconfdir)/profile.d $(eval $(call install-file-as, $(d)/nix-profile.sh, $(profiledir)/nix.sh, 0644)) $(eval $(call install-program-in, $(d)/find-runtime-roots.pl, $(libexecdir)/nix)) $(eval $(call install-program-in, $(d)/build-remote.pl, $(libexecdir)/nix)) +$(eval $(call install-program-in, $(d)/resolve-system-dependencies.pl, $(libexecdir)/nix)) $(foreach prog, $(nix_substituters), $(eval $(call install-program-in, $(prog), $(libexecdir)/nix/substituters))) $(eval $(call install-symlink, nix-build, $(bindir)/nix-shell)) diff --git a/scripts/resolve-system-dependencies.pl.in b/scripts/resolve-system-dependencies.pl.in new file mode 100755 index 000000000..412f07274 --- /dev/null +++ b/scripts/resolve-system-dependencies.pl.in @@ -0,0 +1,123 @@ +#! @perl@ -w @perlFlags@ + +use utf8; +use strict; +use warnings; +use Cwd qw(realpath); +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); +} or do { + lock_store {}, $cache; + $DEPS = {}; +}; + +sub mkset(@) { + my %set; + @set{@_} = (); + \%set +} + +sub union($$) { + my ($set1, $set2) = @_; + my $new = {}; + foreach my $key (keys %$set1) { + $new->{$key} = $set1->{$key}; + } + foreach my $key (keys %$set2) { + $new->{$key} = $set2->{$key}; + } + $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\n"; + } + lock_store($DEPS, $cache); +} else { + print STDERR "Usage: $0 path/to/derivation.drv\n"; + exit 1 +} diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 10f926bf8..0dac1377d 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -60,9 +60,11 @@ #if __APPLE__ #define SANDBOX_ENABLED 1 #define DEFAULT_ALLOWED_IMPURE_PREFIXES "/System/Library /usr /dev /bin/sh" + #define DARWIN_PREBUILD 1 #else #define SANDBOX_ENABLED 0 #define DEFAULT_ALLOWED_IMPURE_PREFIXES "/bin" "/usr/bin" + #define DARWIN_PREBUILD 0 #endif #if CHROOT_ENABLED @@ -2045,6 +2047,11 @@ void DerivationGoal::startBuilder() } } +#if DARWIN_PREBUILD + if (settings.preBuildHook == "") + settings.preBuildHook = settings.nixLibexecDir + "/nix/resolve-system-dependencies.pl"; +#endif + if (settings.preBuildHook != "") { printMsg(lvlChatty, format("executing pre-build hook ‘%1%’") % settings.preBuildHook); diff --git a/src/libstore/local.mk b/src/libstore/local.mk index 4a4ba17c4..f10981ad4 100644 --- a/src/libstore/local.mk +++ b/src/libstore/local.mk @@ -33,4 +33,4 @@ $(d)/local-store.cc: $(d)/schema.sql.hh clean-files += $(d)/schema.sql.hh $(eval $(call install-file-in, $(d)/nix-store.pc, $(prefix)/lib/pkgconfig, 0644)) -$(eval $(call install-file-in, $(d)/sandbox-defaults.sb, $(prefix)/share/nix, 0644)) +$(eval $(call install-file-in, $(d)/sandbox-defaults.sb, $(datadir)/nix, 0644))