#!/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; } } }