source: trunk/fsource/SConstruct @ 319

Last change on this file since 319 was 319, checked in by toby, 10 years ago

more work

File size: 9.8 KB
Line 
1import platform
2import sys
3import os
4import glob
5import subprocess
6#==========================================================================================
7def is_exe(fpath):
8    return os.path.exists(fpath) and os.access(fpath, os.X_OK)
9def which_path(program):
10    "emulates Unix which: finds a program in path, but returns the path"
11    import os, sys
12    if sys.platform == "win32" and os.path.splitext(program)[1].lower() != '.exe':
13        program = program + '.exe'
14    fpath, fname = os.path.split(program)
15    if fpath:
16        if is_exe(program):
17            return fpath
18    else:
19        for path in os.environ["PATH"].split(os.pathsep):
20            exe_file = os.path.join(path, program)
21            if is_exe(exe_file):
22                return path
23    return ""
24#==========================================================================================
25# misc initializations
26# need command-line options for fortran command and fortran options
27F2PYflags = '' # compiler options for f2py command
28F2PYpath = which_path('f2py')       # default path to f2py
29GFORTpath = which_path('gfortran')   # path to compiler
30FCompiler='gfortran'
31G77path = which_path('g77')     # path to compiler
32FORTpath = ""
33FORTflags = ""
34liblist = []
35LDFLAGS = ''
36#==========================================================================================
37# configure platform dependent options here:
38if sys.platform == "win32":
39    F2PYsuffix = '.pyd'
40    FCompiler='g77'
41elif sys.platform == "darwin":
42    LDFLAGS = '-undefined dynamic_lookup -bundle -static-libgfortran -static-libgcc'
43    #F2PYpath = '/Library/Frameworks/Python.framework/Versions/6.2/bin/'     # path to f2py (python 6.2)
44    #F2PYpath = '/Library/Frameworks/Python.framework/Versions/current/bin/' # path to f2py
45    #FORTpath = '/sw/bin'                                                    # path to compilier
46    F2PYsuffix = '.so'
47elif sys.platform == "linux2":
48    #LDFLAGS = '-undefined dynamic_lookup -bundle -static-libgfortran -static-libgcc'
49    #F2PYflags = '--fcompiler=gnu95 --f77exec=gfortran --f77flags="-fno-range-check"'
50    F2PYsuffix = '.so'
51else:
52    print "Sorry, parameters for platform "+sys.platform+" are not yet defined"
53    sys.exit()
54#==========================================================================================
55# help
56if 'help' in COMMAND_LINE_TARGETS:
57    print """Building Fortran routines for use with GSAS-II
58----------------------------------------------
59
60To build the compiled modules files needed to run GSAS-II, invoke this script:
61    scons [options]
62where the following options are defined (all are optional):
63
64-Q      -- produces less output from scons
65
66-n      -- causes scons to show but not execute the commands it will perform
67
68-c      -- clean: causes scons to delete previously created files (don't use
69   with install)
70
71help    -- causes this message to be displayed (no compiling is done)
72
73install -- causes the module files to be placed in an installation directory
74   (../bin<X>NNv.v) rather than ../bin (<X> is mac, win or linux; NN is 64
75   or blank; v.v is the python version (2.6 or 2.7,...). Normally used only
76   by Brian or Bob for distribution of compiled software.
77
78The following options override defaults set in the scons script:
79
80FCompiler=<path>   -- define the name of the fortran compiler; default is to use
81   g77 on Windows and gfortran elsewhere. If you use something other than g77 or
82   gfortran, you must also specify F2PYflags
83
84FORTpath=<path>    -- define a path to the fortran program; default is to use
85   first gfortran (g77 for Windows) found in path
86
87FORTflags='string' -- string of options to be used for Fortran
88   during library build step
89
90F2PYpath=<path>    -- define a path to the f2py program; default is to use
91   first f2py found in path
92
93F2PYflags='string' -- defines optional flags to be supplied to f2py:
94   Typically these option define which fortran compiler to use.
95
96F2PYsuffix='.xxx'  -- extension for output module files (default: win: '.pyd',
97   mac/linux: '.so')
98
99LDFLAGS='string'   -- string of options to be used for f2py during link step
100
101Note that at present, only 32-bit python is supported and python 3.x is
102not supported.
103
104examples:
105    scons -Q
106       (builds into ../bin for current platform using default options)
107    scons -Q install
108       (builds into ../bin<platform> for module distribution)
109    scons -Q install F2PYpath=/Library/Frameworks/Python.framework/Versions/6.2/bin/
110       (builds with a non-default [e.g. older] version of python)
111    """
112    sys.exit()
113#==========================================================================================
114# override from command-line options
115for var in ['F2PYflags','F2PYpath','F2PYsuffix','FCompiler','FORTpath','FORTflags','LDFLAGS']:
116    if ARGUMENTS.get(var, None) is not None:
117        print 'Setting',var,'to',ARGUMENTS.get(var),'based on command line'
118        exec(var + "= ARGUMENTS.get('" + var +"')")
119#==========================================================================================
120# use the compiler choice to set compiler options, but don't change anything
121# specified on the command line
122if FCompiler == 'gfortran':
123    if FORTpath == "": FORTpath = GFORTpath
124    if F2PYflags == "": F2PYflags = '--fcompiler=gnu95 --f77exec=gfortran --f77flags="-fno-range-check"'
125elif FCompiler == 'g77':
126    if FORTpath == "": FORTpath = G77path
127    if F2PYflags == "": F2PYflags = '--fcompiler=gnu --f77exec=g77 --f77flags="-fno-range-check"'
128    if sys.platform == "win32":
129        if FORTflags == "": FORTflags = ' -w -O2 -fno-automatic -finit-local-zero -malign-double -mwindows'
130else:
131    if FORTpath == "": print 'Likely error, FORTpath is not specified'
132    if F2PYflags == "":
133        print 'Error: specify a F2PYflags value'
134        sys.exit()
135
136#==========================================================================================
137# get the python version number from the python image in the f2py directory
138#  find the python location. Note that on Windows it may be in the parent of the f2py location
139# then run it to get info about the verision and the number of bits
140for program in ['python','../python']:
141    if sys.platform == "win32" and os.path.splitext(program)[1].lower() != '.exe':
142        program = program + '.exe'
143    pythonprogram = os.path.normpath(os.path.join(F2PYpath,program))
144    if is_exe(pythonprogram): break
145else:
146    print 'python not found'
147    sys.exit()
148p = subprocess.Popen(pythonprogram, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
149p.stdin.write("import sys,platform;print str(sys.version_info[0]);print str(sys.version_info[1]);print platform.architecture()[0];sys.exit()")
150p.stdin.close()
151p.wait()
152versions = p.stdout.readlines()
153version = str(int(versions[0])) + '.' + str(int(versions[1]))
154PlatformBits = versions[2][:-1]
155#
156
157# Install location
158InstallLoc = '../bin'
159if len(COMMAND_LINE_TARGETS) == 0:
160    Default(InstallLoc)
161elif 'install' in COMMAND_LINE_TARGETS:
162    if PlatformBits == '64bit':
163        bits = '64'
164    else:
165        bits = ''
166    if sys.platform == "win32":
167        prefix = 'binwin'
168    elif sys.platform == "darwin":
169        prefix = 'binmac'
170    elif sys.platform == "linux2":
171        prefix = 'binlinux'
172    InstallLoc = '../' + prefix + bits + version
173    Alias('install',InstallLoc)
174
175# Setup build Environment
176env = Environment()
177# Define a builder to run f2py
178def generate_f2py(source, target, env, for_signature):
179    module = os.path.splitext(str(source[0]))[0]
180    if len(liblist) > 0:
181        for lib in liblist:
182            module = module + ' ' + str(lib)
183    return os.path.join(F2PYpath,'f2py')  + ' -c $SOURCE -m ' + module + ' ' + F2PYflags
184f2py = Builder(generator = generate_f2py)
185env.Append(BUILDERS = {'f2py' : f2py},)
186
187if ARGUMENTS.get('FCompiler', None) is not None or env.get('FORTRAN') is None:
188    # create a builder for the fortran compiler for library compilation, if needed
189    def generate_obj(source, target, env, for_signature):
190        dir = os.path.split(str(source[0]))[0]
191        obj = os.path.splitext(str(source[0]))[0]+'.o'
192        return os.path.join(FORTpath,FCompiler)  + ' -c $SOURCE ' + FORTflags + ' -I' + dir + ' -o' + obj
193    fort = Builder(generator = generate_obj, suffix = '.o',
194                   src_suffix = '.for')
195    env.Append(BUILDERS = {'fort' : fort},)
196    FortranCompile = env.fort
197    print 'Defining a FORTRAN builder'
198else:
199    FortranCompile = Object
200    env['FORTRANFLAGS'] = FORTflags
201
202# Setup build Environment
203if FORTpath != "":  env.PrependENVPath('PATH', FORTpath)
204if F2PYpath != "":  env.PrependENVPath('PATH', F2PYpath)
205var = 'LDFLAGS'
206env['ENV'][var] = eval(var)
207
208# find libraries to build (subdirectories named *subs)
209for sub in glob.glob('*subs'):
210    filelist = []
211    for file in glob.glob(os.path.join(sub,'*.for')):
212        #target = os.path.splitext(file)[0]+'.o'
213        target = FortranCompile(file) # connect .o files to .for files
214        #print 'Compile: ',file, target
215        filelist.append(target)
216    #lib = Library(sub, Glob(os.path.join(sub,'*.for'))) # register library to be created
217    lib = Library(sub, filelist) # register library to be created
218    liblist.append(lib[0].name)
219    filename = str(lib[0])
220    #Install(InstallLoc,filename)
221# find modules that need to be built
222modlist = []
223for src in glob.glob('*.for'):
224    target = os.path.splitext(src)[0] + F2PYsuffix
225    out = env.f2py(target,src)
226    Depends(target, liblist) # make sure libraries are rebuilt if old
227    modlist.append(out[0].name)
228    env.Install(InstallLoc, out[0].name)
229    break # bail out early for testing
230print 80*'='
231for var in ['FCompiler','FORTpath','FORTflags','F2PYflags','F2PYpath','F2PYsuffix','LDFLAGS']:
232    print 'Variable ',var,'is',eval(var)
233print 'Required fortran libraries:',
234for lib in liblist: print " " + lib,
235print ""
236print 'f2py modules:',
237for mod in modlist: print " " + mod,
238print ""
239print 'Using python at', pythonprogram
240print 'Python/f2py version =',version,PlatformBits
241print 'Install directory is',InstallLoc
242print 80*'='
243#print env.Dump()
Note: See TracBrowser for help on using the repository browser.