File Coverage

blib/lib/App/hopen/Gen/Make.pm
Criterion Covered Total %
statement 65 93 69.8
branch 4 18 22.2
condition 1 6 16.6
subroutine 18 25 72.0
pod 4 4 100.0
total 92 146 63.0


line stmt bran cond sub pod time code
1             # App::hopen::Gen::Make - generator for a generic make(1).
2             package App::hopen::Gen::Make;
3 1     1   717 use strict;
  1         2  
  1         39  
4 1     1   7 use Data::Hopen::Base;
  1         3  
  1         12  
5              
6             our $VERSION = '0.000011';
7              
8 1     1   1605 use parent 'App::hopen::Gen';
  1         3  
  1         8  
9 1     1   47 use Class::Tiny qw(targets);
  1         4  
  1         6  
10              
11 1     1   211 use App::hopen::BuildSystemGlobals;
  1         2  
  1         108  
12 1     1   11 use App::hopen::Phases qw(is_last_phase);
  1         2  
  1         55  
13 1     1   7 use Data::Hopen qw(:default getparameters $QUIET);
  1         2  
  1         122  
14 1     1   8 use Data::Hopen::Scope::Hash;
  1         3  
  1         59  
15 1     1   7 use Data::Hopen::Util::Data qw(forward_opts);
  1         2  
  1         54  
16 1     1   503 use File::Which;
  1         972  
  1         64  
17 1     1   514 use Hash::Ordered;
  1         3515  
  1         31  
18              
19 1     1   450 use App::hopen::Gen::Make::AssetGraphNode; # for $OUTPUT
  1         5  
  1         79  
20 1     1   516 use App::hopen::Gen::Make::AssetGraphVisitor;
  1         3  
  1         1230  
21              
22             # Docs {{{1
23              
24             =head1 NAME
25              
26             Data::Hopen::Gen::Make - hopen generator for simple Makefiles
27              
28             =head1 SYNOPSIS
29              
30             This generator makes a Makefile that does its best to run on cmd.exe or sh(1).
31              
32             =head1 ATTRIBUTES
33              
34             =head2 targets
35              
36             A L<Hash::Ordered> of the targets, in the order encountered.
37              
38             =head1 FUNCTIONS
39              
40             =cut
41              
42             # }}}1
43              
44             =head2 visit_goal
45              
46             Add a target corresponding to the name of the goal. Usage:
47              
48             $Generator->visit_goal($node, $node_inputs);
49              
50             This happens while the command graph is being run.
51              
52             =cut
53              
54             sub visit_goal {
55 1     1 1 4532 my ($self, %args) = getparameters('self', [qw(goal node_inputs)], @_);
56 1         150 $self->targets->set($args{goal}->name, $args{goal});
57              
58             # --- Add the goal to the asset graph ---
59              
60 1         102 my $asset_goal = $self->_assets->goal($args{goal}->name);
61              
62             # Pull the inputs. TODO refactor out the code in common with
63             # AhG::Cmd::input_assets().
64             my $hrSourceFiles =
65 1   50     1806 $args{node_inputs}->find(-name => 'made',
66             -set => '*', -levels => 'local') // {};
67             die 'No input files to goal ' . $args{goal}->name
68 1 50       231 unless scalar keys %$hrSourceFiles;
69              
70 1         17 my $lrSourceFiles = $hrSourceFiles->{(keys %$hrSourceFiles)[0]};
71 1     0   11 hlog { 'found inputs to goal', $args{goal}->name, Dumper($lrSourceFiles) } 2;
  0         0  
72              
73             # TODO? verify that all the assets are actually in the graph first?
74 1         18 $self->connect($_, $asset_goal) foreach @$lrSourceFiles;
75              
76             } #visit_goal()
77              
78             =head2 finalize
79              
80             Write out the Makefile.
81              
82             =cut
83              
84             sub finalize {
85 2     2 1 15 my ($self, %args) = getparameters('self', [qw(phase dag data)], @_);
86 2     0   254 hlog { Finalizing => __PACKAGE__ , '- phase', $args{phase} };
  0         0  
87 2 100       26 return unless is_last_phase $args{phase};
88              
89 1     0   8 hlog { __PACKAGE__, 'Asset graph', '' . $self->_assets->_graph } 3;
  0         0  
90              
91             # During the Gen phase, create the Makefile
92 1 50       36 open my $fh, '>', $self->dest_dir->file('Makefile') or die "Couldn't create Makefile";
93 1         362 print $fh <<EOT;
94             # Makefile generated by hopen (https://github.com/hopenbuild/App-hopen)
95 1         18 # at @{[scalar gmtime]} GMT
96 1         30 # From ``@{[$self->proj_dir->absolute]}'' into ``@{[$self->dest_dir->absolute]}''
  1         170  
97              
98             .PHONY: first__goal__
99              
100             EOT
101              
102             # Make sure the first goal is 'all' regardless of order.
103 1         174 print $fh 'first__goal__: ', $args{dag}->default_goal->name, "\n";
104              
105 1         31 my $context = Data::Hopen::Scope::Hash->new;
106 1         34 $context->put(App::hopen::Gen::Make::AssetGraphNode::OUTPUT, $fh);
107              
108             # Write the Makefile. TODO flip the order.
109              
110 1         76 $self->_assets->run(-context => $context,
111             -visitor => App::hopen::Gen::Make::AssetGraphVisitor->new,
112             forward_opts(\%args, {'-'=>1}, qw(phase))
113             );
114              
115 1         134 close $fh;
116             } #finalize()
117              
118             =head2 default_toolset
119              
120             Returns the package name of the default toolset for this generator,
121             which is C<Gnu> (i.e., L<Data::Hopen::T::Gnu>).
122              
123             =cut
124              
125 2     2 1 10 sub default_toolset { 'Gnu' }
126              
127             =head2 _assetop_class
128              
129             The class of asset-graph operations, which in this case is
130             L<App::hopen::Gen::Make::AssetGraphNode>.
131              
132             =cut
133              
134 3     3   10 sub _assetop_class { 'App::hopen::Gen::Make::AssetGraphNode' }
135              
136             =head2 _run_build
137              
138             Implementation of L</run_build>.
139              
140             =cut
141              
142             sub _run_build {
143             # Look for the make(1) executable. Listing make before gmake since a
144             # system with both Cygwin and Strawberry Perl installed has cygwin's
145             # make(1) and Strawberry's gmake(1).
146 0     0   0 foreach my $candidate (qw[make gmake mingw32-make dmake]) {
147 0         0 my $path = File::Which::which($candidate);
148 0 0       0 next unless defined $path;
149 0     0   0 hlog { Running => $path };
  0         0  
150 0         0 system $path, ();
151 0         0 return;
152             }
153 0         0 warn "Could not find a 'make' program to run";
154             } #_run_build()
155              
156             =head1 INTERNALS
157              
158             =head2 _expand
159              
160             Produce the command line or lines associated with a work item. Used by
161             L</finalize>.
162              
163             =cut
164              
165             sub _expand {
166 0 0   0   0 my $item = shift or croak 'Need a work item';
167 0     0   0 hlog { __PACKAGE__ . '::_expand()', Dumper($item) } 2;
  0         0  
168 0 0       0 my $retval = $item->{how} or return ''; # no `how` => no output; not an error
169 0 0       0 $retval = $retval->[0] if ref $retval eq 'ARRAY';
170              
171 0         0 my $first = $item->{from}->[0];
172 0 0       0 $first = $first->orig->relative($DestDir)
173             if $first->DOES('App::hopen::Util::BasedPath');
174              
175 0         0 my $out = $item->{to}->[0];
176 0 0       0 $out = $out->orig->relative($DestDir)
177             if $out->DOES('App::hopen::Util::BasedPath');
178              
179 0   0     0 $retval =~ s{#first\b}{$first // ''}ge; # first input
  0         0  
180 0         0 $retval =~ s{#all\b}{join(' ', @{$item->{from}})}ge; # all inputs
  0         0  
  0         0  
181 0   0     0 $retval =~ s{#out\b}{$out // ''}ge;
  0         0  
182              
183 0         0 return $retval;
184             } #_expand()
185              
186             =head2 BUILD
187              
188             Constructor
189              
190             =cut
191              
192             sub BUILD {
193 2     2 1 2508 my ($self, $hrArgs) = @_;
194 2         20 $self->targets(Hash::Ordered->new());
195             } #BUILD()
196              
197              
198             1;
199             __END__
200             # vi: set fdm=marker: #