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