#!/usr/bin/perl
# $Id: mkmod,v 1.76 2011/08/17 14:28:56 billl Exp $
# mkmod is the updated version of makemod using nmodl INCLUDE statements
# Most mechanisms can be inserted by using a sparse declaration that utilizes
# INCLUDE.
#________________________________________________________________
# E.G.
# NEURON {
# SUFFIX NAME
# }
#
# PARAMETER {
# param1 = 15
# ...
# }
#
# INCLUDE "body.inc"
#________________________________________________________________
#
# mod files that are to simply be compiled as is should use the
# DEFAULT key word
#
$file = "parameters.multi"; # default name
$filecreate = 1;
$nsp = $condor = 0;
$nrnmodlflag = 1;
$uname = $ENV{"CPU"};
$neuronhome = $ENV{"NEURON"};
$nrnmodl = "nrnivmodl";
$loadflags="";
if (-f $ARGV[0]) {
$file = shift;
$nsp = 1; # new special
$oldsp="$uname/special"; $newsp=$file; $newsp =~ s/([^.]+).multi/\1/;
$oldlib="$uname/.libs/libnrnmech.so.0.0.0";
$newlib = "$uname/.libs/libnrnmech.".$newsp;
$newsp = "$uname/special.".$newsp;
if (-f $oldsp) {
rename($oldsp,"spe.SAV");
rename($oldlib,"lib.SAV");
} else { die "$oldsp not found\n"; }
print "Using $file as input file.\n";
} elsif ($ARGV[0] == 1) {
# dummy argument to move on to rest of arg list
shift;
}
# if first arg is nrnmodl just run nrnmodl else
# take the first arg to be a file name if it exists
if ($ARGV[0] eq "nrnmodl") {
$filecreate = 0; shift;
} elsif ($ARGV[0] eq "create") {
$nrnmodlflag = 0; shift;
} elsif ($ARGV[0] eq "nrnoc") {
$nrnmodl = "$neuronhome/bin/nrnocmodl"; shift;
} elsif ($ARGV[0] eq "profile") {
$nrnmodl = "/usr/local/src/nrniv/local/bin/nrnivmodl.prof"; shift;
} elsif ($ARGV[0] eq "condor") {
$condor = 1;
$filecreate = 0;
print "Using $neuronhome/bin/nrnivmodl\n";
$nrnmodl = "condor_compile $neuronhome/bin/nrnivmodl"; shift;
} elsif ($ARGV[0] eq "condordebug") {
$condor = 1;
$filecreate = 0;
print "Using $neuronhome/bin/nrnivmodl.condor.debug\n";
$nrnmodl = "condor_compile $neuronhome/bin/nrnivmodl.condor.debug"; shift;
} elsif ($ARGV[0] eq "localcondor") {
$condor = 1;
$filecreate = 0;
$nrnmodl = "/usr/local/src/nrniv/local/bin/nrnivmodl.localcondor"; shift;
} elsif ($ARGV[0] eq "ldflags") {
shift;
$nrnmodl = qq|nrnivmodl -loadflags "$ARGV[0]"|; shift
} elsif ($ARGV[0] eq "nocmodl") {
$nrnmodl = "$neuronhome/bin/nrnocmodl";
$filecreate = 0; shift;
} elsif ($ARGV[0] eq "clean") {
$nrnmodlflag = 0; $filecreate = 0; $clean = 1; shift;
} elsif ($ARGV[0] eq "files") {
shift; $grep = "@ARGV"; $#ARGV=-1; # clear out rest of the args
$nrnmodlflag = 0; $filecreate = 0; $fullname=1;
} elsif ($ARGV[0] eq "tar") {
shift; @ATAR = @ARGV; $#ARGV=-1; # clear out rest of the args
$nrnmodlflag = 0; $filecreate = 0; $fullname=1; $tar=1;
} elsif ($ARGV[0] eq "zip") {
shift;
if ($ARGV[0] =~ /-f/) { # a list of additional files
open(F,$ARGV[1]);
while (<F>) {chop; push(@ATAR,$_);}
} else {
@ATAR = @ARGV; $#ARGV=-1; # clear out rest of the args
}
$nrnmodlflag = 0; $filecreate = 0; $fullname=1; $tar=2;
} elsif ($ARGV[0] eq "grep") {
shift; $grep = "@ARGV"; $#ARGV=-1; # clear out rest of the args
$nrnmodlflag = 0; $filecreate = 0;
} elsif ($ARGV[0] eq "help") {
shift;
die "\nnrnmodl [filename] [flag or [mech1 mech2 ...]]
if filename is not given assumed to be parameters.multi
name can be given fully or with .multi assumed
possible flags are:
create - produce new .mod files but do not run nrnmodl
nrnmodl - just run nrnmodl, all .mod files should already be present
nrnoc or nocmodl - run $neuronhome/bin/nrnocmodl
grep - just show the compile command
if mech names are given only these will be recreated for recompilation
\n";
}
if ($#ARGV > -1) {
print "Only recompile: @ARGV\n";
grep($sections{$_}=1,@ARGV); # convert to associative array
}
# file to read from, usually parameters.multi
if (!open(IN,$file)) { `nrnivmodl`; exit; }
# will use MODL_INCLUDE path to look for .mod files
@modpath = split(/[ :]/,$ENV{MODL_INCLUDE});
$site = ($ENV{SITE} or "/usr/site");
print "Search path for mod files is @modpath\n";
# block starts with NEURON { SUFFIX NAME }
$block_regexp = '^NEURON\s*{\s*((POINT_PROCESS)|(SUFFIX))\s+(\w+)';
@lines = (); # save lines for blocks of statements
$curfile = ""; # name of file for a given block
(! -l "../$uname") and (symlink("mod/$uname","../$uname") || die "ERROR: Can't create link from ../$uname\n");
while (<IN>) {
if ($_ =~ /$block_regexp/) {
$curfile && &printit; # print the previous block
$curfile = $4; # name comes from the 4th parenset in block_regexp
if ($clean && -f ($objfile = $ENV{"CPU"}."/".$curfile.".o")) {
print "Remove $objfile.\n"; unlink($objfile);
}
push(@lines,$_);
} elsif ($_ =~ /^LDFLAGS (.+)/) {
$loadflags .= qq| $1|;
} elsif ($_ =~ /^DEFAULT/) {
$curfile && &printit; # finish off a block if needed
split; $filename = $_[1].".mod";
push(@modfiles,$_[1]); # stem only to run nrnmodl on
if (($clean || $sections{$_[1]}) && -f ($objfile = $ENV{"CPU"}."/".$_[1].".o")) {
print "Remove: $objfile.\n"; unlink($objfile);
}
if ($_[2] =~ /[0-9]+/ && $filecreate) { # a version number
$co = 0; # a flag
if (-e "RCS/$filename,v") {
print "Checking out version 1.$_[2] of $filename.\n";
$co = 1;
`co -r1.$_[2] $filename`;
} else {
foreach $dir (@modpath) { # look for the file and create link
if (-e "$dir/RCS/$filename,v") { # save and terminate loop
print "Checking out version 1.$_[2] of $dir/$filename.\n";
unlink($filename);
# must use full RCS path to get file into current dir
# instead of into remote directory
`co -r1.$_[2] $dir/RCS/$filename,v`;
$co = 1;
last;
}
}
}
($co==1) || die "WARNING RCS VERSION FOR $filename NOT FOUND.\n";
# look for the file in MODL_INCLUDE path
} elsif (-e $filename) {
$co = 1;
} else {
$co = 0;
foreach $dir (@modpath) { # look for the file and create link
if (-e "$dir/$filename") { # save and terminate loop
$co = 1;
symlink("$dir/$filename",$filename) || die "can't link to $dir/$filename\n";
last;
}
}
}
if ($co == 0 && $filecreate) { # couldn't find the file so look for RCS
if (-e "RCS/$filename,v") {
print "Checking out $filename.\n";
$co = 1; `co $filename`;
} else {
foreach $dir (@modpath) { # look for the file and create link
if (-e "$dir/RCS/$filename,v") { # save and terminate loop
print "Checking out $dir/$filename.\n";
`co $dir/$filename`;
symlink("$dir/$filename",$filename);
$co = 1;
last;
}
}
}
}
if (`grep -c //@ $filename`+0 > 0) { # look for '//@' which will need processing
push(@modfiles,pop(@modfiles)."_"); # stem_
$f1="$modfiles[$#modfiles].mod";
if ((! -f $f1) || (-M $filename < -M $f1)) {
&verbatize($filename); # replace //@ with bracketing VERBATIM/ENDVERBATIM
}
}
($co==1) || die "$filename NOT FOUND; check env variable MODL_INCLUDE.\n";
} elsif ($#lines >= 0) { # only add lines if in a block
push(@lines,$_);
}
}
# need to do terminal check
$curfile && &printit;
$nrnmodlflag || print "COMPILATION COMMAND: \n";
# tell user the mod files being included
print "\t$nrnmodl @modfiles\n";
if ($grep) {
grep($_.=".mod",@modfiles); # put .mod back on ends for filenames
print "grep $grep @modfiles\n";
system("grep $grep @modfiles");
}
if ($fullname) {
grep($_.=".mod",@modfiles); # put .mod back on ends for filenames
open(GREP,"grep INCLUDE @modfiles|");
while (<GREP>) {
if (/"/) {
s/[^"]+"([^"]+)"/\1/;
$filename=$_; chop $filename;
if (grep($_ eq $filename,@modfiles)) { next; }
push(@modfiles,$filename);
if (! -e $filename) {
foreach $dir (@modpath) { # look for the file and create link
if (-e "$dir/$filename") { # save and terminate loop
symlink("$dir/$filename",$filename) || die "can't link to $dir/$filename\n";
last;
}
}
}
}
}
print "\n\t@modfiles\n";
if ($tar) {
$dstr = "b".`datestring`;
print (($tar==1)?
"Creating $dstr.tar; use 'tar rhf $dstr.tar $dstr/filename' if need to append\n":
"Creating $dstr.zip; use 'zip -g $dstr.zip $dstr/filename' if need to append\n");
symlink(".",$dstr);
if (-e "../batch_.hoc"){
symlink("../batch_.hoc","batch_.hoc");
push(@modfiles,"batch_.hoc");
} else {
print "\tNO batch_.hoc\n";
}
symlink("$site/nrniv/local/mod/misc.h","misc.h");
push(@modfiles,"misc.h");
if (! -e "data") {
mkdir data;
push(@modfiles,"data");
} else {
print "data/ dir exists -- not including\n";
}
foreach $file (@ATAR) {
($d,$f)= ($file =~ m|^(.+)/([^/]+)$|);
if ($d!~/^$/) {
symlink("$file","$f");
push(@links,$f);
} else {
$f=$file;
}
push(@modfiles,$f);
}
grep($_="$dstr/$_",@modfiles);
if ($tar==1) {`tar czhf $dstr.tgz @modfiles`;} else {
unlink $dstr.zip;
`zip $dstr.zip @modfiles`;
}
unlink $dstr;
unlink @links;
}
}
if ($nrnmodlflag) {
if ($loadflags) { $nrnmodl .= qq| -loadflags "$loadflags"|; }
(system("export DEFAULT_INCLUDES=-I/$site/nrniv/local/mod;$nrnmodl @modfiles") == 0) ||
die "ERROR IN COMPILATION\n";
}
if ($nsp) { # new special
open(IN,$oldsp);
open(OUT,"> $newsp");
while (<IN>) {
$_ =~ /libnrnmech/ and s|$uname/.libs/libnrnmech.so|$newlib|;
print OUT;
}
close IN; close OUT; chmod 0755, $newsp;
print "\t******** Moving special to $newsp ********\n";
rename($oldlib,$newlib);
rename("spe.SAV",$oldsp);
rename("lib.SAV",$oldlib);
}
# print lines into a new file called $curfile.mod
# clear the lines array and the curfile name
sub printit {
push(@modfiles,$curfile); # name of a file to run nrnmodl on
if ($filecreate && (! %sections || $sections{$curfile})) {
$curfile .= ".mod"; # real file name
if ((! -f $curfile) || (-M $file < -M $curfile)) {
print "Creating $curfile\n";
open(OUT,"> $curfile") || die "Can't open $curfile.\n";
print OUT @lines;
close(OUT);
}
}
@lines = (); # clear the array
$curfile = "";
}
# verbatize makes a line marked by //@ into a VERBATIM block
# need to sheer off the '{' and anything following so that brackets match for nocmodl
# NB can't use if/else block where the if is VERBATIM since then the else is unprecedented
# for nocmodl
sub verbatize {
($in)=@_;
$out=$in; $out=~s/\.mod/_.mod/;
open(I,"<$in"); open(O,">$out");
while (<I>) {
if (m|//@|) {
if (m|([^{]+)({.+)//.+|) {
print O "VERBATIM\n$1\nENDVERBATIM\n$2\n";
} else {
print O "VERBATIM\n$_\nENDVERBATIM\n";
}
} else {
print O;
}
}
}