Blame maint/extractcvars.in

Packit Service c5cf8c
#!/usr/bin/env perl
Packit Service c5cf8c
#
Packit Service c5cf8c
# (C) 2011by Argonne National Laboratory.
Packit Service c5cf8c
#     See COPYRIGHT in top-level directory.
Packit Service c5cf8c
#
Packit Service c5cf8c
Packit Service c5cf8c
# Parse C or header files to search for MPI_T control variable
Packit Service c5cf8c
# and category info, then output the info in source code form.
Packit Service c5cf8c
Packit Service c5cf8c
use strict;
Packit Service c5cf8c
use warnings;
Packit Service c5cf8c
use File::Basename qw(basename);
Packit Service c5cf8c
use Data::Dumper;
Packit Service c5cf8c
use Getopt::Long;
Packit Service c5cf8c
Packit Service c5cf8c
# Help perl find the YAML parsing module
Packit Service c5cf8c
use lib '@abs_srcdir@/local_perl/lib';
Packit Service c5cf8c
use YAML::Tiny qw();
Packit Service c5cf8c
Packit Service c5cf8c
# To format README file
Packit Service c5cf8c
use Text::Wrap;
Packit Service c5cf8c
$Text::Wrap::unexpand = 0; # disable hard tabs in output
Packit Service c5cf8c
Packit Service c5cf8c
##################################################
Packit Service c5cf8c
Packit Service c5cf8c
# set true to enable debug output
Packit Service c5cf8c
my $debug = 0;
Packit Service c5cf8c
my @cvars = ();
Packit Service c5cf8c
my @categories=();
Packit Service c5cf8c
my $yaml = YAML::Tiny->new();
Packit Service c5cf8c
my @dirs = ();
Packit Service c5cf8c
my @cfiles = ();
Packit Service c5cf8c
my %skipfiles = ();
Packit Service c5cf8c
Packit Service c5cf8c
# namespace prefix for function names
Packit Service c5cf8c
my $fn_ns = "MPIR_T_cvar";
Packit Service c5cf8c
# namespace prefix for variable and type names
Packit Service c5cf8c
my $ns = "MPIR_CVAR";
Packit Service c5cf8c
# an alternative namespace used for environment variables, unused if set to ""
Packit Service c5cf8c
my $alt_ns = "MPIR_PARAM";
Packit Service c5cf8c
# deprecated prefix for backward compatibility
Packit Service c5cf8c
my $dep_ns = "MPICH";
Packit Service c5cf8c
Packit Service c5cf8c
# Default :output source files
Packit Service c5cf8c
# NOTE: it's important to use single quote. abs_srcdir may contain sigils
Packit Service c5cf8c
#   e.g. /var/lib/jenkins-slave/workspace/hzhou-custom@2/config/ch3-sock/label/centos64
Packit Service c5cf8c
my $header_file = '@abs_srcdir@/../src/include/mpir_cvars.h';
Packit Service c5cf8c
my $c_file      = '@abs_srcdir@/../src/util/cvar/mpir_cvars.c';
Packit Service c5cf8c
my $readme_file = '@abs_srcdir@/../README.envvar';
Packit Service c5cf8c
Packit Service c5cf8c
sub Usage {
Packit Service c5cf8c
    print <
Packit Service c5cf8c
Packit Service c5cf8c
Usage: $0 [OPTIONS]
Packit Service c5cf8c
Packit Service c5cf8c
Supported options:
Packit Service c5cf8c
    --help              - this output (optional)
Packit Service c5cf8c
    --debug             - enable some debugging output (optional)
Packit Service c5cf8c
    --namespace=STR     - use STR as variable/type prefix in generated code (optional, default=$ns)
Packit Service c5cf8c
    --alt-namespace=STR - use STR as alternaive variable/type prefix in generated code (optional, default=$alt_ns)
Packit Service c5cf8c
    --header=STR        - specify the header file name (optional, default=$header_file)
Packit Service c5cf8c
    --c-file=STR        - specify the C file name (optional, default=$c_file)
Packit Service c5cf8c
    --readme-file=STR   - specify the readme file name (optional, default=$readme_file)
Packit Service c5cf8c
    --dirs=STR          - recursively parse C or header files under the directories as specified
Packit Service c5cf8c
    --skip=STR          - skip parsing files as specified (optional)
Packit Service c5cf8c
Packit Service c5cf8c
EOT
Packit Service c5cf8c
    exit 1;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Step 1: Process options
Packit Service c5cf8c
my $dirline;
Packit Service c5cf8c
my $skipline = "";
Packit Service c5cf8c
GetOptions(
Packit Service c5cf8c
    "help!"           => \&Usage,
Packit Service c5cf8c
    "debug!"          => \$debug,
Packit Service c5cf8c
    "namespace=s"     => \$ns,
Packit Service c5cf8c
    "alt-namespace=s" => \$alt_ns,
Packit Service c5cf8c
    "header=s"        => \$header_file,
Packit Service c5cf8c
    "c-file=s"        => \$c_file,
Packit Service c5cf8c
    "readme-file=s"   => \$readme_file,
Packit Service c5cf8c
    "dirs=s"          => \$dirline,
Packit Service c5cf8c
    "skips=s"         => \$skipline
Packit Service c5cf8c
) or Usage();
Packit Service c5cf8c
Packit Service c5cf8c
Usage unless $dirline;
Packit Service c5cf8c
Packit Service c5cf8c
print "dirline = $dirline\n" if $debug;
Packit Service c5cf8c
@dirs = split(/[:,;\s]+/, $dirline);
Packit Service c5cf8c
Packit Service c5cf8c
my @skips = split(/[:,;\s]+/, $skipline);
Packit Service c5cf8c
%skipfiles = map {$_ => 1} @skips;
Packit Service c5cf8c
Packit Service c5cf8c
# Step 2: Search all cfiles and put them in @cfiles.
Packit Service c5cf8c
foreach my $dir (@dirs) {
Packit Service c5cf8c
    ExpandDir($dir);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Step 3: Parse each cfile and put results in  @cvars and @categories.
Packit Service c5cf8c
foreach my $cfile (@cfiles) {
Packit Service c5cf8c
    ProcessFile($cfile);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Step 4: Preprocess cvars:
Packit Service c5cf8c
# *) Make sure that all categories referenced by cvars actually exist
Packit Service c5cf8c
# *) Strip out the prefix of their name (normally, MPIR_CVAR)
Packit Service c5cf8c
die "missing 'cvars', stopped" unless (@cvars);
Packit Service c5cf8c
my %cat_hash = map {$_->{name} => 1} @categories;
Packit Service c5cf8c
Packit Service c5cf8c
foreach my $p (@cvars) {
Packit Service c5cf8c
    unless (exists $cat_hash{$p->{category}}) {
Packit Service c5cf8c
        warn "Category '".$p->{category}."' referenced by '".$p->{name}."' was not found";
Packit Service c5cf8c
    }
Packit Service c5cf8c
    $p->{name} =~ s/${ns}_//;
Packit Service c5cf8c
    if (exists $p->{'alt-env'}) {
Packit Service c5cf8c
        my @alts = split(/[:,;\s]+/, $p->{'alt-env'});
Packit Service c5cf8c
        foreach my $elmt (@alts) {
Packit Service c5cf8c
            $elmt =~ s/${ns}_//;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        $p->{'alt-env'} = [@alts];
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Step 5: Output cvars and categories
Packit Service c5cf8c
print "Categories include: \n".Dumper(@categories) if $debug;
Packit Service c5cf8c
print "Cvars include :\n".Dumper(@cvars)."\n" if $debug;
Packit Service c5cf8c
Packit Service c5cf8c
my $run_timestamp = gmtime($ENV{SOURCE_DATE_EPOCH} || time)." UTC";
Packit Service c5cf8c
my $uc_ns = uc($ns);
Packit Service c5cf8c
Packit Service c5cf8c
# Setup output files
Packit Service c5cf8c
open(OUTPUT_H,      '>', $header_file);
Packit Service c5cf8c
open(OUTPUT_C,      '>', $c_file);
Packit Service c5cf8c
open(OUTPUT_README, '>', $readme_file);
Packit Service c5cf8c
Packit Service c5cf8c
#===============================================================
Packit Service c5cf8c
# Step 5.1: Dump the header file.
Packit Service c5cf8c
my $hdr_guard = Header2InclGuard($header_file);
Packit Service c5cf8c
print OUTPUT_H <
Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2010 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
/* Automatically generated
Packit Service c5cf8c
 *   by:   $0
Packit Service c5cf8c
 *   on:   $run_timestamp
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * DO NOT EDIT!!!
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
#if !defined($hdr_guard)
Packit Service c5cf8c
#define $hdr_guard
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpitimpl.h" /* for MPIR_T_cvar_range_value_t */
Packit Service c5cf8c
Packit Service c5cf8c
/* Initializes cvar values from the environment */
Packit Service c5cf8c
int ${fn_ns}_init(void);
Packit Service c5cf8c
int ${fn_ns}_finalize(void);
Packit Service c5cf8c
Packit Service c5cf8c
/* Extern declarations for each cvar
Packit Service c5cf8c
 * (definitions in $c_file) */
Packit Service c5cf8c
Packit Service c5cf8c
EOT
Packit Service c5cf8c
Packit Service c5cf8c
foreach my $p (@cvars) {
Packit Service c5cf8c
    printf OUTPUT_H "/* declared in $p->{location} */\n";
Packit Service c5cf8c
    printf OUTPUT_H "extern %s ${uc_ns}_%s;\n", Type2Ctype($p->{type}), $p->{name};
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
print OUTPUT_H <
Packit Service c5cf8c
Packit Service c5cf8c
/* TODO: this should be defined elsewhere */
Packit Service c5cf8c
#define ${ns}_assert MPIR_Assert
Packit Service c5cf8c
Packit Service c5cf8c
/* Arbitrary, simplifies interaction with external interfaces like MPI_T_ */
Packit Service c5cf8c
#define ${uc_ns}_MAX_STRLEN (384)
Packit Service c5cf8c
Packit Service c5cf8c
#endif /* $hdr_guard */
Packit Service c5cf8c
EOT
Packit Service c5cf8c
close(OUTPUT_H);
Packit Service c5cf8c
Packit Service c5cf8c
#===============================================================
Packit Service c5cf8c
# Step 5.2: Dump the C file.
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2010 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
/* automatically generated
Packit Service c5cf8c
 *   by:   $0
Packit Service c5cf8c
 *   at:   $run_timestamp
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * DO NOT EDIT!!!
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpiimpl.h"
Packit Service c5cf8c
Packit Service c5cf8c
/* Actual storage for cvars */
Packit Service c5cf8c
EOT
Packit Service c5cf8c
# Output the definitions
Packit Service c5cf8c
foreach my $p (@cvars) {
Packit Service c5cf8c
    my $default = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit Service c5cf8c
Packit Service c5cf8c
    if ($p->{class} eq 'device') {
Packit Service c5cf8c
        printf OUTPUT_C "#if defined MPID_%s\n", $p->{name};
Packit Service c5cf8c
        printf OUTPUT_C "%s ${uc_ns}_%s = MPID_%s;\n", Type2Ctype($p->{type}), $p->{name},
Packit Service c5cf8c
                       $p->{name};
Packit Service c5cf8c
        printf OUTPUT_C "#else\n";
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if ($p->{type} eq 'string') {
Packit Service c5cf8c
        printf OUTPUT_C "%s ${uc_ns}_%s = (const char*)%s;\n", Type2Ctype($p->{type}), $p->{name}, $default;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        printf OUTPUT_C "%s ${uc_ns}_%s = %s;\n", Type2Ctype($p->{type}), $p->{name}, $default;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if ($p->{class} eq 'device') {
Packit Service c5cf8c
        printf OUTPUT_C "#endif /* MPID_%s */\n\n", $p->{name};
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Generate the init function.
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME ${fn_ns}_init
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int ${fn_ns}_init(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int rc;
Packit Service c5cf8c
    const char *tmp_str;
Packit Service c5cf8c
    static int initialized = FALSE;
Packit Service c5cf8c
    MPIR_T_cvar_value_t defaultval;
Packit Service c5cf8c
Packit Service c5cf8c
    /* FIXME any MT issues here? */
Packit Service c5cf8c
    if (initialized)
Packit Service c5cf8c
        return MPI_SUCCESS;
Packit Service c5cf8c
    initialized = TRUE;
Packit Service c5cf8c
Packit Service c5cf8c
EOT
Packit Service c5cf8c
Packit Service c5cf8c
# Register categories
Packit Service c5cf8c
foreach my $cat (@categories) {
Packit Service c5cf8c
    my $desc = $cat->{description};
Packit Service c5cf8c
    $desc =~ s/"/\\"/g;
Packit Service c5cf8c
    printf OUTPUT_C qq(    /* declared in $cat->{location} */\n);
Packit Service c5cf8c
    printf OUTPUT_C qq(    MPIR_T_cat_add_desc(%s\n%s);\n\n),
Packit Service c5cf8c
        qq("$cat->{name}",),
Packit Service c5cf8c
        qq(        "$desc");
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Register and init cvars
Packit Service c5cf8c
foreach my $p (@cvars) {
Packit Service c5cf8c
    my $count;
Packit Service c5cf8c
    my $mpi_dtype;
Packit Service c5cf8c
    my $dftval;
Packit Service c5cf8c
Packit Service c5cf8c
    # Set count and default value of the car
Packit Service c5cf8c
    if ($p->{type} eq 'string') {
Packit Service c5cf8c
        $mpi_dtype = "MPI_CHAR";
Packit Service c5cf8c
        $count = "${uc_ns}_MAX_STRLEN";
Packit Service c5cf8c
        $dftval = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit Service c5cf8c
        printf OUTPUT_C qq(    defaultval.str = (const char *)%s;\n), $dftval;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    elsif ($p->{type} eq 'int' or $p->{type} eq 'boolean') {
Packit Service c5cf8c
        $mpi_dtype = "MPI_INT";
Packit Service c5cf8c
        $count = 1;
Packit Service c5cf8c
        $dftval = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit Service c5cf8c
        printf OUTPUT_C qq(    defaultval.d = %s;\n), $dftval;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    elsif ($p->{type} eq 'double') {
Packit Service c5cf8c
        $mpi_dtype = "MPI_DOUBLE";
Packit Service c5cf8c
        $count = 1;
Packit Service c5cf8c
        $dftval = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit Service c5cf8c
        printf OUTPUT_C qq(    defaultval.d = %s;\n), $dftval;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    elsif ($p->{type} eq 'range') {
Packit Service c5cf8c
        $mpi_dtype = "MPI_INT";
Packit Service c5cf8c
        $count = 2;
Packit Service c5cf8c
        $dftval = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit Service c5cf8c
        printf OUTPUT_C qq(    {\n);
Packit Service c5cf8c
        printf OUTPUT_C qq(        MPIR_T_cvar_range_value_t tmp = %s;\n), $dftval;
Packit Service c5cf8c
        printf OUTPUT_C qq(        defaultval.range = tmp;\n);
Packit Service c5cf8c
        printf OUTPUT_C qq(    }\n);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    else {
Packit Service c5cf8c
        die "unknown type $p->{type}, stopped";
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    # Register the cvar
Packit Service c5cf8c
    my $desc = $p->{description};
Packit Service c5cf8c
    $desc =~ s/"/\\"/g;
Packit Service c5cf8c
    $desc =~ s/\n/\\\n/g;
Packit Service c5cf8c
    printf OUTPUT_C qq(    MPIR_T_CVAR_REGISTER_STATIC(\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s);\n),
Packit Service c5cf8c
        qq(        $mpi_dtype,),
Packit Service c5cf8c
        qq(        ${uc_ns}_$p->{name}, /* name */),
Packit Service c5cf8c
        qq(        &${uc_ns}_$p->{name}, /* address */),
Packit Service c5cf8c
        qq(        $count, /* count */),
Packit Service c5cf8c
        qq(        $p->{verbosity},),
Packit Service c5cf8c
        qq(        $p->{scope},),
Packit Service c5cf8c
        qq(        defaultval,),
Packit Service c5cf8c
        qq(        "$p->{category}", /* category */),
Packit Service c5cf8c
        qq(        "$desc");
Packit Service c5cf8c
Packit Service c5cf8c
    if ($p->{type} eq 'string') {
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
    ${uc_ns}_GET_DEFAULT_STRING(${uc_ns}_$p->{name}, &tmp_str);
Packit Service c5cf8c
EOT
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    # Get the env variable value.
Packit Service c5cf8c
    my $env_fn = Type2EnvFn($p->{type});
Packit Service c5cf8c
    my @env_names = ();
Packit Service c5cf8c
    my $var_name = "${uc_ns}_" . $p->{name};
Packit Service c5cf8c
Packit Service c5cf8c
    # Process extra envs first so the primary always wins
Packit Service c5cf8c
    push @env_names, map { "${dep_ns}_$_" } @{$p->{'alt-env'}};
Packit Service c5cf8c
    push @env_names, map { "${alt_ns}_$_" } @{$p->{'alt-env'}};
Packit Service c5cf8c
    push @env_names, map { "${uc_ns}_$_" } @{$p->{'alt-env'}};
Packit Service c5cf8c
    push @env_names, "${dep_ns}_" . $p->{name};
Packit Service c5cf8c
    push @env_names, "${alt_ns}_" . $p->{name};
Packit Service c5cf8c
    push @env_names, "${uc_ns}_" . $p->{name};
Packit Service c5cf8c
Packit Service c5cf8c
    foreach my $env_name (@env_names) {
Packit Service c5cf8c
        # assumes rc is defined
Packit Service c5cf8c
        if ($p->{type} eq 'range') {
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
    rc = MPL_env2${env_fn}("$env_name", &($var_name.low), &($var_name.high));
Packit Service c5cf8c
    MPIR_ERR_CHKANDJUMP1((-1 == rc),mpi_errno,MPI_ERR_OTHER,"**envvarparse","**envvarparse %s","$env_name");
Packit Service c5cf8c
EOT
Packit Service c5cf8c
        }
Packit Service c5cf8c
        elsif ($p->{type} eq 'string') {
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
    rc = MPL_env2${env_fn}("$env_name", &tmp_str);
Packit Service c5cf8c
    MPIR_ERR_CHKANDJUMP1((-1 == rc),mpi_errno,MPI_ERR_OTHER,"**envvarparse","**envvarparse %s","$env_name");
Packit Service c5cf8c
EOT
Packit Service c5cf8c
        }
Packit Service c5cf8c
        else {
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
    rc = MPL_env2${env_fn}("$env_name", &($var_name));
Packit Service c5cf8c
    MPIR_ERR_CHKANDJUMP1((-1 == rc),mpi_errno,MPI_ERR_OTHER,"**envvarparse","**envvarparse %s","$env_name");
Packit Service c5cf8c
EOT
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if ($p->{type} eq 'string') {
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
    if (tmp_str != NULL) {
Packit Service c5cf8c
        ${var_name} = MPL_strdup(tmp_str);
Packit Service c5cf8c
        ${ns}_assert(${var_name});
Packit Service c5cf8c
        if (${var_name} == NULL) {
Packit Service c5cf8c
            MPIR_CHKMEM_SETERR(mpi_errno, strlen(tmp_str), "dup of string for ${var_name}");
Packit Service c5cf8c
            goto fn_fail;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    else {
Packit Service c5cf8c
        ${var_name} = NULL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
EOT
Packit Service c5cf8c
    }
Packit Service c5cf8c
    print OUTPUT_C "\n";
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
fn_exit:
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
EOT
Packit Service c5cf8c
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
int ${fn_ns}_finalize(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
EOT
Packit Service c5cf8c
Packit Service c5cf8c
foreach my $p (@cvars) {
Packit Service c5cf8c
    my $var_name = "${uc_ns}_" . $p->{name};
Packit Service c5cf8c
Packit Service c5cf8c
    if ($p->{type} eq 'string') {
Packit Service c5cf8c
        # Need to cleanup after whatever was strduped by the init routine
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
    if (${var_name} != NULL) {
Packit Service c5cf8c
        MPL_free((char *)${var_name});
Packit Service c5cf8c
        ${var_name} = NULL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
EOT
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
print OUTPUT_C <
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
EOT
Packit Service c5cf8c
close(OUTPUT_C);
Packit Service c5cf8c
Packit Service c5cf8c
#===============================================================
Packit Service c5cf8c
#Step 5.3 Dump the readme file
Packit Service c5cf8c
print OUTPUT_README <
Packit Service c5cf8c
(C) 2010 by Argonne National Laboratory.
Packit Service c5cf8c
    See COPYRIGHT in top-level directory.
Packit Service c5cf8c
Packit Service c5cf8c
Automatically generated
Packit Service c5cf8c
  by:   $0
Packit Service c5cf8c
  at:   $run_timestamp
Packit Service c5cf8c
DO NOT EDIT!!!
Packit Service c5cf8c
Packit Service c5cf8c
This file lists the various environment variables available to change the
Packit Service c5cf8c
behavior of the MPICH library.  These are intended to be used by advanced
Packit Service c5cf8c
users.
Packit Service c5cf8c
---------------------------------------------------------------------------
Packit Service c5cf8c
Packit Service c5cf8c
EOT
Packit Service c5cf8c
Packit Service c5cf8c
foreach my $p (@cvars) {
Packit Service c5cf8c
    my @env_names = ();
Packit Service c5cf8c
    my $first;
Packit Service c5cf8c
    my $alt;
Packit Service c5cf8c
    my $default;
Packit Service c5cf8c
Packit Service c5cf8c
    # process extra envs first so the primary always wins
Packit Service c5cf8c
    push @env_names, "${alt_ns}_" . $p->{name};
Packit Service c5cf8c
    push @env_names, "${dep_ns}_" . $p->{name};
Packit Service c5cf8c
    push @env_names, map { "${uc_ns}_$_" } @{$p->{'alt-env'}};
Packit Service c5cf8c
    push @env_names, map { "${alt_ns}_$_" } @{$p->{'alt-env'}};
Packit Service c5cf8c
    push @env_names, map { "${dep_ns}_$_" } @{$p->{'alt-env'}};
Packit Service c5cf8c
Packit Service c5cf8c
    print OUTPUT_README "${uc_ns}_$p->{name}\n";
Packit Service c5cf8c
Packit Service c5cf8c
    $first = 1;
Packit Service c5cf8c
    foreach $alt (@env_names) {
Packit Service c5cf8c
        if ($first) {
Packit Service c5cf8c
            print OUTPUT_README "    Aliases: $alt\n";
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            print OUTPUT_README "             $alt\n";
Packit Service c5cf8c
        }
Packit Service c5cf8c
        $first = 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    print OUTPUT_README wrap("    Description: ", "        ", $p->{description} . "\n");
Packit Service c5cf8c
    $default = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit Service c5cf8c
    print OUTPUT_README "    Default: $default\n";
Packit Service c5cf8c
    print OUTPUT_README "\n";
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
close(OUTPUT_README);
Packit Service c5cf8c
Packit Service c5cf8c
#===============================================================
Packit Service c5cf8c
# Helper subroutines used in this script
Packit Service c5cf8c
Packit Service c5cf8c
# Transform a cvar type to a C-language type
Packit Service c5cf8c
sub Type2Ctype {
Packit Service c5cf8c
    my $type = shift;
Packit Service c5cf8c
    my %typemap = (
Packit Service c5cf8c
        'int'     => 'int',
Packit Service c5cf8c
        'double'  => 'double',
Packit Service c5cf8c
        'string'  => 'const char *',
Packit Service c5cf8c
        'boolean' => 'int',
Packit Service c5cf8c
        'range'   => "MPIR_T_cvar_range_value_t",
Packit Service c5cf8c
    );
Packit Service c5cf8c
    die "unknown type '$type', stopped" unless exists $typemap{$type};
Packit Service c5cf8c
    return $typemap{$type};
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Transform a default value into a C value
Packit Service c5cf8c
sub FmtDefault {
Packit Service c5cf8c
    my $name = shift;
Packit Service c5cf8c
    my $val = shift;
Packit Service c5cf8c
    my $type = shift;
Packit Service c5cf8c
Packit Service c5cf8c
    if ($type eq 'string') {
Packit Service c5cf8c
        $val =~ s/"/\\"/g;
Packit Service c5cf8c
        if ($val eq 'NULL' or $val eq 'null') { return "NULL"; }
Packit Service c5cf8c
        else { return qq("$val"); }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    elsif ($type eq 'boolean') {
Packit Service c5cf8c
        if    ($val =~ m/^(0|f(alse)?|no?)$/i)   { return qq(0); }
Packit Service c5cf8c
        elsif ($val =~ m/^(1|t(rue)?|y(es)?)$/i) { return qq(1); }
Packit Service c5cf8c
        else {
Packit Service c5cf8c
            warn "WARNING: type='$type', bad val='$val', continuing";
Packit Service c5cf8c
            return qq(0); # fail-false
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    elsif ($type eq 'range') {
Packit Service c5cf8c
        if ($val !~ "-?[0-9]+:-?[0-9]+") {
Packit Service c5cf8c
            die "Unable to parse range value '$val', stopped";
Packit Service c5cf8c
        }
Packit Service c5cf8c
        $val =~ s/:/,/;
Packit Service c5cf8c
        return qq({$val});
Packit Service c5cf8c
    }
Packit Service c5cf8c
    else {
Packit Service c5cf8c
        return qq($val);
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# turns /path/foo_BAR-baz.h into FOO_BAR_BAZ_H_INCLUDED
Packit Service c5cf8c
sub Header2InclGuard {
Packit Service c5cf8c
    my $header_file = shift;
Packit Service c5cf8c
    my $guard = basename($header_file);
Packit Service c5cf8c
    $guard =~ tr/a-z\-./A-Z__/;
Packit Service c5cf8c
    $guard .= "_INCLUDED";
Packit Service c5cf8c
    die "guard contains whitespace, stopped" if ($guard =~ m/\s/);
Packit Service c5cf8c
    return $guard;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
sub Type2EnvFn {
Packit Service c5cf8c
    my $type = shift;
Packit Service c5cf8c
    my %typemap = (
Packit Service c5cf8c
        'int' =>  'int',
Packit Service c5cf8c
        'string' => 'str',
Packit Service c5cf8c
        'boolean' => 'bool',
Packit Service c5cf8c
        'double' => 'double',
Packit Service c5cf8c
        'range' => 'range',
Packit Service c5cf8c
    );
Packit Service c5cf8c
Packit Service c5cf8c
    die "unknown type '$type', stopped" unless exists $typemap{$type};
Packit Service c5cf8c
    return $typemap{$type};
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Parse a file, search the MPI_T_CVAR_INFO_BLOCK if any.
Packit Service c5cf8c
# Distill cvars and categories from the block.
Packit Service c5cf8c
# Push the results to back of @cvars and @categories respectively.
Packit Service c5cf8c
sub ProcessFile {
Packit Service c5cf8c
    my $cfile = $_[0];
Packit Service c5cf8c
    my $cvar_info_block = undef;
Packit Service c5cf8c
    my $in_cvar_info_block = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    #print "Processing file $cfile\n" if $debug;
Packit Service c5cf8c
    open my $CFILE_HANDLE, "< $cfile" or die "Error: open file $cfile -- $!\n";
Packit Service c5cf8c
    while (<$CFILE_HANDLE>) {
Packit Service c5cf8c
        if (/END_MPI_T_CVAR_INFO_BLOCK/) {
Packit Service c5cf8c
            last;
Packit Service c5cf8c
        } elsif ($in_cvar_info_block) {
Packit Service c5cf8c
            $cvar_info_block .= $_;
Packit Service c5cf8c
        } elsif (/BEGIN_MPI_T_CVAR_INFO_BLOCK/) {
Packit Service c5cf8c
            $in_cvar_info_block = 1;
Packit Service c5cf8c
            print "Found MPI_T_CVAR_INFO_BLOCK in $cfile\n" if $debug;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    close $CFILE_HANDLE;
Packit Service c5cf8c
Packit Service c5cf8c
    # Do some checking to ensure a correct cvar info block, also
Packit Service c5cf8c
    # add file locations to help users' debugging.
Packit Service c5cf8c
    if ($cvar_info_block) {
Packit Service c5cf8c
        my $info = ($yaml->read_string($cvar_info_block))->[0];
Packit Service c5cf8c
        if (exists $info->{cvars}) {
Packit Service c5cf8c
            # Remember location where the cvar is defined. Put that into
Packit Service c5cf8c
            # comments of the generated *.h file so that users know where
Packit Service c5cf8c
            # to look when meeting compilation errors.
Packit Service c5cf8c
            foreach my $cvar (@{$info->{cvars}}) {
Packit Service c5cf8c
                $cvar->{location} = $cfile;
Packit Service c5cf8c
                die "ERROR: cvar has no name in $cfile\n" unless exists $cvar->{name};
Packit Service c5cf8c
                die "ERROR: cvar $cvar->{name} has no type in $cfile\n" unless exists $cvar->{type};
Packit Service c5cf8c
                die "ERROR: cvar $cvar->{name} has no verbosity in $cfile\n" unless exists $cvar->{verbosity};
Packit Service c5cf8c
                die "ERROR: cvar $cvar->{name} has no scope in $cfile\n" unless exists $cvar->{scope};
Packit Service c5cf8c
                die "ERROR: cvar $cvar->{name} has no class in $cfile\n" unless exists $cvar->{class};
Packit Service c5cf8c
                die "ERROR: cvar $cvar->{name} has no description in $cfile\n" unless exists $cvar->{description};
Packit Service c5cf8c
            }
Packit Service c5cf8c
            push (@cvars, @{$info->{cvars}});
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        if (exists $info->{categories}) {
Packit Service c5cf8c
            # Do the same trick to categories
Packit Service c5cf8c
            foreach my $cat (@{$info->{categories}}) {
Packit Service c5cf8c
                $cat->{location} = $cfile;
Packit Service c5cf8c
                die "ERROR: category has no name in $cfile\n" unless exists $cat->{name};
Packit Service c5cf8c
                die "ERROR: category $cat->{name} has no description in $cfile\n"
Packit Service c5cf8c
                    unless exists $cat->{description};
Packit Service c5cf8c
            }
Packit Service c5cf8c
            push (@categories, @{$info->{categories}});
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
# Search cfiles recursively in the directory passed in.
Packit Service c5cf8c
# Push file names along with their paths to back of @cfiles.
Packit Service c5cf8c
sub ExpandDir {
Packit Service c5cf8c
    my $dir = $_[0];
Packit Service c5cf8c
    my @subdirs = ();
Packit Service c5cf8c
    my $DIR_HANDLE;
Packit Service c5cf8c
    opendir $DIR_HANDLE, "$dir" or die "Error: open directory $dir -- $!\n";
Packit Service c5cf8c
    for my $filename (sort readdir $DIR_HANDLE) {
Packit Service c5cf8c
        if ($filename =~ /^\./) {
Packit Service c5cf8c
            next;
Packit Service c5cf8c
        } elsif (-d "$dir/$filename") {
Packit Service c5cf8c
            $subdirs[$#subdirs + 1] = "$dir/$filename";
Packit Service c5cf8c
        } elsif ($filename =~ /(.*\.[Cchi])(pp){0,1}$/) {
Packit Service c5cf8c
            if (!defined($skipfiles{"$dir/$filename"}))
Packit Service c5cf8c
            {
Packit Service c5cf8c
                $cfiles[$#cfiles + 1] = "$dir/$filename";
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    closedir $DIR_HANDLE;
Packit Service c5cf8c
Packit Service c5cf8c
    # Recursively search subdirs
Packit Service c5cf8c
    foreach $dir (@subdirs) {
Packit Service c5cf8c
        ExpandDir($dir);
Packit Service c5cf8c
    }
Packit Service c5cf8c
}