1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498 |
- # ------------------------------------------------------------------------------
- # NAME
- # Fcm::BuildSrc
- #
- # DESCRIPTION
- # This is a class to group functionalities of source in a build.
- #
- # COPYRIGHT
- # (C) Crown copyright Met Office. All rights reserved.
- # For further details please refer to the file COPYRIGHT.txt
- # which you should have received as part of this distribution.
- # ------------------------------------------------------------------------------
- use strict;
- use warnings;
- package Fcm::BuildSrc;
- use base qw{Fcm::Base};
- use Carp qw{croak};
- use Cwd qw{cwd};
- use Fcm::Build::Fortran;
- use Fcm::CfgFile;
- use Fcm::CfgLine;
- use Fcm::Config;
- use Fcm::Timer qw{timestamp_command};
- use Fcm::Util qw{find_file_in_path run_command};
- use File::Basename qw{basename dirname};
- use File::Spec;
- # List of scalar property methods for this class
- my @scalar_properties = (
- 'children', # list of children packages
- 'is_updated', # is this source (or its associated settings) updated?
- 'mtime', # modification time of src
- 'ppmtime', # modification time of ppsrc
- 'ppsrc', # full path of the pre-processed source
- 'pkgname', # package name of the source
- 'progname', # program unit name in the source
- 'src', # full path of the source
- 'type', # type of the source
- );
- # List of hash property methods for this class
- my @hash_properties = (
- 'dep', # dependencies
- 'ppdep', # pre-process dependencies
- 'rules', # make rules
- );
- # Error message formats
- my %ERR_MESS_OF = (
- CHDIR => '%s: cannot change directory (%s), abort',
- OPEN => '%s: cannot open (%s), abort',
- CLOSE_PIPE => '%s: failed (%d), abort',
- );
- # Event message formats and levels
- my %EVENT_SETTING_OF = (
- CHDIR => ['%s: change directory' , 2],
- F_INTERFACE_NONE => ['%s: Fortran interface generation is off', 3],
- GET_DEPENDENCY => ['%s: %d line(s), %d auto dependency(ies)', 3],
- );
- my %RE_OF = (
- F_PREFIX => qr{
- (?:
- (?:ELEMENTAL|PURE(?:\s+RECURSIVE)?|RECURSIVE(?:\s+PURE)?)
- \s+
- )?
- }imsx,
- F_SPEC => qr{
- (?:
- (?:CHARACTER|COMPLEX|DOUBLE\s*PRECISION|INTEGER|LOGICAL|REAL|TYPE)
- (?: \s* \( .+ \) | \s* \* \d+ \s*)??
- \s+
- )?
- }imsx,
- );
- {
- # Returns a singleton instance of Fcm::Build::Fortran.
- my $FORTRAN_UTIL;
- sub _get_fortran_util {
- $FORTRAN_UTIL ||= Fcm::Build::Fortran->new();
- return $FORTRAN_UTIL;
- }
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $obj = Fcm::BuildSrc->new (%args);
- #
- # DESCRIPTION
- # This method constructs a new instance of the Fcm::BuildSrc class. See
- # above for allowed list of properties. (KEYS should be in uppercase.)
- # ------------------------------------------------------------------------------
- sub new {
- my ($class, %args) = @_;
- my $self = bless(Fcm::Base->new(%args), $class);
- for my $key (@scalar_properties, @hash_properties) {
- $self->{$key}
- = exists($args{uc($key)}) ? $args{uc($key)}
- : undef
- ;
- }
- $self;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $value = $obj->X;
- # $obj->X ($value);
- #
- # DESCRIPTION
- # Details of these properties are explained in @scalar_properties.
- # ------------------------------------------------------------------------------
- for my $name (@scalar_properties) {
- no strict 'refs';
- *$name = sub {
- my $self = shift;
- # Argument specified, set property to specified argument
- if (@_) {
- $self->{$name} = $_[0];
- if ($name eq 'ppsrc') {
- $self->ppmtime (undef);
- } elsif ($name eq 'src') {
- $self->mtime (undef);
- }
- }
- # Default value for property
- if (not defined $self->{$name}) {
- if ($name eq 'children') {
- # Reference to an empty array
- $self->{$name} = [];
-
- } elsif ($name =~ /^(?:is_cur|pkgname|ppsrc|src)$/) {
- # Empty string
- $self->{$name} = '';
-
- } elsif ($name eq 'mtime') {
- # Modification time
- $self->{$name} = (stat $self->src)[9] if $self->src;
-
- } elsif ($name eq 'ppmtime') {
- # Modification time
- $self->{$name} = (stat $self->ppsrc)[9] if $self->ppsrc;
-
- } elsif ($name eq 'type') {
- # Attempt to get the type if src is set
- $self->{$name} = $self->get_type if $self->src;
- }
- }
- return $self->{$name};
- }
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # %hash = %{ $obj->X () };
- # $obj->X (\%hash);
- #
- # $value = $obj->X ($index);
- # $obj->X ($index, $value);
- #
- # DESCRIPTION
- # Details of these properties are explained in @hash_properties.
- #
- # If no argument is set, this method returns a hash containing a list of
- # objects. If an argument is set and it is a reference to a hash, the objects
- # are replaced by the the specified hash.
- #
- # If a scalar argument is specified, this method returns a reference to an
- # object, if the indexed object exists or undef if the indexed object does
- # not exist. If a second argument is set, the $index element of the hash will
- # be set to the value of the argument.
- # ------------------------------------------------------------------------------
- for my $name (@hash_properties) {
- no strict 'refs';
- *$name = sub {
- my ($self, $arg1, $arg2) = @_;
- # Ensure property is defined as a reference to a hash
- if (not defined $self->{$name}) {
- if ($name eq 'rules') {
- $self->{$name} = $self->get_rules;
- } else {
- $self->{$name} = {};
- }
- }
- # Argument 1 can be a reference to a hash or a scalar index
- my ($index, %hash);
- if (defined $arg1) {
- if (ref ($arg1) eq 'HASH') {
- %hash = %$arg1;
- } else {
- $index = $arg1;
- }
- }
- if (defined $index) {
- # A scalar index is defined, set and/or return the value of an element
- $self->{$name}{$index} = $arg2 if defined $arg2;
- return (
- exists $self->{$name}{$index} ? $self->{$name}{$index} : undef
- );
- } else {
- # A scalar index is not defined, set and/or return the hash
- $self->{$name} = \%hash if defined $arg1;
- return $self->{$name};
- }
- }
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $value = $obj->X;
- # $obj->X ($value);
- #
- # DESCRIPTION
- # This method returns/sets property X, all derived from src, where X is:
- # base - (read-only) basename of src
- # dir - (read-only) dirname of src
- # ext - (read-only) file extension of src
- # root - (read-only) basename of src without the file extension
- # ------------------------------------------------------------------------------
- sub base {
- return &basename ($_[0]->src);
- }
- # ------------------------------------------------------------------------------
- sub dir {
- return &dirname ($_[0]->src);
- }
- # ------------------------------------------------------------------------------
- sub ext {
- return substr $_[0]->base, length ($_[0]->root);
- }
- # ------------------------------------------------------------------------------
- sub root {
- (my $root = $_[0]->base) =~ s/\.\w+$//;
- return $root;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $value = $obj->X;
- # $obj->X ($value);
- #
- # DESCRIPTION
- # This method returns/sets property X, all derived from ppsrc, where X is:
- # ppbase - (read-only) basename of ppsrc
- # ppdir - (read-only) dirname of ppsrc
- # ppext - (read-only) file extension of ppsrc
- # pproot - (read-only) basename of ppsrc without the file extension
- # ------------------------------------------------------------------------------
- sub ppbase {
- return &basename ($_[0]->ppsrc);
- }
- # ------------------------------------------------------------------------------
- sub ppdir {
- return &dirname ($_[0]->ppsrc);
- }
- # ------------------------------------------------------------------------------
- sub ppext {
- return substr $_[0]->ppbase, length ($_[0]->pproot);
- }
- # ------------------------------------------------------------------------------
- sub pproot {
- (my $root = $_[0]->ppbase) =~ s/\.\w+$//;
- return $root;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $value = $obj->X;
- #
- # DESCRIPTION
- # This method returns/sets property X, derived from src or ppsrc, where X is:
- # curbase - (read-only) basename of cursrc
- # curdir - (read-only) dirname of cursrc
- # curext - (read-only) file extension of cursrc
- # curmtime - (read-only) modification time of cursrc
- # curroot - (read-only) basename of cursrc without the file extension
- # cursrc - ppsrc or src
- # ------------------------------------------------------------------------------
- for my $name (qw/base dir ext mtime root src/) {
- no strict 'refs';
- my $subname = 'cur' . $name;
- *$subname = sub {
- my $self = shift;
- my $method = $self->ppsrc ? 'pp' . $name : $name;
- return $self->$method (@_);
- }
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $base = $obj->X ();
- #
- # DESCRIPTION
- # This method returns a basename X for the source, where X is:
- # donebase - "done" file name
- # etcbase - target for copying data files
- # exebase - executable name for source containing a main program
- # interfacebase - Fortran interface file name
- # libbase - library file name
- # objbase - object name for source containing compilable source
- # If the source file contains a compilable procedure, this method returns
- # the name of the object file.
- # ------------------------------------------------------------------------------
- sub donebase {
- my $self = shift;
- my $return;
- if ($self->is_type_all ('SOURCE')) {
- if ($self->objbase and not $self->is_type_all ('PROGRAM')) {
- $return = ($self->progname ? $self->progname : lc ($self->curroot)) .
- $self->setting (qw/OUTFILE_EXT DONE/);
- }
- } elsif ($self->is_type_all ('INCLUDE')) {
- $return = $self->curbase . $self->setting (qw/OUTFILE_EXT IDONE/);
- }
- return $return;
- }
- # ------------------------------------------------------------------------------
- sub etcbase {
- my $self = shift;
- my $return = @{ $self->children }
- ? $self->pkgname . $self->setting (qw/OUTFILE_EXT ETC/)
- : undef;
- return $return;
- }
- # ------------------------------------------------------------------------------
- sub exebase {
- my $self = shift;
- my $return;
- if ($self->objbase and $self->is_type_all ('PROGRAM')) {
- if ($self->setting ('BLD_EXE_NAME', $self->curroot)) {
- $return = $self->setting ('BLD_EXE_NAME', $self->curroot);
- } else {
- $return = $self->curroot . $self->setting (qw/OUTFILE_EXT EXE/);
- }
- }
- return $return;
- }
- # ------------------------------------------------------------------------------
- sub interfacebase {
- my $self = shift();
- if (
- uc($self->get_setting(qw/TOOL GENINTERFACE/)) ne 'NONE'
- && $self->progname()
- && $self->is_type_all(qw/SOURCE/)
- && $self->is_type_any(qw/FORTRAN9X FPP9X/)
- && !$self->is_type_any(qw/PROGRAM MODULE BLOCKDATA/)
- ) {
- my $flag = lc($self->get_setting(qw/TOOL INTERFACE/));
- my $ext = $self->setting(qw/OUTFILE_EXT INTERFACE/);
- return (($flag eq 'program' ? $self->progname() : $self->curroot()) . $ext);
- }
- return;
- }
- # ------------------------------------------------------------------------------
- sub objbase {
- my $self = shift;
- my $return;
- if ($self->is_type_all ('SOURCE')) {
- my $ext = $self->setting (qw/OUTFILE_EXT OBJ/);
- if ($self->is_type_any (qw/FORTRAN FPP/)) {
- $return = lc ($self->progname) . $ext if $self->progname;
- } else {
- $return = lc ($self->curroot) . $ext;
- }
- }
- return $return;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $value = $obj->flagsbase ($flag, [$index,]);
- #
- # DESCRIPTION
- # This method returns the property flagsbase (derived from pkgname) the base
- # name of the flags-file (to indicate changes in a particular build tool) for
- # $flag, which can have the value:
- # *FLAGS - compiler flags flags-file
- # *PPKEYS - pre-processor keys (i.e. macro definitions) flags-file
- # LD - linker flags-file
- # LDFLAGS - linker flags flags-file
- # If $index is set, the $index'th element in pkgnames is used for the package
- # name.
- # ------------------------------------------------------------------------------
- sub flagsbase {
- my ($self, $flag, $index) = @_;
- (my $pkg = $index ? $self->pkgnames->[$index] : $self->pkgname) =~ s/\.\w+$//;
- if ($self->is_type_all ('SOURCE')) {
- if ($flag eq 'FLAGS' or $flag eq 'PPKEYS' and $self->lang) {
- my %tool_src = %{ $self->setting ('TOOL_SRC') };
- $flag = $tool_src{$self->lang}{$flag} ? $tool_src{$self->lang}{$flag} : '';
- }
- }
- if ($flag) {
- return join ('__', ($flag, $pkg ? $pkg : ())) .
- $self->setting (qw/OUTFILE_EXT FLAGS/);
- } else {
- return undef;
- }
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $value = $obj->libbase ([$prefix], [$suffix]);
- #
- # DESCRIPTION
- # This method returns the property libbase (derived from pkgname) the base
- # name of the library archive. $prefix and $suffix defaults to 'lib' and '.a'
- # respectively.
- # ------------------------------------------------------------------------------
- sub libbase {
- my ($self, $prefix, $suffix) = @_;
- $prefix ||= 'lib';
- $suffix ||= $self->setting(qw/OUTFILE_EXT LIB/);
- if ($self->src()) { # applies to directories only
- return;
- }
- my $name = $self->setting('BLD_LIB', $self->pkgname());
- if (!defined($name)) {
- $name = $self->pkgname();
- }
- $prefix . $name . $suffix;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $value = $obj->lang ([$setting]);
- #
- # DESCRIPTION
- # This method returns the property lang (derived from type) the programming
- # language name if type matches one supported in the TOOL_SRC setting. If
- # $setting is specified, use $setting instead of TOOL_SRC.
- # ------------------------------------------------------------------------------
- sub lang {
- my ($self, $setting) = @_;
- my @keys = keys %{ $self->setting ($setting ? $setting : 'TOOL_SRC') };
- my $return = undef;
- for my $key (@keys) {
- next unless $self->is_type_all ('SOURCE', $key);
- $return = $key;
- last;
- }
- return $return;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $value = $obj->pkgnames;
- #
- # DESCRIPTION
- # This method returns a list of container packages, derived from pkgname:
- # ------------------------------------------------------------------------------
- sub pkgnames {
- my $self = shift;
- my $return = [];
- if ($self->pkgname) {
- my @names = split (/__/, $self->pkgname);
- for my $i (0 .. $#names) {
- push @$return, join ('__', (@names[0 .. $i]));
- }
- unshift @$return, '';
- }
- return $return;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # %dep = %{$obj->get_dep()};
- # %dep = %{$obj->get_dep($flag)};
- #
- # DESCRIPTION
- # This method scans the current source file for dependencies and returns the
- # dependency hash (keys = dependencies, values = dependency types). If $flag
- # is specified, the config setting for $flag is used to determine the types of
- # types. Otherwise, those specified in 'BLD_TYPE_DEP' is used.
- # ------------------------------------------------------------------------------
- sub get_dep {
- my ($self, $flag) = @_;
- # Work out list of exclude for this file, using its sub-package name
- my %EXCLUDE_SET = map {($_, 1)} @{$self->get_setting('BLD_DEP_EXCL')};
- # Determine what dependencies are supported by this known type
- my %DEP_TYPE_OF = %{$self->setting($flag ? $flag : 'BLD_TYPE_DEP')};
- my %PATTERN_OF = %{$self->setting('BLD_DEP_PATTERN')};
- my @dep_types = ();
- if (!$self->get_setting('BLD_DEP_N')) {
- DEP_TYPE:
- while (my ($key, $dep_type_string) = each(%DEP_TYPE_OF)) {
- # Check if current file is a type of file requiring dependency scan
- if (!$self->is_type_all($key)) {
- next DEP_TYPE;
- }
- # Get list of dependency type for this file
- for my $dep_type (split(/$Fcm::Config::DELIMITER/, $dep_type_string)) {
- if (exists($PATTERN_OF{$dep_type}) && !exists($EXCLUDE_SET{$dep_type})) {
- push(@dep_types, $dep_type);
- }
- }
- }
- }
- # Automatic dependencies
- my %dep_of;
- my $can_get_symbol # Also scan for program unit name in Fortran source
- = !$flag
- && $self->is_type_all('SOURCE')
- && $self->is_type_any(qw/FPP FORTRAN/)
- ;
- my $has_read_file;
- if ($can_get_symbol || @dep_types) {
- my $handle = _open($self->cursrc());
- LINE:
- while (my $line = readline($handle)) {
- chomp($line);
- if ($line =~ qr{\A \s* \z}msx) { # empty lines
- next LINE;
- }
- if ($can_get_symbol) {
- my $symbol = _get_dep_symbol($line);
- if ($symbol) {
- $self->progname($symbol);
- $can_get_symbol = 0;
- next LINE;
- }
- }
- DEP_TYPE:
- for my $dep_type (@dep_types) {
- my ($match) = $line =~ /$PATTERN_OF{$dep_type}/i;
- if (!$match) {
- next DEP_TYPE;
- }
- # $match may contain multiple items delimited by space
- for my $item (split(qr{\s+}msx, $match)) {
- my $key = uc($dep_type . $Fcm::Config::DELIMITER . $item);
- if (!exists($EXCLUDE_SET{$key})) {
- $dep_of{$item} = $dep_type;
- }
- }
- next LINE;
- }
- }
- $self->_event('GET_DEPENDENCY', $self->pkgname(), $., scalar(keys(%dep_of)));
- close($handle);
- $has_read_file = 1;
- }
- # Manual dependencies
- my $manual_deps_ref
- = $self->setting('BLD_DEP' . ($flag ? '_PP' : ''), $self->pkgname());
- if (defined($manual_deps_ref)) {
- for (@{$manual_deps_ref}) {
- my ($dep_type, $item) = split(/$Fcm::Config::DELIMITER/, $_, 2);
- $dep_of{$item} = $dep_type;
- }
- }
- return ($has_read_file, \%dep_of);
- }
- # Returns, if possible, the program unit declared in the $line.
- sub _get_dep_symbol {
- my $line = shift();
- for my $pattern (
- qr{\A \s* $RE_OF{F_PREFIX} SUBROUTINE \s+ ([A-Za-z]\w*)}imsx,
- qr{\A \s* MODULE (?!\s+PROCEDURE) \s+ ([A-Za-z]\w*)}imsx,
- qr{\A \s* PROGRAM \s+ ([A-Za-z]\w*)}imsx,
- qr{\A \s* $RE_OF{F_PREFIX} $RE_OF{F_SPEC} FUNCTION \s+ ([A-Za-z]\w*)}imsx,
- qr{\A \s* BLOCK\s*DATA \s+ ([A-Za-z]\w*)}imsx,
- ) {
- my ($match) = $line =~ $pattern;
- if ($match) {
- return lc($match);
- }
- }
- return;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # @out = @{ $obj->get_fortran_interface () };
- #
- # DESCRIPTION
- # This method invokes the Fortran interface block generator to generate
- # an interface block for the current source file. It returns a reference to
- # an array containing the lines of the interface block.
- # ------------------------------------------------------------------------------
- sub get_fortran_interface {
- my $self = shift();
- my %ACTION_OF = (
- q{} => \&_get_fortran_interface_by_internal_code,
- f90aib => \&_get_fortran_interface_by_f90aib,
- none => sub {$self->_event('F_INTERFACE_NONE', $self->root()); []},
- );
- my $key = lc($self->get_setting(qw/TOOL GENINTERFACE/));
- if (!$key || !exists($ACTION_OF{$key})) {
- $key = q{};
- }
- $ACTION_OF{$key}->($self->cursrc());
- }
- # Generates Fortran interface block using "f90aib".
- sub _get_fortran_interface_by_f90aib {
- my $path = shift();
- my $command = sprintf(q{f90aib <'%s' 2>'%s'}, $path, File::Spec->devnull());
- my $pipe = _open($command, '-|');
- my @lines = readline($pipe);
- close($pipe) || croak($ERR_MESS_OF{CLOSE_PIPE}, $command, $?);
- \@lines;
- }
- # Generates Fortran interface block using internal code.
- sub _get_fortran_interface_by_internal_code {
- my $path = shift();
- my $handle = _open($path);
- my @lines = _get_fortran_util()->extract_interface($handle);
- close($handle);
- \@lines;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # @out = @{ $obj->get_pre_process () };
- #
- # DESCRIPTION
- # This method invokes the pre-processor on the source file and returns a
- # reference to an array containing the lines of the pre-processed source on
- # success.
- # ------------------------------------------------------------------------------
- sub get_pre_process {
- my $self = shift;
- # Supported source files
- my $lang = $self->lang ('TOOL_SRC_PP');
- return unless $lang;
- # List of include directories
- my @inc = @{ $self->setting (qw/PATH INC/) };
- # Build the pre-processor command according to file type
- my %tool = %{ $self->setting ('TOOL') };
- my %tool_src_pp = %{ $self->setting ('TOOL_SRC_PP', $lang) };
- # The pre-processor command and its options
- my @command = ($tool{$tool_src_pp{COMMAND}});
- my @ppflags = split /\s+/, $self->get_setting ('TOOL', $tool_src_pp{FLAGS});
- # List of defined macros, add "-D" in front of each macro
- my @ppkeys = split /\s+/, $self->get_setting ('TOOL', $tool_src_pp{PPKEYS});
- @ppkeys = map {($tool{$tool_src_pp{DEFINE}} . $_)} @ppkeys;
- # Add "-I" in front of each include directories
- @inc = map {($tool{$tool_src_pp{INCLUDE}} . $_)} @inc;
- push @command, (@ppflags, @ppkeys, @inc, $self->base);
- # Change to container directory of source file
- my $old_cwd = $self->_chdir($self->dir());
- # Execute the command, getting the output lines
- my $verbose = $self->verbose;
- my @outlines = &run_command (
- \@command, METHOD => 'qx', PRINT => $verbose > 1, TIME => $verbose > 2,
- );
- # Change back to original directory
- $self->_chdir($old_cwd);
- return \@outlines;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $rules = %{ $self->get_rules };
- #
- # DESCRIPTION
- # This method returns a reference to a hash in the following format:
- # $rules = {
- # target => {ACTION => action, DEP => [dependencies], ...},
- # ... => {...},
- # };
- # where the 1st rank keys are the available targets for building this source
- # file, the second rank keys are ACTION and DEP. The value of ACTION is the
- # action for building the target, which can be "COMPILE", "LOAD", "TOUCH",
- # "CP" or "AR". The value of DEP is a refernce to an array containing a list
- # of dependencies suitable for insertion into the Makefile.
- # ------------------------------------------------------------------------------
- sub get_rules {
- my $self = shift;
- my $rules;
- my %outfile_ext = %{ $self->setting ('OUTFILE_EXT') };
- if ($self->is_type_all (qw/SOURCE/)) {
- # Source file
- # --------------------------------------------------------------------------
- # Determine whether the language of the source file is supported
- my %tool_src = %{ $self->setting ('TOOL_SRC') };
- return () unless $self->lang;
- # Compile object
- # --------------------------------------------------------------------------
- if ($self->objbase) {
- # Depends on the source file
- my @dep = ($self->rule_src);
- # Depends on the compiler flags flags-file
- my @flags;
- push @flags, ('FLAGS' )
- if $self->flagsbase ('FLAGS' );
- push @flags, ('PPKEYS')
- if $self->flagsbase ('PPKEYS') and not $self->ppsrc;
- push @dep, $self->flagsbase ($_) for (@flags);
- # Source file dependencies
- for my $name (sort keys %{ $self->dep }) {
- # A Fortran 9X module, lower case object file name
- if ($self->dep ($name) eq 'USE') {
- (my $root = $name) =~ s/\.\w+$//;
- push @dep, lc ($root) . $outfile_ext{OBJ};
- # An include file
- } elsif ($self->dep ($name) =~ /^(?:INC|H|INTERFACE)$/) {
- push @dep, $name;
- }
- }
- $rules->{$self->objbase} = {ACTION => 'COMPILE', DEP => \@dep};
- # Touch flags-files
- # ------------------------------------------------------------------------
- for my $flag (@flags) {
- next unless $self->flagsbase ($flag);
- $rules->{$self->flagsbase ($flag)} = {
- ACTION => 'TOUCH',
- DEP => [
- $self->flagsbase ($tool_src{$self->lang}{$flag}, -2),
- ],
- DEST => '$(FCM_FLAGSDIR)',
- };
- }
- }
- if ($self->exebase) {
- # Link into an executable
- # ------------------------------------------------------------------------
- my @dep = ();
- push @dep, $self->objbase if $self->objbase;
- push @dep, $self->flagsbase ('LD' ) if $self->flagsbase ('LD' );
- push @dep, $self->flagsbase ('LDFLAGS') if $self->flagsbase ('LDFLAGS');
- # Depends on BLOCKDATA program units, for Fortran programs
- my %blockdata = %{ $self->setting ('BLD_BLOCKDATA') };
- my @blkobj = ();
- if ($self->is_type_any (qw/FPP FORTRAN/) and keys %blockdata) {
- # List of BLOCKDATA object files
- if (exists $blockdata{$self->exebase}) {
- @blkobj = split /\s+/, $blockdata{$self->exebase};
- } elsif (exists $blockdata{''}) {
- @blkobj = split /\s+/, $blockdata{''};
- }
- for my $name (@blkobj) {
- (my $root = $name) =~ s/\.\w+$//;
- $name = $root . $outfile_ext{OBJ};
- push @dep, $root . $outfile_ext{DONE};
- }
- }
- # Extra executable dependencies
- my %exe_dep = %{ $self->setting ('BLD_DEP_EXE') };
- if (keys %exe_dep) {
- my @exe_deps;
- if (exists $exe_dep{$self->exebase}) {
- @exe_deps = split /\s+/, $exe_dep{$self->exebase};
- } elsif (exists $exe_dep{''}) {
- @exe_deps = $exe_dep{''} ? split (/\s+/, $exe_dep{''}) : ('');
- }
- my $pattern = '\\' . $outfile_ext{OBJ} . '$';
- for my $name (@exe_deps) {
- if ($name =~ /$pattern/) {
- # Extra dependency is an object
- (my $root = $name) =~ s/\.\w+$//;
- push @dep, $root . $outfile_ext{DONE};
- } else {
- # Extra dependency is a sub-package
- my $var;
- if ($self->setting ('FCM_PCK_OBJECTS', $name)) {
- # sub-package name contains unusual characters
- $var = $self->setting ('FCM_PCK_OBJECTS', $name);
- } else {
- # sub-package name contains normal characters
- $var = $name ? join ('__', ('OBJECTS', $name)) : 'OBJECTS';
- }
- push @dep, '$(' . $var . ')';
- }
- }
- }
- # Source file dependencies
- for my $name (sort keys %{ $self->dep }) {
- (my $root = $name) =~ s/\.\w+$//;
- # Lowercase name for object dependency
- $root = lc ($root) unless $self->dep ($name) =~ /^(?:INC|H)$/;
- # Select "done" file extension
- if ($self->dep ($name) =~ /^(?:INC|H)$/) {
- push @dep, $name . $outfile_ext{IDONE};
- } else {
- push @dep, $root . $outfile_ext{DONE};
- }
- }
- $rules->{$self->exebase} = {
- ACTION => 'LOAD', DEP => \@dep, BLOCKDATA => \@blkobj,
- };
- # Touch Linker flags-file
- # ------------------------------------------------------------------------
- for my $flag (qw/LD LDFLAGS/) {
- $rules->{$self->flagsbase ($flag)} = {
- ACTION => 'TOUCH',
- DEP => [$self->flagsbase ($flag, -2)],
- DEST => '$(FCM_FLAGSDIR)',
- };
- }
- }
- if ($self->donebase) {
- # Touch done file
- # ------------------------------------------------------------------------
- my @dep = ($self->objbase);
- for my $name (sort keys %{ $self->dep }) {
- (my $root = $name) =~ s/\.\w+$//;
- # Lowercase name for object dependency
- $root = lc ($root) unless $self->dep ($name) =~ /^(?:INC|H)$/;
- # Select "done" file extension
- if ($self->dep ($name) =~ /^(?:INC|H)$/) {
- push @dep, $name . $outfile_ext{IDONE};
- } else {
- push @dep, $root . $outfile_ext{DONE};
- }
- }
- $rules->{$self->donebase} = {
- ACTION => 'TOUCH', DEP => \@dep, DEST => '$(FCM_DONEDIR)',
- };
- }
-
- if ($self->interfacebase) {
- # Interface target
- # ------------------------------------------------------------------------
- # Source file dependencies
- my @dep = ();
- for my $name (sort keys %{ $self->dep }) {
- # Depends on Fortran 9X modules
- push @dep, lc ($name) . $outfile_ext{OBJ}
- if $self->dep ($name) eq 'USE';
- }
- $rules->{$self->interfacebase} = {ACTION => '', DEP => \@dep};
- }
- } elsif ($self->is_type_all ('INCLUDE')) {
- # Copy include target
- # --------------------------------------------------------------------------
- my @dep = ($self->rule_src);
- for my $name (sort keys %{ $self->dep }) {
- # A Fortran 9X module, lower case object file name
- if ($self->dep ($name) eq 'USE') {
- (my $root = $name) =~ s/\.\w+$//;
- push @dep, lc ($root) . $outfile_ext{OBJ};
- # An include file
- } elsif ($self->dep ($name) =~ /^(?:INC|H|INTERFACE)$/) {
- push @dep, $name;
- }
- }
- $rules->{$self->curbase} = {
- ACTION => 'CP', DEP => \@dep, DEST => '$(FCM_INCDIR)',
- };
- # Touch IDONE file
- # --------------------------------------------------------------------------
- if ($self->donebase) {
- my @dep = ($self->rule_src);
- for my $name (sort keys %{ $self->dep }) {
- (my $root = $name) =~ s/\.\w+$//;
- # Lowercase name for object dependency
- $root = lc ($root) unless $self->dep ($name) =~ /^(?:INC|H)$/;
- # Select "done" file extension
- if ($self->dep ($name) =~ /^(?:INC|H)$/) {
- push @dep, $name . $outfile_ext{IDONE};
- } else {
- push @dep, $root . $outfile_ext{DONE};
- }
- }
- $rules->{$self->donebase} = {
- ACTION => 'TOUCH', DEP => \@dep, DEST => '$(FCM_DONEDIR)',
- };
- }
- } elsif ($self->is_type_any (qw/EXE SCRIPT/)) {
- # Copy executable file
- # --------------------------------------------------------------------------
- my @dep = ($self->rule_src);
- # Depends on dummy copy file, if file is an "always build type"
- push @dep, $self->setting (qw/BLD_CPDUMMY/)
- if $self->is_type_any (split (
- /$Fcm::Config::DELIMITER_LIST/, $self->setting ('BLD_TYPE_ALWAYS_BUILD')
- ));
- # Depends on other executable files
- for my $name (sort keys %{ $self->dep }) {
- push @dep, $name if $self->dep ($name) eq 'EXE';
- }
- $rules->{$self->curbase} = {
- ACTION => 'CP', DEP => \@dep, DEST => '$(FCM_BINDIR)',
- };
- } elsif (@{ $self->children }) {
- # Targets for top level and package flags files and dummy dependencies
- # --------------------------------------------------------------------------
- my %tool_src = %{ $self->setting ('TOOL_SRC') };
- my %flags_tool = (LD => '', LDFLAGS => '');
- for my $key (keys %tool_src) {
- $flags_tool{$tool_src{$key}{FLAGS}} = $tool_src{$key}{COMMAND}
- if exists $tool_src{$key}{FLAGS};
- $flags_tool{$tool_src{$key}{PPKEYS}} = ''
- if exists $tool_src{$key}{PPKEYS};
- }
- for my $name (sort keys %flags_tool) {
- my @dep = $self->pkgname eq '' ? () : $self->flagsbase ($name, -2);
- push @dep, $self->flagsbase ($flags_tool{$name})
- if $self->pkgname eq '' and $flags_tool{$name};
- $rules->{$self->flagsbase ($flags_tool{$name})} = {
- ACTION => 'TOUCH',
- DEST => '$(FCM_FLAGSDIR)',
- } if $self->pkgname eq '' and $flags_tool{$name};
- $rules->{$self->flagsbase ($name)} = {
- ACTION => 'TOUCH',
- DEP => \@dep,
- DEST => '$(FCM_FLAGSDIR)',
- };
- }
- # Package object and library
- # --------------------------------------------------------------------------
- {
- my @dep;
- # Add objects from children
- for my $child (sort {$a->pkgname cmp $b->pkgname} @{ $self->children }) {
- push @dep, $child->rule_obj_var (1)
- if $child->libbase and $child->rules ($child->libbase);
- push @dep, $child->objbase
- if $child->cursrc and $child->objbase and
- not $child->is_type_any (qw/PROGRAM BLOCKDATA/);
- }
- if (@dep) {
- $rules->{$self->libbase} = {ACTION => 'AR', DEP => \@dep};
- }
- }
- # Package data files
- # --------------------------------------------------------------------------
- {
- my @dep;
- for my $child (@{ $self->children }) {
- push @dep, $child->rule_src if $child->src and not $child->type;
- }
- if (@dep) {
- push @dep, $self->setting (qw/BLD_CPDUMMY/);
- $rules->{$self->etcbase} = {
- ACTION => 'CP_DATA', DEP => \@dep, DEST => '$(FCM_ETCDIR)',
- };
- }
- }
- }
- return $rules;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $value = $obj->get_setting ($setting[, @prefix]);
- #
- # DESCRIPTION
- # This method gets the correct $setting for the current source by following
- # its package name. If @prefix is set, get the setting with the given prefix.
- # ------------------------------------------------------------------------------
- sub get_setting {
- my ($self, $setting, @prefix) = @_;
- my $val;
- for my $name (reverse @{ $self->pkgnames }) {
- my @names = split /__/, $name;
- $val = $self->setting ($setting, join ('__', (@prefix, @names)));
- $val = $self->setting ($setting, join ('__', (@prefix, @names)))
- if (not defined $val) and @names and $names[-1] =~ s/\.[^\.]+$//;
- last if defined $val;
- }
- return $val;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $type = $self->get_type();
- #
- # DESCRIPTION
- # This method determines whether the source is a type known to the
- # build system. If so, it returns the type flags delimited by "::".
- # ------------------------------------------------------------------------------
- sub get_type {
- my $self = shift();
- my @IGNORE_LIST
- = split(/$Fcm::Config::DELIMITER_LIST/, $self->setting('INFILE_IGNORE'));
- if (grep {$self->curbase() eq $_} @IGNORE_LIST) {
- return q{};
- }
- # User defined
- my $type = $self->setting('BLD_TYPE', $self->pkgname());
- # Extension
- if (!defined($type)) {
- my $ext = $self->curext() ? substr($self->curext(), 1) : q{};
- $type = $self->setting('INFILE_EXT', $ext);
- }
- # Pattern of name
- if (!defined($type)) {
- my %NAME_PATTERN_TO_TYPE_HASH = %{$self->setting('INFILE_PAT')};
- PATTERN:
- while (my ($pattern, $value) = each(%NAME_PATTERN_TO_TYPE_HASH)) {
- if ($self->curbase() =~ $pattern) {
- $type = $value;
- last PATTERN;
- }
- }
- }
- # Pattern of #! line
- if (!defined($type) && -s $self->cursrc() && -T _) {
- my $handle = _open($self->cursrc());
- my $line = readline($handle);
- close($handle);
- my %SHEBANG_PATTERN_TO_TYPE_HASH = %{$self->setting('INFILE_TXT')};
- PATTERN:
- while (my ($pattern, $value) = each(%SHEBANG_PATTERN_TO_TYPE_HASH)) {
- if ($line =~ qr{^\#!.*$pattern}msx) {
- $type = $value;
- last PATTERN;
- }
- }
- }
- if (!$type) {
- return $type;
- }
- # Extra type information for selected file types
- my %EXTRA_FOR = (
- qr{\b (?:FORTRAN|FPP) \b}msx => \&_get_type_extra_for_fortran,
- qr{\b C \b}msx => \&_get_type_extra_for_c,
- );
- EXTRA:
- while (my ($key, $code_ref) = each(%EXTRA_FOR)) {
- if ($type =~ $key) {
- my $handle = _open($self->cursrc());
- LINE:
- while (my $line = readline($handle)) {
- my $extra = $code_ref->($line);
- if ($extra) {
- $type .= $Fcm::Config::DELIMITER . $extra;
- last LINE;
- }
- }
- close($handle);
- last EXTRA;
- }
- }
- return $type;
- }
- sub _get_type_extra_for_fortran {
- my ($match) = $_[0] =~ qr{\A \s* (PROGRAM|MODULE|BLOCK\s*DATA) \b}imsx;
- if (!$match) {
- return;
- }
- $match =~ s{\s}{}g;
- uc($match)
- }
- sub _get_type_extra_for_c {
- ($_[0] =~ qr{int\s+main\s*\(}msx) ? 'PROGRAM' : undef;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $flag = $obj->is_in_package ($name);
- #
- # DESCRIPTION
- # This method returns true if current package is in the package $name.
- # ------------------------------------------------------------------------------
- sub is_in_package {
- my ($self, $name) = @_;
-
- my $return = 0;
- for (@{ $self->pkgnames }) {
- next unless /^$name(?:\.\w+)?$/;
- $return = 1;
- last;
- }
- return $return;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $flag = $obj->is_type_all ($arg, ...);
- # $flag = $obj->is_type_any ($arg, ...);
- #
- # DESCRIPTION
- # This method returns a flag for the following:
- # is_type_all - does type match all of the arguments?
- # is_type_any - does type match any of the arguments?
- # ------------------------------------------------------------------------------
- for my $name ('all', 'any') {
- no strict 'refs';
- my $subname = 'is_type_' . $name;
- *$subname = sub {
- my ($self, @intypes) = @_;
- my $rc = 0;
- if ($self->type) {
- my %types = map {($_, 1)} split /$Fcm::Config::DELIMITER/, $self->type;
- for my $intype (@intypes) {
- $rc = exists $types{$intype};
- last if ($name eq 'all' and not $rc) or ($name eq 'any' and $rc);
- }
- }
- return $rc;
- }
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $string = $obj->rule_obj_var ([$read]);
- #
- # DESCRIPTION
- # This method returns a string containing the make rule object variable for
- # the current package. If $read is set, return $($string)
- # ------------------------------------------------------------------------------
- sub rule_obj_var {
- my ($self, $read) = @_;
- my $return;
- if ($self->setting ('FCM_PCK_OBJECTS', $self->pkgname)) {
- # Package name registered in unusual list
- $return = $self->setting ('FCM_PCK_OBJECTS', $self->pkgname);
- } else {
- # Package name not registered in unusual list
- $return = $self->pkgname
- ? join ('__', ('OBJECTS', $self->pkgname)) : 'OBJECTS';
- }
- $return = $read ? '$(' . $return . ')' : $return;
- return $return;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $string = $obj->rule_src ();
- #
- # DESCRIPTION
- # This method returns a string containing the location of the source file
- # relative to the build root. This string will be suitable for use in a
- # "Make" rule file for FCM.
- # ------------------------------------------------------------------------------
- sub rule_src {
- my $self = shift;
- my $return = $self->cursrc;
- LABEL: for my $name (qw/SRC PPSRC/) {
- for my $i (0 .. @{ $self->setting ('PATH', $name) } - 1) {
- my $dir = $self->setting ('PATH', $name)->[$i];
- next unless index ($self->cursrc, $dir) == 0;
- $return = File::Spec->catfile (
- '$(FCM_' . $name . 'DIR' . ($i ? $i : '') . ')',
- File::Spec->abs2rel ($self->cursrc, $dir),
- );
- last LABEL;
- }
- }
- return $return;
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $rc = $obj->write_lib_dep_excl ();
- #
- # DESCRIPTION
- # This method writes a set of exclude dependency configurations for the
- # library of this package.
- # ------------------------------------------------------------------------------
- sub write_lib_dep_excl {
- my $self = shift();
- if (!find_file_in_path($self->libbase(), $self->setting(qw/PATH LIB/))) {
- return 0;
- }
- my $ETC_DIR = $self->setting(qw/PATH ETC/)->[0];
- my $CFG_EXT = $self->setting(qw/OUTFILE_EXT CFG/);
- my $LABEL_OF_EXCL_DEP = $self->cfglabel('BLD_DEP_EXCL');
- my @SETTINGS = (
- #dependency #source file type list #dependency name function
- ['H' , [qw{INCLUDE CPP }], sub {$_[0]->base()} ],
- ['INTERFACE', [qw{INCLUDE INTERFACE }], sub {$_[0]->base()} ],
- ['INC' , [qw{INCLUDE }], sub {$_[0]->base()} ],
- ['USE' , [qw{SOURCE FORTRAN MODULE}], sub {$_[0]->root()} ],
- ['INTERFACE', [qw{SOURCE FORTRAN }], sub {$_[0]->interfacebase()}],
- ['OBJ' , [qw{SOURCE }], sub {$_[0]->root()} ],
- );
- my $cfg = Fcm::CfgFile->new();
- my @stack = ($self);
- NODE:
- while (my $node = pop(@stack)) {
- # Is a directory
- if (@{$node->children()}) {
- push(@stack, reverse(@{$node->children()}));
- next NODE;
- }
- # Is a typed file
- if (
- $node->cursrc()
- && $node->type()
- && !$node->is_type_any(qw{PROGRAM BLOCKDATA})
- ) {
- for (@SETTINGS) {
- my ($key, $type_list_ref, $name_func_ref) = @{$_};
- my $name = $name_func_ref->($node);
- if ($name && $node->is_type_all(@{$type_list_ref})) {
- push(
- @{$cfg->lines()},
- Fcm::CfgLine->new(
- label => $LABEL_OF_EXCL_DEP,
- value => $key . $Fcm::Config::DELIMITER . $name,
- ),
- );
- next NODE;
- }
- }
- }
- }
- # Write to configuration file
- $cfg->print_cfg(
- File::Spec->catfile($ETC_DIR, $self->libbase('lib', $CFG_EXT)),
- );
- }
- # ------------------------------------------------------------------------------
- # SYNOPSIS
- # $string = $obj->write_rules ();
- #
- # DESCRIPTION
- # This method returns a string containing the "Make" rules for building the
- # source file.
- # ------------------------------------------------------------------------------
- sub write_rules {
- my $self = shift;
- my $mk = '';
- for my $target (sort keys %{ $self->rules }) {
- my $rule = $self->rules ($target);
- next unless defined ($rule->{ACTION});
- if ($rule->{ACTION} eq 'AR') {
- my $var = $self->rule_obj_var;
- $mk .= ($var eq 'OBJECTS' ? 'export ' : '') . $var . ' =';
- $mk .= ' ' . join (' ', @{ $rule->{DEP} });
- $mk .= "\n\n";
- }
- $mk .= $target . ':';
-
- if ($rule->{ACTION} eq 'AR') {
- $mk .= ' ' . $self->rule_obj_var (1);
- } else {
- for my $dep (@{ $rule->{DEP} }) {
- $mk .= ' ' . $dep;
- }
- }
- $mk .= "\n";
- if (exists $rule->{ACTION}) {
- if ($rule->{ACTION} eq 'AR') {
- $mk .= "\t" . 'fcm_internal archive $@ $^' . "\n";
- } elsif ($rule->{ACTION} eq 'CP') {
- $mk .= "\t" . 'cp $< ' . $rule->{DEST} . "\n";
- $mk .= "\t" . 'chmod u+w ' .
- File::Spec->catfile ($rule->{DEST}, '$@') . "\n";
- } elsif ($rule->{ACTION} eq 'CP_DATA') {
- $mk .= "\t" . 'cp $^ ' . $rule->{DEST} . "\n";
- $mk .= "\t" . 'touch ' .
- File::Spec->catfile ($rule->{DEST}, '$@') . "\n";
- } elsif ($rule->{ACTION} eq 'COMPILE') {
- if ($self->lang) {
- $mk .= "\t" . 'fcm_internal compile:' . substr ($self->lang, 0, 1) .
- ' ' . $self->pkgnames->[-2] . ' $< $@';
- $mk .= ' 1' if ($self->flagsbase ('PPKEYS') and not $self->ppsrc);
- $mk .= "\n";
- }
- } elsif ($rule->{ACTION} eq 'LOAD') {
- if ($self->lang) {
- $mk .= "\t" . 'fcm_internal load:' . substr ($self->lang, 0, 1) .
- ' ' . $self->pkgnames->[-2] . ' $< $@';
- $mk .= ' ' . join (' ', @{ $rule->{BLOCKDATA} })
- if @{ $rule->{BLOCKDATA} };
- $mk .= "\n";
- }
- } elsif ($rule->{ACTION} eq 'TOUCH') {
- $mk .= "\t" . 'touch ' .
- File::Spec->catfile ($rule->{DEST}, '$@') . "\n";
- }
- }
- $mk .= "\n";
- }
- return $mk;
- }
- # Wraps "chdir". Returns old directory.
- sub _chdir {
- my ($self, $dir) = @_;
- my $old_cwd = cwd();
- $self->_event('CHDIR', $dir);
- chdir($dir) || croak(sprintf($ERR_MESS_OF{CHDIR}, $dir));
- $old_cwd;
- }
- # Wraps an event.
- sub _event {
- my ($self, $key, @args) = @_;
- my ($format, $level) = @{$EVENT_SETTING_OF{$key}};
- $level ||= 1;
- if ($self->verbose() >= $level) {
- printf($format . ".\n", @args);
- }
- }
- # Wraps "open".
- sub _open {
- my ($path, $mode) = @_;
- $mode ||= '<';
- open(my $handle, $mode, $path) || croak(sprintf($ERR_MESS_OF{OPEN}, $path, $!));
- $handle;
- }
- # ------------------------------------------------------------------------------
- 1;
- __END__
|