#!/usr/bin/env perl #----------------------------------------------------------------------------------------------- # # configure # # # This utility allows the CLM user to specify compile-time configuration # options via a commandline interface. The output from configure is a # Makefile and a cache file that contains all configuration parameters # required to produce the Makefile. A subsequent invocation of configure # can use the cache file as input (via the -defaults argument) to reproduce # the CLM configuration contained in it. Note that when a cache file is # used to set default values only the model parameters are used. The # parameters that are platform dependent (e.g., compiler options, library # locations, etc) are ignored. # # As the build time configurable options of CLM are changed, this script # must also be changed. Thus configure is maintained under revision # control in the CLM source tree and it is assumed that only the version of # configure in the source tree will be used to build CLM. Thus we assume # that the root of the source tree can be derived from the location of this # script. # #----------------------------------------------------------------------------------------------- use strict; #use warnings; #use diagnostics; use Cwd; use English; use Getopt::Long; use IO::File; use IO::Handle; use File::Copy; my $crpmode = "nocrop"; my %maxpatchpft; $maxpatchpft{'crop'} = 21; $maxpatchpft{'nocrop'} = 17; #----------------------------------------------------------------------------------------------- sub usage { die <). Any value that contains white-space must be quoted. Long option names may be supplied with either single or double leading dashes. A consequence of this is that single letter options may NOT be bundled. -bgc Build CLM with BGC package [ none | cn | cndv ] (default is none). -c13 Turn on C13 mode for BGC setting of CN [on | off] (default is off). -cache Name of output cache file (default: config_cache.xml). -cachedir Name of directory where output cache file is written (default: CLM build directory). -clm_root Root directory of clm source code (default: directory above location of this script) -cppdefs A string of user specified CPP defines. Appended to Makefile defaults. e.g. -cppdefs '-DVAR1 -DVAR2' -crop Toggle for prognostic crop model. [on | off] (default is off) (can ONLY be turned on when BGC type is CN or CNDV) -comp_intf Component interface to use (ESMF or MCT) (default MCT) -defaults Specify full path to a configuration file which will be used to supply defaults instead of the defaults in bld/config_files. This file is used to specify model configuration parameters only. Parameters relating to the build which are system dependent will be ignored. -help [or -h] Print usage to STDOUT. -nofire Turn off wildfires for BGC setting of CN (default includes fire for CN) -noio Turn history output completely off (typically for testing). -pergro Switch enables building CLM for perturbation growth tests. [on | off] (default is off) -silent [or -s] Turns on silent mode - only fatal messages issued. -sitespf_pt Setup for the given site specific single-point resolution. -snicar_frc Turn on SNICAR radiative forcing calculation. [on | off] (default is off) -spinup Turn on given spinup mode for BGC setting of CN (level) AD Turn on Accelerated Decomposition from (5) bare-soil exit Jump directly from AD spinup to normal mode (2) normal Normal decomposition ("final spinup mode") (0) (default) Valid sequence: 5-2-0 -usr_src [,[,[...]]] Directories containing user source code. -verbose [or -v] Turn on verbose echoing of settings made by configure. -version Echo the SVN tag name used to check out this CLM distribution. EOF } #----------------------------------------------------------------------------------------------- # Setting autoflush (an IO::Handle method) on STDOUT helps in debugging. It forces the test # descriptions to be printed to STDOUT before the error messages start. *STDOUT->autoflush(); #----------------------------------------------------------------------------------------------- # Set the directory that contains the CLM configuration scripts. If the configure command was # issued using a relative or absolute path, that path is in $ProgDir. Otherwise assume the # command was issued from the current working directory. (my $ProgName = $0) =~ s!(.*)/!!; # name of this script my $ProgDir = $1; # name of directory containing this script -- may be a # relative or absolute path, or null if the script is in # the user's PATH my $cwd = getcwd(); # current working directory my $cfgdir; # absolute pathname of directory that contains this script if ($ProgDir) { $cfgdir = absolute_path($ProgDir); } else { $cfgdir = $cwd; } #----------------------------------------------------------------------------------------------- # Save commandline my $commandline = "$cfgdir/configure @ARGV"; #----------------------------------------------------------------------------------------------- # Parse command-line options. my %opts = ( cache => "config_cache.xml", nofire => undef, noio => undef, clm_root => undef, spinup => "normal", ); GetOptions( "c13=s" => \$opts{'c13'}, "spinup=s" => \$opts{'spinup'}, "bgc=s" => \$opts{'bgc'}, "cache=s" => \$opts{'cache'}, "cachedir=s" => \$opts{'cachedir'}, "snicar_frc=s" => \$opts{'snicar_frc'}, "clm_root=s" => \$opts{'clm_root'}, "cppdefs=s" => \$opts{'cppdefs'}, "comp_intf=s" => \$opts{'comp_intf'}, "defaults=s" => \$opts{'defaults'}, "h|help" => \$opts{'help'}, "nofire" => \$opts{'nofire'}, "noio" => \$opts{'noio'}, "pergro=s" => \$opts{'pergro'}, "snicar_frc=s" => \$opts{'snicar_frc'}, "s|silent" => \$opts{'silent'}, "sitespf_pt=s" => \$opts{'sitespf_pt'}, "usr_src=s" => \$opts{'usr_src'}, "v|verbose" => \$opts{'verbose'}, "version" => \$opts{'version'}, "crop=s" => \$opts{'crop'}, ) or usage(); # Give usage message. usage() if $opts{'help'}; # Echo version info. version($cfgdir) if $opts{'version'}; # Check for unparsed arguments if (@ARGV) { print "ERROR: unrecognized arguments: @ARGV\n"; usage(); } # Define 3 print levels: # 0 - only issue fatal error messages # 1 - only informs what files are created (default) # 2 - verbose my $print = 1; if ($opts{'silent'}) { $print = 0; } if ($opts{'verbose'}) { $print = 2; } my $eol = "\n"; my %cfg = (); # build configuration #----------------------------------------------------------------------------------------------- # Make sure we can find required perl modules and configuration files. # Look for them in the directory that contains the configure script. # Check for the configuration definition file. my $config_def_file = "config_definition.xml"; (-f "$cfgdir/config_files/$config_def_file") or die <<"EOF"; ** Cannot find configuration definition file \"$config_def_file\" in directory \"$cfgdir/config_files\" ** EOF # The configuration defaults file modifies the generic defaults in the configuration # definition file. Note that the -defaults option has precedence over all other options. my $config_defaults_file; my $std_config_defaults_file = "$cfgdir/config_files/config_defaults.xml"; if ($opts{'defaults'}) { $config_defaults_file = $opts{'defaults'}; } elsif (defined($opts{'sitespf_pt'})) { $config_defaults_file = "$cfgdir/config_files/config_defaults_$opts{'sitespf_pt'}.xml"; if ( ! -f $config_defaults_file ) { $config_defaults_file = "$std_config_defaults_file"; } } else { $config_defaults_file = "$std_config_defaults_file"; } (-f "$config_defaults_file") or die <<"EOF"; ** Cannot find configuration defaults file \"$config_defaults_file\" ** EOF # The XML::Lite module is required to parse the XML configuration files. (-f "$cfgdir/../../../../scripts/ccsm_utils/Tools/perl5lib/XML/Lite.pm") or die <<"EOF"; ** Cannot find perl module \"XML/Lite.pm\" in directory \"$cfgdir/../../../../scripts/ccsm_utils/Tools/perl5lib\" ** EOF # The Build::Config module provides utilities to store and manipulate the configuration. (-f "$cfgdir/../../../../scripts/ccsm_utils/Tools/perl5lib/Build/Config.pm") or die <<"EOF"; ** Cannot find perl module \"Build/Config.pm\" in directory \"$cfgdir/../../../../scripts/ccsm_utils/Tools/perl5lib\" ** EOF if ($print>=2) { print "Setting CLM configuration script directory to $cfgdir$eol"; } if ($print>=2) { print "Using configuration defaults file $config_defaults_file$eol"; } #----------------------------------------------------------------------------------------------- # Add $cfgdir/perl5lib to the list of paths that Perl searches for modules my $casecfgdir = "$cfgdir/../../../../scripts/ccsm_utils/Case.template"; my @dirs = ( $cfgdir, "$cfgdir/../../../../scripts/ccsm_utils/Tools/perl5lib", $casecfgdir); unshift @INC, @dirs; require XML::Lite; require Build::Config; # Initialize the configuration. The $config_def_file provides the definition of a CLM # configuration, and the $config_defaults_file provides default values for a specific CLM # configuration. $cfg_ref is a reference to the new configuration object. my $cfg_ref = Build::Config->new("$cfgdir/config_files/$config_def_file", "$config_defaults_file"); #----------------------------------------------------------------------------------------------- # CLM root directory. my $clm_root; if ( ! defined($opts{'clm_root'} ) ) { $clm_root = absolute_path("$cfgdir/.."); } else { $clm_root = $opts{'clm_root'}; } if ( &is_valid_directory( "$clm_root/src", allowEnv=>1 ) ) { $cfg_ref->set('clm_root', $clm_root); } else { die <<"EOF"; ** Invalid CLM root directory: $clm_root ** ** The CLM root directory must contain the subdirectory /src/. ** clm_root can be entered on the command line or it will be derived ** from the location of this script. EOF } if ($print>=2) { print "Setting CLM root directory to $clm_root$eol"; } #----------------------------------------------------------------------------------------------- # CLM build directory is current directory my $clm_bld = `pwd`; chomp( $clm_bld ); # Make sure directory is valid if ( ! &is_valid_directory( $clm_bld ) and ! mkdirp($clm_bld)) { die <<"EOF"; ** Could not create the specified CLM build directory: $clm_bld EOF } if ($print>=2) { print "Setting CLM build directory to $clm_bld$eol"; } #----------------------------------------------------------------------------------------------- # User source directories. my $usr_src = ''; if (defined $opts{'usr_src'}) { my @dirs = split ',', $opts{'usr_src'}; my @adirs; while ( my $dir = shift @dirs ) { if (&is_valid_directory( "$dir", allowEnv=>1 ) ) { push @adirs, $dir; } else { die "** User source directory does not exist: $dir\n"; } } $usr_src = join ',', @adirs; $cfg_ref->set('usr_src', $usr_src); } if ($print>=2) { print "Setting user source directories to $usr_src$eol"; } #----------------------------------------------------------------------------------------------- # configuration cache directory and file. my $config_cache_dir; my $config_cache_file; if (defined $opts{'cachedir'}) { $config_cache_dir = absolute_path($opts{'cachedir'}); } else { $config_cache_dir = $clm_bld; } if (&is_valid_directory( $config_cache_dir, allowEnv=>1 ) or mkdirp($config_cache_dir)) { $config_cache_file = "$config_cache_dir/$opts{'cache'}"; } else { die <<"EOF"; ** Could not create the specified directory for configuration cache file: $config_cache_dir EOF } if ($print>=2) { print "The configuration cache file will be created in $config_cache_file$eol"; } #----------------------------------------------------------------------------------------------- # supported single point configurations if( defined($opts{'sitespf_pt'}) ) { $cfg_ref->set('sitespf_pt', $opts{'sitespf_pt'}); } my $sitespf_pt = $cfg_ref->get('sitespf_pt'); if ($print>=2) { if( defined($opts{'sitespf_pt'}) ) { print "Using $sitespf_pt for supported single point configuration.$eol"; } } #----------------------------------------------------------------------------------------------- # NOIO option if (defined $opts{'noio'}) { $cfg_ref->set('noio', "on" ); } my $noio = $cfg_ref->get('noio'); if ($print>=2) { if ( $noio eq "on") { print "ALL history output is turned OFF.$eol"; } } #----------------------------------------------------------------------------------------------- # BGC option if (defined $opts{'bgc'}) { $cfg_ref->set('bgc', $opts{'bgc'}); } my $bgc_mode = $cfg_ref->get('bgc'); if ($print>=2) { print "Using $bgc_mode for bgc.$eol"; } # NOFIRE option -- currently only in bgc=CN if (defined $opts{'nofire'}) { $cfg_ref->set('nofire', "on" ); } my $nofire = $cfg_ref->get('nofire'); if ( ($nofire eq "on") && ($bgc_mode ne "cn") ) { die <<"EOF"; ** Cannot turn nofire mode on -- without cn for bgc mode** EOF } if ($print>=2 && $bgc_mode =~ /^cn/ ) { if ( $nofire eq "off") { print "Wildfires are active as normal.$eol"; } else { print "Wildfires are turned off.$eol"; } } #----------------------------------------------------------------------------------------------- # SPINUP option for BGC/CN mode only if (defined $opts{'spinup'}) { $cfg_ref->set('spinup', $opts{'spinup'}); } my $spinup = $cfg_ref->get('spinup'); if ( ($spinup ne "normal" ) && ($bgc_mode ne "cn") ) { die <<"EOF"; ** Cannot turn spinup mode on -- without cn for bgc mode** ** ** Set the bgc mode by the following means from highest to lowest precedence: ** * by the command-line option -bgc cn ** * by a default configuration file, specified by -defaults EOF } if ($print>=2) { print "Using $spinup for spinup for cn mode.$eol"; } # C13 option for BGC/CN mode only if (defined $opts{'c13'}) { $cfg_ref->set('c13', $opts{'c13'}); } my $c13 = $cfg_ref->get('c13'); if ( ($c13 eq "on" ) && ($bgc_mode ne "cn") ) { die <<"EOF"; ** Cannot turn c13 mode on -- without cn for bgc mode** EOF } if ($print>=2) { print "Using $c13 for c13 for cn mode.$eol"; } #----------------------------------------------------------------------------------------------- # comp_intf option if (defined $opts{'comp_intf'}) { $cfg_ref->set('comp_intf', $opts{'comp_intf'}); } my $comp_intf = $cfg_ref->get('comp_intf'); if ($print>=2) { print "Using $comp_intf for comp_intf.$eol"; } #----------------------------------------------------------------------------------------------- # CROP option if (defined $opts{'crop'}) { $cfg_ref->set('crop', $opts{'crop'}); } my $crop = $cfg_ref->get('crop'); if ( $crop eq "on" ) { $crpmode = "crop"; } if ( ($crop eq "on" ) && ($bgc_mode ne "cn") && ($bgc_mode ne "cndv") ) { die <<"EOF"; ** Cannot turn crop mode on -- without some form of cn for bgc mode** ** ** Set the bgc mode by the following means from highest to lowest precedence: ** * by the command-line options -bgc cn ** * by a default configuration file, specified by -defaults EOF } if ( ($c13 eq "on" ) && ($crop eq "on") ) { die <<"EOF"; ** Cannot turn crop mode on -- AND C13 mode on at the same time** ** ** Set the crop and C13 modes by the following means from highest to lowest precedence: ** * by the command-line options -crop and -c13 ** * by a default configuration file, specified by -defaults EOF } if ($print>=2) { print "Using $crop for crop.$eol"; } #----------------------------------------------------------------------------------------------- # MAXPFT option $cfg_ref->set('maxpft', $maxpatchpft{$crpmode} ); my $maxpft = $cfg_ref->get('maxpft'); if ( (($bgc_mode eq "cn") || ($bgc_mode eq "cndv")) && ($maxpft != $maxpatchpft{$crpmode}) ) { die <<"EOF"; ** For CN or CNDV BGC mode you MUST set max patch PFT's to $maxpatchpft{$crpmode} ** ** When the crop model is on then it must be set to $maxpatchpft{'crop'} otherwise to $maxpatchpft{'nocrop'} ** Set the bgc mode, crop and maxpft by the following means from highest to lowest precedence: ** * by the command-line options -bgc, -crop and -maxpft ** * by a default configuration file, specified by -defaults ** EOF } if ( $maxpft > $maxpatchpft{$crpmode} ) { die <<"EOF"; ** Max patch PFT's can NOT exceed $maxpatchpft{$crpmode} ** ** Set maxpft by the following means from highest to lowest precedence: ** * by the command-line options -maxpft ** * by a default configuration file, specified by -defaults ** EOF } if ($print>=2) { print "Using $maxpft for maxpft.$eol"; } #----------------------------------------------------------------------------------------------- # PERGRO option if (defined $opts{'pergro'}) { $cfg_ref->set('pergro', $opts{'pergro'}); } my $pergro = $cfg_ref->get('pergro'); if ($print>=2) { print "Using $pergro for pergro.$eol"; } #----------------------------------------------------------------------------------------------- # SNICAR_FRC option if (defined $opts{'snicar_frc'}) { $cfg_ref->set('snicar_frc', $opts{'snicar_frc'}); } my $snicar_frc = $cfg_ref->get('snicar_frc'); if ($print>=2) { print "Using $snicar_frc for snicar_frc.$eol"; } #----------------------------------------------------------------------------------------------- # Makefile configuration ####################################################################### #----------------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------------- # Name of CLM executable. my $clm_exe = "clm"; if ($print>=2) { print "Name of CLM executable: $clm_exe.$eol"; } #----------------------------------------------------------------------------------------------- # For the CPP tokens, start with the defaults (from defaults file) and append the specifications # from the commandline. That way the user can override defaults since the commandline versions # occur last. my $usr_cppdefs = $cfg_ref->get('cppdefs'); if (defined $opts{'cppdefs'}) { $usr_cppdefs .= " $opts{'cppdefs'}"; } $cfg_ref->set('cppdefs', $usr_cppdefs); if ($usr_cppdefs and $print>=2) { print "Default and user CPP definitions: \'$usr_cppdefs\'$eol";} # The following CPP macro definitions are used to implement the compile-time options. They are # determined by the configuration parameters that have been set above. They will be appended to # the CPP definitions that were explicitly set in the defaults file or by the user on the commandline. my $cfg_cppdefs = ''; $cfg_cppdefs .= " -DMAXPATCH_PFT=$maxpft"; if ($bgc_mode eq 'cn') { $cfg_cppdefs .= " -DCN"; } if ($crop eq 'on') { $cfg_cppdefs .= " -DCROP"; } if ($bgc_mode eq 'cndv') { $cfg_cppdefs .= " -DCNDV -DCN"; } if ($nofire eq 'on') { $cfg_cppdefs .= " -DNOFIRE"; } if ($noio eq 'on') { $cfg_cppdefs .= " -D_NOIO"; } if ($c13 eq 'on') { $cfg_cppdefs .= " -DC13"; } if ($spinup eq 'AD') { $cfg_cppdefs .= " -DAD_SPINUP"; } if ($spinup eq 'exit') { $cfg_cppdefs .= " -DEXIT_SPINUP"; } if ( $pergro eq 'on' ) { $cfg_cppdefs .= " -DPERGRO"; } if ( $snicar_frc eq 'on' ) { $cfg_cppdefs .= " -DSNICAR_FRC"; } # CPP defines to put on Makefile my $make_cppdefs = "$usr_cppdefs $cfg_cppdefs"; if ($print>=2) { print "CPP definitions set by configure: \'$cfg_cppdefs\'$eol"; } #----------------------------------------------------------------------------------------------- # Write configuration files #################################################################### #----------------------------------------------------------------------------------------------- my $fp_filename = 'Filepath'; # name of output filepath file my $cpp_filename = 'CESM_cppdefs'; # name of output file for clm's cppdefs in cesm # Write the filepath file for cesm. write_filepath_cesmbld("$clm_bld/$fp_filename", $cfg_ref, allowEnv=>1 ); if ($print>=2) { print "creating $clm_bld/$fp_filename\n"; } # Write the file for clm's cppdefs needed in cesm. write_cppdefs("$clm_bld/$cpp_filename", $make_cppdefs); if ($print>=2) { print "creating $clm_bld/$cpp_filename\n"; } # Write the configuration file. $cfg_ref->write_file($config_cache_file, $commandline); if ($print>=2) { print "creating $config_cache_file\n"; } #----------------------------------------------------------------------------------------------- # Done chdir( $cwd ) || die <<"EOF"; ** Trouble changing directory back to $cwd ** EOF if ($print) { print "CLM configure done.\n"; } exit; #----------------------------------------------------------------------------------------------- # FINISHED #################################################################################### #----------------------------------------------------------------------------------------------- #------------------------------------------------------------------------------- sub write_filepath_cesmbld { my ($file, $cfg_ref, %opts) = @_; my $fh = new IO::File; $fh->open(">$file") or die "** can't open filepath file: $file\n"; # configuration parameters used to determine paths my $usr_src = $cfg_ref->get('usr_src'); my $clm_root = $cfg_ref->get('clm_root'); my $comp_intf = $cfg_ref->get('comp_intf'); # Source root my $srcdir = "$clm_root/src"; if ( ! &is_valid_directory( "$srcdir", %opts ) ) { die "** source directory does not exist: $srcdir\n"; } # User specified source directories. if ($usr_src =~ /\S+/) { my @dirs = split ',', $usr_src; while ( my $dir = shift @dirs ) { print $fh "$dir\n"; } } else { print $fh "../SourceMods/src.clm\n"; } my @dirs = ( "cpl_share", "main", "biogeophys", "biogeochem"); if ( $comp_intf eq "MCT" ) { push( @dirs, "cpl_mct" ); } elsif ( $comp_intf eq "ESMF" ) { push( @dirs, "cpl_esmf" ); } else { die "** Invalid comp_intf: $comp_intf\n"; } foreach my $dir ( @dirs ) { if ( &is_valid_directory( "$srcdir/$dir", %opts ) ) { print $fh "$srcdir/$dir\n"; } else { die "** source directory does not exist: $srcdir/$dir\n"; } } $fh->close; } #------------------------------------------------------------------------------- sub write_cppdefs { my ($file, $make_cppdefs) = @_; my $fh = new IO::File; $fh->open(">$file") or die "** can't open cpp defs file: $file\n"; print $fh "$make_cppdefs\n"; $fh->close; } #------------------------------------------------------------------------------- sub absolute_path { # # Convert a pathname into an absolute pathname, expanding any . or .. characters. # Assumes pathnames refer to a local filesystem. # Assumes the directory separator is "/". # my $path = shift; my $cwd = getcwd(); # current working directory my $abspath; # resulting absolute pathname # Strip off any leading or trailing whitespace. (This pattern won't match if # there's embedded whitespace. $path =~ s!^\s*(\S*)\s*$!$1!; # Convert relative to absolute path. if ($path =~ m!^\.$!) { # path is "." return $cwd; } elsif ($path =~ m!^\./!) { # path starts with "./" $path =~ s!^\.!$cwd!; } elsif ($path =~ m!^\.\.$!) { # path is ".." $path = "$cwd/.."; } elsif ($path =~ m!^\.\./!) { # path starts with "../" $path = "$cwd/$path"; } elsif ($path =~ m!^[^/]!) { # path starts with non-slash character $path = "$cwd/$path"; } my ($dir, @dirs2); my @dirs = split "/", $path, -1; # The -1 prevents split from stripping trailing nulls # This enables correct processing of the input "/". # Remove any "" that are not leading. for (my $i=0; $i<=$#dirs; ++$i) { if ($i == 0 or $dirs[$i] ne "") { push @dirs2, $dirs[$i]; } } @dirs = (); # Remove any "." foreach $dir (@dirs2) { unless ($dir eq ".") { push @dirs, $dir; } } @dirs2 = (); # Remove the "subdir/.." parts. foreach $dir (@dirs) { if ( $dir !~ /^\.\.$/ ) { push @dirs2, $dir; } else { pop @dirs2; # remove previous dir when current dir is .. } } if ($#dirs2 == 0 and $dirs2[0] eq "") { return "/"; } $abspath = join '/', @dirs2; return( $abspath ); } #------------------------------------------------------------------------------- sub subst_env_path { # # Substitute for any environment variables contained in a pathname. # Assumes the directory separator is "/". # my $path = shift; my $newpath; # resulting pathname my $nm = "subst_env_path"; # Strip off any leading or trailing whitespace. (This pattern won't match if # there's embedded whitespace. $path =~ s!^\s*(\S*)\s*$!$1!; my ($dir, @dirs2); my @dirs = split "/", $path, -1; # The -1 prevents split from stripping trailing nulls # This enables correct processing of the input "/". foreach $dir (@dirs) { if ( $dir =~ m/(^[^\$]*)\$(.*$)/ ) { my $startvar = $1; my $envvarnm = $2; if ( ! defined($ENV{$envvarnm}) ) { die "${nm}:: ENV variable $envvarnm is in pathname ($path) -- but NOT defined\n"; } push @dirs2, "$startvar$ENV{$envvarnm}"; } elsif ( $dir =~ m/\$/) { die "${nm}:: malformed ENV variable is in pathname ($path)\n"; } else { push @dirs2, $dir; } } $newpath = join '/', @dirs2; return( $newpath ); } #------------------------------------------------------------------------------- sub mkdirp { my ($dir) = @_; my (@dirs) = split /\//, $dir; my (@subdirs, $path); # if $dir is absolute pathname then @dirs will start with "" if ($dirs[0] eq "") { push @subdirs, shift @dirs; } while ( @dirs ) { # check that each subdir exists and mkdir if it doesn't push @subdirs, shift @dirs; $path = join '/', @subdirs; unless (-d $path or mkdir($path, 0777)) { return 0; } } return 1; } #------------------------------------------------------------------------------- sub version { # The version is found in CLM's ChangeLog file. # $cfgdir is set by the configure script to the name of its directory. my ($cfgdir) = @_; my $logfile = "$cfgdir/../doc/ChangeLog"; my $fh = IO::File->new($logfile, '<') or die "** can't open ChangeLog file: $logfile\n"; while (my $line = <$fh>) { if ($line =~ /^Tag name:\s*[clm0-9_.-]*\s*[toin]*\s*([cesmclm0-9_.-]+)$/ ) { print "$1\n"; exit; } } } #------------------------------------------------------------------------------- sub is_valid_directory { # # Validate that the input is a valid existing directory. # If allowEnv=>1 expand environment variables. # my ($dir, %opts) = @_; my $nm = "is_valid_directory"; my $valid = 0; # Expand environment variables if ( $opts{'allowEnv'} ) { $dir = subst_env_path( $dir ); } if ( -d $dir ) { $valid = 1; } return( $valid ); }