"Variable $foo will not stay shared" Warning/Error in Perl While Calling Subroutine

As per perldoc's perldiag for that error, your problem is that the inner sub is referencing a lexical variable (%marked) defined in the outer sub.

The fix is in the third paragraph (use anonymous sub):

(Warning; closure) An inner (nested) named subroutine is referencing a lexical variable defined in an outer named subroutine.

When the inner subroutine is called, it will see the value of the outer subroutine's variable as it was before and during the first call to the outer subroutine; in this case, after the first call to the outer subroutine is complete, the inner and outer subroutines will no longer share a common value for the variable. In other words, the variable will no longer be shared.

This problem can usually be solved by making the inner subroutine anonymous, using the sub {} syntax. When inner anonymous subs that reference variables in outer subroutines are created, they are automatically rebound to the current values of such variables.

Fixed code using anonymous sub:

# ....
my $connected_sub;
$connected_sub = sub {
    no warnings 'recursion';
    my $node = shift;
    return if exists $marked{$node};  # Line 280
    $marked{$node} = 1;
    push @stack, $node;   # Line 282
    my $children = $links{$node};  # Line 283
    &$connected_sub($_) for keys %$children;
};

for my $node (sort keys %links) {
    next if exists $marked{$node};
    @stack = ();
    &$connected_sub($node);
    #print "@stack\n";
    push @all_ccomp, [@stack];
}
# ....

Another (maybe simpler) way out is declare variables as "our" instead of "my"

So,

our %marked;

instead of

my %marked;

etc.


When getting a diagnostic message from perl, it's usually a good idea to check out perldiag to find out what it means. That manpage also happens to cover the warning you're getting.

Basically, named subroutines don't nest in the way you were expecting them to. Solutions include using anonymous inner subroutines, not nesting named subroutines and just passing state on between them explicitly, or using something like mysubs from CPAN.