xref: /petsc/systems/Apple/iOS/bin/iosbuilder.py (revision b59f628eff0cd0541d0457de20841eec6c6bc428)
1525d6f2eSBarry Smith#!/usr/bin/env python
2525d6f2eSBarry Smith#
3a95d84e0SBarry Smith#   Builds a iOS static library of PETSc
4525d6f2eSBarry Smith#
5a95d84e0SBarry Smith#   Before using remove /usr/include/mpi.h and /Developer/SDKs/MacOSX10.5.sdk/usr/include/mpi.h or
6525d6f2eSBarry Smith#      Xcode will use those instead of the MPIuni one we point to
7525d6f2eSBarry Smith#
8d9dc08c3SBarry Smith#   export PETSC_ARCH=arch-ios-simular
9a95d84e0SBarry Smith#
10525d6f2eSBarry Smith#   ./systems/Apple/iOS/bin/arch-ios.py [use --with-debugging=0 to get iPhone/iPad version, otherwise creates simulator version]
11525d6f2eSBarry Smith#      this sets up the appropriate configuration file
12525d6f2eSBarry Smith#
13525d6f2eSBarry Smith#   ./systems/Apple/iOS/bin/iosbuilder.py
14525d6f2eSBarry Smith#      this creates the PETSc iPhone/iPad library
15525d6f2eSBarry Smith#      this will open Xcode and give you directions to follow
16525d6f2eSBarry Smith#
17a95d84e0SBarry Smith#   open systems/Apple/iOS/examples/examples.xcodeproj
18525d6f2eSBarry Smith#       Project -> Edit Project Setting  -> Configuration (make sure it is Release or Debug depending on if you used --with-debugging=0)
19525d6f2eSBarry Smith#       Build -> Build and Debug
20525d6f2eSBarry Smith#
21525d6f2eSBarry Smithimport os, sys
22525d6f2eSBarry Smith
23525d6f2eSBarry Smithsys.path.insert(0, os.path.join(os.environ['PETSC_DIR'], 'config'))
24525d6f2eSBarry Smithsys.path.insert(0, os.path.join(os.environ['PETSC_DIR'], 'config', 'BuildSystem'))
25525d6f2eSBarry Smith
26525d6f2eSBarry Smithimport script
27525d6f2eSBarry Smith
28525d6f2eSBarry Smithclass PETScMaker(script.Script):
29525d6f2eSBarry Smith def __init__(self):
30525d6f2eSBarry Smith   import RDict
31525d6f2eSBarry Smith   import os
32525d6f2eSBarry Smith
33525d6f2eSBarry Smith   argDB = RDict.RDict(None, None, 0, 0, readonly = True)
34525d6f2eSBarry Smith   argDB.saveFilename = os.path.join(os.environ['PETSC_DIR'], os.environ['PETSC_ARCH'], 'conf', 'RDict.db')
35525d6f2eSBarry Smith   argDB.load()
36525d6f2eSBarry Smith   script.Script.__init__(self, argDB = argDB)
37525d6f2eSBarry Smith   self.log = sys.stdout
38525d6f2eSBarry Smith   return
39525d6f2eSBarry Smith
40525d6f2eSBarry Smith def setupModules(self):
41525d6f2eSBarry Smith   self.mpi           = self.framework.require('config.packages.MPI',         None)
42525d6f2eSBarry Smith   self.base          = self.framework.require('config.base',                 None)
43525d6f2eSBarry Smith   self.setCompilers  = self.framework.require('config.setCompilers',         None)
4444b85a23SBarry Smith   self.arch          = self.framework.require('PETSc.options.arch',        None)
4544b85a23SBarry Smith   self.petscdir      = self.framework.require('PETSc.options.petscdir',    None)
4644b85a23SBarry Smith   self.languages     = self.framework.require('PETSc.options.languages',   None)
4744b85a23SBarry Smith   self.debugging     = self.framework.require('PETSc.options.debugging',   None)
4844b85a23SBarry Smith   self.opengles      = self.framework.require('config.packages.opengles',     None)
49525d6f2eSBarry Smith   self.make          = self.framework.require('config.programs',             None)
50525d6f2eSBarry Smith   self.compilers     = self.framework.require('config.compilers',            None)
51525d6f2eSBarry Smith   self.types         = self.framework.require('config.types',                None)
52525d6f2eSBarry Smith   self.headers       = self.framework.require('config.headers',              None)
53525d6f2eSBarry Smith   self.functions     = self.framework.require('config.functions',            None)
54525d6f2eSBarry Smith   self.libraries     = self.framework.require('config.libraries',            None)
5544b85a23SBarry Smith   self.scalarType    = self.framework.require('PETSc.options.scalarTypes', None)
5644b85a23SBarry Smith   self.memAlign      = self.framework.require('PETSc.options.memAlign',    None)
5744b85a23SBarry Smith   self.libraryOptions= self.framework.require('PETSc.options.libraryOptions', None)
58525d6f2eSBarry Smith   self.compilerFlags = self.framework.require('config.compilerFlags', self)
59525d6f2eSBarry Smith   return
60525d6f2eSBarry Smith
61525d6f2eSBarry Smith def setupHelp(self, help):
62525d6f2eSBarry Smith   import nargs
63525d6f2eSBarry Smith
64525d6f2eSBarry Smith   help = script.Script.setupHelp(self, help)
65525d6f2eSBarry Smith   help.addArgument('RepManager', '-rootDir', nargs.ArgDir(None, os.environ['PETSC_DIR'], 'The root directory for this build', isTemporary = 1))
66525d6f2eSBarry Smith   help.addArgument('RepManager', '-dryRun',  nargs.ArgBool(None, False, 'Only output what would be run', isTemporary = 1))
6733be3048SBarry Smith   help.addArgument('RepManager', '-skipXCode',  nargs.ArgBool(None, False, 'Do not run XCode application/files have not been added/removed', isTemporary = 1))
68525d6f2eSBarry Smith   help.addArgument('RepManager', '-verbose', nargs.ArgInt(None, 0, 'The verbosity level', min = 0, isTemporary = 1))
69525d6f2eSBarry Smith   return help
70525d6f2eSBarry Smith
71525d6f2eSBarry Smith def setup(self):
72525d6f2eSBarry Smith   script.Script.setup(self)
73525d6f2eSBarry Smith   self.framework = self.loadConfigure()
74525d6f2eSBarry Smith   self.setupModules()
75525d6f2eSBarry Smith   return
76525d6f2eSBarry Smith
77525d6f2eSBarry Smith @property
78525d6f2eSBarry Smith def verbose(self):
79525d6f2eSBarry Smith   '''The verbosity level'''
80525d6f2eSBarry Smith   return self.argDB['verbose']
81525d6f2eSBarry Smith
82525d6f2eSBarry Smith @property
8333be3048SBarry Smith def skipXCode(self):
8433be3048SBarry Smith   '''Skip XCode application'''
8533be3048SBarry Smith   return self.argDB['skipXCode']
8633be3048SBarry Smith
8733be3048SBarry Smith @property
88525d6f2eSBarry Smith def dryRun(self):
89525d6f2eSBarry Smith   '''Flag for only output of what would be run'''
90525d6f2eSBarry Smith   return self.argDB['dryRun']
91525d6f2eSBarry Smith
92525d6f2eSBarry Smith def getPackageInfo(self):
93525d6f2eSBarry Smith   packageIncludes = []
94525d6f2eSBarry Smith   packageLibs     = []
95525d6f2eSBarry Smith   for p in self.framework.packages:
96525d6f2eSBarry Smith     # Could put on compile line, self.addDefine('HAVE_'+i.PACKAGE, 1)
97525d6f2eSBarry Smith     if hasattr(p, 'lib'):
98525d6f2eSBarry Smith       if not isinstance(p.lib, list):
99525d6f2eSBarry Smith         packageLibs.append(p.lib)
100525d6f2eSBarry Smith       else:
101525d6f2eSBarry Smith         packageLibs.extend(p.lib)
102525d6f2eSBarry Smith     if hasattr(p, 'include'):
103525d6f2eSBarry Smith       if not isinstance(p.include, list):
104525d6f2eSBarry Smith         packageIncludes.append(p.include)
105525d6f2eSBarry Smith       else:
106525d6f2eSBarry Smith         packageIncludes.extend(p.include)
107525d6f2eSBarry Smith   packageLibs     = self.libraries.toStringNoDupes(packageLibs+self.libraries.math)
108525d6f2eSBarry Smith   packageIncludes = self.headers.toStringNoDupes(packageIncludes)
109525d6f2eSBarry Smith   return packageIncludes, packageLibs
110525d6f2eSBarry Smith
111525d6f2eSBarry Smith def buildDir(self, dirname):
112525d6f2eSBarry Smith   ''' This is run in a PETSc source directory'''
113525d6f2eSBarry Smith   if self.verbose: print 'Entering '+dirname
114525d6f2eSBarry Smith   os.chdir(dirname)
115525d6f2eSBarry Smith   l = len(os.environ['PETSC_DIR'])
116525d6f2eSBarry Smith   basedir = os.path.join(os.environ['PETSC_DIR'],os.environ['PETSC_ARCH'],'xcode-links')
117525d6f2eSBarry Smith   #newdirname = os.path.join(basedir,dirname[l+1:])
118525d6f2eSBarry Smith   #os.mkdir(newdirname)
119525d6f2eSBarry Smith
120525d6f2eSBarry Smith
121525d6f2eSBarry Smith   # Get list of source files in the directory
122525d6f2eSBarry Smith   cnames = []
123525d6f2eSBarry Smith   onames = []
124525d6f2eSBarry Smith   fnames = []
125525d6f2eSBarry Smith   hnames = []
126525d6f2eSBarry Smith   for f in os.listdir(dirname):
127525d6f2eSBarry Smith     ext = os.path.splitext(f)[1]
128525d6f2eSBarry Smith     if ext == '.c':
129525d6f2eSBarry Smith       cnames.append(f)
130525d6f2eSBarry Smith       onames.append(f.replace('.c', '.o'))
131525d6f2eSBarry Smith     if ext == '.h':
132525d6f2eSBarry Smith       hnames.append(f)
133525d6f2eSBarry Smith   if cnames:
134525d6f2eSBarry Smith     if self.verbose: print 'Linking C files',cnames
135525d6f2eSBarry Smith     for i in cnames:
136525d6f2eSBarry Smith       j = i[l+1:]
137a95d84e0SBarry 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:
13833be3048SBarry Smith         if i.endswith('openglops.c') and not os.path.islink(os.path.join(basedir,'openglops.m')):
139f72c6c23SBarry Smith           os.symlink(os.path.join(dirname,i),os.path.join(basedir,'openglops.m'))
140f72c6c23SBarry Smith         else:
141525d6f2eSBarry Smith           os.symlink(os.path.join(dirname,i),os.path.join(basedir,i))
142525d6f2eSBarry Smith   # do not need to link these because xcode project points to original source code directory
143525d6f2eSBarry Smith   #if hnames:
144525d6f2eSBarry Smith   #  if self.verbose: print 'Linking h files',hnames
145525d6f2eSBarry Smith   #  for i in hnames:
146525d6f2eSBarry Smith   #    if not os.path.islink(os.path.join(basedir,i)):
147525d6f2eSBarry Smith   #      os.symlink(os.path.join(dirname,i),os.path.join(basedir,i))
148525d6f2eSBarry Smith   return
149525d6f2eSBarry Smith
150525d6f2eSBarry Smith def checkDir(self, dirname):
151525d6f2eSBarry Smith   '''Checks whether we should recurse into this directory
152525d6f2eSBarry Smith   - Excludes projects directory
153525d6f2eSBarry Smith   - Excludes examples directory
154525d6f2eSBarry Smith   - Excludes contrib directory
155525d6f2eSBarry Smith   - Excludes tutorials directory
156525d6f2eSBarry Smith   - Excludes benchmarks directory
157525d6f2eSBarry Smith   - Checks makefile to see if compiler is allowed to visit this directory for this configuration'''
158525d6f2eSBarry Smith#   print self.functions.functions
159525d6f2eSBarry Smith#   print self.base.defines
160525d6f2eSBarry Smith   base = os.path.basename(dirname)
161525d6f2eSBarry Smith
162525d6f2eSBarry Smith   if base == 'examples': return False
163525d6f2eSBarry Smith   if base == 'projects': return False
164525d6f2eSBarry Smith   if base.startswith('ftn-') or base.startswith('f90-'): return False
165525d6f2eSBarry Smith   if base == 'contrib':  return False
166525d6f2eSBarry Smith   if base == 'tutorials':  return False
167525d6f2eSBarry Smith   if base == 'benchmarks':  return False
168f72c6c23SBarry Smith   if base == 'systems':  return False
169a95d84e0SBarry Smith# for some reason agrmes is in the repository but not used!
170a95d84e0SBarry Smith   if base == 'agmres':  return False
171a95d84e0SBarry Smith   if base == 'test-dir':  return False
172525d6f2eSBarry Smith   if base.startswith('arch-'):  return False
173525d6f2eSBarry Smith
174525d6f2eSBarry Smith   import re
175525d6f2eSBarry Smith   reg   = re.compile(' [ ]*')
176525d6f2eSBarry Smith   fname = os.path.join(dirname, 'makefile')
177525d6f2eSBarry Smith   if not os.path.isfile(fname):
178525d6f2eSBarry Smith     if os.path.isfile(os.path.join(dirname, 'Makefile')): print 'ERROR: Change Makefile to makefile in',dirname
179525d6f2eSBarry Smith     return False
180525d6f2eSBarry Smith   fd = open(fname)
181525d6f2eSBarry Smith   text = fd.readline()
182525d6f2eSBarry Smith   while text:
183525d6f2eSBarry Smith     if text.startswith('#requires'):
184525d6f2eSBarry Smith       text = text[9:-1].strip()
185525d6f2eSBarry Smith       text = reg.sub(' ',text)
186525d6f2eSBarry Smith       rtype = text.split(' ')[0]
187525d6f2eSBarry Smith       rvalue = text.split(' ')[1]
188525d6f2eSBarry Smith
189525d6f2eSBarry Smith       if rvalue == "'"+'PETSC_HAVE_FORTRAN'+"'" or rvalue == "'"+'PETSC_USING_F90'+"'" or rvalue == "'"+'PETSC_USING_F2003'+"'":
190525d6f2eSBarry Smith         if not hasattr(self.compilers, 'FC'):
191525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because fortran is not being used'
192525d6f2eSBarry Smith           return 0
193525d6f2eSBarry Smith       elif rvalue == "'"+'PETSC_USE_LOG'+"'":
194525d6f2eSBarry Smith         if not self.libraryOptions.useLog:
195525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because logging is turned off'
196525d6f2eSBarry Smith           return 0
197525d6f2eSBarry Smith       elif rvalue == "'"+'PETSC_USE_FORTRAN_KERNELS'+"'":
198525d6f2eSBarry Smith         if not self.libraryOptions.useFortranKernels:
199525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because fortran kernels are turned off'
200525d6f2eSBarry Smith           return 0
201525d6f2eSBarry Smith       elif rtype == 'scalar' and not self.scalarType.scalartype == rvalue:
202525d6f2eSBarry Smith         if self.verbose: print 'Rejecting',dirname,'because scalar type '+self.scalarType.scalartype+' is not '+rvalue
203525d6f2eSBarry Smith         return 0
204525d6f2eSBarry Smith       elif rtype == 'language':
205525d6f2eSBarry Smith         if rvalue == 'CXXONLY' and self.languages.clanguage == 'C':
206525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because language is '+self.languages.clanguage+' is not C++'
207525d6f2eSBarry Smith           return 0
208525d6f2eSBarry Smith       elif rtype == 'precision' and not rvalue == self.scalarType.precision:
209525d6f2eSBarry Smith         if self.verbose: print 'Rejecting',dirname,'because precision '+self.scalarType.precision+' is not '+rvalue
210525d6f2eSBarry Smith         return 0
211525d6f2eSBarry Smith       elif rtype == 'package':
212525d6f2eSBarry Smith         found = 0
213525d6f2eSBarry Smith         if self.mpi.usingMPIUni:
214525d6f2eSBarry Smith           pname = 'PETSC_HAVE_MPIUNI'
215525d6f2eSBarry Smith           pname = "'"+pname+"'"
216525d6f2eSBarry Smith           if pname == rvalue: found = 1
217525d6f2eSBarry Smith         for i in self.framework.packages:
218525d6f2eSBarry Smith           pname = 'PETSC_HAVE_'+i.PACKAGE
219525d6f2eSBarry Smith           pname = "'"+pname+"'"
220525d6f2eSBarry Smith           if pname == rvalue: found = 1
221525d6f2eSBarry Smith         if not found:
222a95d84e0SBarry Smith           for i in self.base.defines:
223a95d84e0SBarry Smith             pname = 'PETSC_'+i.upper()
224a95d84e0SBarry Smith             pname = "'"+pname+"'"
225a95d84e0SBarry Smith             if pname == rvalue: found = 1
226bcd1c4acSBarry Smith           for i in self.opengles.defines:
227bcd1c4acSBarry Smith             pname = 'PETSC_'+i.upper()
228bcd1c4acSBarry Smith             pname = "'"+pname+"'"
229bcd1c4acSBarry Smith             if pname == rvalue: found = 1
230a95d84e0SBarry Smith           if not found:
231525d6f2eSBarry Smith             if self.verbose: print 'Rejecting',dirname,'because package '+rvalue+' does not exist'
232525d6f2eSBarry Smith             return 0
233525d6f2eSBarry Smith       elif rtype == 'define':
234525d6f2eSBarry Smith         found = 0
235525d6f2eSBarry Smith         for i in self.base.defines:
236525d6f2eSBarry Smith           pname = 'PETSC_'+i.upper()
237525d6f2eSBarry Smith           pname = "'"+pname+"'"
238525d6f2eSBarry Smith           if pname == rvalue: found = 1
239525d6f2eSBarry Smith         if not found:
240525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because define '+rvalue+' does not exist'
241525d6f2eSBarry Smith           return 0
242525d6f2eSBarry Smith       elif rtype == 'function':
243525d6f2eSBarry Smith         found = 0
244525d6f2eSBarry Smith         for i in self.functions.functions:
245525d6f2eSBarry Smith           pname = 'PETSC_HAVE_'+i.upper()
246525d6f2eSBarry Smith           pname = "'"+pname+"'"
247525d6f2eSBarry Smith#           print pname
248525d6f2eSBarry Smith#           print rvalue
249525d6f2eSBarry Smith           if pname == rvalue: found = 1
250525d6f2eSBarry Smith         if not found:
251525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because function '+rvalue+' does not exist'
252525d6f2eSBarry Smith           return 0
253525d6f2eSBarry Smith
254525d6f2eSBarry Smith     text = fd.readline()
255525d6f2eSBarry Smith   fd.close()
256525d6f2eSBarry Smith   return True
257525d6f2eSBarry Smith
258525d6f2eSBarry Smith def buildAll(self, rootDir = None):
259525d6f2eSBarry Smith   import shutil
260525d6f2eSBarry Smith   self.setup()
261525d6f2eSBarry Smith   if rootDir is None:
262525d6f2eSBarry Smith     rootDir = self.argDB['rootDir']
263525d6f2eSBarry Smith   if not self.checkDir(rootDir):
264525d6f2eSBarry Smith     print 'Nothing to be done'
265525d6f2eSBarry Smith   if rootDir == os.environ['PETSC_DIR']:
266525d6f2eSBarry Smith     basedir = os.path.join(self.petscdir.dir, self.arch.arch, 'xcode-links')
267525d6f2eSBarry Smith     if os.path.isdir(basedir):
268525d6f2eSBarry Smith       if self.verbose: print 'Removing '+basedir
269525d6f2eSBarry Smith       shutil.rmtree(basedir)
270525d6f2eSBarry Smith   os.mkdir(basedir)
271525d6f2eSBarry Smith   for root, dirs, files in os.walk(rootDir):
272525d6f2eSBarry Smith     self.buildDir(root)
273525d6f2eSBarry Smith     for badDir in [d for d in dirs if not self.checkDir(os.path.join(root, d))]:
274525d6f2eSBarry Smith       dirs.remove(badDir)
275525d6f2eSBarry Smith
27633be3048SBarry Smith   if not self.skipXCode:
27733be3048SBarry Smith
278a95d84e0SBarry Smith     print 'In Xcode mouse click on Other Sources then xcode-links and the delete key, then'
279525d6f2eSBarry Smith     print 'control mouse click on "Other Sources" and select "Add files to PETSc ...", then'
280525d6f2eSBarry Smith     print 'in the finder window locate ${PETSC_DIR}/arch-ios/xcode-links and select it. Now'
281525d6f2eSBarry Smith     print 'exit Xcode'
282525d6f2eSBarry Smith
283525d6f2eSBarry Smith     try:
284525d6f2eSBarry Smith       import subprocess
285525d6f2eSBarry Smith       subprocess.call('cd '+os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc')+';open -W PETSc.xcodeproj', shell=True)
286525d6f2eSBarry Smith     except RuntimeError, e:
287525d6f2eSBarry Smith       raise RuntimeError('Error opening xcode project '+str(e))
288525d6f2eSBarry Smith
289525d6f2eSBarry Smith
29044b85a23SBarry Smith   sdk         = ' -sdk iphonesimulator8.0 '
291525d6f2eSBarry Smith   destination = 'iphonesimulator'
292525d6f2eSBarry Smith   debug       = 'Debug'
293525d6f2eSBarry Smith   debugdir    = 'Debug-'+destination
294525d6f2eSBarry Smith   if not self.compilerFlags.debugging:
295525d6f2eSBarry Smith     debug = 'Release'
296525d6f2eSBarry Smith     debugdir = 'Release-'+destination
297525d6f2eSBarry Smith   try:
298525d6f2eSBarry Smith     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)
299525d6f2eSBarry Smith   except RuntimeError, e:
300525d6f2eSBarry Smith     raise RuntimeError('Error making iPhone/iPad version of PETSc libraries: '+str(e))
301525d6f2eSBarry Smith
302*b59f628eSBarry Smith   liblocation = os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc','build','Debug-iphonesimulator','PETSc.framework','PETSc')
303525d6f2eSBarry Smith   if not os.path.exists(liblocation):
304525d6f2eSBarry Smith     raise RuntimeError('Error library '+liblocation+' not created')
305525d6f2eSBarry Smith   try:
306525d6f2eSBarry Smith     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)
307525d6f2eSBarry Smith   except RuntimeError, e:
308525d6f2eSBarry Smith     raise RuntimeError('Error copying iPhone/iPad version of PETSc libraries: '+str(e))
309525d6f2eSBarry Smith
310525d6f2eSBarry Smith   return
311525d6f2eSBarry Smith
312525d6f2eSBarry Smithdef noCheckCommand(command, status, output, error):
313525d6f2eSBarry Smith  ''' Do no check result'''
314525d6f2eSBarry Smith  return
315525d6f2eSBarry Smith  noCheckCommand = staticmethod(noCheckCommand)
316525d6f2eSBarry Smith
317525d6f2eSBarry Smithif __name__ == '__main__':
318525d6f2eSBarry Smith  PETScMaker().buildAll()
319