#
# --cross-compile-prefix Add specified prefix to binutils components.
#
-# --api One of 0.9.8, 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, or 3.0.0 / 3.
-# Do not compile support for interfaces deprecated as of the
-# specified OpenSSL version.
+# --api One of 0.9.8, 1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, or 3.0
+# Define the public APIs as they were for that version
+# including patch releases. If 'no-deprecated' is also
+# given, do not compile support for interfaces deprecated
+# up to and including the specified OpenSSL version.
#
# no-hw-xxx do not compile support for specific crypto hardware.
# Generic OpenSSL-style methods relating to this support
# no-sse2 disables IA-32 SSE2 code in assembly modules, the above
# mentioned '386' option implies this one
# no-<cipher> build without specified algorithm (rsa, idea, rc5, ...)
-# -<xxx> +<xxx> compiler options are passed through
+# -<xxx> +<xxx> All options which are unknown to the 'Configure' script are
+# /<xxx> passed through to the compiler. Unix-style options beginning
+# with a '-' or '+' are recognized, as well as Windows-style
+# options beginning with a '/'. If the option contains arguments
+# separated by spaces, then the URL-style notation %20 can be
+# used for the space character in order to avoid having to quote
+# the option. For example, -opt%20arg gets expanded to -opt arg.
+# In fact, any ASCII character can be encoded as %xx using its
+# hexadecimal encoding.
# -static while -static is also a pass-through compiler option (and
# as such is limited to environments where it's actually
# meaningful), it triggers a number configuration options,
-Wmissing-variable-declarations
);
+my @cl_devteam_warn = qw(
+ /WX
+);
+
# This adds backtrace information to the memory leak info. Is only used
# when crypto-mdebug-backtrace is enabled.
my $memleak_devteam_backtrace = "-rdynamic";
#
# API compatibility name to version number mapping.
#
-my $maxapi = "3.0.0"; # API for "no-deprecated" builds
my $apitable = {
- "3.0.0" => 3,
- "1.1.1" => 2,
- "1.1.0" => 2,
- "1.0.2" => 1,
- "1.0.1" => 1,
- "1.0.0" => 1,
- "0.9.8" => 0,
+ # This table expresses when API additions or changes can occur.
+ # The numbering used changes from 3.0 and on because we updated
+ # (solidified) our version numbering scheme at that point.
+
+ # From 3.0 and on, we internalise the given version number in dedcimal
+ # as MAJOR * 10000 + MINOR * 100 + 0
+ "3.0.0" => 30000,
+ "3.0" => 30000,
+
+ # Note that before 3.0, we didn't have the same version number scheme.
+ # Still, the numbering we use here covers what we need.
+ "1.1.1" => 10101,
+ "1.1.0" => 10100,
+ "1.0.2" => 10002,
+ "1.0.1" => 10001,
+ "1.0.0" => 10000,
+ "0.9.8" => 908,
};
our %table = ();
$config{perlargv} = [ @argvcopy ];
# Collect version numbers
-$config{major} = "unknown";
-$config{minor} = "unknown";
-$config{patch} = "unknown";
-$config{prerelease} = "";
-$config{build_metadata} = "";
-$config{shlib_version} = "unknown";
+my %version = ();
collect_information(
- collect_from_file(catfile($srcdir,'include/openssl/opensslv.h')),
- qr/#\s+define\s+OPENSSL_VERSION_MAJOR\s+(\d+)/ =>
- sub { $config{major} = $1; },
- qr/#\s+define\s+OPENSSL_VERSION_MINOR\s+(\d+)/ =>
- sub { $config{minor} = $1; },
- qr/#\s+define\s+OPENSSL_VERSION_PATCH\s+(\d+)/ =>
- sub { $config{patch} = $1; },
- qr/#\s+define\s+OPENSSL_VERSION_PRE_RELEASE\s+"((?:\\.|[^"])*)"/ =>
- sub { $config{prerelease} = $1; },
- qr/#\s+define\s+OPENSSL_VERSION_BUILD_METADATA\s+"((?:\\.|[^"])*)"/ =>
- sub { $config{build_metadata} = $1; },
- qr/#\s+define\s+OPENSSL_SHLIB_VERSION\s+([\d\.]+)/ =>
- sub { $config{shlib_version} = $1; },
+ collect_from_file(catfile($srcdir,'VERSION')),
+ qr/\s*(\w+)\s*=\s*(.*?)\s*$/ =>
+ sub {
+ # Only define it if there is a value at all
+ $version{uc $1} = $2 if $2 ne '';
+ },
+ "OTHERWISE" =>
+ sub { die "Something wrong with this line:\n$_\nin $srcdir/VERSION" },
);
-die "erroneous version information in opensslv.h: ",
- "$config{major}.$config{minor}.$config{patch}, $config{shlib_version}\n"
- if ($config{major} eq "unknown"
- || $config{minor} eq "unknown"
- || $config{patch} eq "unknown"
- || $config{shlib_version} eq "unknown");
+
+$config{major} = $version{MAJOR} // 'unknown';
+$config{minor} = $version{MINOR} // 'unknown';
+$config{patch} = $version{PATCH} // 'unknown';
+$config{prerelease} =
+ defined $version{PRE_RELEASE_TAG} ? "-$version{PRE_RELEASE_TAG}" : '';
+$config{build_metadata} =
+ defined $version{BUILD_METADATA} ? "+$version{BUILD_METADATA}" : '';
+$config{shlib_version} = $version{SHLIB_VERSION} // 'unknown';
+$config{release_date} = $version{RELEASE_DATE} // 'xx XXX xxxx';
$config{version} = "$config{major}.$config{minor}.$config{patch}";
$config{full_version} = "$config{version}$config{prerelease}$config{build_metadata}";
+die "erroneous version information in VERSION: ",
+ "$config{version}, $config{shlib_version}\n"
+ unless (defined $version{MAJOR}
+ && defined $version{MINOR}
+ && defined $version{PATCH}
+ && defined $version{SHLIB_VERSION});
+
# Collect target configurations
my $pattern = catfile(dirname($0), "Configurations", "*.conf");
# or modules.
"pic" => [ "shared", "module" ],
- "module" => [ "fips", "legacy" ],
+ "module" => [ "fips" ],
"engine" => [ grep /eng$/, @disablables ],
"hw" => [ "padlockeng" ],
{
die "FIPS mode not supported\n";
}
- elsif (/^[-+]/)
+ elsif (m|^[-+/]|)
{
if (/^--prefix=(.*)$/)
{
}
elsif (/^--api=(.*)$/)
{
- $config{api}=$1;
+ my $api = $1;
+ die "Unknown API compatibility level $api"
+ unless defined $apitable->{$api};
+ $config{api}=$apitable->{$api};
}
elsif (/^--libdir=(.*)$/)
{
{
push @{$useradd{LDFLAGS}}, $_;
}
- elsif (/^-D(.*)$/)
+ elsif (m|^[-/]D(.*)$|)
{
push @{$useradd{CPPDEFINES}}, $1;
}
- elsif (/^-I(.*)$/)
+ elsif (m|^[-/]I(.*)$|)
{
push @{$useradd{CPPINCLUDES}}, $1;
}
}
else # common if (/^[-+]/), just pass down...
{
+ # Treat %xx as an ASCII code (e.g. replace %20 by a space character).
+ # This provides a simple way to pass options with arguments separated
+ # by spaces without quoting (e.g. -opt%20arg translates to -opt arg).
$_ =~ s/%([0-9a-f]{1,2})/chr(hex($1))/gei;
push @{$useradd{CFLAGS}}, $_;
push @{$useradd{CXXFLAGS}}, $_;
}
}
+ elsif (m|^/|)
+ {
+ # Treat %xx as an ASCII code (e.g. replace %20 by a space character).
+ # This provides a simple way to pass options with arguments separated
+ # by spaces without quoting (e.g. /opt%20arg translates to /opt arg).
+ $_ =~ s/%([0-9a-f]{1,2})/chr(hex($1))/gei;
+ push @{$useradd{CFLAGS}}, $_;
+ push @{$useradd{CXXFLAGS}}, $_;
+ }
else
{
die "target already defined - $target (offending arg: $_)\n" if ($target ne "");
}
}
-if (defined($config{api}) && !exists $apitable->{$config{api}}) {
- die "***** Unsupported api compatibility level: $config{api}\n",
-}
-
if (keys %deprecated_options)
{
warn "***** Deprecated options: ",
# The actual processing of these entries is done in the build.info lookup
# loop further down.
#
-# The key is a Unix formated path in the source tree, the value is an index
+# The key is a Unix formatted path in the source tree, the value is an index
# into %disabled_info, so any existing path gets added to a corresponding
# 'skipped' entry in there with the list of skipped directories.
my %skipdir = ();
push @{$config{openssl_feature_defines}}, "OPENSSL_THREADS";
}
-# With "deprecated" disable all deprecated features.
-if (defined($disabled{"deprecated"})) {
- $config{api} = $maxapi;
-}
-
my $no_shared_warn=0;
if ($target{shared_target} eq "")
{
die "Exactly one of SIXTY_FOUR_BIT|SIXTY_FOUR_BIT_LONG|THIRTY_TWO_BIT can be set in bn_ops\n"
if $count > 1;
+$config{api} = $config{major} * 10000 + $config{minor} * 100
+ unless $config{api};
# Hack cflags for better warnings (dev option) #######################
@{$config{cxxflags}} ] if $config{CXX};
$config{openssl_api_defines} = [
- "OPENSSL_MIN_API=".($apitable->{$config{api} // ""} // -1)
+ "OPENSSL_CONFIGURED_API=".$config{api}
];
my @strict_warnings_collection=();
my $wopt;
my $gccver = $predefined_C{__GNUC__} // -1;
- warn "WARNING --strict-warnings requires gcc[>=4] or gcc-alike"
- unless $gccver >= 4;
- push @strict_warnings_collection, @gcc_devteam_warn;
- push @strict_warnings_collection, @clang_devteam_warn
- if (defined($predefined_C{__clang__}));
+ if ($gccver >= 4)
+ {
+ push @strict_warnings_collection, @gcc_devteam_warn;
+ push @strict_warnings_collection, @clang_devteam_warn
+ if (defined($predefined_C{__clang__}));
+ }
+ elsif ($config{target} =~ /^VC-/)
+ {
+ push @strict_warnings_collection, @cl_devteam_warn;
+ }
+ else
+ {
+ warn "WARNING --strict-warnings requires gcc[>=4] or gcc-alike, or MSVC"
+ }
}
if (grep { $_ eq '-static' } @{$config{LDFLAGS}}) {
if ($verstr[2] < $minver) {
disable('too-old-kernel', 'ktls');
}
+ } elsif ($target =~ m/^BSD/) {
+ my $cc = $config{CROSS_COMPILE}.$config{CC};
+ system("printf '#include <sys/types.h>\n#include <sys/ktls.h>' | $cc -E - >/dev/null 2>&1");
+ if ($? != 0) {
+ disable('too-old-freebsd', 'ktls');
+ }
} else {
- disable('not-linux', 'ktls');
+ disable('not-linux-or-freebsd', 'ktls');
}
}
my @modules = ();
my @scripts = ();
- my %attributes = ();
my %sources = ();
my %shared_sources = ();
my %includes = ();
# contains a dollar sign, it had better be escaped, or it will be
# taken for a variable name prefix.
my %variables = ();
- my $variable_re = qr/\$([[:alpha:]][[:alnum:]_]*)/;
+ my $variable_re = qr/\$(?P<VARIABLE>[[:alpha:]][[:alnum:]_]*)/;
my $expand_variables = sub {
my $value = '';
my $value_rest = shift;
+ if ($ENV{CONFIGURE_DEBUG_VARIABLE_EXPAND}) {
+ print STDERR
+ "DEBUG[\$expand_variables] Parsed '$value_rest' into:\n"
+ }
while ($value_rest =~ /(?<!\\)${variable_re}/) {
$value .= $`;
- $value .= $variables{$1};
+ $value .= $variables{$+{VARIABLE}};
$value_rest = $';
}
+ if ($ENV{CONFIGURE_DEBUG_VARIABLE_EXPAND}) {
+ print STDERR
+ "DEBUG[\$expand_variables] ... '$value$value_rest'\n";
+ }
return $value . $value_rest;
};
+ # Support for attributes in build.info files
+ my %attributes = ();
+ my $handle_attributes = sub {
+ my $attr_str = shift;
+ my $ref = shift;
+ my @goals = @_;
+
+ return unless defined $attr_str;
+
+ my @a = tokenize($attr_str, qr|\s*,\s*|);
+ foreach my $a (@a) {
+ my $ac = 1;
+ my $ak = $a;
+ my $av = 1;
+ if ($a =~ m|^(!)?(.*?)\s* = \s*(.*?)$|) {
+ $ac = ! $1;
+ $ak = $1;
+ $av = $2;
+ }
+ foreach my $g (@goals) {
+ if ($ac) {
+ $$ref->{$g}->{$ak} = $av;
+ } else {
+ delete $$ref->{$g}->{$ak};
+ }
+ }
+ }
+ };
+
# We want to detect configdata.pm in the source tree, so we
# don't use it if the build tree is different.
my $src_configdata = cleanfile($srcdir, "configdata.pm", $blddir);
# 1 last was positive (don't skip lines until next ELSE, ELSIF or ENDIF)
# 2 positive ELSE (following ELSIF should fail)
my @skip = ();
+
+ # A few useful generic regexps
+ my $index_re = qr/\[\s*(?P<INDEX>(?:\\.|.)*?)\s*\]/;
+ my $cond_re = qr/\[\s*(?P<COND>(?:\\.|.)*?)\s*\]/;
+ my $attribs_re = qr/(?:\{\s*(?P<ATTRIBS>(?:\\.|.)*?)\s*\})?/;
+ my $value_re = qr/\s*(?P<VALUE>.*?)\s*/;
collect_information(
collect_from_array([ @text ],
qr/\\$/ => sub { my $l1 = shift; my $l2 = shift;
$l1 =~ s/\\$//; $l1.$l2 }),
# Info we're looking for
- qr/^\s*IF\[((?:\\.|[^\\\]])*)\]\s*$/
+ qr/^\s* IF ${cond_re} \s*$/x
=> sub {
if (! @skip || $skip[$#skip] > 0) {
- push @skip, !! $expand_variables->($1);
+ push @skip, !! $expand_variables->($+{COND});
} else {
push @skip, -1;
}
},
- qr/^\s*ELSIF\[((?:\\.|[^\\\]])*)\]\s*$/
+ qr/^\s* ELSIF ${cond_re} \s*$/x
=> sub { die "ELSIF out of scope" if ! @skip;
die "ELSIF following ELSE" if abs($skip[$#skip]) == 2;
$skip[$#skip] = -1 if $skip[$#skip] != 0;
- $skip[$#skip] = !! $expand_variables->($1)
+ $skip[$#skip] = !! $expand_variables->($+{COND})
if $skip[$#skip] == 0; },
- qr/^\s*ELSE\s*$/
+ qr/^\s* ELSE \s*$/x
=> sub { die "ELSE out of scope" if ! @skip;
$skip[$#skip] = -2 if $skip[$#skip] != 0;
$skip[$#skip] = 2 if $skip[$#skip] == 0; },
- qr/^\s*ENDIF\s*$/
+ qr/^\s* ENDIF \s*$/x
=> sub { die "ENDIF out of scope" if ! @skip;
pop @skip; },
- qr/^\s*${variable_re}\s*=\s*(.*?)\s*$/
+ qr/^\s* ${variable_re} \s* = ${value_re} $/x
=> sub {
if (!@skip || $skip[$#skip] > 0) {
- my $n = $1;
- my $v = $2;
- $variables{$n} = $expand_variables->($v);
+ $variables{$+{VARIABLE}} = $expand_variables->($+{VALUE});
}
},
- qr/^\s*SUBDIRS\s*=\s*(.*)\s*$/
+ qr/^\s* SUBDIRS \s* = ${value_re} $/x
=> sub {
if (!@skip || $skip[$#skip] > 0) {
- foreach (tokenize($expand_variables->($1))) {
+ foreach (tokenize($expand_variables->($+{VALUE}))) {
push @build_dirs, [ @curd, splitdir($_, 1) ];
}
}
},
- qr/^\s*PROGRAMS(?:{([\w=]+(?:\s*,\s*[\w=]+)*)})?\s*=\s*(.*)\s*$/
+ qr/^\s* PROGRAMS ${attribs_re} \s* = ${value_re} $/x
=> sub {
if (!@skip || $skip[$#skip] > 0) {
- my @a = tokenize($1, qr|\s*,\s*|);
- my @p = tokenize($expand_variables->($2));
+ my @p = tokenize($expand_variables->($+{VALUE}));
push @programs, @p;
- foreach my $a (@a) {
- my $ak = $a;
- my $av = 1;
- if ($a =~ m|^(.*?)\s*=\s*(.*?)$|) {
- $ak = $1;
- $av = $2;
- }
- foreach my $p (@p) {
- $attributes{$p}->{$ak} = $av;
- }
- }
+ $handle_attributes->($+{ATTRIBS},
+ \$attributes{programs},
+ @p);
}
},
- qr/^\s*LIBS(?:{([\w=]+(?:\s*,\s*[\w=]+)*)})?\s*=\s*(.*)\s*$/
+ qr/^\s* LIBS ${attribs_re} \s* = ${value_re} $/x
=> sub {
if (!@skip || $skip[$#skip] > 0) {
- my @a = tokenize($1, qr|\s*,\s*|);
- my @l = tokenize($expand_variables->($2));
+ my @l = tokenize($expand_variables->($+{VALUE}));
push @libraries, @l;
- foreach my $a (@a) {
- my $ak = $a;
- my $av = 1;
- if ($a =~ m|^(.*?)\s*=\s*(.*?)$|) {
- $ak = $1;
- $av = $2;
- }
- foreach my $l (@l) {
- $attributes{$l}->{$ak} = $av;
- }
- }
+ $handle_attributes->($+{ATTRIBS},
+ \$attributes{libraries},
+ @l);
}
},
- qr/^\s*MODULES(?:{([\w=]+(?:\s*,\s*[\w=]+)*)})?\s*=\s*(.*)\s*$/
+ qr/^\s* MODULES ${attribs_re} \s* = ${value_re} $/x
=> sub {
if (!@skip || $skip[$#skip] > 0) {
- my @a = tokenize($1, qr|\s*,\s*|);
- my @m = tokenize($expand_variables->($2));
+ my @m = tokenize($expand_variables->($+{VALUE}));
push @modules, @m;
- foreach my $a (@a) {
- my $ak = $a;
- my $av = 1;
- if ($a =~ m|^(.*?)\s*=\s*(.*?)$|) {
- $ak = $1;
- $av = $2;
- }
- foreach my $m (@m) {
- $attributes{$m}->{$ak} = $av;
- }
- }
+ $handle_attributes->($+{ATTRIBS},
+ \$attributes{modules},
+ @m);
}
},
- qr/^\s*SCRIPTS(?:{([\w=]+(?:\s*,\s*[\w=]+)*)})?\s*=\s*(.*)\s*$/
+ qr/^\s* SCRIPTS ${attribs_re} \s* = ${value_re} $/x
=> sub {
if (!@skip || $skip[$#skip] > 0) {
- my @a = tokenize($1, qr|\s*,\s*|);
- my @s = tokenize($expand_variables->($2));
+ my @s = tokenize($expand_variables->($+{VALUE}));
push @scripts, @s;
- foreach my $a (@a) {
- my $ak = $a;
- my $av = 1;
- if ($a =~ m|^(.*?)\s*=\s*(.*?)$|) {
- $ak = $1;
- $av = $2;
- }
- foreach my $s (@s) {
- $attributes{$s}->{$ak} = $av;
- }
- }
+ $handle_attributes->($+{ATTRIBS},
+ \$attributes{scripts},
+ @s);
}
},
- qr/^\s*ORDINALS\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/,
- => sub { push @{$ordinals{$1}}, tokenize($expand_variables->($2))
- if !@skip || $skip[$#skip] > 0 },
- qr/^\s*SOURCE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
- => sub { push @{$sources{$1}}, tokenize($expand_variables->($2))
+ qr/^\s* ORDINALS ${index_re} = ${value_re} $/x
+ => sub { push @{$ordinals{$expand_variables->($+{INDEX})}},
+ tokenize($expand_variables->($+{VALUE}))
if !@skip || $skip[$#skip] > 0 },
- qr/^\s*SHARED_SOURCE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
- => sub { push @{$shared_sources{$1}},
- tokenize($expand_variables->($2))
+ qr/^\s* SOURCE ${index_re} = ${value_re} $/x
+ => sub { push @{$sources{$expand_variables->($+{INDEX})}},
+ tokenize($expand_variables->($+{VALUE}))
if !@skip || $skip[$#skip] > 0 },
- qr/^\s*INCLUDE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
- => sub { push @{$includes{$1}}, tokenize($expand_variables->($2))
+ qr/^\s* SHARED_SOURCE ${index_re} = ${value_re} $/x
+ => sub { push @{$shared_sources{$expand_variables->($+{INDEX})}},
+ tokenize($expand_variables->($+{VALUE}))
if !@skip || $skip[$#skip] > 0 },
- qr/^\s*DEFINE\[((?:\\.|[^\\\]])*)\]\s*=\s*(.*)\s*$/
- => sub { push @{$defines{$1}}, tokenize($expand_variables->($2))
+ qr/^\s* INCLUDE ${index_re} = ${value_re} $/x
+ => sub { push @{$includes{$expand_variables->($+{INDEX})}},
+ tokenize($expand_variables->($+{VALUE}))
if !@skip || $skip[$#skip] > 0 },
- qr/^\s*DEPEND\[((?:\\.|[^\\\]])*)\]\s*=\s*(.*)\s*$/
- => sub { push @{$depends{$1}}, tokenize($expand_variables->($2))
+ qr/^\s* DEFINE ${index_re} = ${value_re} $/x
+ => sub { push @{$defines{$expand_variables->($+{INDEX})}},
+ tokenize($expand_variables->($+{VALUE}))
if !@skip || $skip[$#skip] > 0 },
- qr/^\s*GENERATE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
- => sub { push @{$generate{$1}}, $2
+ qr/^\s* DEPEND ${index_re} ${attribs_re} = ${value_re} $/x
+ => sub {
+ if (!@skip || $skip[$#skip] > 0) {
+ my $i = $expand_variables->($+{INDEX});
+ my @d = tokenize($expand_variables->($+{VALUE}));
+ push @{$depends{$i}}, @d;
+ $handle_attributes->($+{ATTRIBS},
+ \$attributes{depends}->{$i},
+ @d);
+ }
+ },
+ qr/^\s* GENERATE ${index_re} = ${value_re} $/x
+ => sub { push @{$generate{$expand_variables->($+{INDEX})}},
+ $+{VALUE}
if !@skip || $skip[$#skip] > 0 },
- qr/^\s*(?:#.*)?$/ => sub { },
+ qr/^\s* (?:\#.*)? $/x => sub { },
"OTHERWISE" => sub { die "Something wrong with this line:\n$_\nat $sourced/$f" },
"BEFORE" => sub {
if ($buildinfo_debug) {
);
die "runaway IF?" if (@skip);
- if (grep { defined $attributes{$_}->{engine} } keys %attributes
+ if (grep { defined $attributes{modules}->{$_}->{engine} } keys %attributes
and !$config{dynamic_engines}) {
die <<"EOF"
ENGINES can only be used if configured with 'dynamic-engine'.
EOF
}
- foreach (keys %attributes) {
- my $dest = $_;
- my $ddest = cleanfile($buildd, $_, $blddir);
- foreach (keys %{$attributes{$dest} // {}}) {
- $unified_info{attributes}->{$ddest}->{$_} =
- $attributes{$dest}->{$_};
- }
- }
-
{
my %infos = ( programs => [ @programs ],
libraries => [ @libraries ],
foreach (@{$infos{$k}}) {
my $item = cleanfile($buildd, $_, $blddir);
$unified_info{$k}->{$item} = 1;
+
+ # Fix up associated attributes
+ $unified_info{attributes}->{$k}->{$item} =
+ $attributes{$k}->{$_}
+ if defined $attributes{$k}->{$_};
}
}
}
my $e = $1 // "";
$d = $`.$e;
$unified_info{depends}->{$ddest}->{$d} = 1;
+
+ # Fix up associated attributes
+ $unified_info{attributes}->{depends}->{$ddest}->{$d} =
+ $attributes{depends}->{$dest}->{$_}
+ if defined $attributes{depends}->{$dest}->{$_};
}
}