package ExtUtils::Builder; $ExtUtils::Builder::VERSION = '0.016'; use strict; use warnings; 1; #ABSTRACT: An overview of the foundations of the ExtUtils::Builder Plan framework __END__ =pod =encoding UTF-8 =head1 NAME ExtUtils::Builder - An overview of the foundations of the ExtUtils::Builder Plan framework =head1 VERSION version 0.016 =head1 DESCRIPTION This document describes the foundations of the ExtUtils::Builder Plan framework, including Actions, Nodes and Plans. =head1 OVERVIEW =head2 Action basics Actions are the cornerstone of the ExtUtils::Builder framework. They provide an interface between build tools (e.g. L<ExtUtils::MakeMaker|ExtUtils::MakeMaker>, L<Module::Build|Module::Build>, ...) and building extensions. This allows producing and consuming sides to be completely independent from each other. It is a flexible abstraction around pieces of work, this work can be a piece of perl code, an external command, a mix of those or possibly other things. An action can be consumed in many ways. =over 4 =item * execute(%args) This is often the simplest way of dealing with an action. It simple performs the action immediately, and will throw an exception on failure. =item * to_command(%opts) This converts the action into a list of commands to be executed. The elements of this list are arrayrefs to that can each be executed using along these lines: for my $command ($work->to_command) { system(@$command); } It can take two optional named arguments: C<perl> for the path to perl, and C<config> for an L<ExtUtils::Config> object used the find the current perl. =item * to_code() This converts the action into a list of strings to be C<eval>ed in order to execute them. This can be useful when you want to serialize the work that is to be done but don't want to force it to shell out. =item * to_code_hash() This converts the action into a hash that can be used to create a new L<ExtUtils::Builder::Action::Code>. =item * flatten() This will return all primitive actions involved in this action. It may return C<$self>, it may return an empty list. On L<composite|ExtUtils::Builder::Action::Composite> actions, C<flatten> can be called to retrieve the constituent actions, C<flatten> is guaranteed to only return primitive actions. =item * preference(@options) If a consumer can consume actions in more than one way, the C<preference> method can be used to choose between options. This function expects a list of options out of C<code>, C<command>, C<execute> and C<flatten>. You probably want to flatten your action first, as different constituents may have different preferences. for my $action ($work->flatten) { my $preference = $self->preference('code', 'command'); push @serialized, ($preference eq 'code') ? [ eval => $action->to_code ] : [ exec => $action->to_command ]; } =back =head2 Primitives On primitive actions, all serialization methods will return a single item list. There are two types of of primitive actions shipped with this dist: L<Command|ExtUtils::Builder::Command> and L<Code|ExtUtils::Builder::Code>. Commands are essentially an abstraction around a call to an external command, Codes are an abstraction around a piece of Perl code. While these are all implementing the same interfaces, they have their own (hopefully obvious) preferences on how to be treated. C<flatten> is just an identity operator for primitive actions. =head2 Composites Composite actions are actions that may consist out of multiple actions (though in some cases they may contain only one or even zero actions). C<flatten> will return all its constituents. C<execute>, C<to_code> and C<to_command> will all call their respective method on all those values. C<preference> is of little use, and will always prefer to flatten when given that option. =head3 Nodes Nodes are composite Actions. Nodes are a simple class with three attributes: =over 4 =item * target This is the filename of the result of this build step. =item * dependencies This is an unordered set of zero or more files that must be build (and must be up-to-date) before the target is build. =item * actions This is a sequence of zero or more actions that must be performed to build the target. =back Essentially, a Node is equivalent to entry in a Makefile =head2 Plans Plans are the equivalent of a (piece of a) Makefile. They are a bunch of nodes that should interconnect. It has one attribute. =over 4 =item * nodes This is a hash mapping (target) names to nodes. =back The C<run> method will perform a topological sort much like C<make>. It will check which steps are necessary and skip the ones which are not. =head1 RATIONALE Writing extensions for various build tools can be a daunting task. This module tries to abstract steps of build processes into reusable building blocks for creating platform and build system agnostic executable descriptions of work. =head1 USAGE package Frobnicator; use ExtUtils::Builder::Action::Code; ... sub add_plans { my ($self, $planner) = @_; my $action = ExtUtils::Builder::Action::Code->new( code => ..., ); $planner->create_node( target => 'frob', actions => [ $action ], ); $planner->create_node( target => 'pure_all', dependencies => [ 'frob' ], phony => 1, ); } ... =head2 Makefile.PL use ExtUtils::MakeMaker; use ExtUtils::Builder::MakeMaker; ... WriteMakeFile( NAME => 'Foo', VERSION => 0.001, ..., ); sub MY::make_plans { my ($self, $planner) = @_; Frobnicator->add_plans($planner); } =head1 AUTHOR Leon Timmermans <fawaka@gmail.com> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2013 by Leon Timmermans. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut