xref: /petsc/systems/Apple/iOS/bin/iosbuilder.py (revision f66eea085cceefc5191b4b3d61f096e7c3d8e689)
1525d6f2eSBarry Smith#!/usr/bin/env python
2525d6f2eSBarry Smith#
3*f66eea08SBarry Smith#   Builds a iOS Framework of PETSc
4525d6f2eSBarry Smith#
5*f66eea08SBarry Smith#   export PETSC_ARCH=arch-ios-simulator
6a95d84e0SBarry Smith#
7525d6f2eSBarry Smith#   ./systems/Apple/iOS/bin/arch-ios.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#
18525d6f2eSBarry Smithimport os, sys
19525d6f2eSBarry Smith
20525d6f2eSBarry Smithsys.path.insert(0, os.path.join(os.environ['PETSC_DIR'], 'config'))
21525d6f2eSBarry Smithsys.path.insert(0, os.path.join(os.environ['PETSC_DIR'], 'config', 'BuildSystem'))
22525d6f2eSBarry Smith
23525d6f2eSBarry Smithimport script
24525d6f2eSBarry Smith
25525d6f2eSBarry Smithclass PETScMaker(script.Script):
26525d6f2eSBarry Smith def __init__(self):
27525d6f2eSBarry Smith   import RDict
28525d6f2eSBarry Smith   import os
29525d6f2eSBarry Smith
30525d6f2eSBarry Smith   argDB = RDict.RDict(None, None, 0, 0, readonly = True)
31525d6f2eSBarry Smith   argDB.saveFilename = os.path.join(os.environ['PETSC_DIR'], os.environ['PETSC_ARCH'], 'conf', 'RDict.db')
32525d6f2eSBarry Smith   argDB.load()
33525d6f2eSBarry Smith   script.Script.__init__(self, argDB = argDB)
34525d6f2eSBarry Smith   self.log = sys.stdout
35525d6f2eSBarry Smith   return
36525d6f2eSBarry Smith
37525d6f2eSBarry Smith def setupModules(self):
38525d6f2eSBarry Smith   self.mpi           = self.framework.require('config.packages.MPI',         None)
39525d6f2eSBarry Smith   self.base          = self.framework.require('config.base',                 None)
40525d6f2eSBarry Smith   self.setCompilers  = self.framework.require('config.setCompilers',         None)
4144b85a23SBarry Smith   self.arch          = self.framework.require('PETSc.options.arch',        None)
4244b85a23SBarry Smith   self.petscdir      = self.framework.require('PETSc.options.petscdir',    None)
4344b85a23SBarry Smith   self.languages     = self.framework.require('PETSc.options.languages',   None)
4444b85a23SBarry Smith   self.debugging     = self.framework.require('PETSc.options.debugging',   None)
4544b85a23SBarry Smith   self.opengles      = self.framework.require('config.packages.opengles',     None)
46525d6f2eSBarry Smith   self.make          = self.framework.require('config.programs',             None)
47525d6f2eSBarry Smith   self.compilers     = self.framework.require('config.compilers',            None)
48525d6f2eSBarry Smith   self.types         = self.framework.require('config.types',                None)
49525d6f2eSBarry Smith   self.headers       = self.framework.require('config.headers',              None)
50525d6f2eSBarry Smith   self.functions     = self.framework.require('config.functions',            None)
51525d6f2eSBarry Smith   self.libraries     = self.framework.require('config.libraries',            None)
5244b85a23SBarry Smith   self.scalarType    = self.framework.require('PETSc.options.scalarTypes', None)
5344b85a23SBarry Smith   self.memAlign      = self.framework.require('PETSc.options.memAlign',    None)
5444b85a23SBarry Smith   self.libraryOptions= self.framework.require('PETSc.options.libraryOptions', None)
55525d6f2eSBarry Smith   self.compilerFlags = self.framework.require('config.compilerFlags', self)
56525d6f2eSBarry Smith   return
57525d6f2eSBarry Smith
58525d6f2eSBarry Smith def setupHelp(self, help):
59525d6f2eSBarry Smith   import nargs
60525d6f2eSBarry Smith
61525d6f2eSBarry Smith   help = script.Script.setupHelp(self, help)
62525d6f2eSBarry Smith   help.addArgument('RepManager', '-rootDir', nargs.ArgDir(None, os.environ['PETSC_DIR'], 'The root directory for this build', isTemporary = 1))
63525d6f2eSBarry Smith   help.addArgument('RepManager', '-dryRun',  nargs.ArgBool(None, False, 'Only output what would be run', isTemporary = 1))
6433be3048SBarry Smith   help.addArgument('RepManager', '-skipXCode',  nargs.ArgBool(None, False, 'Do not run XCode application/files have not been added/removed', isTemporary = 1))
65525d6f2eSBarry Smith   help.addArgument('RepManager', '-verbose', nargs.ArgInt(None, 0, 'The verbosity level', min = 0, isTemporary = 1))
66525d6f2eSBarry Smith   return help
67525d6f2eSBarry Smith
68525d6f2eSBarry Smith def setup(self):
69525d6f2eSBarry Smith   script.Script.setup(self)
70525d6f2eSBarry Smith   self.framework = self.loadConfigure()
71525d6f2eSBarry Smith   self.setupModules()
72525d6f2eSBarry Smith   return
73525d6f2eSBarry Smith
74525d6f2eSBarry Smith @property
75525d6f2eSBarry Smith def verbose(self):
76525d6f2eSBarry Smith   '''The verbosity level'''
77525d6f2eSBarry Smith   return self.argDB['verbose']
78525d6f2eSBarry Smith
79525d6f2eSBarry Smith @property
8033be3048SBarry Smith def skipXCode(self):
8133be3048SBarry Smith   '''Skip XCode application'''
8233be3048SBarry Smith   return self.argDB['skipXCode']
8333be3048SBarry Smith
8433be3048SBarry Smith @property
85525d6f2eSBarry Smith def dryRun(self):
86525d6f2eSBarry Smith   '''Flag for only output of what would be run'''
87525d6f2eSBarry Smith   return self.argDB['dryRun']
88525d6f2eSBarry Smith
89525d6f2eSBarry Smith def getPackageInfo(self):
90525d6f2eSBarry Smith   packageIncludes = []
91525d6f2eSBarry Smith   packageLibs     = []
92525d6f2eSBarry Smith   for p in self.framework.packages:
93525d6f2eSBarry Smith     # Could put on compile line, self.addDefine('HAVE_'+i.PACKAGE, 1)
94525d6f2eSBarry Smith     if hasattr(p, 'lib'):
95525d6f2eSBarry Smith       if not isinstance(p.lib, list):
96525d6f2eSBarry Smith         packageLibs.append(p.lib)
97525d6f2eSBarry Smith       else:
98525d6f2eSBarry Smith         packageLibs.extend(p.lib)
99525d6f2eSBarry Smith     if hasattr(p, 'include'):
100525d6f2eSBarry Smith       if not isinstance(p.include, list):
101525d6f2eSBarry Smith         packageIncludes.append(p.include)
102525d6f2eSBarry Smith       else:
103525d6f2eSBarry Smith         packageIncludes.extend(p.include)
104525d6f2eSBarry Smith   packageLibs     = self.libraries.toStringNoDupes(packageLibs+self.libraries.math)
105525d6f2eSBarry Smith   packageIncludes = self.headers.toStringNoDupes(packageIncludes)
106525d6f2eSBarry Smith   return packageIncludes, packageLibs
107525d6f2eSBarry Smith
108525d6f2eSBarry Smith def buildDir(self, dirname):
109525d6f2eSBarry Smith   ''' This is run in a PETSc source directory'''
110525d6f2eSBarry Smith   if self.verbose: print 'Entering '+dirname
111525d6f2eSBarry Smith   os.chdir(dirname)
112525d6f2eSBarry Smith   l = len(os.environ['PETSC_DIR'])
113525d6f2eSBarry Smith   basedir = os.path.join(os.environ['PETSC_DIR'],os.environ['PETSC_ARCH'],'xcode-links')
114525d6f2eSBarry Smith   #newdirname = os.path.join(basedir,dirname[l+1:])
115525d6f2eSBarry Smith   #os.mkdir(newdirname)
116525d6f2eSBarry Smith
117525d6f2eSBarry Smith
118525d6f2eSBarry Smith   # Get list of source files in the directory
119525d6f2eSBarry Smith   cnames = []
120525d6f2eSBarry Smith   onames = []
121525d6f2eSBarry Smith   fnames = []
122525d6f2eSBarry Smith   hnames = []
123525d6f2eSBarry Smith   for f in os.listdir(dirname):
124525d6f2eSBarry Smith     ext = os.path.splitext(f)[1]
125525d6f2eSBarry Smith     if ext == '.c':
126525d6f2eSBarry Smith       cnames.append(f)
127525d6f2eSBarry Smith       onames.append(f.replace('.c', '.o'))
128525d6f2eSBarry Smith     if ext == '.h':
129525d6f2eSBarry Smith       hnames.append(f)
130525d6f2eSBarry Smith   if cnames:
131525d6f2eSBarry Smith     if self.verbose: print 'Linking C files',cnames
132525d6f2eSBarry Smith     for i in cnames:
133525d6f2eSBarry Smith       j = i[l+1:]
134a95d84e0SBarry 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:
13533be3048SBarry Smith         if i.endswith('openglops.c') and not os.path.islink(os.path.join(basedir,'openglops.m')):
136f72c6c23SBarry Smith           os.symlink(os.path.join(dirname,i),os.path.join(basedir,'openglops.m'))
137f72c6c23SBarry Smith         else:
138525d6f2eSBarry Smith           os.symlink(os.path.join(dirname,i),os.path.join(basedir,i))
139525d6f2eSBarry Smith   # do not need to link these because xcode project points to original source code directory
140525d6f2eSBarry Smith   #if hnames:
141525d6f2eSBarry Smith   #  if self.verbose: print 'Linking h files',hnames
142525d6f2eSBarry Smith   #  for i in hnames:
143525d6f2eSBarry Smith   #    if not os.path.islink(os.path.join(basedir,i)):
144525d6f2eSBarry Smith   #      os.symlink(os.path.join(dirname,i),os.path.join(basedir,i))
145525d6f2eSBarry Smith   return
146525d6f2eSBarry Smith
147525d6f2eSBarry Smith def checkDir(self, dirname):
148525d6f2eSBarry Smith   '''Checks whether we should recurse into this directory
149525d6f2eSBarry Smith   - Excludes projects directory
150525d6f2eSBarry Smith   - Excludes examples directory
151525d6f2eSBarry Smith   - Excludes contrib directory
152525d6f2eSBarry Smith   - Excludes tutorials directory
153525d6f2eSBarry Smith   - Excludes benchmarks directory
154525d6f2eSBarry Smith   - Checks makefile to see if compiler is allowed to visit this directory for this configuration'''
155525d6f2eSBarry Smith#   print self.functions.functions
156525d6f2eSBarry Smith#   print self.base.defines
157525d6f2eSBarry Smith   base = os.path.basename(dirname)
158525d6f2eSBarry Smith
159525d6f2eSBarry Smith   if base == 'examples': return False
160525d6f2eSBarry Smith   if base == 'projects': return False
161525d6f2eSBarry Smith   if base.startswith('ftn-') or base.startswith('f90-'): return False
162525d6f2eSBarry Smith   if base == 'contrib':  return False
163525d6f2eSBarry Smith   if base == 'tutorials':  return False
164525d6f2eSBarry Smith   if base == 'benchmarks':  return False
165f72c6c23SBarry Smith   if base == 'systems':  return False
166a95d84e0SBarry Smith# for some reason agrmes is in the repository but not used!
167a95d84e0SBarry Smith   if base == 'agmres':  return False
168a95d84e0SBarry Smith   if base == 'test-dir':  return False
169525d6f2eSBarry Smith   if base.startswith('arch-'):  return False
170525d6f2eSBarry Smith
171525d6f2eSBarry Smith   import re
172525d6f2eSBarry Smith   reg   = re.compile(' [ ]*')
173525d6f2eSBarry Smith   fname = os.path.join(dirname, 'makefile')
174525d6f2eSBarry Smith   if not os.path.isfile(fname):
175525d6f2eSBarry Smith     if os.path.isfile(os.path.join(dirname, 'Makefile')): print 'ERROR: Change Makefile to makefile in',dirname
176525d6f2eSBarry Smith     return False
177525d6f2eSBarry Smith   fd = open(fname)
178525d6f2eSBarry Smith   text = fd.readline()
179525d6f2eSBarry Smith   while text:
180525d6f2eSBarry Smith     if text.startswith('#requires'):
181525d6f2eSBarry Smith       text = text[9:-1].strip()
182525d6f2eSBarry Smith       text = reg.sub(' ',text)
183525d6f2eSBarry Smith       rtype = text.split(' ')[0]
184525d6f2eSBarry Smith       rvalue = text.split(' ')[1]
185525d6f2eSBarry Smith
186525d6f2eSBarry Smith       if rvalue == "'"+'PETSC_HAVE_FORTRAN'+"'" or rvalue == "'"+'PETSC_USING_F90'+"'" or rvalue == "'"+'PETSC_USING_F2003'+"'":
187525d6f2eSBarry Smith         if not hasattr(self.compilers, 'FC'):
188525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because fortran is not being used'
189525d6f2eSBarry Smith           return 0
190525d6f2eSBarry Smith       elif rvalue == "'"+'PETSC_USE_LOG'+"'":
191525d6f2eSBarry Smith         if not self.libraryOptions.useLog:
192525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because logging is turned off'
193525d6f2eSBarry Smith           return 0
194525d6f2eSBarry Smith       elif rvalue == "'"+'PETSC_USE_FORTRAN_KERNELS'+"'":
195525d6f2eSBarry Smith         if not self.libraryOptions.useFortranKernels:
196525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because fortran kernels are turned off'
197525d6f2eSBarry Smith           return 0
198525d6f2eSBarry Smith       elif rtype == 'scalar' and not self.scalarType.scalartype == rvalue:
199525d6f2eSBarry Smith         if self.verbose: print 'Rejecting',dirname,'because scalar type '+self.scalarType.scalartype+' is not '+rvalue
200525d6f2eSBarry Smith         return 0
201525d6f2eSBarry Smith       elif rtype == 'language':
202525d6f2eSBarry Smith         if rvalue == 'CXXONLY' and self.languages.clanguage == 'C':
203525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because language is '+self.languages.clanguage+' is not C++'
204525d6f2eSBarry Smith           return 0
205525d6f2eSBarry Smith       elif rtype == 'precision' and not rvalue == self.scalarType.precision:
206525d6f2eSBarry Smith         if self.verbose: print 'Rejecting',dirname,'because precision '+self.scalarType.precision+' is not '+rvalue
207525d6f2eSBarry Smith         return 0
208525d6f2eSBarry Smith       elif rtype == 'package':
209525d6f2eSBarry Smith         found = 0
210525d6f2eSBarry Smith         if self.mpi.usingMPIUni:
211525d6f2eSBarry Smith           pname = 'PETSC_HAVE_MPIUNI'
212525d6f2eSBarry Smith           pname = "'"+pname+"'"
213525d6f2eSBarry Smith           if pname == rvalue: found = 1
214525d6f2eSBarry Smith         for i in self.framework.packages:
215525d6f2eSBarry Smith           pname = 'PETSC_HAVE_'+i.PACKAGE
216525d6f2eSBarry Smith           pname = "'"+pname+"'"
217525d6f2eSBarry Smith           if pname == rvalue: found = 1
218525d6f2eSBarry Smith         if not found:
219a95d84e0SBarry Smith           for i in self.base.defines:
220a95d84e0SBarry Smith             pname = 'PETSC_'+i.upper()
221a95d84e0SBarry Smith             pname = "'"+pname+"'"
222a95d84e0SBarry Smith             if pname == rvalue: found = 1
223bcd1c4acSBarry Smith           for i in self.opengles.defines:
224bcd1c4acSBarry Smith             pname = 'PETSC_'+i.upper()
225bcd1c4acSBarry Smith             pname = "'"+pname+"'"
226bcd1c4acSBarry Smith             if pname == rvalue: found = 1
227a95d84e0SBarry Smith           if not found:
228525d6f2eSBarry Smith             if self.verbose: print 'Rejecting',dirname,'because package '+rvalue+' does not exist'
229525d6f2eSBarry Smith             return 0
230525d6f2eSBarry Smith       elif rtype == 'define':
231525d6f2eSBarry Smith         found = 0
232525d6f2eSBarry Smith         for i in self.base.defines:
233525d6f2eSBarry Smith           pname = 'PETSC_'+i.upper()
234525d6f2eSBarry Smith           pname = "'"+pname+"'"
235525d6f2eSBarry Smith           if pname == rvalue: found = 1
236525d6f2eSBarry Smith         if not found:
237525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because define '+rvalue+' does not exist'
238525d6f2eSBarry Smith           return 0
239525d6f2eSBarry Smith       elif rtype == 'function':
240525d6f2eSBarry Smith         found = 0
241525d6f2eSBarry Smith         for i in self.functions.functions:
242525d6f2eSBarry Smith           pname = 'PETSC_HAVE_'+i.upper()
243525d6f2eSBarry Smith           pname = "'"+pname+"'"
244525d6f2eSBarry Smith#           print pname
245525d6f2eSBarry Smith#           print rvalue
246525d6f2eSBarry Smith           if pname == rvalue: found = 1
247525d6f2eSBarry Smith         if not found:
248525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because function '+rvalue+' does not exist'
249525d6f2eSBarry Smith           return 0
250525d6f2eSBarry Smith
251525d6f2eSBarry Smith     text = fd.readline()
252525d6f2eSBarry Smith   fd.close()
253525d6f2eSBarry Smith   return True
254525d6f2eSBarry Smith
255525d6f2eSBarry Smith def buildAll(self, rootDir = None):
256525d6f2eSBarry Smith   import shutil
257525d6f2eSBarry Smith   self.setup()
258525d6f2eSBarry Smith   if rootDir is None:
259525d6f2eSBarry Smith     rootDir = self.argDB['rootDir']
260525d6f2eSBarry Smith   if not self.checkDir(rootDir):
261525d6f2eSBarry Smith     print 'Nothing to be done'
262525d6f2eSBarry Smith   if rootDir == os.environ['PETSC_DIR']:
263525d6f2eSBarry Smith     basedir = os.path.join(self.petscdir.dir, self.arch.arch, 'xcode-links')
264525d6f2eSBarry Smith     if os.path.isdir(basedir):
265525d6f2eSBarry Smith       if self.verbose: print 'Removing '+basedir
266525d6f2eSBarry Smith       shutil.rmtree(basedir)
267525d6f2eSBarry Smith   os.mkdir(basedir)
268525d6f2eSBarry Smith   for root, dirs, files in os.walk(rootDir):
269525d6f2eSBarry Smith     self.buildDir(root)
270525d6f2eSBarry Smith     for badDir in [d for d in dirs if not self.checkDir(os.path.join(root, d))]:
271525d6f2eSBarry Smith       dirs.remove(badDir)
272525d6f2eSBarry Smith
27333be3048SBarry Smith   if not self.skipXCode:
27433be3048SBarry Smith
275a95d84e0SBarry Smith     print 'In Xcode mouse click on Other Sources then xcode-links and the delete key, then'
276525d6f2eSBarry Smith     print 'control mouse click on "Other Sources" and select "Add files to PETSc ...", then'
277525d6f2eSBarry Smith     print 'in the finder window locate ${PETSC_DIR}/arch-ios/xcode-links and select it. Now'
278525d6f2eSBarry Smith     print 'exit Xcode'
279525d6f2eSBarry Smith
280525d6f2eSBarry Smith     try:
281525d6f2eSBarry Smith       import subprocess
282525d6f2eSBarry Smith       subprocess.call('cd '+os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc')+';open -W PETSc.xcodeproj', shell=True)
283525d6f2eSBarry Smith     except RuntimeError, e:
284525d6f2eSBarry Smith       raise RuntimeError('Error opening xcode project '+str(e))
285525d6f2eSBarry Smith
286525d6f2eSBarry Smith
287*f66eea08SBarry Smith   sdk         = ' -sdk iphonesimulator '
288525d6f2eSBarry Smith   destination = 'iphonesimulator'
289525d6f2eSBarry Smith   debug       = 'Debug'
290525d6f2eSBarry Smith   debugdir    = 'Debug-'+destination
291525d6f2eSBarry Smith   if not self.compilerFlags.debugging:
292525d6f2eSBarry Smith     debug = 'Release'
293525d6f2eSBarry Smith     debugdir = 'Release-'+destination
294525d6f2eSBarry Smith   try:
2958506f42dSBarry 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)
296525d6f2eSBarry Smith   except RuntimeError, e:
297525d6f2eSBarry Smith     raise RuntimeError('Error making iPhone/iPad version of PETSc libraries: '+str(e))
298525d6f2eSBarry Smith
299b59f628eSBarry Smith   liblocation = os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc','build','Debug-iphonesimulator','PETSc.framework','PETSc')
300525d6f2eSBarry Smith   if not os.path.exists(liblocation):
301525d6f2eSBarry Smith     raise RuntimeError('Error library '+liblocation+' not created')
302525d6f2eSBarry Smith   try:
3035ce846c0SBarry Smith     output,err,ret  = self.executeShellCommand('cp -f '+liblocation+' '+os.path.join(os.environ['PETSC_DIR'],os.environ['PETSC_ARCH'],'lib'), timeout=30, log = self.log)
304525d6f2eSBarry Smith   except RuntimeError, e:
305525d6f2eSBarry Smith     raise RuntimeError('Error copying iPhone/iPad version of PETSc libraries: '+str(e))
306525d6f2eSBarry Smith
307525d6f2eSBarry Smith   return
308525d6f2eSBarry Smith
309525d6f2eSBarry Smithdef noCheckCommand(command, status, output, error):
310525d6f2eSBarry Smith  ''' Do no check result'''
311525d6f2eSBarry Smith  return
312525d6f2eSBarry Smith  noCheckCommand = staticmethod(noCheckCommand)
313525d6f2eSBarry Smith
314525d6f2eSBarry Smithif __name__ == '__main__':
315525d6f2eSBarry Smith  PETScMaker().buildAll()
316