📄 cons
字号:
# Every builder must now have at least an associated environment,
# so we can find its sigarray and calculate the proper signature.
sub find {
my($class, $env) = @_;
$builder{$env} || do {
my $self = { env => $env };
$builder{$env} = bless $self, $class;
}
}
# Null signature for dynamic includes.
sub includes { () }
# Null signature for build script.
sub scriptsig { () }
# Not compatible with any other builder, by default.
sub compatible { 0 }
# Builder module for the Install command.
package build::install;
use vars qw( @ISA );
BEGIN { @ISA = qw(build) }
# Caching not supported for Install: generally install is trivial anyway,
# and we don't want to clutter the cache.
sub cachin { undef }
sub cachout { }
# Do the installation.
sub action {
my($self, $tgt) = @_;
my($src) = $tgt->{sources}[0];
main::showcom("Install ${\$src->rpath} as ${\$tgt->path}")
if ($param::install && $param::quiet < 1);
return unless $param::build;
futil::install($src->rpath, $tgt);
return 1;
}
# Builder module for generic UNIX commands.
package build::command;
use vars qw( @ISA %com );
BEGIN { @ISA = qw(build) }
sub find {
my($class, $env, $cmd, $package) = @_;
my($act) = action::new($env, $cmd);
$package ||= '';
$com{$env,$act,$package} || do {
my $self = { env => $env, act => $act, 'package' => $package };
$com{$env,$act,$package} = bless $self, $class;
}
}
# Default cache in function.
sub cachin {
my($self, $tgt, $sig) = @_;
if (cache::in($tgt, $sig)) {
if ($param::cachecom) {
$self->{act}->show($self->{env}, $tgt);
} else {
printf("Retrieved %s from cache\n", $tgt->path)
if ($param::quiet < 1);
}
return 1;
}
return undef;
}
# Default cache out function.
sub cachout {
my($self, $tgt, $sig) = @_;
cache::out($tgt, $sig);
}
# Build the target using the previously specified commands.
sub action {
my($self, $tgt) = @_;
$self->{act}->execute($self->{env}, $tgt, $self->{'package'});
}
# Return script signature.
sub scriptsig {
$_[0]->{act}->scriptsig
}
# Create a linked module.
package build::command::link;
use vars qw( @ISA );
BEGIN { @ISA = qw(build::command) }
# Find an appropriate linker.
sub find {
my($class, $env, $command) = @_;
if (!exists $env->{_LDIRS}) {
my($ldirs) = '';
my($wd) = $env->{_cwd};
my($pdirs) = $env->{LIBPATH};
if (! defined $pdirs) {
$pdirs = [ ];
} elsif (ref($pdirs) ne 'ARRAY') {
$pdirs = [ split(/$main::PATH_SEPARATOR/o, $pdirs) ];
}
my($dir, $dpath);
for $dir (map($wd->lookupdir($env->_subst($_)), @$pdirs)) {
$dpath = $dir->path;
# Add the (presumably local) directory to the -L flags
# if we're not using repositories, the directory exists,
# or it's Linked to a source directory (that is, it *will*
# exist by the time the link occurs).
$ldirs .= " ".$env->{LIBDIRPREFIX}.$dpath.$env->{LIBDIRSUFFIX}
if ! @param::rpath || -d $dpath || $dir->is_linked;
next if File::Spec->file_name_is_absolute($dpath);
if (@param::rpath) {
my $d;
if ($dpath eq $dir::CURDIR) {
foreach $d (map($_->path, @param::rpath)) {
$ldirs .= " " . $env->{LIBDIRPREFIX} .
$d . $env->{LIBDIRSUFFIX};
}
} else {
my($rpath);
foreach $d (map($_->path, @param::rpath)) {
$rpath = File::Spec->catfile($d, $dpath);
$ldirs .= " ". $env->{LIBDIRPREFIX} .
$rpath . $env->{LIBDIRSUFFIX} if -d $rpath;
}
}
}
}
$env->{_LDIRS} = "%($ldirs%)";
}
# Introduce a new magic _LIBS symbol which allows to use the
# Unix-style -lNAME syntax for Win32 only. -lNAME will be replaced
# with %{PREFLIB}NAME%{SUFLIB}. <schwarze@isa.de> 1998-06-18
if ($main::_WIN32 && !exists $env->{_LIBS}) {
my $libs;
my $name;
for $name (split(' ', $env->_subst($env->{LIBS} || ''))) {
if ($name =~ /^-l(.*)/) {
$name = "$env->{PREFLIB}$1$env->{SUFLIB}";
}
$libs .= ' ' . $name;
}
$env->{_LIBS} = $libs ? "%($libs%)" : '';
}
bless find build::command($env, $command);
}
# Called from file::build. Make sure any libraries needed by the
# environment are built, and return the collected signatures
# of the libraries in the path.
sub includes {
return $_[0]->{'bsig'} if exists $_[0]->{'bsig'};
my($self, $tgt) = @_;
my($env) = $self->{env};
my($ewd) = $env->{_cwd};
my $ldirs = $env->{LIBPATH};
if (! defined $ldirs) {
$ldirs = [ ];
} elsif (ref($ldirs) ne 'ARRAY') {
$ldirs = [ split(/$main::PATH_SEPARATOR/o, $ldirs) ];
}
my @lpath = map($ewd->lookupdir($_), @$ldirs);
my(@sigs);
my(@names);
# Pass %LIBS symbol through %-substituition
# <schwarze@isa.de> 1998-06-18
@names = split(' ', $env->_subst($env->{LIBS} || ''));
my $name;
for $name (@names) {
my ($lpath, @allnames);
if ($name =~ /^-l(.*)/) {
# -l style names are looked up on LIBPATH, using all
# possible lib suffixes in the same search order the
# linker uses (according to SUFLIBS).
# Recognize new PREFLIB symbol, which should be 'lib' on
# Unix, and empty on Win32. TODO: What about shared
# library suffixes? <schwarze@isa.de> 1998-05-13
@allnames = map("$env->{PREFLIB}$1$_",
split(/:/, $env->{SUFLIBS}));
$lpath = \@lpath;
} else {
@allnames = ($name);
# On Win32, all library names are looked up in LIBPATH
# <schwarze@isa.de> 1998-05-13
if ($main::_WIN32) {
$lpath = [$dir::top, @lpath];
}
else {
$lpath = [$dir::top];
}
}
my $dir;
DIR: for $dir (@$lpath) {
my $n;
for $n (@allnames) {
my($lib) = $dir->lookup_accessible($n);
if ($lib) {
last DIR if $lib->ignore;
if ((build $lib) eq 'errors') {
$tgt->{status} = 'errors';
return undef;
}
push(@sigs, 'sig'->signature($lib));
last DIR;
}
}
}
}
$self->{'bsig'} = 'sig'->collect(@sigs);
}
# Always compatible with other such builders, so the user
# can define a single program or module from multiple places.
sub compatible {
my($self, $other) = @_;
ref($other) eq "build::command::link";
}
# Link a program.
package build::command::linkedmodule;
use vars qw( @ISA );
BEGIN { @ISA = qw(build::command) }
# Always compatible with other such builders, so the user
# can define a single linked module from multiple places.
sub compatible {
my($self, $other) = @_;
ref($other) eq "build::command::linkedmodule";
}
# Builder for a C module
package build::command::cc;
use vars qw( @ISA );
BEGIN { @ISA = qw(build::command) }
sub find {
$_[1]->{_cc} || do {
my($class, $env) = @_;
my($cpppath) = $env->_subst($env->{CPPPATH});
my($cscanner) = find scan::cpp($env->{_cwd}, $cpppath);
$env->{_IFLAGS} = "%(" . $cscanner->iflags($env) . "%)";
my($self) = find build::command($env, $env->{CCCOM});
$self->{scanner} = $cscanner;
bless $env->{_cc} = $self;
}
}
# Invoke the associated C scanner to get signature of included files.
sub includes {
my($self, $tgt) = @_;
$self->{scanner}->includes($tgt, $tgt->{sources}[0]);
}
# Builder for a C++ module
package build::command::cxx;
use vars qw( @ISA );
BEGIN { @ISA = qw(build::command) }
sub find {
$_[1]->{_cxx} || do {
my($class, $env) = @_;
my($cpppath) = $env->_subst($env->{CPPPATH});
my($cscanner) = find scan::cpp($env->{_cwd}, $cpppath);
$env->{_IFLAGS} = "%(" . $cscanner->iflags($env) . "%)";
my($self) = find build::command($env, $env->{CXXCOM});
$self->{scanner} = $cscanner;
bless $env->{_cxx} = $self;
}
}
# Invoke the associated C scanner to get signature of included files.
sub includes {
my($self, $tgt) = @_;
$self->{scanner}->includes($tgt, $tgt->{sources}[0]);
}
# Builder for a user command (cons::Command). We assume that a user
# command might be built and implement the appropriate dependencies on
# the command itself (actually, just on the first word of the command
# line).
package build::command::user;
use vars qw( @ISA );
BEGIN { @ISA = qw(build::command) }
sub includes {
my($self, $tgt) = @_;
my($sig) = '';
# Check for any quick scanners attached to source files.
my $dep;
for $dep (@{$tgt->{dep}}, @{$tgt->{sources}}) {
my($scanner) = $dep->{'srcscan',$self->{env}};
if ($scanner) {
$sig .= $scanner->includes($tgt, $dep);
}
}
# XXX Optimize this to not use ignored paths.
if (! exists $self->{_comsig}) {
my($env) = $self->{env};
$self->{_comsig} = '';
my($com, $dir);
com:
for $com ($self->{act}->commands) {
my($pdirs) = $env->{ENV}->{PATH};
if (! defined $pdirs) {
$pdirs = [ ];
} elsif (ref($pdirs) ne 'ARRAY') {
$pdirs = [ split(/$main::PATH_SEPARATOR/o, $pdirs) ];
}
for $dir (map($dir::top->lookupdir($_), @$pdirs)) {
my($prog) = $dir->lookup_accessible($com);
if ($prog) { # XXX Not checking execute permission.
if ((build $prog) eq 'errors') {
$tgt->{status} = 'errors';
return $sig;
}
next com if $prog->ignore;
$self->{_comsig} .= 'sig'->signature($prog);
next com;
}
}
}
}
return $self->{_comsig} . $sig
}
# Builder for a library module (archive).
# We assume that a user command might be built and implement the
# appropriate dependencies on the command itself.
package build::command::library;
use vars qw( @ISA );
BEGIN { @ISA = qw(build::command) }
sub find {
my($class, $env) = @_;
bless find build::command($env, $env->{ARCOM})
}
# Always compatible with other library builders, so the user
# can define a single library from multiple places.
sub compatible {
my($self, $other) = @_;
ref($other) eq "build::command::library";
}
# A multi-target builder.
# This allows multiple targets to be associated with a single build
# script, without forcing all the code to be aware of multiple targets.
package build::multiple;
sub new {
my($class, $builder, $tgts) = @_;
bless { 'builder' => $builder, 'env' => $builder->{env}, 'tgts' => $tgts };
}
sub scriptsig {
my($self, $tgt) = @_;
$self->{builder}->scriptsig($tgt);
}
sub includes {
my($self, $tgt) = @_;
$self->{builder}->includes($tgt);
}
sub compatible {
my($self, $tgt) = @_;
$self->{builder}->compatible($tgt);
}
sub cachin {
my($self, $tgt, $sig) = @_;
$self->{builder}->cachin($tgt, $sig);
}
sub cachout {
my($self, $tgt, $sig) = @_;
$self->{builder}->cachout($tgt, $sig);
}
sub action {
my($self, $invoked_tgt) = @_;
return $self->{built} if exists $self->{built};
# Make sure all targets in the group are unlinked before building any.
my($tgts) = $self->{tgts};
my $tgt;
for $tgt (@$tgts) {
futil::mkdir($tgt->{dir});
unlink($tgt->path) if ! $tgt->precious;
}
# Now do the action to build all the targets. For consistency
# we always call the action on the first target, just so that
# $> is deterministic.
$self->{built} = $self->{builder}->action($tgts->[0]);
# Now "build" all the other targets (except for the one
# we were called with). This guarantees that the signature
# of each target is updated appropriately. We force the
# targets to be built even if they have been previously
# considered and found to be OK; the only effect this
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -