PSCF v1.1
make.py
1'''! Python scripts used by the PSCF makefile build system. '''
2
3import os
4import os.path
5import glob
6from string import *
7
8from pscfpp.file import *
9from pscfpp.text import *
10
11
30def createDependencyFileCpp(processor, options, cfile, srcdir, blddir, extraDependencies=''):
31
32 # Isolate base source file name
33 base = os.path.basename(cfile)
34 groups = base.split('.')
35 base = groups[0]
36
37 # Calculate source file directory path relative to srcdir
38 abspath = os.path.abspath(cfile)
39 relpath = os.path.relpath(abspath, srcdir)
40 reldir = os.path.dirname(relpath)
41
42 # Construct paths to subdirectories of build and src directories
43 if (reldir != '.' and reldir != ''):
44 blddir = os.path.normpath(os.path.join(blddir, reldir))
45 srcdir = os.path.normpath(os.path.join(srcdir, reldir))
46
47 # Construct paths to dependency files
48 # pfile - temporary file created by the compiler (erased)
49 # dfile - final dependnecy file
50 pfile = os.path.normpath(os.path.join(srcdir, base)) + '.p'
51 dfile = os.path.normpath(os.path.join(blddir, base)) + '.d'
52
53 # Create and execute compiler command to calculate dependencies
54 command = processor + ' '
55 command += pfile + ' '
56 command += options + ' '
57 command += cfile
58 os.system(command)
59
60 #Edit dependency file
61 editDepend(pfile, dfile, blddir, extraDependencies)
62 os.remove(pfile)
63
64
65
84def createDependencyFileCuda(processor, options, cfile, srcdir, blddir, extraDependencies=''):
85
86 # Store unmodified srcdir
87 srcroot = srcdir
88
89 # Isolate base source file name
90 base = os.path.basename(cfile)
91 groups = base.split('.')
92 base = groups[0]
93
94 # Calculate source file directory path relative to srcdir
95 abspath = os.path.abspath(cfile)
96 relpath = os.path.relpath(abspath, srcdir)
97 reldir = os.path.dirname(relpath)
98
99 # Construct paths to subdirectories of build and src directories
100 if (reldir != '.' and reldir != ''):
101 blddir = os.path.normpath(os.path.join(blddir, reldir))
102 srcdir = os.path.normpath(os.path.join(srcdir, reldir))
103
104 # Construct paths to dependency files
105 # pfile - temporary file created by the compiler (erased)
106 # dfile - final dependnecy file
107 pfile = os.path.normpath(os.path.join(srcdir, base)) + '.p'
108 dfile = os.path.normpath(os.path.join(blddir, base)) + '.d'
109
110 # Create and execute compiler command to calculate dependencies
111 command = processor + ' '
112 command += options + ' '
113 command += cfile
114 command += ' > ' + pfile
115 os.system(command)
116
117 # Edit dependency file and remove temporary pfile
118 editDependLocal(pfile, dfile, blddir, srcroot, extraDependencies)
119 os.remove(pfile)
120
121
122
134def editDepend(pfile, dfile, blddir, extraDependencies):
135 file = open(pfile, 'r')
136 lines = file.readlines()
137 file.close()
138
139 # Extract target from first line
140 groups = lines[0].split(":")
141 target = groups[0]
142 lines[0] = groups[1]
143
144 # Replace target by file in build directory
145 base = os.path.basename(target)
146 target = os.path.normpath(os.path.join(blddir, base))
147
148 # Replace dependencies by absolute paths
149 text = Wrapper('\\\n', 8)
150 for i in range(len(lines)):
151 line = lines[i]
152 if line[-1] == '\n':
153 line = line[:-1]
154 if line[-1] == '\\':
155 line = line[:-1]
156 lines[i] = line
157 if i == 0:
158 text.append(target + ': ')
159 deps = line.split()
160 for dep in deps:
161 path = os.path.abspath(dep)
162 text.append(path)
163
164 # Process extraDependencies (if any)
165 if extraDependencies:
166 deps = extraDependencies.split()
167 for dep in deps:
168 path = os.path.abspath(dep)
169 text.append(path)
170
171 file = open(dfile, 'w')
172 file.write(str(text))
173 file.close()
174
175
188def editDependLocal(pfile, dfile, blddir, srcroot, extraDependencies):
189 file = open(pfile, 'r')
190 lines = file.readlines()
191 file.close()
192
193 # Extract target from first line
194 groups = lines[0].split(":")
195 target = groups[0]
196 lines[0] = groups[1]
197
198 # Replace target by file in build directory
199 base = os.path.basename(target)
200 target = os.path.normpath(os.path.join(blddir, base))
201
202 # Replace local dependencies by absolute paths
203 text = Wrapper('\\\n', 8)
204 for i in range(len(lines)):
205 line = lines[i]
206 if line[-1] == '\n':
207 line = line[:-1]
208 if line[-1] == '\\':
209 line = line[:-1]
210 lines[i] = line
211 if i == 0:
212 text.append(target + ': ')
213 deps = line.split()
214 for dep in deps:
215 pair = [srcroot, dep]
216 if (os.path.commonprefix(pair) == srcroot):
217 path = os.path.abspath(dep)
218 text.append(path)
219
220 # Process extraDependencies (if any)
221 if extraDependencies:
222 deps = extraDependencies.split()
223 for dep in deps:
224 path = os.path.abspath(dep)
225 text.append(path)
226
227 file = open(dfile, 'w')
228 file.write(str(text))
229 file.close()
230
231
236
237
246 def __init__(self, path = '.', pathFromSrc = '.', pathToSrc ='.', parent = None, isTest=False):
247
248 self.path = path # path from working directory
249 self.pathFromSrc = pathFromSrc # path from $(SRC_DIR)
250 self.pathToSrc = pathToSrc # path to $(SRC_DIR)
251 self.parent = parent
252 self.isTest = isTest
253 self.hasLib = False
254 self.globalInclude = ''
255 self.defines = ''
256
257 if parent:
258 self.root = parent.root
259 self.generation = parent.generation + 1
260 else:
261 self.root = self
262 self.generation = 0
263
264 # Parse directory path
265 if self.pathFromSrc == '.':
266 self.dirparts = []
267 self.dirname = 'SRC'
268 else:
269 self.dirparts = self.pathFromSrc.split(os.sep)
270 self.dirname = '_'.join(self.dirparts)
271
272 # Read dir.txt file
273 dirFilePath = self.makePath('dir.txt')
274 if os.path.exists(dirFilePath):
275 file = open(dirFilePath,'r')
276 self.dirList = readLabelledList(file, 'subDirectories')
277 file.close()
278 else:
279 self.dirList = []
280
281 # Create a child MakeMaker for each directory
282 self.dirs = []
283 for dir in self.dirList:
284 path = self.makePath(dir)
285 if os.path.isdir(path):
286 if self.pathFromSrc == '.':
287 pathFromSrc = dir
288 pathToSrc = '..'
289 else:
290 pathFromSrc = self.pathFromSrc + os.sep + dir
291 pathToSrc = '..' + os.sep + self.pathToSrc
292 if dir == 'tests':
293 maker = MakeMaker(path, pathFromSrc, pathToSrc, self, True)
294 else:
295 maker = MakeMaker(path, pathFromSrc, pathToSrc, self, self.isTest)
296 self.dirs.append(maker)
297
298 def setGlobalInclude(self, text):
299 self.globalInclude = text
300 for dir in self.dirs:
301 dir.setGlobalInclude(text)
302
303 def setDefines(self, text):
304 self.defines = text
305 for dir in self.dirs:
306 dir.setDefines(text)
307
308 def addLibrary(self, libName, libObjs):
309 self.hasLib = True
310 self.libName = libName
311 self.libObjs = libObjs
312
313 def setLinkObjs(self, text):
314 self.linkObjs = text
315 for dir in self.dirs:
316 dir.setLinkObjs(text)
317
318 def makeInclude(self, base):
319 ''' Make include line suitable for a makefile'''
320 if self.pathFromSrc == '.':
321 return 'include $(SRC_DIR)' + os.sep + base + '\n'
322 else:
323 return 'include $(SRC_DIR)' + os.sep + self.pathFromSrc + os.sep + base + '\n'
324
325 def srcSuffix(self):
326 ''' Return suffix for source files: cpp or cc '''
327 if (self.isTest):
328 return 'cc'
329 else:
330 return 'cpp'
331
332 def find(self):
333 '''
334 Find all header and source files in this directory.
335 Note: Does not recursively descend into subdirectories
336 '''
337 # Find source files
338 self.srcs = []
339 self.hasSrcs = False
340 for name in os.listdir(self.path):
341 if name != '.':
342 path = self.makePath(name)
343 if os.path.isfile(path):
344 base = os.path.basename(path)
345 groups = base.split('.')
346 if len(groups) == 2:
347 base = groups[0]
348 suffix = groups[1]
349 if suffix == self.srcSuffix():
350 path = self.makePathFromSrc(base)
351 self.srcs.append(base)
352 self.hasSrcs = True
353
354 # Find *.h header files
355 self.hdrs = []
356 self.hasHdrs = False
357 for name in os.listdir(self.path):
358 if name != '.':
359 path = self.makePath(name)
360 if os.path.isfile(path):
361 base = os.path.basename(path)
362 groups = base.split('.')
363 if len(groups) == 2:
364 base = groups[0]
365 suffix = groups[1]
366 if suffix == 'h':
367 if base not in self.srcs:
368 self.hdrs.append(base)
369 self.hasHdrs = True
370
371 def make(self):
372
373 # Find all the source and header files in this directory
374 self.find()
375
376 # Recursively descend into subdirectories
377 for dir in self.dirs:
378 dir.make()
379
380 # ---------------------------------------------------------------------
381 # Open and write sources.mk file
382 file = open_w(self.makePath('sources.mk'))
383
384 # Include subdirectory sources.mk files
385 if len(self.dirs) > 0:
386 for dir in self.dirs:
387 basename = os.path.basename(dir.path)
388 if basename != 'tests':
389 varpath = basename + os.sep + 'sources.mk'
390 file.write(self.makeInclude(varpath))
391 file.write('\n')
392
393 # Construct prefix for aggregate names
394 if self.dirname == 'SRC':
395 prefix = ''
396 else:
397 prefix = self.dirname + '_'
398
399 wrapper = Wrapper('\\\n', 4)
400
401 # Write aggregate definition for SRCS
402 wrapper.clear()
403 wrapper.append(prefix + 'SRCS=')
404 for dir in self.dirs:
405 basename = os.path.basename(dir.path)
406 if basename != 'tests':
407 wrapper.append('$(' + dir.dirname + '_SRCS) ')
408 for base in self.srcs:
409 name = '$(SRC_DIR)' + os.sep + self.makePathFromSrc(base)
410 name += '.' + self.srcSuffix() + ' '
411 wrapper.append(name)
412 file.write(str(wrapper))
413 file.write('\n\n')
414
415 # Write aggregate definition for OBJS
416 file.write(prefix + 'OBJS=$(')
417 file.write(prefix + 'SRCS:.' + self.srcSuffix() + '=.o)')
418 file.write('\n\n')
419 #file.write(prefix + 'DEPS=$(')
420 #file.write(prefix + 'SRCS:.' + self.srcSuffix() + '=.d)')
421 #file.write('\n\n')
422
423 # Add library target, if any
424 if self.hasLib:
425 file.write(self.libName + ': ' + self.libObjs + '\n')
426 file.write('\t$(AR) rcs ' + self.libName + ' ' + self.libObjs + '\n')
427 file.write('\n')
428
429 file.close()
430
431 # --------------------------------------------------------------------
432 # Write makefile
433
434 file = open(self.makePath('makefile'), 'w')
435 file.write('SRC_DIR_REL =' + self.pathToSrc + '\n\n')
436 file.write(self.globalInclude)
437 if self.isTest:
438 file.write('include $(SRC_DIR_REL)/test/sources.mk\n')
439 file.write('include sources.mk\n')
440 file.write('\n')
441 if self.dirname == 'SRC':
442 objs = 'OBJS'
443 else:
444 objs = self.dirname + '_OBJS'
445 targets = '$(' + objs + ')'
446 deps = '$(' + objs + ':.o=.d)'
447 if self.isTest:
448 for base in self.srcs:
449 targets += ' ' + base
450 file.write('all: ' + targets)
451 if self.hasLib:
452 file.write(' ' + self.libName)
453 file.write('\n\n')
454 file.write('clean:\n\trm -f ' + targets + ' ' + deps)
455 if self.hasLib:
456 file.write(' ' + self.libName)
457 file.write('\n\n')
458 file.write('clean-deps:\n\trm -f ' + deps)
459 file.write('\n\n')
460 if self.isTest:
461 for base in self.srcs:
462 file.write(base + ': ' + base + '.o ' + self.linkObjs + '\n')
463 file.write('\t$(CXX) $(LDFLAGS) $(INCLUDES) $(DEFINES)')
464 file.write(' -o ' + base + ' ' + base + '.o \\\n')
465 file.write('\t ' + self.linkObjs + '\n\n')
466 #file.write('-include $(' + objs + ':.o=.d)\n\n')
467 file.write('-include ' + deps + '\n\n')
468 file.close()
469
470 def makePath(self, string):
471 if self.path and self.path != '.':
472 return self.path + os.sep + string
473 else:
474 return string
475
476 def makePathFromSrc(self, string):
477 if self.pathFromSrc and self.pathFromSrc != '.':
478 return self.pathFromSrc + os.sep + string
479 else:
480 return string
481
482 def srcDirPath(self):
483 if self.generation == 0:
484 return self.path
485 else:
486 shifts = []
487 for i in range(self.generation):
488 shifts.append('..')
489 return os.sep.join(shifts)
490
491 def clear(self):
492 self.hdrs = []
493 self.srcs = []
494 self.dirs = []
495
496 def filenames(self, pattern = '*', recursive = 1):
497 r = glob.glob( self.path + '/' + pattern)
498 if recursive:
499 for dir in self.dirs:
500 r.extend(dir.filenames(pattern))
501 return r
502
503 def __repr__(self):
504 r = []
505 r.append( self.path + '\n' )
506 for x in self.hdrs:
507 r.append( str(x) + '\n' )
508 for x in self.srcs.keys() :
509 r.append( str(x) + '\n' )
510 for x in self.dirs:
511 r.append( str(x) )
512 return join(r,'')
513
514 def __str__(self):
515 return __repr__()
516
517 def ls(self):
518 for x in self.hdrs:
519 print(x)
520 for x in self.srcs:
521 print(x)
522 for x in self.dirs:
523 print(x + os.sep)
524
Class to construct makefile system for a set of source files.
Definition: make.py:235
def srcSuffix(self)
Return suffix for source files: cpp or cc.
Definition: make.py:325
def makeInclude(self, base)
Make include line suitable for a makefile.
Definition: make.py:318
def makePathFromSrc(self, string)
Definition: make.py:476
def makePath(self, string)
Definition: make.py:470
def __init__(self, path='.', pathFromSrc='.', pathToSrc='.', parent=None, isTest=False)
Constructor.
Definition: make.py:246
def find(self)
Find all header and source files in this directory.
Definition: make.py:332
Class to wrap line breaks.
Definition: text.py:12
Utilities for manipulating files and paths.
Definition: file.py:1
def open_w(path)
Open file with specified path for writing, return file object.
Definition: file.py:57
def editDepend(pfile, dfile, blddir, extraDependencies)
Edit the dependency file created for a C/C++ file by the compiler.
Definition: make.py:134
def createDependencyFileCpp(processor, options, cfile, srcdir, blddir, extraDependencies='')
Create a *.d dependency file for a C/C++ source file.
Definition: make.py:30
def createDependencyFileCuda(processor, options, cfile, srcdir, blddir, extraDependencies='')
Create a *.d dependency file for a CUDA source file.
Definition: make.py:84
def editDependLocal(pfile, dfile, blddir, srcroot, extraDependencies)
Edit the dependency file created for a CUDA file by the compiler.
Definition: make.py:188
Utilities for manipulating and searching text strings.
Definition: text.py:1
def readLabelledList(file, label)
Read line of form "label = string", in which string may contains spaces.
Definition: text.py:263