source: trunk/fsource/SConstruct @ 1148

Last change on this file since 1148 was 1148, checked in by vondreele, 10 years ago

major changes to 2-D detector calibration; now works for strongly tilted detectors & short sample to detector distances.
Distance is now defined as sample to detector plane. Previously it was sample to intercept of detector plane with incident beam (Bragg cone axis).
The "penetration" parameter is still suspect.

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