| Server IP : 216.92.14.13 / Your IP : 216.73.216.171 Web Server : Apache System : Linux vps4089.pairvps.com 5.15.0-190-generic #200-Ubuntu SMP Fri Aug 7 15:06:04 UTC 2026 x86_64 User : rmlac2fmr ( 1040637) PHP Version : 8.2.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/local/bin/ |
Upload File : |
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use Make;
my (%opt, $redundancy);
if (!GetOptions(
## no critic (BuiltinFunctions::RequireBlockMap)
(map +("$_!" => \$opt{$_}), qw(D g n p)),
(map +("$_=s" => \$opt{$_}), qw(f C)),
(map +("$_=i" => \$opt{$_}), qw(j)),
## use critic
'analyse-redundancy!' => \$redundancy,
)) {
require Pod::Usage;
Pod::Usage::pod2usage(1);
}
chdir $opt{C} if $opt{C};
my $info = Make->new(
GNU => $opt{g},
Vars => { MAKE => "$^X $0" },
Jobs => $opt{j},
);
$info->parse($opt{f});
if ( $opt{D} ) {
require Data::Dumper;
print Data::Dumper::DumperX($info);
}
elsif ( $opt{p} ) {
$info->Print(@ARGV);
}
elsif ( $opt{n} ) {
print $info->Script(@ARGV);
}
elsif ( $redundancy ) {
my $g = $info->as_graph(no_rules => 1);
my $tcg = $g->transitive_closure(path_count => 1);
## no critic (BuiltinFunctions::RequireBlockGrep BuiltinFunctions::RequireBlockMap)
my @r = grep $tcg->path_length(@$_) > 1, $g->edges;
if (!@r) {
print "No redundant rules found\n";
exit 0;
}
@r = sort { $a->[0] cmp $b->[0] or $a->[1] cmp $b->[1] } @r;
my %seen = map +("@$_" => 1), @r;
for my $e (@r) {
print "Redundant direct dep: @$e\n";
my @direct_recipes = make_recipe_tuples($g, $e);
my %seen_recipe;
if (map @{ $_->[1] }, @direct_recipes) {
$seen_recipe{$_->[0]}++ for @direct_recipes;
print print_recipe_tuple($_, 2) for @direct_recipes;
}
for my $l (sort {"@$a" cmp "@$b"} grep !$seen{"@$_"}++, $tcg->all_paths(@$e)) {
print " @$l\n";
my @link_recipes = make_recipe_tuples($g, [ @$l[0,1] ]);
next if !map @{ $_->[1] }, @link_recipes;
for my $lr (@link_recipes) {
if ($seen_recipe{$lr->[0]}++) {
print " (already seen $lr->[0])\n";
} else {
print print_recipe_tuple($_, 6) for @link_recipes;
}
}
}
}
## use critic
}
else {
$info->Make(@ARGV);
}
sub make_recipe_tuples {
my ($g, $e) = @_;
## no critic (BuiltinFunctions::RequireBlockGrep BuiltinFunctions::RequireBlockMap)
return map [
"$e->[0]:$_", $g->get_edge_attribute_by_id(@$e, $_, 'recipe_raw')
], $g->get_multiedge_ids(@$e);
## use critic
}
sub print_recipe_tuple {
my ($t, $indent) = @_;
## no critic (BuiltinFunctions::RequireBlockGrep BuiltinFunctions::RequireBlockMap)
return join '', map "$_\n",
(" " x $indent)."Recipe $t->[0]:",
map { my $t = $_; $t =~ s/^/\t/gm; $t } @{ $t->[1] },
;
## use critic
}
=head1 NAME
pure-perl-make - a perl 'make' replacement
=head1 SYNOPSIS
pure-perl-make [-D] [-n] [-p] [-g] [-f Makefile] [-C directory]
[--analyse-redundancy]
[targets] [vars]
=head1 DESCRIPTION
Performs the same function as make(1) but is written entirely in perl.
A subset of GNU make extensions is supported.
For details see L<Make> for the underlying perl module.
=head1 FLAGS
=head2 -D
Don't build, just L<Data::Dumper/DumperX> the L<Make> object.
=head2 -n
Don't build, just print what building would have done.
=head2 -p
Don't build, just print the expanded makefile.
=head2 -g
Turn on L<Make/GNU>.
=head2 --analyse-redundancy
See if there are direct dependencies that are redundant with indirect
dependencies. E.g.:
all: L1 L2 # no need to specify L2
L1: L2
=head1 BUGS
=over
=item *
No B<-k> flag
=back
=head1 SEE ALSO
L<Make>, make(1), L<Graph>
=head1 AUTHOR
Nick Ing-Simmons
=cut