#! /usr/bin/python
#+
# NAME:
# mk
# CALLING SEQUENCE:
# mk.py main sub1 sub2 ... -dir=
# INPUTS:
# main sub1 sub2 ...
# name of main program, followed by additional
# files needed for the compilation.
# The file type, if specified, is ignored and is
# replaced by .f
# OPTIONAL INPUTS:
# -g77 use g77 compiler
# -intel use Intel Fortran 90 compiler
# -pgi use Portland compiler
# -absoft use Absoft Fortran compiler
#
# -nogen do not include the forgen library
# -nofits do not include the cfitsio library
# -noincl do not use default include paths
#
# If none of these command line switches is set then
# the script will try to locate g77 first, then the Intel
# compiler.
#
# -dir=dir destination directory for object files or executable/
# The default destination is the current directory.
# -cc include libraries for linking C/C++ code
# -static adds switch -static to compile command
# -obj only creates object files (used by olb script)
# -verbose verbose mode
# OUTPUTS:
# The executable will be named 'main' (the name of the main program).
# RESTRICTIONS:
# The g77 command includes the switches
# -ffixed-line-length-none
# SIDE EFFECTS:
# Cannot be executed in the 'root' account.
#
# Include directories:
# $SMEI_FOR/h, $SMEI_FOR/h/linux and $SMEI/for/h
# Library directory :
# Libraries should be located in $SMEI_LIB or $FOR
# Two libraries are expected: gen and cfitsio.
# $SMEI_LIB should always contain these.
# MODIFICATION HISTORY:
# JAN-2000, Paul Hick (UCSD/CASS)
# JAN-2001, Paul Hick (UCSD/CASS)
# Added loop to handle compilation of multiple files.
# SEP-2002, Paul Hick (UCSD/CASS)
# Removed -fdollar-ok option from g77 compilations (all dollar
# signs in variable names should have been removed by now).
# DEC-2003, Paul Hick (UCSD/CASS)
# Added -lcfitsio to compile command (for Fortran FITS routines).
# MAY-2004, Paul Hick (UCSD/CASS)
# Modifications to get this to run on the stesun Unix machines.
# Use awk instead of gawk (on our Linux boxes awk is a soft link
# to gawk). Changed the syntax for variable assignment from
# awk -v i=$i '{print $i}' to awk '{print $i}' i=$i
# The first one doesn't work properly on the stesun machines.
# JUL-2004, Paul Hick (UCSD/CASS)
# Added -Vaxlib switch for Intel compiler
# SEP-2004, Paul Hick (UCSD/CASS)
# The default location for the libgen library is now $SMEI_LIB
# (was $FOR).
# OCT-2004, Paul Hick (UCSD/CASS)
# Added Portland compiler.
# JAN-2005, Paul Hick (UCSD/CASS)
# Added -cc switch (will add a couple of C/C++ libraries
# needed to cross compile Fortran and C/C++ code).
# JAN-2005, Paul Hick (UCSD/CASS)
# Converted from bash to Python.
# JUL-2005, Paul Hick (UCSD/CASS)
# Added code to handle .o, .c and .cpp files
# The main program still must be a Fortran program.
# MAR-2007, Paul Hick (UCSD/CASS)
# SpatialIndex library is no longer included for linking.
# OCT-2007, Paul Hick (UCSD/CASS; pphick@ucsd.edu)
# Added -nogen and -nofits keyword
# Added test for existence of get_compiler_ function.
# If it exists already, use it. If not, create one.
# Previously the file was always created, resulting with
# a conflict with an existing one.
#-
import os
from tiny import is_there, start, args, hide_env, which, run_cmd
def set_compiler( f77id ):
import tempfile
tempfile.tempdir = os.environ['TUB']
tempfile = tempfile.mktemp('get_compiler.f')
content = [ \
' subroutine get_compiler(f77id)' , \
' character f77id*(*)' , \
" f77id = '"+f77id+"'" , \
' return' , \
' end' ]
(open(tempfile,'w')).write('\n'.join(content))
return tempfile
def mk( argv ):
no_result = dict ( [ ('f77', []), ('obj', []) ] )
say = 'mk, '
user = os.environ['USER']
if user == 'root':
print say+'do not use from root account'
return no_result
# Check for keywords
incl_cc = is_there( '-cc' , argv )
static = is_there( '-static', argv )
verbose = is_there( '-verbose',argv )
obj = is_there( '-obj' , argv )
all = is_there( '-all' , argv )
nogen = is_there( '-nogen' , argv )
nofits = is_there( '-nofits', argv )
noincl = is_there( '-noincl', argv )
out_dir = start ( '-dir=' , argv )
if out_dir == '':
to_remote = False
out_dir = os.environ['PWD']
else:
to_remote = out_dir.find( ':' ) != -1
if to_remote:
remote_dir = out_dir
out_dir = os.environ['TUB']
fortran_files = []
cminus_files = []
cplus_files = []
object_files = []
if all:
names = os.listdir( os.environ['PWD'] )
for name in names:
tmp = os.path.splitext( name )
if tmp[1] == '.f':
fortran_files.append( tmp[0] )
if tmp[1] == '.c':
cminus_files.append ( tmp[0] )
if tmp[1] == '.cpp':
cplus_files.append ( tmp[0] )
if tmp[1] == '.o':
object_files.append ( name )
found = 0
for main in fortran_files:
tmp = (open( os.path.join( '.', main+'.f') )).read()
tmp = tmp.split('\n')
for line in tmp:
if len(line) > 9:
found = line.expandtabs(7).lower().find(' program ') == 0
if found:
break
if found:
break
else:
print say+'no main program found'
return no_result
fortran_files.remove(main)
fortran_files.insert(0,main)
else:
names = args( argv )
names = names[1:len(names)]
for name in names:
tmp = os.path.splitext( name )
if tmp[1] == '.f' or tmp[1] == '':
fortran_files.append( tmp[0] )
if tmp[1] == '.c':
cminus_files.append ( tmp[0] )
if tmp[1] == '.cpp':
cplus_files.append ( tmp[0] )
if tmp[1] == '.o':
object_files.append ( name )
if len(fortran_files) == 0:
print say+'usage: mk.py main file1 file2 -dir='
return no_result
if not os.path.isdir( out_dir ): # Exit if out_dir does not exist
print say+hide_env(out_dir)+' does not exist'
return no_result
if is_there( '-g77' , argv ):
f77 = 'g77'
elif is_there( '-gfortran', argv ):
f77 = 'gfortran'
elif is_there( '-intel' , argv ):
f77 = 'ifort'
elif is_there( '-pgi' , argv ):
f77 = 'pgf77'
elif is_there( '-absoft' , argv ):
f77 = 'abf77'
else:
f77 = ''
if f77 != '':
f77_save = f77
if which( f77 ) == '':
f77 = ''
if f77_save == 'ifort':
if which( 'ifc' ) != '':
f77 = 'ifc'
if f77 == '':
print say+'compiler '+f77_save+' not available'
return no_result
elif which( 'g77' ):
f77 = 'g77'
elif which( 'gfortran' ):
f77 = 'gfortran'
elif which( 'ifort' ):
f77 = 'ifort'
elif which( 'ifc' ):
f77 = 'ifc'
elif which( 'pgf77' ):
f77 = 'pgf77'
elif which( 'abf77' ):
f77 = 'abf77'
else:
print say+'no Fortran compiler found'
return no_result
if f77 == 'g77':
cc = 'gcc'
cpp = 'g++'
elif f77 == 'gfortran':
cc = 'gcc'
cpp = 'g++'
elif f77 == 'ifort':
cc = 'icc'
cpp = 'icpc'
elif f77 == 'pgf77':
cc = 'pgcc'
cpp = 'pgCC'
elif f77 == 'abf77':
cc = ''
cpp = ''
f77link = []
if f77 == 'g77':
f77cc = f77+' -w -ffixed-line-length-none'
f77id = '_'+os.environ['GNU_COMPILER']
elif f77 == 'gfortran':
f77cc = f77+' -w -ffixed-line-length-none'
f77id = '_'+os.environ['GNU_COMPILER']
elif f77 == 'ifc':
f77cc = f77+' -w -132'
f77id = '_'+os.environ['INTEL_COMPILER']
f77link.append('-Vaxlib')
elif f77 == 'ifort':
f77cc = f77+' -w -132 -assume byterecl'
f77id = '_'+os.environ['INTEL_COMPILER']
f77link.append('-Vaxlib')
# Fix known bug in V9.0 compiler.
# http://support.intel.com/support/performancetools/fortran/linux/sb/CS-021696.htm
if os.environ['INTEL_COMPILER'].find('intel_9.0') != -1:
f77link.append('-no-ipo')
# Suppress warning messages for unused statment function declarations
if os.environ['INTEL_COMPILER'].find('intel_9.1') != -1:
f77cc = f77cc+' -warn nouncalled'
elif f77 == 'pgf77':
f77cc = f77+' -w -Mextend'
f77id = '_'+os.environ['PGI_COMPILER']
elif f77 == 'abf77':
f77cc = f77+' -W -V -N109'
f77id = '_'+os.environ['ABSOFT_COMPILER']
f77link.append('-lU77')
f77link.append('-lV77')
print say+'using '+which( f77 )
# Kludges needed to cross compile with C/C++
if incl_cc:
if f77 == 'g77':
f77link.append('-lstdc++')
elif f77 == 'gfortran':
f77link.append('-lstdc++')
elif f77 == 'ifort':
f77link.append('-cxxlib-gcc')
f77link.append('-lstdc++')
elif f77 == 'pgf77':
f77link.append('-lC')
f77link.append('-lstd')
if noincl:
include_f77 = ''
else:
include_f77 = '-I'+os.path.join(os.environ['SMEI'],'for','h')+\
' -I'+os.path.join(os.environ['SMEI_FOR'],'h')+\
' -I'+os.path.join(os.environ['SMEI_FOR'],'h','linux')
#include_cminus = '-I'+os.path.join(os.environ['SMEI'],'cpp','htmIndex20','include')
#include_cplus = '-I'+os.path.join(os.environ['SMEI'],'cpp','htmIndex20','include')
if static:
f77link.append('-static')
sources = []
objects = []
top_dirs = [ 'PWD','FOR','SMEI_FOR']
source_dirs = []
for source_dir in top_dirs:
if os.environ.has_key( source_dir ):
tmp = os.environ[ source_dir ]
if os.path.isdir( tmp ):
source_dirs.append( tmp )
for entry in fortran_files:
base_name = os.path.splitext(entry)
if base_name[1] == '.f':
base_name = base_name[0]
else:
base_name = entry
found = 0
for source_dir in source_dirs:
for root, dirs, files in os.walk( source_dir ):
for tmp in ['win','unix','vms','CVS']:
if dirs.count(tmp) == 1:
dirs.remove(tmp)
found = files.count( base_name+'.f' ) == 1
if found:
source = os.path.join( root, base_name+'.f' )
sources.append( source )
print say+hide_env(source)
object = os.path.join( out_dir, base_name+'.o' )
cmd = 'rm -f '+object+'; '+f77cc+' -c '+include_f77+' '+source+' -o'+object
run_cmd( cmd, verbose)
if os.path.isfile( object ):
objects.append( object )
else:
if not obj and entry == fortran_files[0]:
print say+' error compiling main program'
return
break
if found:
break
top_dirs = [ 'PWD','SMEI_CPP']
source_dirs = []
for source_dir in top_dirs:
if os.environ.has_key( source_dir ):
tmp = os.environ[ source_dir ]
if os.path.isdir( tmp ):
source_dirs.append( tmp )
for entry in cminus_files:
base_name = os.path.splitext(entry)
if base_name[1] == '.c':
base_name = base_name[0]
else:
base_name = entry
found = 0
for source_dir in source_dirs:
for root, dirs, files in os.walk( source_dir ):
for tmp in ['CVS']:
if dirs.count(tmp) == 1:
dirs.remove(tmp)
found = files.count( base_name+'.c' ) == 1
if found:
source = os.path.join( root, base_name+'.c' )
sources.append( source )
print say+hide_env(source)
object = os.path.join( out_dir, base_name+'.o' )
#cmd = 'rm -f '+object+'; '+cc+' -c '+include_cminus+' '+source+' -o'+object
cmd = 'rm -f '+object+'; '+cc+' -c '+source+' -o'+object
run_cmd( cmd, verbose)
if os.path.isfile( object ):
objects.append( object )
break
if found:
break
top_dirs = [ 'PWD','SMEI_CPP']
source_dirs = []
for source_dir in top_dirs:
if os.environ.has_key( source_dir ):
tmp = os.environ[ source_dir ]
if os.path.isdir( tmp ):
source_dirs.append( tmp )
for entry in cplus_files:
base_name = os.path.splitext(entry)
if base_name[1] == '.cpp':
base_name = base_name[0]
else:
base_name = entry
found = 0
for source_dir in source_dirs:
for root, dirs, files in os.walk( source_dir ):
for tmp in ['CVS']:
if dirs.count(tmp) == 1:
dirs.remove(tmp)
found = files.count( base_name+'.cpp' ) == 1
if found:
source = os.path.join( root, base_name+'.cpp' )
sources.append( source )
print say+hide_env(source)
object = os.path.join( out_dir, base_name+'.o' )
#cmd = 'rm -f '+object+'; '+cpp+' -c '+include_cplus+' '+source+' -o'+object
cmd = 'rm -f '+object+'; '+cpp+' -c '+' '+source+' -o'+object
run_cmd( cmd, verbose)
if os.path.isfile( object ):
objects.append( object )
break
if found:
break
objects.extend(object_files)
if len(sources) == 0:
print say+'no source file(s) specified'
return no_result
if len(objects) == 0:
print say+'no objects file(s) created'
return no_result
if obj:
status = dict ( [ ('f77', [f77,f77cc,f77id]), ('obj', objects) ] )
return status
# Extract the file name part as name for the executable
exename = start ( '-name=' , argv )
if exename == '':
exename = fortran_files[0]
exename = (os.path.split (exename))[1]
exename = (os.path.splitext(exename))[0]
exename = os.path.join(out_dir,exename)
libsdir = ['-L'+os.environ['SMEI_LIB']]
if os.environ.has_key('FOR'):
tmp = os.environ['FOR']
if os.path.isdir( tmp ):
libsdir.append( '-L'+tmp )
all_libs = []
if not nogen : all_libs.append( 'gen' )
if not nofits: all_libs.append( 'cfitsio' )
libs = []
for lib in all_libs:
tmp = os.path.join(os.environ['SMEI_LIB'],'lib'+lib+f77id+'.a')
if os.path.isfile( tmp ):
libs.append( '-l'+lib+f77id )
else:
print say+hide_env(tmp)+' not found'
source = 'get_compiler_'+f77id
if fortran_files.count(source) == 0:
source = set_compiler(f77id)
object = os.path.splitext(source)[0]+'.o'
cmd = f77cc+' -c '+source+' -o'+object
run_cmd( cmd, verbose)
if os.path.isfile( object ):
objects.append( object )
os.remove(source)
cmd = f77cc+ \
' '+include_f77 + \
' '+' '.join(libsdir)+ \
' '+' '.join(objects)+ \
' '+' '.join(libs) + \
' '+' '.join(f77link)+ \
' -o'+exename
run_cmd( cmd, verbose)
if os.path.isfile(exename):
print say+'exec: '+hide_env(exename)
if to_remote:
run_cmd( 'scp '+exename+' '+remote_dir, True )
os.remove(exename)
else:
print say+'fail: '+hide_env(exename)
run_cmd( 'rm -f '+' '.join(objects), verbose )
status = dict ( [ ('f77', [f77,f77cc,f77id]), ('exe', exename) ] )
return status
if __name__ == '__main__':
import sys
mk( sys.argv )
sys.exit()