source: trunk/fsource/SConstruct @ 323

Last change on this file since 323 was 323, checked in by toby, 12 years ago

incorporate linux changes

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