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