#!/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 qw(getcwd abs_path); use English; use Getopt::Long; use IO::File; use IO::Handle; use File::Copy; #----------------------------------------------------------------------------------------------- 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). -cache Name of output cache file (default: config_cache.xml). -cachedir Name of directory where output cache file is written (default: CLM build directory). -cimeroot REQUIRED: Path to cime 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). -phys Value of clm4_0, clm4_5, or clm5_0 (default is clm4_0) -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 CLM 4.0 Only. For CLM 4.5, spinup is controlled from build-namelist. Turn on given spinup mode for BGC setting of CN (level) AD Turn on Accelerated Decomposition from (2) bare-soil exit Jump directly from AD spinup to normal mode (1) normal Normal decomposition ("final spinup mode") (0) (default) The recommended sequence is 2-1-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 = abs_path($ProgDir); } else { $cfgdir = $cwd; } #----------------------------------------------------------------------------------------------- # Save commandline my $commandline = "$cfgdir/configure @ARGV"; #----------------------------------------------------------------------------------------------- # Parse command-line options. my %opts = ( cache => "config_cache.xml", phys => "clm4_0", nofire => undef, noio => undef, cimeroot => undef, clm_root => undef, spinup => "normal", ); GetOptions( "spinup=s" => \$opts{'spinup'}, "bgc=s" => \$opts{'bgc'}, "cache=s" => \$opts{'cache'}, "cachedir=s" => \$opts{'cachedir'}, "snicar_frc=s" => \$opts{'snicar_frc'}, "cimeroot=s" => \$opts{'cimeroot'}, "clm_root=s" => \$opts{'clm_root'}, "cppdefs=s" => \$opts{'cppdefs'}, "comp_intf=s" => \$opts{'comp_intf'}, "defaults=s" => \$opts{'defaults'}, "clm4me=s" => \$opts{'clm4me'}, "h|help" => \$opts{'help'}, "nofire" => \$opts{'nofire'}, "noio" => \$opts{'noio'}, "phys=s" => \$opts{'phys'}, "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. my $cimeroot = $opts{'cimeroot'}; if ( ! defined($cimeroot) ) { $cimeroot = "$cfgdir/../cime"; if ( -d $cimeroot ) { } elsif ( -d "$cfgdir/../../../cime" ) { $cimeroot = "$cfgdir/../../../cime"; } else { die <<"EOF"; ** Cannot find the root of the cime directory enter it using the -cimeroot option Did you run the checkout_externals scripts? EOF } } my $casecfgdir = "$cimeroot/scripts/Tools"; my $perl5lib = "$cimeroot/utils/perl5lib/"; # The Build::Config module provides utilities to store and manipulate the configuration. my $file = "$perl5lib/Build/Config.pm"; (-f "$file") or die <<"EOF"; ** Cannot find perl module \"Build/Config.pm\" in path \"$file\" ** EOF #----------------------------------------------------------------------------------------------- # Add $cfgdir/perl5lib to the list of paths that Perl searches for modules my @dirs = ( $cfgdir, "$perl5lib", $casecfgdir); unshift @INC, @dirs; require Build::Config; require config_files::clm_phys_vers; # Get the physics version my $phys = config_files::clm_phys_vers->new($opts{'phys'}); # Check for the physics specific configuration definition file. my $phys_string = $phys->as_filename(); my $config_def_file = "config_definition_$phys_string.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'}) and $phys->as_long() == $phys->as_long( "clm4_0" ) ) { $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 if ($print>=2) { print "Setting CLM configuration script directory to $cfgdir$eol"; } if ($print>=2) { print "Using configuration defaults file $config_defaults_file$eol"; } # 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 = abs_path("$cfgdir/.."); } else { $clm_root = $opts{'clm_root'}; } if ( &is_valid_directory( "$clm_root/src", allowEnv=>0 ) ) { $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=>0 ) ) { 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 = abs_path($opts{'cachedir'}); } else { $config_cache_dir = $clm_bld; } if (&is_valid_directory( $config_cache_dir, allowEnv=>0 ) 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"; } #----------------------------------------------------------------------------------------------- # physics $cfg_ref->set('phys', $opts{'phys'}); my $phys_string = $phys->as_string(); if ($print>=2) { if( defined($opts{'phys'}) ) { print "Using version $phys_string physics.$eol"; } } #----------------------------------------------------------------------------------------------- # supported single point configurations my $sitespf_pt = undef; if ($phys->as_long() == $phys->as_long("clm4_0") ) { if( defined($opts{'sitespf_pt'}) ) { $cfg_ref->set('sitespf_pt', $opts{'sitespf_pt'}); } $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 my $noio = undef; if ($phys->as_long() == $phys->as_long("clm4_0") ) { if (defined $opts{'noio'}) { $cfg_ref->set('noio', "on" ); } $noio = $cfg_ref->get('noio'); if ($print>=2) { if ( $noio eq "on") { print "ALL history output is turned OFF.$eol"; } } } #----------------------------------------------------------------------------------------------- # BGC option my $bgc_mode = undef; if ($phys->as_long() == $phys->as_long("clm4_0") ) { if (defined $opts{'bgc'}) { $cfg_ref->set('bgc', $opts{'bgc'}); } $bgc_mode = $cfg_ref->get('bgc'); if ($print>=2) { print "Using $bgc_mode for bgc.$eol"; } if ( $bgc_mode eq "casa" ) { print "Warning:: bgc=casa is NOT validated / scientifically supported.$eol"; } } # NOFIRE option -- currently only in bgc=CN my $nofire = undef; if ($phys->as_long() == $phys->as_long("clm4_0") ) { if (defined $opts{'nofire'}) { $cfg_ref->set('nofire', "on" ); } $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 my $spinup = undef; if ($phys->as_long() == $phys->as_long("clm4_0") ) { if (defined $opts{'spinup'}) { $cfg_ref->set('spinup', $opts{'spinup'}); } $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"; } } else { if ($opts{'spinup'} ne "normal") { die <<"EOF"; ** Spinup mode can only be controlled with configure for CLM 4.0. ** For CLM 4.5 use the bgc_spinup option to build-namelist EOF } } #----------------------------------------------------------------------------------------------- # 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 my $crpmode = undef; my $crop = undef; if ($phys->as_long() == $phys->as_long("clm4_0") ) { if (defined $opts{'crop'}) { $cfg_ref->set('crop', $opts{'crop'}); } $crpmode = "nocrop"; $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 } } #----------------------------------------------------------------------------------------------- # MAXPFT option my %maxpatchpft; my $maxpft = undef; if ($phys->as_long() == $phys->as_long("clm4_0") ) { $maxpatchpft{'crop'} = 21; $maxpatchpft{'nocrop'} = 17; $cfg_ref->set('maxpft', $maxpatchpft{$crpmode} ); $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 ( $maxpft != $maxpatchpft{$crpmode} ) { print "Warning:: running with maxpft NOT equal to $maxpatchpft{$crpmode} is " . "NOT validated / scientifically supported.$eol"; } if ($print>=2) { print "Using $maxpft for maxpft.$eol"; } } #----------------------------------------------------------------------------------------------- # SNICAR_FRC option my $snicar_frc = undef; if ($phys->as_long() == $phys->as_long("clm4_0") ) { if (defined $opts{'snicar_frc'}) { $cfg_ref->set('snicar_frc', $opts{'snicar_frc'}); } $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'}"; print "Warning:: running with user defined cppdefs is NOT validated / " . "scientifically supported.$eol"; } $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 = ''; if ($phys->as_long() == $phys->as_long("clm4_0") ) { $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 ($spinup eq 'AD') { $cfg_cppdefs .= " -DAD_SPINUP"; } elsif ($spinup eq 'exit') { $cfg_cppdefs .= " -DEXIT_SPINUP"; } if ( $snicar_frc eq 'on' ) { $cfg_cppdefs .= " -DSNICAR_FRC"; } } elsif ($phys->as_long() >= $phys->as_long("clm4_5") ) { # clm4_5 cppdefs -- SHOULD NOT BE ANY! if ( $cfg_cppdefs ne '' ) { die <<"EOF"; ** CPP definitions should be empty for clm5_0 and is NOT ** EOF } } elsif ($phys->as_long() == $phys->as_long("clm5_0") ) { # clm5_0 cppdefs -- SHOULD NOT BE ANY! if ( $cfg_cppdefs ne '' ) { die <<"EOF"; ** CPP definitions should be empty for clm5_0 and is NOT ** EOF } } else { # this should NOT happen die <<"EOF"; ** Bad CLM physics version ** EOF } # 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, $phys, allowEnv=>0 ); 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, $phys, %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'); # 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"; } if ($phys->as_long() == $phys->as_long("clm4_0") ) { # source root my $srcdir = "$clm_root/src_clm40"; if ( ! &is_valid_directory( "$srcdir", %opts ) ) { die "** source directory does not exist: $srcdir\n"; } # source directories under root my @dirs = ( "main", "biogeophys", "biogeochem" ); 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"; } } } else { # source root my $srcdir = "$clm_root/src"; if ( ! &is_valid_directory( "$srcdir", %opts ) ) { die "** source directory does not exist: $srcdir\n"; } # source directories under root my @dirs = ( "main", "biogeophys", "biogeochem", "soilbiogeochem", "dyn_subgrid", "init_interp", "fates", "fates/main", "fates/biogeophys", "fates/biogeochem", "fates/fire", "fates/parteh", "utils", "cpl" ); 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 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. # my ($dir, %opts) = @_; my $nm = "is_valid_directory"; my $valid = 0; if ( -d $dir ) { $valid = 1; } return( $valid ); }