11b37a2a7SPierre Jolivet#!/usr/bin/env python3 2525d6f2eSBarry Smith# 3f66eea08SBarry Smith# Builds a iOS Framework of PETSc 4525d6f2eSBarry Smith# 5f66eea08SBarry Smith# export PETSC_ARCH=arch-ios-simulator 6a95d84e0SBarry Smith# 7e611a964SBarry Smith# ./systems/Apple/iOS/bin/arch-ios-simulator.py [use --with-debugging=0 to get iPhone/iPad version, otherwise creates simulator version] 8525d6f2eSBarry Smith# this sets up the appropriate configuration file 9525d6f2eSBarry Smith# 10525d6f2eSBarry Smith# ./systems/Apple/iOS/bin/iosbuilder.py 11525d6f2eSBarry Smith# this creates the PETSc iPhone/iPad library 12525d6f2eSBarry Smith# this will open Xcode and give you directions to follow 13525d6f2eSBarry Smith# 14a95d84e0SBarry Smith# open systems/Apple/iOS/examples/examples.xcodeproj 15525d6f2eSBarry Smith# Project -> Edit Project Setting -> Configuration (make sure it is Release or Debug depending on if you used --with-debugging=0) 16525d6f2eSBarry Smith# Build -> Build and Debug 17525d6f2eSBarry Smith# 185b6bfdb9SJed Brownfrom __future__ import print_function 19525d6f2eSBarry Smithimport os, sys 20525d6f2eSBarry Smith 21525d6f2eSBarry Smithsys.path.insert(0, os.path.join(os.environ['PETSC_DIR'], 'config')) 22525d6f2eSBarry Smithsys.path.insert(0, os.path.join(os.environ['PETSC_DIR'], 'config', 'BuildSystem')) 23525d6f2eSBarry Smith 24525d6f2eSBarry Smithimport script 25525d6f2eSBarry Smith 26525d6f2eSBarry Smithclass PETScMaker(script.Script): 27525d6f2eSBarry Smith def __init__(self): 28525d6f2eSBarry Smith import RDict 29525d6f2eSBarry Smith import os 30525d6f2eSBarry Smith 31525d6f2eSBarry Smith argDB = RDict.RDict(None, None, 0, 0, readonly = True) 32575a0592SBarry Smith argDB.saveFilename = os.path.join(os.environ['PETSC_DIR'], os.environ['PETSC_ARCH'], 'lib','petsc','conf', 'RDict.db') 33525d6f2eSBarry Smith argDB.load() 34525d6f2eSBarry Smith script.Script.__init__(self, argDB = argDB) 35525d6f2eSBarry Smith self.log = sys.stdout 36525d6f2eSBarry Smith return 37525d6f2eSBarry Smith 38525d6f2eSBarry Smith def setupModules(self): 39525d6f2eSBarry Smith self.mpi = self.framework.require('config.packages.MPI', None) 40525d6f2eSBarry Smith self.base = self.framework.require('config.base', None) 41525d6f2eSBarry Smith self.setCompilers = self.framework.require('config.setCompilers', None) 4244b85a23SBarry Smith self.arch = self.framework.require('PETSc.options.arch', None) 4344b85a23SBarry Smith self.petscdir = self.framework.require('PETSc.options.petscdir', None) 4444b85a23SBarry Smith self.languages = self.framework.require('PETSc.options.languages', None) 4544b85a23SBarry Smith self.debugging = self.framework.require('PETSc.options.debugging', None) 4644b85a23SBarry Smith self.opengles = self.framework.require('config.packages.opengles', None) 47525d6f2eSBarry Smith self.make = self.framework.require('config.programs', None) 48525d6f2eSBarry Smith self.compilers = self.framework.require('config.compilers', None) 49525d6f2eSBarry Smith self.types = self.framework.require('config.types', None) 50525d6f2eSBarry Smith self.headers = self.framework.require('config.headers', None) 51525d6f2eSBarry Smith self.functions = self.framework.require('config.functions', None) 52525d6f2eSBarry Smith self.libraries = self.framework.require('config.libraries', None) 5344b85a23SBarry Smith self.scalarType = self.framework.require('PETSc.options.scalarTypes', None) 5444b85a23SBarry Smith self.memAlign = self.framework.require('PETSc.options.memAlign', None) 5544b85a23SBarry Smith self.libraryOptions= self.framework.require('PETSc.options.libraryOptions', None) 56525d6f2eSBarry Smith self.compilerFlags = self.framework.require('config.compilerFlags', self) 57525d6f2eSBarry Smith return 58525d6f2eSBarry Smith 59525d6f2eSBarry Smith def setupHelp(self, help): 60525d6f2eSBarry Smith import nargs 61525d6f2eSBarry Smith 62525d6f2eSBarry Smith help = script.Script.setupHelp(self, help) 63525d6f2eSBarry Smith help.addArgument('RepManager', '-rootDir', nargs.ArgDir(None, os.environ['PETSC_DIR'], 'The root directory for this build', isTemporary = 1)) 64525d6f2eSBarry Smith help.addArgument('RepManager', '-dryRun', nargs.ArgBool(None, False, 'Only output what would be run', isTemporary = 1)) 6533be3048SBarry Smith help.addArgument('RepManager', '-skipXCode', nargs.ArgBool(None, False, 'Do not run XCode application/files have not been added/removed', isTemporary = 1)) 66525d6f2eSBarry Smith help.addArgument('RepManager', '-verbose', nargs.ArgInt(None, 0, 'The verbosity level', min = 0, isTemporary = 1)) 67525d6f2eSBarry Smith return help 68525d6f2eSBarry Smith 69525d6f2eSBarry Smith def setup(self): 70525d6f2eSBarry Smith script.Script.setup(self) 71525d6f2eSBarry Smith self.framework = self.loadConfigure() 72525d6f2eSBarry Smith self.setupModules() 73525d6f2eSBarry Smith return 74525d6f2eSBarry Smith 75525d6f2eSBarry Smith @property 76525d6f2eSBarry Smith def verbose(self): 77525d6f2eSBarry Smith '''The verbosity level''' 78525d6f2eSBarry Smith return self.argDB['verbose'] 79525d6f2eSBarry Smith 80525d6f2eSBarry Smith @property 8133be3048SBarry Smith def skipXCode(self): 8233be3048SBarry Smith '''Skip XCode application''' 8333be3048SBarry Smith return self.argDB['skipXCode'] 8433be3048SBarry Smith 8533be3048SBarry Smith @property 86525d6f2eSBarry Smith def dryRun(self): 87525d6f2eSBarry Smith '''Flag for only output of what would be run''' 88525d6f2eSBarry Smith return self.argDB['dryRun'] 89525d6f2eSBarry Smith 90525d6f2eSBarry Smith def getPackageInfo(self): 91525d6f2eSBarry Smith packageIncludes = [] 92525d6f2eSBarry Smith packageLibs = [] 93525d6f2eSBarry Smith for p in self.framework.packages: 94525d6f2eSBarry Smith # Could put on compile line, self.addDefine('HAVE_'+i.PACKAGE, 1) 95525d6f2eSBarry Smith if hasattr(p, 'lib'): 96525d6f2eSBarry Smith if not isinstance(p.lib, list): 97525d6f2eSBarry Smith packageLibs.append(p.lib) 98525d6f2eSBarry Smith else: 99525d6f2eSBarry Smith packageLibs.extend(p.lib) 100525d6f2eSBarry Smith if hasattr(p, 'include'): 101525d6f2eSBarry Smith if not isinstance(p.include, list): 102525d6f2eSBarry Smith packageIncludes.append(p.include) 103525d6f2eSBarry Smith else: 104525d6f2eSBarry Smith packageIncludes.extend(p.include) 105525d6f2eSBarry Smith packageLibs = self.libraries.toStringNoDupes(packageLibs+self.libraries.math) 106525d6f2eSBarry Smith packageIncludes = self.headers.toStringNoDupes(packageIncludes) 107525d6f2eSBarry Smith return packageIncludes, packageLibs 108525d6f2eSBarry Smith 109525d6f2eSBarry Smith def buildDir(self, dirname): 110525d6f2eSBarry Smith ''' This is run in a PETSc source directory''' 1115b6bfdb9SJed Brown if self.verbose: print('Entering '+dirname) 112525d6f2eSBarry Smith os.chdir(dirname) 113525d6f2eSBarry Smith l = len(os.environ['PETSC_DIR']) 114525d6f2eSBarry Smith basedir = os.path.join(os.environ['PETSC_DIR'],os.environ['PETSC_ARCH'],'xcode-links') 115525d6f2eSBarry Smith #newdirname = os.path.join(basedir,dirname[l+1:]) 116525d6f2eSBarry Smith #os.mkdir(newdirname) 117525d6f2eSBarry Smith 118525d6f2eSBarry Smith 119525d6f2eSBarry Smith # Get list of source files in the directory 120525d6f2eSBarry Smith cnames = [] 121525d6f2eSBarry Smith onames = [] 122525d6f2eSBarry Smith fnames = [] 123525d6f2eSBarry Smith hnames = [] 124525d6f2eSBarry Smith for f in os.listdir(dirname): 125525d6f2eSBarry Smith ext = os.path.splitext(f)[1] 126525d6f2eSBarry Smith if ext == '.c': 127525d6f2eSBarry Smith cnames.append(f) 128525d6f2eSBarry Smith onames.append(f.replace('.c', '.o')) 129525d6f2eSBarry Smith if ext == '.h': 130525d6f2eSBarry Smith hnames.append(f) 131525d6f2eSBarry Smith if cnames: 1325b6bfdb9SJed Brown if self.verbose: print('Linking C files',cnames) 133525d6f2eSBarry Smith for i in cnames: 134525d6f2eSBarry Smith j = i[l+1:] 135a95d84e0SBarry Smith 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: 13633be3048SBarry Smith if i.endswith('openglops.c') and not os.path.islink(os.path.join(basedir,'openglops.m')): 137f72c6c23SBarry Smith os.symlink(os.path.join(dirname,i),os.path.join(basedir,'openglops.m')) 138f72c6c23SBarry Smith else: 139525d6f2eSBarry Smith os.symlink(os.path.join(dirname,i),os.path.join(basedir,i)) 140525d6f2eSBarry Smith # do not need to link these because xcode project points to original source code directory 141525d6f2eSBarry Smith #if hnames: 142525d6f2eSBarry Smith # if self.verbose: print 'Linking h files',hnames 143525d6f2eSBarry Smith # for i in hnames: 144525d6f2eSBarry Smith # if not os.path.islink(os.path.join(basedir,i)): 145525d6f2eSBarry Smith # os.symlink(os.path.join(dirname,i),os.path.join(basedir,i)) 146525d6f2eSBarry Smith return 147525d6f2eSBarry Smith 148525d6f2eSBarry Smith def checkDir(self, dirname): 149525d6f2eSBarry Smith '''Checks whether we should recurse into this directory 150525d6f2eSBarry Smith - Excludes projects directory 151525d6f2eSBarry Smith - Excludes examples directory 152525d6f2eSBarry Smith - Excludes contrib directory 153525d6f2eSBarry Smith - Excludes tutorials directory 154525d6f2eSBarry Smith - Excludes benchmarks directory 155525d6f2eSBarry Smith - Checks makefile to see if compiler is allowed to visit this directory for this configuration''' 156525d6f2eSBarry Smith# print self.functions.functions 157525d6f2eSBarry Smith# print self.base.defines 158525d6f2eSBarry Smith base = os.path.basename(dirname) 159525d6f2eSBarry Smith 160525d6f2eSBarry Smith if base == 'examples': return False 161525d6f2eSBarry Smith if base == 'projects': return False 1626dd63270SBarry Smith if base.startswith('ftn-'): return False 163525d6f2eSBarry Smith if base == 'contrib': return False 164525d6f2eSBarry Smith if base == 'tutorials': return False 165525d6f2eSBarry Smith if base == 'benchmarks': return False 166f72c6c23SBarry Smith if base == 'systems': return False 167a95d84e0SBarry Smith# for some reason agrmes is in the repository but not used! 168a95d84e0SBarry Smith if base == 'agmres': return False 169a95d84e0SBarry Smith if base == 'test-dir': return False 170525d6f2eSBarry Smith if base.startswith('arch-'): return False 171525d6f2eSBarry Smith 172525d6f2eSBarry Smith import re 173525d6f2eSBarry Smith reg = re.compile(' [ ]*') 174525d6f2eSBarry Smith fname = os.path.join(dirname, 'makefile') 175525d6f2eSBarry Smith if not os.path.isfile(fname): 1765b6bfdb9SJed Brown if os.path.isfile(os.path.join(dirname, 'Makefile')): print('ERROR: Change Makefile to makefile in',dirname) 177525d6f2eSBarry Smith return False 178525d6f2eSBarry Smith fd = open(fname) 179525d6f2eSBarry Smith text = fd.readline() 180525d6f2eSBarry Smith while text: 181525d6f2eSBarry Smith if text.startswith('#requires'): 182525d6f2eSBarry Smith text = text[9:-1].strip() 183525d6f2eSBarry Smith text = reg.sub(' ',text) 184525d6f2eSBarry Smith rtype = text.split(' ')[0] 185525d6f2eSBarry Smith rvalue = text.split(' ')[1] 186525d6f2eSBarry Smith 187*ccfb0f9fSMartin Diehl if rvalue == "'"+'PETSC_USE_FORTRAN'+"'": 188525d6f2eSBarry Smith if not hasattr(self.compilers, 'FC'): 1895b6bfdb9SJed Brown if self.verbose: print('Rejecting',dirname,'because fortran is not being used') 190525d6f2eSBarry Smith return 0 191525d6f2eSBarry Smith elif rvalue == "'"+'PETSC_USE_LOG'+"'": 192525d6f2eSBarry Smith if not self.libraryOptions.useLog: 1935b6bfdb9SJed Brown if self.verbose: print('Rejecting',dirname,'because logging is turned off') 194525d6f2eSBarry Smith return 0 195525d6f2eSBarry Smith elif rvalue == "'"+'PETSC_USE_FORTRAN_KERNELS'+"'": 196525d6f2eSBarry Smith if not self.libraryOptions.useFortranKernels: 1975b6bfdb9SJed Brown if self.verbose: print('Rejecting',dirname,'because fortran kernels are turned off') 198525d6f2eSBarry Smith return 0 199525d6f2eSBarry Smith elif rtype == 'scalar' and not self.scalarType.scalartype == rvalue: 2005b6bfdb9SJed Brown if self.verbose: print('Rejecting',dirname,'because scalar type '+self.scalarType.scalartype+' is not '+rvalue) 201525d6f2eSBarry Smith return 0 202525d6f2eSBarry Smith elif rtype == 'language': 203525d6f2eSBarry Smith if rvalue == 'CXXONLY' and self.languages.clanguage == 'C': 2045b6bfdb9SJed Brown if self.verbose: print('Rejecting',dirname,'because language is '+self.languages.clanguage+' is not C++') 205525d6f2eSBarry Smith return 0 206525d6f2eSBarry Smith elif rtype == 'precision' and not rvalue == self.scalarType.precision: 2075b6bfdb9SJed Brown if self.verbose: print('Rejecting',dirname,'because precision '+self.scalarType.precision+' is not '+rvalue) 208525d6f2eSBarry Smith return 0 209525d6f2eSBarry Smith elif rtype == 'package': 210525d6f2eSBarry Smith found = 0 211525d6f2eSBarry Smith if self.mpi.usingMPIUni: 212525d6f2eSBarry Smith pname = 'PETSC_HAVE_MPIUNI' 213525d6f2eSBarry Smith pname = "'"+pname+"'" 214525d6f2eSBarry Smith if pname == rvalue: found = 1 215525d6f2eSBarry Smith for i in self.framework.packages: 216525d6f2eSBarry Smith pname = 'PETSC_HAVE_'+i.PACKAGE 217525d6f2eSBarry Smith pname = "'"+pname+"'" 218525d6f2eSBarry Smith if pname == rvalue: found = 1 219525d6f2eSBarry Smith if not found: 220a95d84e0SBarry Smith for i in self.base.defines: 221a95d84e0SBarry Smith pname = 'PETSC_'+i.upper() 222a95d84e0SBarry Smith pname = "'"+pname+"'" 223a95d84e0SBarry Smith if pname == rvalue: found = 1 224bcd1c4acSBarry Smith for i in self.opengles.defines: 225bcd1c4acSBarry Smith pname = 'PETSC_'+i.upper() 226bcd1c4acSBarry Smith pname = "'"+pname+"'" 227bcd1c4acSBarry Smith if pname == rvalue: found = 1 228a95d84e0SBarry Smith if not found: 2295b6bfdb9SJed Brown if self.verbose: print('Rejecting',dirname,'because package '+rvalue+' does not exist') 230525d6f2eSBarry Smith return 0 231525d6f2eSBarry Smith elif rtype == 'define': 232525d6f2eSBarry Smith found = 0 233525d6f2eSBarry Smith for i in self.base.defines: 234525d6f2eSBarry Smith pname = 'PETSC_'+i.upper() 235525d6f2eSBarry Smith pname = "'"+pname+"'" 236525d6f2eSBarry Smith if pname == rvalue: found = 1 237525d6f2eSBarry Smith if not found: 2385b6bfdb9SJed Brown if self.verbose: print('Rejecting',dirname,'because define '+rvalue+' does not exist') 239525d6f2eSBarry Smith return 0 240525d6f2eSBarry Smith elif rtype == 'function': 241525d6f2eSBarry Smith found = 0 242525d6f2eSBarry Smith for i in self.functions.functions: 243525d6f2eSBarry Smith pname = 'PETSC_HAVE_'+i.upper() 244525d6f2eSBarry Smith pname = "'"+pname+"'" 245525d6f2eSBarry Smith# print pname 246525d6f2eSBarry Smith# print rvalue 247525d6f2eSBarry Smith if pname == rvalue: found = 1 248525d6f2eSBarry Smith if not found: 2495b6bfdb9SJed Brown if self.verbose: print('Rejecting',dirname,'because function '+rvalue+' does not exist') 250525d6f2eSBarry Smith return 0 251525d6f2eSBarry Smith 252525d6f2eSBarry Smith text = fd.readline() 253525d6f2eSBarry Smith fd.close() 254525d6f2eSBarry Smith return True 255525d6f2eSBarry Smith 256525d6f2eSBarry Smith def buildAll(self, rootDir = None): 257525d6f2eSBarry Smith import shutil 258525d6f2eSBarry Smith self.setup() 259525d6f2eSBarry Smith if rootDir is None: 260525d6f2eSBarry Smith rootDir = self.argDB['rootDir'] 261525d6f2eSBarry Smith if not self.checkDir(rootDir): 2625b6bfdb9SJed Brown print('Nothing to be done') 263525d6f2eSBarry Smith if rootDir == os.environ['PETSC_DIR']: 264525d6f2eSBarry Smith basedir = os.path.join(self.petscdir.dir, self.arch.arch, 'xcode-links') 265525d6f2eSBarry Smith if os.path.isdir(basedir): 2665b6bfdb9SJed Brown if self.verbose: print('Removing '+basedir) 267525d6f2eSBarry Smith shutil.rmtree(basedir) 268525d6f2eSBarry Smith os.mkdir(basedir) 269525d6f2eSBarry Smith for root, dirs, files in os.walk(rootDir): 270525d6f2eSBarry Smith self.buildDir(root) 271525d6f2eSBarry Smith for badDir in [d for d in dirs if not self.checkDir(os.path.join(root, d))]: 272525d6f2eSBarry Smith dirs.remove(badDir) 273525d6f2eSBarry Smith 27433be3048SBarry Smith if not self.skipXCode: 27533be3048SBarry Smith 2765b6bfdb9SJed Brown print('In Xcode mouse click on Other Sources then xcode-links and the delete key, then') 2775b6bfdb9SJed Brown print('control mouse click on "Other Sources" and select "Add files to PETSc ...", then') 2785b6bfdb9SJed Brown print('in the finder window locate ${PETSC_DIR}/arch-ios/xcode-links and select it. Now') 2795b6bfdb9SJed Brown print('exit Xcode') 280525d6f2eSBarry Smith 281525d6f2eSBarry Smith try: 282525d6f2eSBarry Smith import subprocess 283525d6f2eSBarry Smith subprocess.call('cd '+os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc')+';open -W PETSc.xcodeproj', shell=True) 2845b6bfdb9SJed Brown except RuntimeError as e: 285525d6f2eSBarry Smith raise RuntimeError('Error opening xcode project '+str(e)) 286525d6f2eSBarry Smith 287525d6f2eSBarry Smith 288f66eea08SBarry Smith sdk = ' -sdk iphonesimulator ' 289525d6f2eSBarry Smith destination = 'iphonesimulator' 290525d6f2eSBarry Smith debug = 'Debug' 291525d6f2eSBarry Smith debugdir = 'Debug-'+destination 292525d6f2eSBarry Smith if not self.compilerFlags.debugging: 293525d6f2eSBarry Smith debug = 'Release' 294525d6f2eSBarry Smith debugdir = 'Release-'+destination 295525d6f2eSBarry Smith try: 2968506f42dSBarry Smith 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) 2975b6bfdb9SJed Brown except RuntimeError as e: 298525d6f2eSBarry Smith raise RuntimeError('Error making iPhone/iPad version of PETSc libraries: '+str(e)) 299525d6f2eSBarry Smith 300b59f628eSBarry Smith liblocation = os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc','build','Debug-iphonesimulator','PETSc.framework','PETSc') 301525d6f2eSBarry Smith if not os.path.exists(liblocation): 302525d6f2eSBarry Smith raise RuntimeError('Error library '+liblocation+' not created') 303525d6f2eSBarry Smith try: 304575a0592SBarry Smith 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) 3055b6bfdb9SJed Brown except RuntimeError as e: 306525d6f2eSBarry Smith raise RuntimeError('Error copying iPhone/iPad version of PETSc libraries: '+str(e)) 307525d6f2eSBarry Smith 308525d6f2eSBarry Smith return 309525d6f2eSBarry Smith 310525d6f2eSBarry Smithdef noCheckCommand(command, status, output, error): 311525d6f2eSBarry Smith ''' Do no check result''' 312525d6f2eSBarry Smith return 313525d6f2eSBarry Smith noCheckCommand = staticmethod(noCheckCommand) 314525d6f2eSBarry Smith 315525d6f2eSBarry Smithif __name__ == '__main__': 316525d6f2eSBarry Smith PETScMaker().buildAll() 317