xref: /petsc/systems/Apple/iOS/bin/iosbuilder.py (revision f72c6c23b85e3338cbe1612df3544669d3a1c793)
1525d6f2eSBarry Smith#!/usr/bin/env python
2525d6f2eSBarry Smith#
3525d6f2eSBarry Smith#   Builds a iPhone/iPad static library of PETSc
4525d6f2eSBarry Smith#
5525d6f2eSBarry Smith#   Before using removed /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#
8525d6f2eSBarry Smith#   export PETSC_ARCH=arch-ios
9525d6f2eSBarry 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#
17525d6f2eSBarry Smith#   open xcode/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)
44525d6f2eSBarry Smith   self.arch          = self.framework.require('PETSc.utilities.arch',        None)
45525d6f2eSBarry Smith   self.petscdir      = self.framework.require('PETSc.utilities.petscdir',    None)
46525d6f2eSBarry Smith   self.languages     = self.framework.require('PETSc.utilities.languages',   None)
47525d6f2eSBarry Smith   self.debugging     = self.framework.require('PETSc.utilities.debugging',   None)
48525d6f2eSBarry Smith   self.make          = self.framework.require('config.programs',             None)
49525d6f2eSBarry Smith   self.compilers     = self.framework.require('config.compilers',            None)
50525d6f2eSBarry Smith   self.types         = self.framework.require('config.types',                None)
51525d6f2eSBarry Smith   self.headers       = self.framework.require('config.headers',              None)
52525d6f2eSBarry Smith   self.functions     = self.framework.require('config.functions',            None)
53525d6f2eSBarry Smith   self.libraries     = self.framework.require('config.libraries',            None)
54525d6f2eSBarry Smith   self.scalarType    = self.framework.require('PETSc.utilities.scalarTypes', None)
55525d6f2eSBarry Smith   self.memAlign      = self.framework.require('PETSc.utilities.memAlign',    None)
56525d6f2eSBarry Smith   self.libraryOptions= self.framework.require('PETSc.utilities.libraryOptions', None)
57525d6f2eSBarry Smith   self.compilerFlags = self.framework.require('config.compilerFlags', self)
58525d6f2eSBarry Smith   return
59525d6f2eSBarry Smith
60525d6f2eSBarry Smith def setupHelp(self, help):
61525d6f2eSBarry Smith   import nargs
62525d6f2eSBarry Smith
63525d6f2eSBarry Smith   help = script.Script.setupHelp(self, help)
64525d6f2eSBarry Smith   help.addArgument('RepManager', '-rootDir', nargs.ArgDir(None, os.environ['PETSC_DIR'], 'The root directory for this build', isTemporary = 1))
65525d6f2eSBarry Smith   help.addArgument('RepManager', '-dryRun',  nargs.ArgBool(None, False, 'Only output what would be run', 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
81525d6f2eSBarry Smith def dryRun(self):
82525d6f2eSBarry Smith   '''Flag for only output of what would be run'''
83525d6f2eSBarry Smith   return self.argDB['dryRun']
84525d6f2eSBarry Smith
85525d6f2eSBarry Smith def getPackageInfo(self):
86525d6f2eSBarry Smith   packageIncludes = []
87525d6f2eSBarry Smith   packageLibs     = []
88525d6f2eSBarry Smith   for p in self.framework.packages:
89525d6f2eSBarry Smith     # Could put on compile line, self.addDefine('HAVE_'+i.PACKAGE, 1)
90525d6f2eSBarry Smith     if hasattr(p, 'lib'):
91525d6f2eSBarry Smith       if not isinstance(p.lib, list):
92525d6f2eSBarry Smith         packageLibs.append(p.lib)
93525d6f2eSBarry Smith       else:
94525d6f2eSBarry Smith         packageLibs.extend(p.lib)
95525d6f2eSBarry Smith     if hasattr(p, 'include'):
96525d6f2eSBarry Smith       if not isinstance(p.include, list):
97525d6f2eSBarry Smith         packageIncludes.append(p.include)
98525d6f2eSBarry Smith       else:
99525d6f2eSBarry Smith         packageIncludes.extend(p.include)
100525d6f2eSBarry Smith   packageLibs     = self.libraries.toStringNoDupes(packageLibs+self.libraries.math)
101525d6f2eSBarry Smith   packageIncludes = self.headers.toStringNoDupes(packageIncludes)
102525d6f2eSBarry Smith   return packageIncludes, packageLibs
103525d6f2eSBarry Smith
104525d6f2eSBarry Smith def buildDir(self, dirname):
105525d6f2eSBarry Smith   ''' This is run in a PETSc source directory'''
106525d6f2eSBarry Smith   if self.verbose: print 'Entering '+dirname
107525d6f2eSBarry Smith   os.chdir(dirname)
108525d6f2eSBarry Smith   l = len(os.environ['PETSC_DIR'])
109525d6f2eSBarry Smith   basedir = os.path.join(os.environ['PETSC_DIR'],os.environ['PETSC_ARCH'],'xcode-links')
110525d6f2eSBarry Smith   #newdirname = os.path.join(basedir,dirname[l+1:])
111525d6f2eSBarry Smith   #os.mkdir(newdirname)
112525d6f2eSBarry Smith
113525d6f2eSBarry Smith
114525d6f2eSBarry Smith   # Get list of source files in the directory
115525d6f2eSBarry Smith   cnames = []
116525d6f2eSBarry Smith   onames = []
117525d6f2eSBarry Smith   fnames = []
118525d6f2eSBarry Smith   hnames = []
119525d6f2eSBarry Smith   for f in os.listdir(dirname):
120525d6f2eSBarry Smith     ext = os.path.splitext(f)[1]
121525d6f2eSBarry Smith     if ext == '.c':
122525d6f2eSBarry Smith       cnames.append(f)
123525d6f2eSBarry Smith       onames.append(f.replace('.c', '.o'))
124525d6f2eSBarry Smith     if ext == '.h':
125525d6f2eSBarry Smith       hnames.append(f)
126525d6f2eSBarry Smith   if cnames:
127525d6f2eSBarry Smith     if self.verbose: print 'Linking C files',cnames
128525d6f2eSBarry Smith     for i in cnames:
129525d6f2eSBarry Smith       j = i[l+1:]
130525d6f2eSBarry Smith       if not os.path.islink(os.path.join(basedir,i)):
131*f72c6c23SBarry Smith         if i.endswith('openglops.c'):
132*f72c6c23SBarry Smith           os.symlink(os.path.join(dirname,i),os.path.join(basedir,'openglops.m'))
133*f72c6c23SBarry Smith         else:
134525d6f2eSBarry Smith           os.symlink(os.path.join(dirname,i),os.path.join(basedir,i))
135525d6f2eSBarry Smith   # do not need to link these because xcode project points to original source code directory
136525d6f2eSBarry Smith   #if hnames:
137525d6f2eSBarry Smith   #  if self.verbose: print 'Linking h files',hnames
138525d6f2eSBarry Smith   #  for i in hnames:
139525d6f2eSBarry Smith   #    if not os.path.islink(os.path.join(basedir,i)):
140525d6f2eSBarry Smith   #      os.symlink(os.path.join(dirname,i),os.path.join(basedir,i))
141525d6f2eSBarry Smith   return
142525d6f2eSBarry Smith
143525d6f2eSBarry Smith def checkDir(self, dirname):
144525d6f2eSBarry Smith   '''Checks whether we should recurse into this directory
145525d6f2eSBarry Smith   - Excludes projects directory
146525d6f2eSBarry Smith   - Excludes examples directory
147525d6f2eSBarry Smith   - Excludes contrib directory
148525d6f2eSBarry Smith   - Excludes tutorials directory
149525d6f2eSBarry Smith   - Excludes benchmarks directory
150525d6f2eSBarry Smith   - Checks makefile to see if compiler is allowed to visit this directory for this configuration'''
151525d6f2eSBarry Smith#   print self.functions.functions
152525d6f2eSBarry Smith#   print self.base.defines
153525d6f2eSBarry Smith   base = os.path.basename(dirname)
154525d6f2eSBarry Smith
155525d6f2eSBarry Smith   if base == 'examples': return False
156525d6f2eSBarry Smith   if base == 'projects': return False
157525d6f2eSBarry Smith   if base.startswith('ftn-') or base.startswith('f90-'): return False
158525d6f2eSBarry Smith   if base == 'contrib':  return False
159525d6f2eSBarry Smith   if base == 'tutorials':  return False
160525d6f2eSBarry Smith   if base == 'benchmarks':  return False
161*f72c6c23SBarry Smith   if base == 'systems':  return False
162525d6f2eSBarry Smith   if base.startswith('arch-'):  return False
163525d6f2eSBarry Smith
164525d6f2eSBarry Smith   import re
165525d6f2eSBarry Smith   reg   = re.compile(' [ ]*')
166525d6f2eSBarry Smith   fname = os.path.join(dirname, 'makefile')
167525d6f2eSBarry Smith   if not os.path.isfile(fname):
168525d6f2eSBarry Smith     if os.path.isfile(os.path.join(dirname, 'Makefile')): print 'ERROR: Change Makefile to makefile in',dirname
169525d6f2eSBarry Smith     return False
170525d6f2eSBarry Smith   fd = open(fname)
171525d6f2eSBarry Smith   text = fd.readline()
172525d6f2eSBarry Smith   while text:
173525d6f2eSBarry Smith     if text.startswith('#requires'):
174525d6f2eSBarry Smith       text = text[9:-1].strip()
175525d6f2eSBarry Smith       text = reg.sub(' ',text)
176525d6f2eSBarry Smith       rtype = text.split(' ')[0]
177525d6f2eSBarry Smith       rvalue = text.split(' ')[1]
178525d6f2eSBarry Smith
179525d6f2eSBarry Smith       if rvalue == "'"+'PETSC_HAVE_FORTRAN'+"'" or rvalue == "'"+'PETSC_USING_F90'+"'" or rvalue == "'"+'PETSC_USING_F2003'+"'":
180525d6f2eSBarry Smith         if not hasattr(self.compilers, 'FC'):
181525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because fortran is not being used'
182525d6f2eSBarry Smith           return 0
183525d6f2eSBarry Smith       elif rvalue == "'"+'PETSC_USE_LOG'+"'":
184525d6f2eSBarry Smith         if not self.libraryOptions.useLog:
185525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because logging is turned off'
186525d6f2eSBarry Smith           return 0
187525d6f2eSBarry Smith       elif rvalue == "'"+'PETSC_USE_FORTRAN_KERNELS'+"'":
188525d6f2eSBarry Smith         if not self.libraryOptions.useFortranKernels:
189525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because fortran kernels are turned off'
190525d6f2eSBarry Smith           return 0
191525d6f2eSBarry Smith       elif rtype == 'scalar' and not self.scalarType.scalartype == rvalue:
192525d6f2eSBarry Smith         if self.verbose: print 'Rejecting',dirname,'because scalar type '+self.scalarType.scalartype+' is not '+rvalue
193525d6f2eSBarry Smith         return 0
194525d6f2eSBarry Smith       elif rtype == 'language':
195525d6f2eSBarry Smith         if rvalue == 'CXXONLY' and self.languages.clanguage == 'C':
196525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because language is '+self.languages.clanguage+' is not C++'
197525d6f2eSBarry Smith           return 0
198525d6f2eSBarry Smith       elif rtype == 'precision' and not rvalue == self.scalarType.precision:
199525d6f2eSBarry Smith         if self.verbose: print 'Rejecting',dirname,'because precision '+self.scalarType.precision+' is not '+rvalue
200525d6f2eSBarry Smith         return 0
201525d6f2eSBarry Smith       elif rtype == 'package':
202525d6f2eSBarry Smith         found = 0
203525d6f2eSBarry Smith         if self.mpi.usingMPIUni:
204525d6f2eSBarry Smith           pname = 'PETSC_HAVE_MPIUNI'
205525d6f2eSBarry Smith           pname = "'"+pname+"'"
206525d6f2eSBarry Smith           if pname == rvalue: found = 1
207525d6f2eSBarry Smith         for i in self.framework.packages:
208525d6f2eSBarry Smith           pname = 'PETSC_HAVE_'+i.PACKAGE
209525d6f2eSBarry Smith           pname = "'"+pname+"'"
210525d6f2eSBarry Smith           if pname == rvalue: found = 1
211525d6f2eSBarry Smith         if not found:
212525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because package '+rvalue+' does not exist'
213525d6f2eSBarry Smith           return 0
214525d6f2eSBarry Smith       elif rtype == 'define':
215525d6f2eSBarry Smith         found = 0
216525d6f2eSBarry Smith         for i in self.base.defines:
217525d6f2eSBarry Smith           pname = 'PETSC_'+i.upper()
218525d6f2eSBarry Smith           pname = "'"+pname+"'"
219525d6f2eSBarry Smith           if pname == rvalue: found = 1
220525d6f2eSBarry Smith         if not found:
221525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because define '+rvalue+' does not exist'
222525d6f2eSBarry Smith           return 0
223525d6f2eSBarry Smith       elif rtype == 'function':
224525d6f2eSBarry Smith         found = 0
225525d6f2eSBarry Smith         for i in self.functions.functions:
226525d6f2eSBarry Smith           pname = 'PETSC_HAVE_'+i.upper()
227525d6f2eSBarry Smith           pname = "'"+pname+"'"
228525d6f2eSBarry Smith#           print pname
229525d6f2eSBarry Smith#           print rvalue
230525d6f2eSBarry Smith           if pname == rvalue: found = 1
231525d6f2eSBarry Smith         if not found:
232525d6f2eSBarry Smith           if self.verbose: print 'Rejecting',dirname,'because function '+rvalue+' does not exist'
233525d6f2eSBarry Smith           return 0
234525d6f2eSBarry Smith
235525d6f2eSBarry Smith     text = fd.readline()
236525d6f2eSBarry Smith   fd.close()
237525d6f2eSBarry Smith   return True
238525d6f2eSBarry Smith
239525d6f2eSBarry Smith def buildAll(self, rootDir = None):
240525d6f2eSBarry Smith   import shutil
241525d6f2eSBarry Smith   self.setup()
242525d6f2eSBarry Smith   if rootDir is None:
243525d6f2eSBarry Smith     rootDir = self.argDB['rootDir']
244525d6f2eSBarry Smith   if not self.checkDir(rootDir):
245525d6f2eSBarry Smith     print 'Nothing to be done'
246525d6f2eSBarry Smith   if rootDir == os.environ['PETSC_DIR']:
247525d6f2eSBarry Smith     basedir = os.path.join(self.petscdir.dir, self.arch.arch, 'xcode-links')
248525d6f2eSBarry Smith     if os.path.isdir(basedir):
249525d6f2eSBarry Smith       if self.verbose: print 'Removing '+basedir
250525d6f2eSBarry Smith       shutil.rmtree(basedir)
251525d6f2eSBarry Smith   os.mkdir(basedir)
252525d6f2eSBarry Smith   for root, dirs, files in os.walk(rootDir):
253525d6f2eSBarry Smith     self.buildDir(root)
254525d6f2eSBarry Smith     for badDir in [d for d in dirs if not self.checkDir(os.path.join(root, d))]:
255525d6f2eSBarry Smith       dirs.remove(badDir)
256525d6f2eSBarry Smith
257525d6f2eSBarry Smith   print 'In Xcode mouse click on xcode-links and the delete key, then'
258525d6f2eSBarry Smith   print 'control mouse click on "Other Sources" and select "Add files to PETSc ...", then'
259525d6f2eSBarry Smith   print 'in the finder window locate ${PETSC_DIR}/arch-ios/xcode-links and select it. Now'
260525d6f2eSBarry Smith   print 'exit Xcode'
261525d6f2eSBarry Smith
262525d6f2eSBarry Smith   try:
263525d6f2eSBarry Smith     import subprocess
264525d6f2eSBarry Smith     subprocess.call('cd '+os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc')+';open -W PETSc.xcodeproj', shell=True)
265525d6f2eSBarry Smith   except RuntimeError, e:
266525d6f2eSBarry Smith     raise RuntimeError('Error opening xcode project '+str(e))
267525d6f2eSBarry Smith
268525d6f2eSBarry Smith
269525d6f2eSBarry Smith   sdk         = ' -sdk iphonesimulator5.1 '
270525d6f2eSBarry Smith   destination = 'iphonesimulator'
271525d6f2eSBarry Smith   debug       = 'Debug'
272525d6f2eSBarry Smith   debugdir    = 'Debug-'+destination
273525d6f2eSBarry Smith   if not self.compilerFlags.debugging:
274525d6f2eSBarry Smith     debug = 'Release'
275525d6f2eSBarry Smith     debugdir = 'Release-'+destination
276525d6f2eSBarry Smith   try:
277525d6f2eSBarry 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)
278525d6f2eSBarry Smith   except RuntimeError, e:
279525d6f2eSBarry Smith     raise RuntimeError('Error making iPhone/iPad version of PETSc libraries: '+str(e))
280525d6f2eSBarry Smith
281525d6f2eSBarry Smith   liblocation = os.path.join(os.environ['PETSC_DIR'],'systems','Apple','iOS','PETSc','build',debugdir,'libPETSc.a')
282525d6f2eSBarry Smith   if not os.path.exists(liblocation):
283525d6f2eSBarry Smith     raise RuntimeError('Error library '+liblocation+' not created')
284525d6f2eSBarry Smith   try:
285525d6f2eSBarry 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)
286525d6f2eSBarry Smith   except RuntimeError, e:
287525d6f2eSBarry Smith     raise RuntimeError('Error copying iPhone/iPad version of PETSc libraries: '+str(e))
288525d6f2eSBarry Smith
289525d6f2eSBarry Smith   return
290525d6f2eSBarry Smith
291525d6f2eSBarry Smithdef noCheckCommand(command, status, output, error):
292525d6f2eSBarry Smith  ''' Do no check result'''
293525d6f2eSBarry Smith  return
294525d6f2eSBarry Smith  noCheckCommand = staticmethod(noCheckCommand)
295525d6f2eSBarry Smith
296525d6f2eSBarry Smithif __name__ == '__main__':
297525d6f2eSBarry Smith  PETScMaker().buildAll()
298