xref: /petsc/config/gmakegen.py (revision 8d5d1ea2c993327b92bbea91ecab18f2862874e4)
1df3bd252SSatish Balay#!/usr/bin/env python3
20ee81e68SLisandro Dalcin
30ee81e68SLisandro Dalcinimport os
4becf0a19SJed Brownfrom sysconfig import _parse_makefile as parse_makefile
50ee81e68SLisandro Dalcinimport sys
60ee81e68SLisandro Dalcinimport logging
70ee81e68SLisandro Dalcinsys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
87b8851e6SJed Brownfrom collections import defaultdict
90ee81e68SLisandro Dalcin
10b892d579SJed BrownAUTODIRS = set('ftn-auto ftn-custom f90-custom ftn-auto-interfaces'.split()) # Automatically recurse into these, if they exist
11b75c6efcSBarry SmithSKIPDIRS = set('benchmarks build mex-scripts tests tutorials'.split())       # Skip these during the build
12dc0529c6SBarry Smith
134bfab837SSebastian Grimbergdef pathsplit(pkg_dir, path):
14dc0529c6SBarry Smith    """Recursively split a path, returns a tuple"""
15dc0529c6SBarry Smith    stem, basename = os.path.split(path)
164bfab837SSebastian Grimberg    if stem == '' or stem == pkg_dir:
17dc0529c6SBarry Smith        return (basename,)
18dc0529c6SBarry Smith    if stem == path: # fixed point, likely '/'
1951de3720SJed Brown        return (None,)
204bfab837SSebastian Grimberg    return pathsplit(pkg_dir, stem) + (basename,)
21dc0529c6SBarry Smith
22c0558f20SBarry Smithdef getlangext(name):
23c0558f20SBarry Smith    """Returns everything after the first . in the filename, including the ."""
24c0558f20SBarry Smith    file = os.path.basename(name)
25c0558f20SBarry Smith    loc = file.find('.')
26c0558f20SBarry Smith    if loc > -1: return file[loc:]
27c0558f20SBarry Smith    else: return ''
28c0558f20SBarry Smith
29c0558f20SBarry Smithdef getlangsplit(name):
30c0558f20SBarry Smith    """Returns everything before the first . in the filename, excluding the ."""
31c0558f20SBarry Smith    file = os.path.basename(name)
32c0558f20SBarry Smith    loc = file.find('.')
33c0558f20SBarry Smith    if loc > -1: return os.path.join(os.path.dirname(name),file[:loc])
34c0558f20SBarry Smith    raise RuntimeError("No . in filename")
35c0558f20SBarry Smith
36dc0529c6SBarry Smithclass Mistakes(object):
37dc0529c6SBarry Smith    def __init__(self, log, verbose=False):
38dc0529c6SBarry Smith        self.mistakes = []
39dc0529c6SBarry Smith        self.verbose = verbose
40dc0529c6SBarry Smith        self.log = log
41dc0529c6SBarry Smith
42dc0529c6SBarry Smith    def compareDirLists(self,root, mdirs, dirs):
4351de3720SJed Brown        if SKIPDIRS.intersection(pathsplit(None, root)):
44dc0529c6SBarry Smith            return
45183d35a2SBarry Smith        smdirs = set(mdirs).difference(AUTODIRS)
46dc0529c6SBarry Smith        sdirs  = set(dirs).difference(AUTODIRS)
47dc0529c6SBarry Smith        if not smdirs.issubset(sdirs):
48cca3327aSJed Brown            self.mistakes.append('%s/makefile contains a directory not on the filesystem: %r' % (root, sorted(smdirs - sdirs)))
49dc0529c6SBarry Smith        if not self.verbose: return
50dc0529c6SBarry Smith        if smdirs != sdirs:
51dc0529c6SBarry Smith            from sys import stderr
52dc0529c6SBarry Smith            stderr.write('Directory mismatch at %s:\n\t%s: %r\n\t%s: %r\n\t%s: %r\n'
53dc0529c6SBarry Smith                         % (root,
54dc0529c6SBarry Smith                            'in makefile   ',sorted(smdirs),
55dc0529c6SBarry Smith                            'on filesystem ',sorted(sdirs),
56dc0529c6SBarry Smith                            'symmetric diff',sorted(smdirs.symmetric_difference(sdirs))))
57dc0529c6SBarry Smith
58dc0529c6SBarry Smith    def summary(self):
59dc0529c6SBarry Smith        for m in self.mistakes:
60dc0529c6SBarry Smith            self.log.write(m + '\n')
61dc0529c6SBarry Smith        if self.mistakes:
62a943032dSBarry Smith            raise RuntimeError('\n\nThe PETSc makefiles contain mistakes or files are missing on the filesystem.\n%s\nPossible reasons:\n\t1. Files were deleted locally, try "git checkout filename", where "filename" is the missing file.\n\t2. Files were deleted from the repository, but were not removed from the makefile. Send mail to petsc-maint@mcs.anl.gov.\n\t3. Someone forgot to "add" new files to the repository. Send mail to petsc-maint@mcs.anl.gov.\n\n' % ('\n'.join(self.mistakes)))
63dc0529c6SBarry Smith
64dc0529c6SBarry Smithdef stripsplit(line):
65dc0529c6SBarry Smith  return line[len('#requires'):].replace("'","").split()
66dc0529c6SBarry Smith
6747fd361eSStefano ZampiniPetscPKGS = 'sys vec mat dm ksp snes ts tao'.split()
68c0558f20SBarry Smith# the key is actually the language suffix, it won't work for suffixes such as 'kokkos.cxx' so use an _ and replace the _ as needed with .
695a7ab478SBarry SmithLANGS = dict(kokkos_cxx='KOKKOS', hip_cpp='HIP', sycl_cxx='SYCL', raja_cxx='RAJA', c='C', cxx='CXX', cpp='CPP', cu='CU', F='F', F90='F90')
700ee81e68SLisandro Dalcin
710ee81e68SLisandro Dalcinclass debuglogger(object):
720ee81e68SLisandro Dalcin    def __init__(self, log):
730ee81e68SLisandro Dalcin        self._log = log
740ee81e68SLisandro Dalcin
750ee81e68SLisandro Dalcin    def write(self, string):
760ee81e68SLisandro Dalcin        self._log.debug(string)
770ee81e68SLisandro Dalcin
780ee81e68SLisandro Dalcinclass Petsc(object):
7947fd361eSStefano Zampini    def __init__(self, petsc_dir=None, petsc_arch=None, pkg_dir=None, pkg_name=None, pkg_arch=None, pkg_pkgs=None, verbose=False):
800ee81e68SLisandro Dalcin        if petsc_dir is None:
810ee81e68SLisandro Dalcin            petsc_dir = os.environ.get('PETSC_DIR')
820ee81e68SLisandro Dalcin            if petsc_dir is None:
830ee81e68SLisandro Dalcin                try:
84af0996ceSBarry Smith                    petsc_dir = parse_makefile(os.path.join('lib','petsc','conf', 'petscvariables')).get('PETSC_DIR')
850ee81e68SLisandro Dalcin                finally:
860ee81e68SLisandro Dalcin                    if petsc_dir is None:
870ee81e68SLisandro Dalcin                        raise RuntimeError('Could not determine PETSC_DIR, please set in environment')
880ee81e68SLisandro Dalcin        if petsc_arch is None:
890ee81e68SLisandro Dalcin            petsc_arch = os.environ.get('PETSC_ARCH')
900ee81e68SLisandro Dalcin            if petsc_arch is None:
910ee81e68SLisandro Dalcin                try:
92af0996ceSBarry Smith                    petsc_arch = parse_makefile(os.path.join(petsc_dir, 'lib','petsc','conf', 'petscvariables')).get('PETSC_ARCH')
930ee81e68SLisandro Dalcin                finally:
940ee81e68SLisandro Dalcin                    if petsc_arch is None:
950ee81e68SLisandro Dalcin                        raise RuntimeError('Could not determine PETSC_ARCH, please set in environment')
96add6df95SStefano Zampini        self.petsc_dir = os.path.normpath(petsc_dir)
97add6df95SStefano Zampini        self.petsc_arch = petsc_arch.rstrip(os.sep)
98add6df95SStefano Zampini        self.pkg_dir = pkg_dir
99add6df95SStefano Zampini        self.pkg_name = pkg_name
100c4bccdb5SStefano Zampini        self.pkg_arch = pkg_arch
101add6df95SStefano Zampini        if self.pkg_dir is None:
102add6df95SStefano Zampini          self.pkg_dir = petsc_dir
103add6df95SStefano Zampini          self.pkg_name = 'petsc'
104c4bccdb5SStefano Zampini          self.pkg_arch = self.petsc_arch
105add6df95SStefano Zampini        if self.pkg_name is None:
106add6df95SStefano Zampini          self.pkg_name = os.path.basename(os.path.normpath(self.pkg_dir))
107c4bccdb5SStefano Zampini        if self.pkg_arch is None:
108c4bccdb5SStefano Zampini          self.pkg_arch = self.petsc_arch
10947fd361eSStefano Zampini        self.pkg_pkgs = PetscPKGS
11047fd361eSStefano Zampini        if pkg_pkgs is not None:
111*8d5d1ea2SBarry Smith          if pkg_pkgs.find(',') > 0: npkgs = set(pkg_pkgs.split(','))
112*8d5d1ea2SBarry Smith          else: npkgs = set(pkg_pkgs.split(' '))
113*8d5d1ea2SBarry Smith          self.pkg_pkgs += list(npkgs - set(self.pkg_pkgs))
11447fd361eSStefano Zampini        self.read_conf()
1158e69c5ecSJed Brown        try:
116add6df95SStefano Zampini            logging.basicConfig(filename=self.pkg_arch_path('lib',self.pkg_name,'conf', 'gmake.log'), level=logging.DEBUG)
1178e69c5ecSJed Brown        except IOError:
1188e69c5ecSJed Brown            # Disable logging if path is not writeable (e.g., prefix install)
1198e69c5ecSJed Brown            logging.basicConfig(filename='/dev/null', level=logging.DEBUG)
1200ee81e68SLisandro Dalcin        self.log = logging.getLogger('gmakegen')
1210ee81e68SLisandro Dalcin        self.mistakes = Mistakes(debuglogger(self.log), verbose=verbose)
1220ee81e68SLisandro Dalcin        self.gendeps = []
1230ee81e68SLisandro Dalcin
1240ee81e68SLisandro Dalcin    def arch_path(self, *args):
1250ee81e68SLisandro Dalcin        return os.path.join(self.petsc_dir, self.petsc_arch, *args)
1260ee81e68SLisandro Dalcin
127add6df95SStefano Zampini    def pkg_arch_path(self, *args):
128c4bccdb5SStefano Zampini        return os.path.join(self.pkg_dir, self.pkg_arch, *args)
129add6df95SStefano Zampini
1300ee81e68SLisandro Dalcin    def read_conf(self):
1310ee81e68SLisandro Dalcin        self.conf = dict()
132021a2b48SJed Brown        with open(self.arch_path('include', 'petscconf.h')) as petscconf_h:
133021a2b48SJed Brown            for line in petscconf_h:
1340ee81e68SLisandro Dalcin                if line.startswith('#define '):
1350ee81e68SLisandro Dalcin                    define = line[len('#define '):]
1360ee81e68SLisandro Dalcin                    space = define.find(' ')
1370ee81e68SLisandro Dalcin                    key = define[:space]
1380ee81e68SLisandro Dalcin                    val = define[space+1:]
1390ee81e68SLisandro Dalcin                    self.conf[key] = val
140af0996ceSBarry Smith        self.conf.update(parse_makefile(self.arch_path('lib','petsc','conf', 'petscvariables')))
14147fd361eSStefano Zampini        # allow parsing package additional configurations (if any)
14247fd361eSStefano Zampini        if self.pkg_name != 'petsc' :
14347fd361eSStefano Zampini            f = self.pkg_arch_path('include', self.pkg_name + 'conf.h')
14447fd361eSStefano Zampini            if os.path.isfile(f):
145021a2b48SJed Brown                with open(self.pkg_arch_path('include', self.pkg_name + 'conf.h')) as pkg_conf_h:
146021a2b48SJed Brown                    for line in pkg_conf_h:
14747fd361eSStefano Zampini                        if line.startswith('#define '):
14847fd361eSStefano Zampini                            define = line[len('#define '):]
14947fd361eSStefano Zampini                            space = define.find(' ')
15047fd361eSStefano Zampini                            key = define[:space]
15147fd361eSStefano Zampini                            val = define[space+1:]
15247fd361eSStefano Zampini                            self.conf[key] = val
15347fd361eSStefano Zampini            f = self.pkg_arch_path('lib',self.pkg_name,'conf', self.pkg_name + 'variables')
15447fd361eSStefano Zampini            if os.path.isfile(f):
15547fd361eSStefano Zampini                self.conf.update(parse_makefile(self.pkg_arch_path('lib',self.pkg_name,'conf', self.pkg_name + 'variables')))
156fbf9dbe5SBarry Smith        self.have_fortran = int(self.conf.get('PETSC_USE_FORTRAN_BINDINGS', '0'))
1570ee81e68SLisandro Dalcin
1580ee81e68SLisandro Dalcin    def inconf(self, key, val):
1590ee81e68SLisandro Dalcin        if key in ['package', 'function', 'define']:
1600ee81e68SLisandro Dalcin            return self.conf.get(val)
1610ee81e68SLisandro Dalcin        elif key == 'precision':
1620ee81e68SLisandro Dalcin            return val == self.conf['PETSC_PRECISION']
1630ee81e68SLisandro Dalcin        elif key == 'scalar':
1640ee81e68SLisandro Dalcin            return val == self.conf['PETSC_SCALAR']
1650ee81e68SLisandro Dalcin        elif key == 'language':
1660ee81e68SLisandro Dalcin            return val == self.conf['PETSC_LANGUAGE']
1670ee81e68SLisandro Dalcin        raise RuntimeError('Unknown conf check: %s %s' % (key, val))
1680ee81e68SLisandro Dalcin
1690ee81e68SLisandro Dalcin    def relpath(self, root, src):
170add6df95SStefano Zampini        return os.path.relpath(os.path.join(root, src), self.pkg_dir)
1710ee81e68SLisandro Dalcin
1725a7ab478SBarry Smith    def get_sources_from_files(self, files):
1730ee81e68SLisandro Dalcin        """Return dict {lang: list_of_source_files}"""
1740ee81e68SLisandro Dalcin        source = dict()
1750ee81e68SLisandro Dalcin        for lang, sourcelang in LANGS.items():
1765a7ab478SBarry Smith            source[lang] = [f for f in files if f.endswith('.'+lang.replace('_','.'))]
1775a7ab478SBarry Smith            files = [f for f in files if not f.endswith('.'+lang.replace('_','.'))]
1780ee81e68SLisandro Dalcin        return source
1790ee81e68SLisandro Dalcin
1800ee81e68SLisandro Dalcin    def gen_pkg(self, pkg):
18113d87ab8SBarry Smith        from itertools import chain
1820ee81e68SLisandro Dalcin        pkgsrcs = dict()
1830ee81e68SLisandro Dalcin        for lang in LANGS:
1840ee81e68SLisandro Dalcin            pkgsrcs[lang] = []
185c729af5eSJose E. Roman        for root, dirs, files in chain.from_iterable(os.walk(path) for path in [os.path.join(self.pkg_dir, 'src', pkg),os.path.join(self.pkg_dir, self.pkg_arch, 'src', pkg)]):
1864bfab837SSebastian Grimberg            if SKIPDIRS.intersection(pathsplit(self.pkg_dir, root)): continue
18709a6cbfcSBernhard M. Wiedemann            dirs.sort()
18809a6cbfcSBernhard M. Wiedemann            files.sort()
1890ee81e68SLisandro Dalcin            makefile = os.path.join(root,'makefile')
19013d87ab8SBarry Smith            if os.path.isfile(makefile):
191021a2b48SJed Brown              with open(makefile) as mklines:
1920ee81e68SLisandro Dalcin                conditions = set(tuple(stripsplit(line)) for line in mklines if line.startswith('#requires'))
1930ee81e68SLisandro Dalcin              if not all(self.inconf(key, val) for key, val in conditions):
1940ee81e68SLisandro Dalcin                dirs[:] = []
1950ee81e68SLisandro Dalcin                continue
1960ee81e68SLisandro Dalcin              makevars = parse_makefile(makefile)
1970ee81e68SLisandro Dalcin              mdirs = makevars.get('DIRS','').split() # Directories specified in the makefile
1980ee81e68SLisandro Dalcin              self.mistakes.compareDirLists(root, mdirs, dirs) # diagnostic output to find unused directories
1990ee81e68SLisandro Dalcin              candidates = set(mdirs).union(AUTODIRS).difference(SKIPDIRS)
2000ee81e68SLisandro Dalcin              dirs[:] = list(candidates.intersection(dirs))
2010ee81e68SLisandro Dalcin            allsource = []
2020ee81e68SLisandro Dalcin            def mkrel(src):
2030ee81e68SLisandro Dalcin                return self.relpath(root, src)
20413d87ab8SBarry Smith            if files:
2055a7ab478SBarry Smith              source = self.get_sources_from_files(files)
2060ee81e68SLisandro Dalcin              for lang, s in source.items():
2072b757757SJed Brown                  pkgsrcs[lang] += [mkrel(t) for t in s]
20813d87ab8SBarry Smith              if os.path.isfile(makefile): self.gendeps.append(self.relpath(root, 'makefile'))
2090ee81e68SLisandro Dalcin        return pkgsrcs
2100ee81e68SLisandro Dalcin
211b0790570SJed Brown    def gen_gnumake(self, fd):
2120ee81e68SLisandro Dalcin        def write(stem, srcs):
2130ee81e68SLisandro Dalcin            for lang in LANGS:
214c0558f20SBarry Smith                fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang.replace('_','.'), srcs=' '.join(srcs[lang])))
21547fd361eSStefano Zampini        for pkg in self.pkg_pkgs:
2160ee81e68SLisandro Dalcin            srcs = self.gen_pkg(pkg)
217b0790570SJed Brown            write('srcs-' + pkg, srcs)
2180ee81e68SLisandro Dalcin        return self.gendeps
2190ee81e68SLisandro Dalcin
2200ee81e68SLisandro Dalcin    def gen_ninja(self, fd):
2210ee81e68SLisandro Dalcin        libobjs = []
22247fd361eSStefano Zampini        for pkg in self.pkg_pkgs:
2230ee81e68SLisandro Dalcin            srcs = self.gen_pkg(pkg)
2240ee81e68SLisandro Dalcin            for lang in LANGS:
2250ee81e68SLisandro Dalcin                for src in srcs[lang]:
2260ee81e68SLisandro Dalcin                    obj = '$objdir/%s.o' % src
227add6df95SStefano Zampini                    fd.write('build %(obj)s : %(lang)s_COMPILE %(src)s\n' % dict(obj=obj, lang=lang.upper(), src=os.path.join(self.pkg_dir,src)))
2280ee81e68SLisandro Dalcin                    libobjs.append(obj)
2290ee81e68SLisandro Dalcin        fd.write('\n')
2300ee81e68SLisandro Dalcin        fd.write('build $libdir/libpetsc.so : %s_LINK_SHARED %s\n\n' % ('CF'[self.have_fortran], ' '.join(libobjs)))
2310ee81e68SLisandro Dalcin        fd.write('build petsc : phony || $libdir/libpetsc.so\n\n')
2320ee81e68SLisandro Dalcin
2330ee81e68SLisandro Dalcin    def summary(self):
2340ee81e68SLisandro Dalcin        self.mistakes.summary()
2350ee81e68SLisandro Dalcin
2360ee81e68SLisandro Dalcindef WriteGnuMake(petsc):
237add6df95SStefano Zampini    arch_files = petsc.pkg_arch_path('lib',petsc.pkg_name,'conf', 'files')
238021a2b48SJed Brown    with open(arch_files, 'w') as fd:
2390ee81e68SLisandro Dalcin        gendeps = petsc.gen_gnumake(fd)
2400ee81e68SLisandro Dalcin        fd.write('\n')
2410ee81e68SLisandro Dalcin        fd.write('# Dependency to regenerate this file\n')
242add6df95SStefano Zampini        fd.write('%s : %s %s\n' % (os.path.relpath(arch_files, petsc.pkg_dir),
243add6df95SStefano Zampini                                   os.path.relpath(__file__, os.path.realpath(petsc.pkg_dir)),
2440ee81e68SLisandro Dalcin                                   ' '.join(gendeps)))
2450ee81e68SLisandro Dalcin        fd.write('\n')
2460ee81e68SLisandro Dalcin        fd.write('# Dummy dependencies in case makefiles are removed\n')
2470ee81e68SLisandro Dalcin        fd.write(''.join([dep + ':\n' for dep in gendeps]))
2480ee81e68SLisandro Dalcin
2490ee81e68SLisandro Dalcindef WriteNinja(petsc):
2500ee81e68SLisandro Dalcin    conf = dict()
251af0996ceSBarry Smith    parse_makefile(os.path.join(petsc.petsc_dir, 'lib', 'petsc','conf', 'variables'), conf)
252af0996ceSBarry Smith    parse_makefile(petsc.arch_path('lib','petsc','conf', 'petscvariables'), conf)
2530ee81e68SLisandro Dalcin    build_ninja = petsc.arch_path('build.ninja')
254021a2b48SJed Brown    with open(build_ninja, 'w') as fd:
2550ee81e68SLisandro Dalcin        fd.write('objdir = obj-ninja\n')
2560ee81e68SLisandro Dalcin        fd.write('libdir = lib\n')
2570ee81e68SLisandro Dalcin        fd.write('c_compile = %(PCC)s\n' % conf)
2580ee81e68SLisandro Dalcin        fd.write('c_flags = %(PETSC_CC_INCLUDES)s %(PCC_FLAGS)s %(CCPPFLAGS)s\n' % conf)
2590ee81e68SLisandro Dalcin        fd.write('c_link = %(PCC_LINKER)s\n' % conf)
2600ee81e68SLisandro Dalcin        fd.write('c_link_flags = %(PCC_LINKER_FLAGS)s\n' % conf)
2610ee81e68SLisandro Dalcin        if petsc.have_fortran:
2620ee81e68SLisandro Dalcin            fd.write('f_compile = %(FC)s\n' % conf)
2630ee81e68SLisandro Dalcin            fd.write('f_flags = %(PETSC_FC_INCLUDES)s %(FC_FLAGS)s %(FCPPFLAGS)s\n' % conf)
2640ee81e68SLisandro Dalcin            fd.write('f_link = %(FC_LINKER)s\n' % conf)
2650ee81e68SLisandro Dalcin            fd.write('f_link_flags = %(FC_LINKER_FLAGS)s\n' % conf)
2660ee81e68SLisandro Dalcin        fd.write('petsc_external_lib = %(PETSC_EXTERNAL_LIB_BASIC)s\n' % conf)
2670ee81e68SLisandro Dalcin        fd.write('python = %(PYTHON)s\n' % conf)
2680ee81e68SLisandro Dalcin        fd.write('\n')
2690ee81e68SLisandro Dalcin        fd.write('rule C_COMPILE\n'
2700ee81e68SLisandro Dalcin                 '  command = $c_compile -MMD -MF $out.d $c_flags -c $in -o $out\n'
2710ee81e68SLisandro Dalcin                 '  description = CC $out\n'
2720ee81e68SLisandro Dalcin                 '  depfile = $out.d\n'
2730ee81e68SLisandro Dalcin                 # '  deps = gcc\n') # 'gcc' is default, 'msvc' only recognized by newer versions of ninja
2740ee81e68SLisandro Dalcin                 '\n')
2750ee81e68SLisandro Dalcin        fd.write('rule C_LINK_SHARED\n'
2760ee81e68SLisandro Dalcin                 '  command = $c_link $c_link_flags -shared -o $out $in $petsc_external_lib\n'
2770ee81e68SLisandro Dalcin                 '  description = CLINK_SHARED $out\n'
2780ee81e68SLisandro Dalcin                 '\n')
2790ee81e68SLisandro Dalcin        if petsc.have_fortran:
2800ee81e68SLisandro Dalcin            fd.write('rule F_COMPILE\n'
2810ee81e68SLisandro Dalcin                     '  command = $f_compile -MMD -MF $out.d $f_flags -c $in -o $out\n'
2820ee81e68SLisandro Dalcin                     '  description = FC $out\n'
2830ee81e68SLisandro Dalcin                     '  depfile = $out.d\n'
2840ee81e68SLisandro Dalcin                     '\n')
2850ee81e68SLisandro Dalcin            fd.write('rule F_LINK_SHARED\n'
2860ee81e68SLisandro Dalcin                     '  command = $f_link $f_link_flags -shared -o $out $in $petsc_external_lib\n'
2870ee81e68SLisandro Dalcin                     '  description = FLINK_SHARED $out\n'
2880ee81e68SLisandro Dalcin                     '\n')
2890ee81e68SLisandro Dalcin        fd.write('rule GEN_NINJA\n'
2900ee81e68SLisandro Dalcin                 '  command = $python $in --output=ninja\n'
2910ee81e68SLisandro Dalcin                 '  generator = 1\n'
2920ee81e68SLisandro Dalcin                 '\n')
2930ee81e68SLisandro Dalcin        petsc.gen_ninja(fd)
2940ee81e68SLisandro Dalcin        fd.write('\n')
2950ee81e68SLisandro Dalcin        fd.write('build %s : GEN_NINJA | %s %s %s %s\n' % (build_ninja,
2960ee81e68SLisandro Dalcin                                                           os.path.abspath(__file__),
297af0996ceSBarry Smith                                                           os.path.join(petsc.petsc_dir, 'lib','petsc','conf', 'variables'),
298af0996ceSBarry Smith                                                           petsc.arch_path('lib','petsc','conf', 'petscvariables'),
299add6df95SStefano Zampini                                                       ' '.join(os.path.join(petsc.pkg_dir, dep) for dep in petsc.gendeps)))
3000ee81e68SLisandro Dalcin
30147fd361eSStefano Zampinidef main(petsc_dir=None, petsc_arch=None, pkg_dir=None, pkg_name=None, pkg_arch=None, pkg_pkgs=None, output=None, verbose=False):
3020ee81e68SLisandro Dalcin    if output is None:
3030ee81e68SLisandro Dalcin        output = 'gnumake'
3040ee81e68SLisandro Dalcin    writer = dict(gnumake=WriteGnuMake, ninja=WriteNinja)
30547fd361eSStefano Zampini    petsc = Petsc(petsc_dir=petsc_dir, petsc_arch=petsc_arch, pkg_dir=pkg_dir, pkg_name=pkg_name, pkg_arch=pkg_arch, pkg_pkgs=pkg_pkgs, verbose=verbose)
3060ee81e68SLisandro Dalcin    writer[output](petsc)
3070ee81e68SLisandro Dalcin    petsc.summary()
3080ee81e68SLisandro Dalcin
3090ee81e68SLisandro Dalcinif __name__ == '__main__':
3100ee81e68SLisandro Dalcin    import optparse
3110ee81e68SLisandro Dalcin    parser = optparse.OptionParser()
3120ee81e68SLisandro Dalcin    parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False)
3130ee81e68SLisandro Dalcin    parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH'))
314add6df95SStefano Zampini    parser.add_option('--pkg-dir', help='Set the directory of the package (different from PETSc) you want to generate the makefile rules for', default=None)
315add6df95SStefano Zampini    parser.add_option('--pkg-name', help='Set the name of the package you want to generate the makefile rules for', default=None)
316c4bccdb5SStefano Zampini    parser.add_option('--pkg-arch', help='Set the package arch name you want to generate the makefile rules for', default=None)
31747fd361eSStefano Zampini    parser.add_option('--pkg-pkgs', help='Set the package folders (comma separated list, different from the usual sys,vec,mat etc) you want to generate the makefile rules for', default=None)
3180ee81e68SLisandro Dalcin    parser.add_option('--output', help='Location to write output file', default=None)
3190ee81e68SLisandro Dalcin    opts, extra_args = parser.parse_args()
3200ee81e68SLisandro Dalcin    if extra_args:
3210ee81e68SLisandro Dalcin        import sys
3220ee81e68SLisandro Dalcin        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
3230ee81e68SLisandro Dalcin        exit(1)
32447fd361eSStefano Zampini    main(petsc_arch=opts.petsc_arch, pkg_dir=opts.pkg_dir, pkg_name=opts.pkg_name, pkg_arch=opts.pkg_arch, pkg_pkgs=opts.pkg_pkgs, output=opts.output, verbose=opts.verbose)
325