1#!/usr/bin/env python 2# 3# Builds a iOS static library of PETSc 4# 5# Before using remove /usr/include/mpi.h and /Developer/SDKs/MacOSX10.5.sdk/usr/include/mpi.h or 6# Xcode will use those instead of the MPIuni one we point to 7# 8# export PETSC_ARCH=arch-ios-simular 9# 10# ./systems/Apple/iOS/bin/arch-ios.py [use --with-debugging=0 to get iPhone/iPad version, otherwise creates simulator version] 11# this sets up the appropriate configuration file 12# 13# ./systems/Apple/iOS/bin/iosbuilder.py 14# this creates the PETSc iPhone/iPad library 15# this will open Xcode and give you directions to follow 16# 17# open systems/Apple/iOS/examples/examples.xcodeproj 18# Project -> Edit Project Setting -> Configuration (make sure it is Release or Debug depending on if you used --with-debugging=0) 19# Build -> Build and Debug 20# 21import os, sys 22 23sys.path.insert(0, os.path.join(os.environ['PETSC_DIR'], 'config')) 24sys.path.insert(0, os.path.join(os.environ['PETSC_DIR'], 'config', 'BuildSystem')) 25 26import script 27 28class PETScMaker(script.Script): 29 def __init__(self): 30 import RDict 31 import os 32 33 argDB = RDict.RDict(None, None, 0, 0, readonly = True) 34 argDB.saveFilename = os.path.join(os.environ['PETSC_DIR'], os.environ['PETSC_ARCH'], 'conf', 'RDict.db') 35 argDB.load() 36 script.Script.__init__(self, argDB = argDB) 37 self.log = sys.stdout 38 return 39 40 def setupModules(self): 41 self.mpi = self.framework.require('config.packages.MPI', None) 42 self.base = self.framework.require('config.base', None) 43 self.setCompilers = self.framework.require('config.setCompilers', None) 44 self.arch = self.framework.require('PETSc.options.arch', None) 45 self.petscdir = self.framework.require('PETSc.options.petscdir', None) 46 self.languages = self.framework.require('PETSc.options.languages', None) 47 self.debugging = self.framework.require('PETSc.options.debugging', None) 48 self.opengles = self.framework.require('config.packages.opengles', None) 49 self.make = self.framework.require('config.programs', None) 50 self.compilers = self.framework.require('config.compilers', None) 51 self.types = self.framework.require('config.types', None) 52 self.headers = self.framework.require('config.headers', None) 53 self.functions = self.framework.require('config.functions', None) 54 self.libraries = self.framework.require('config.libraries', None) 55 self.scalarType = self.framework.require('PETSc.options.scalarTypes', None) 56 self.memAlign = self.framework.require('PETSc.options.memAlign', None) 57 self.libraryOptions= self.framework.require('PETSc.options.libraryOptions', None) 58 self.compilerFlags = self.framework.require('config.compilerFlags', self) 59 return 60 61 def setupHelp(self, help): 62 import nargs 63 64 help = script.Script.setupHelp(self, help) 65 help.addArgument('RepManager', '-rootDir', nargs.ArgDir(None, os.environ['PETSC_DIR'], 'The root directory for this build', isTemporary = 1)) 66 help.addArgument('RepManager', '-dryRun', nargs.ArgBool(None, False, 'Only output what would be run', isTemporary = 1)) 67 help.addArgument('RepManager', '-skipXCode', nargs.ArgBool(None, False, 'Do not run XCode application/files have not been added/removed', isTemporary = 1)) 68 help.addArgument('RepManager', '-verbose', nargs.ArgInt(None, 0, 'The verbosity level', min = 0, isTemporary = 1)) 69 return help 70 71 def setup(self): 72 script.Script.setup(self) 73 self.framework = self.loadConfigure() 74 self.setupModules() 75 return 76 77 @property 78 def verbose(self): 79 '''The verbosity level''' 80 return self.argDB['verbose'] 81 82 @property 83 def skipXCode(self): 84 '''Skip XCode application''' 85 return self.argDB['skipXCode'] 86 87 @property 88 def dryRun(self): 89 '''Flag for only output of what would be run''' 90 return self.argDB['dryRun'] 91 92 def getPackageInfo(self): 93 packageIncludes = [] 94 packageLibs = [] 95 for p in self.framework.packages: 96 # Could put on compile line, self.addDefine('HAVE_'+i.PACKAGE, 1) 97 if hasattr(p, 'lib'): 98 if not isinstance(p.lib, list): 99 packageLibs.append(p.lib) 100 else: 101 packageLibs.extend(p.lib) 102 if hasattr(p, 'include'): 103 if not isinstance(p.include, list): 104 packageIncludes.append(p.include) 105 else: 106 packageIncludes.extend(p.include) 107 packageLibs = self.libraries.toStringNoDupes(packageLibs+self.libraries.math) 108 packageIncludes = self.headers.toStringNoDupes(packageIncludes) 109 return packageIncludes, packageLibs 110 111 def buildDir(self, dirname): 112 ''' This is run in a PETSc source directory''' 113 if self.verbose: print 'Entering '+dirname 114 os.chdir(dirname) 115 l = len(os.environ['PETSC_DIR']) 116 basedir = os.path.join(os.environ['PETSC_DIR'],os.environ['PETSC_ARCH'],'xcode-links') 117 #newdirname = os.path.join(basedir,dirname[l+1:]) 118 #os.mkdir(newdirname) 119 120 121 # Get list of source files in the directory 122 cnames = [] 123 onames = [] 124 fnames = [] 125 hnames = [] 126 for f in os.listdir(dirname): 127 ext = os.path.splitext(f)[1] 128 if ext == '.c': 129 cnames.append(f) 130 onames.append(f.replace('.c', '.o')) 131 if ext == '.h': 132 hnames.append(f) 133 if cnames: 134 if self.verbose: print 'Linking C files',cnames 135 for i in cnames: 136 j = i[l+1:] 137 if not os.path.islink(os.path.join(basedir,i)) and not i.startswith('.') and i.find(".BACKUP") == -1 and i.find(".LOCAL") == -1 and i.find(".BASE") == -1: 138 if i.endswith('openglops.c') and not os.path.islink(os.path.join(basedir,'openglops.m')): 139 os.symlink(os.path.join(dirname,i),os.path.join(basedir,'openglops.m')) 140 else: 141 os.symlink(os.path.join(dirname,i),os.path.join(basedir,i)) 142 # do not need to link these because xcode project points to original source code directory 143 #if hnames: 144 # if self.verbose: print 'Linking h files',hnames 145 # for i in hnames: 146 # if not os.path.islink(os.path.join(basedir,i)): 147 # os.symlink(os.path.join(dirname,i),os.path.join(basedir,i)) 148 return 149 150 def checkDir(self, dirname): 151 '''Checks whether we should recurse into this directory 152 - Excludes projects directory 153 - Excludes examples directory 154 - Excludes contrib directory 155 - Excludes tutorials directory 156 - Excludes benchmarks directory 157 - Checks makefile to see if compiler is allowed to visit this directory for this configuration''' 158# print self.functions.functions 159# print self.base.defines 160 base = os.path.basename(dirname) 161 162 if base == 'examples': return False 163 if base == 'projects': return False 164 if base.startswith('ftn-') or base.startswith('f90-'): return False 165 if base == 'contrib': return False 166 if base == 'tutorials': return False 167 if base == 'benchmarks': return False 168 if base == 'systems': return False 169# for some reason agrmes is in the repository but not used! 170 if base == 'agmres': return False 171 if base == 'test-dir': return False 172 if base.startswith('arch-'): return False 173 174 import re 175 reg = re.compile(' [ ]*') 176 fname = os.path.join(dirname, 'makefile') 177 if not os.path.isfile(fname): 178 if os.path.isfile(os.path.join(dirname, 'Makefile')): print 'ERROR: Change Makefile to makefile in',dirname 179 return False 180 fd = open(fname) 181 text = fd.readline() 182 while text: 183 if text.startswith('#requires'): 184 text = text[9:-1].strip() 185 text = reg.sub(' ',text) 186 rtype = text.split(' ')[0] 187 rvalue = text.split(' ')[1] 188 189 if rvalue == "'"+'PETSC_HAVE_FORTRAN'+"'" or rvalue == "'"+'PETSC_USING_F90'+"'" or rvalue == "'"+'PETSC_USING_F2003'+"'": 190 if not hasattr(self.compilers, 'FC'): 191 if self.verbose: print 'Rejecting',dirname,'because fortran is not being used' 192 return 0 193 elif rvalue == "'"+'PETSC_USE_LOG'+"'": 194 if not self.libraryOptions.useLog: 195 if self.verbose: print 'Rejecting',dirname,'because logging is turned off' 196 return 0 197 elif rvalue == "'"+'PETSC_USE_FORTRAN_KERNELS'+"'": 198 if not self.libraryOptions.useFortranKernels: 199 if self.verbose: print 'Rejecting',dirname,'because fortran kernels are turned off' 200 return 0 201 elif rtype == 'scalar' and not self.scalarType.scalartype == rvalue: 202 if self.verbose: print 'Rejecting',dirname,'because scalar type '+self.scalarType.scalartype+' is not '+rvalue 203 return 0 204 elif rtype == 'language': 205 if rvalue == 'CXXONLY' and self.languages.clanguage == 'C': 206 if self.verbose: print 'Rejecting',dirname,'because language is '+self.languages.clanguage+' is not C++' 207 return 0 208 elif rtype == 'precision' and not rvalue == self.scalarType.precision: 209 if self.verbose: print 'Rejecting',dirname,'because precision '+self.scalarType.precision+' is not '+rvalue 210 return 0 211 elif rtype == 'package': 212 found = 0 213 if self.mpi.usingMPIUni: 214 pname = 'PETSC_HAVE_MPIUNI' 215 pname = "'"+pname+"'" 216 if pname == rvalue: found = 1 217 for i in self.framework.packages: 218 pname = 'PETSC_HAVE_'+i.PACKAGE 219 pname = "'"+pname+"'" 220 if pname == rvalue: found = 1 221 if not found: 222 for i in self.base.defines: 223 pname = 'PETSC_'+i.upper() 224 pname = "'"+pname+"'" 225 if pname == rvalue: found = 1 226 for i in self.opengles.defines: 227 pname = 'PETSC_'+i.upper() 228 pname = "'"+pname+"'" 229 if pname == rvalue: found = 1 230 if not found: 231 if self.verbose: print 'Rejecting',dirname,'because package '+rvalue+' does not exist' 232 return 0 233 elif rtype == 'define': 234 found = 0 235 for i in self.base.defines: 236 pname = 'PETSC_'+i.upper() 237 pname = "'"+pname+"'" 238 if pname == rvalue: found = 1 239 if not found: 240 if self.verbose: print 'Rejecting',dirname,'because define '+rvalue+' does not exist' 241 return 0 242 elif rtype == 'function': 243 found = 0 244 for i in self.functions.functions: 245 pname = 'PETSC_HAVE_'+i.upper() 246 pname = "'"+pname+"'" 247# print pname 248# print rvalue 249 if pname == rvalue: found = 1 250 if not found: 251 if self.verbose: print 'Rejecting',dirname,'because function '+rvalue+' does not exist' 252 return 0 253 254 text = fd.readline() 255 fd.close() 256 return True 257 258 def buildAll(self, rootDir = None): 259 import shutil 260 self.setup() 261 if rootDir is None: 262 rootDir = self.argDB['rootDir'] 263 if not self.checkDir(rootDir): 264 print 'Nothing to be done' 265 if rootDir == os.environ['PETSC_DIR']: 266 basedir = os.path.join(self.petscdir.dir, self.arch.arch, 'xcode-links') 267 if os.path.isdir(basedir): 268 if self.verbose: print 'Removing '+basedir 269 shutil.rmtree(basedir) 270 os.mkdir(basedir) 271 for root, dirs, files in os.walk(rootDir): 272 self.buildDir(root) 273 for badDir in [d for d in dirs if not self.checkDir(os.path.join(root, d))]: 274 dirs.remove(badDir) 275 276 if not self.skipXCode: 277 278 print 'In Xcode mouse click on Other Sources then xcode-links and the delete key, then' 279 print 'control mouse click on "Other Sources" and select "Add files to PETSc ...", then' 280 print 'in the finder window locate ${PETSC_DIR}/arch-ios/xcode-links and select it. Now' 281 print 'exit Xcode' 282 283 try: 284 import subprocess 285 subprocess.call('cd '+os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc')+';open -W PETSc.xcodeproj', shell=True) 286 except RuntimeError, e: 287 raise RuntimeError('Error opening xcode project '+str(e)) 288 289 290 sdk = ' -sdk iphonesimulator8.0 ' 291 destination = 'iphonesimulator' 292 debug = 'Debug' 293 debugdir = 'Debug-'+destination 294 if not self.compilerFlags.debugging: 295 debug = 'Release' 296 debugdir = 'Release-'+destination 297 try: 298 output,err,ret = self.executeShellCommand('cd '+os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc')+';xcodebuild -configuration '+debug+sdk, timeout=3000, log = self.log) 299 except RuntimeError, e: 300 raise RuntimeError('Error making iPhone/iPad version of PETSc libraries: '+str(e)) 301 302 liblocation = os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc','build','Debug-iphonesimulator','PETSc.framework','PETSc') 303 if not os.path.exists(liblocation): 304 raise RuntimeError('Error library '+liblocation+' not created') 305 try: 306 output,err,ret = self.executeShellCommand('mv -f '+liblocation+' '+os.path.join(os.environ['PETSC_DIR'],os.environ['PETSC_ARCH'],'lib'), timeout=30, log = self.log) 307 except RuntimeError, e: 308 raise RuntimeError('Error copying iPhone/iPad version of PETSc libraries: '+str(e)) 309 310 return 311 312def noCheckCommand(command, status, output, error): 313 ''' Do no check result''' 314 return 315 noCheckCommand = staticmethod(noCheckCommand) 316 317if __name__ == '__main__': 318 PETScMaker().buildAll() 319