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