xref: /petsc/config/gmakegen.py (revision b75c6efc21bfcba5897c8ca359bc3d0e82c122c1)
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
11*b75c6efcSBarry SmithSKIPDIRS = set('benchmarks build mex-scripts tests tutorials'.split())       # Skip these during the build
12dc0529c6SBarry Smith
13dc0529c6SBarry Smithdef pathsplit(path):
14dc0529c6SBarry Smith    """Recursively split a path, returns a tuple"""
15dc0529c6SBarry Smith    stem, basename = os.path.split(path)
16dc0529c6SBarry Smith    if stem == '':
17dc0529c6SBarry Smith        return (basename,)
18dc0529c6SBarry Smith    if stem == path:            # fixed point, likely '/'
19dc0529c6SBarry Smith        return (path,)
20dc0529c6SBarry Smith    return pathsplit(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):
43*b75c6efcSBarry Smith        if SKIPDIRS.intersection(pathsplit(root)):
44dc0529c6SBarry Smith            return
45dc0529c6SBarry Smith        smdirs = set(mdirs)
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:
11147fd361eSStefano Zampini          self.pkg_pkgs += list(set(pkg_pkgs.split(','))-set(self.pkg_pkgs))
11247fd361eSStefano Zampini        self.read_conf()
1138e69c5ecSJed Brown        try:
114add6df95SStefano Zampini            logging.basicConfig(filename=self.pkg_arch_path('lib',self.pkg_name,'conf', 'gmake.log'), level=logging.DEBUG)
1158e69c5ecSJed Brown        except IOError:
1168e69c5ecSJed Brown            # Disable logging if path is not writeable (e.g., prefix install)
1178e69c5ecSJed Brown            logging.basicConfig(filename='/dev/null', level=logging.DEBUG)
1180ee81e68SLisandro Dalcin        self.log = logging.getLogger('gmakegen')
1190ee81e68SLisandro Dalcin        self.mistakes = Mistakes(debuglogger(self.log), verbose=verbose)
1200ee81e68SLisandro Dalcin        self.gendeps = []
1210ee81e68SLisandro Dalcin
1220ee81e68SLisandro Dalcin    def arch_path(self, *args):
1230ee81e68SLisandro Dalcin        return os.path.join(self.petsc_dir, self.petsc_arch, *args)
1240ee81e68SLisandro Dalcin
125add6df95SStefano Zampini    def pkg_arch_path(self, *args):
126c4bccdb5SStefano Zampini        return os.path.join(self.pkg_dir, self.pkg_arch, *args)
127add6df95SStefano Zampini
1280ee81e68SLisandro Dalcin    def read_conf(self):
1290ee81e68SLisandro Dalcin        self.conf = dict()
130021a2b48SJed Brown        with open(self.arch_path('include', 'petscconf.h')) as petscconf_h:
131021a2b48SJed Brown            for line in petscconf_h:
1320ee81e68SLisandro Dalcin                if line.startswith('#define '):
1330ee81e68SLisandro Dalcin                    define = line[len('#define '):]
1340ee81e68SLisandro Dalcin                    space = define.find(' ')
1350ee81e68SLisandro Dalcin                    key = define[:space]
1360ee81e68SLisandro Dalcin                    val = define[space+1:]
1370ee81e68SLisandro Dalcin                    self.conf[key] = val
138af0996ceSBarry Smith        self.conf.update(parse_makefile(self.arch_path('lib','petsc','conf', 'petscvariables')))
13947fd361eSStefano Zampini        # allow parsing package additional configurations (if any)
14047fd361eSStefano Zampini        if self.pkg_name != 'petsc' :
14147fd361eSStefano Zampini            f = self.pkg_arch_path('include', self.pkg_name + 'conf.h')
14247fd361eSStefano Zampini            if os.path.isfile(f):
143021a2b48SJed Brown                with open(self.pkg_arch_path('include', self.pkg_name + 'conf.h')) as pkg_conf_h:
144021a2b48SJed Brown                    for line in pkg_conf_h:
14547fd361eSStefano Zampini                        if line.startswith('#define '):
14647fd361eSStefano Zampini                            define = line[len('#define '):]
14747fd361eSStefano Zampini                            space = define.find(' ')
14847fd361eSStefano Zampini                            key = define[:space]
14947fd361eSStefano Zampini                            val = define[space+1:]
15047fd361eSStefano Zampini                            self.conf[key] = val
15147fd361eSStefano Zampini            f = self.pkg_arch_path('lib',self.pkg_name,'conf', self.pkg_name + 'variables')
15247fd361eSStefano Zampini            if os.path.isfile(f):
15347fd361eSStefano Zampini                self.conf.update(parse_makefile(self.pkg_arch_path('lib',self.pkg_name,'conf', self.pkg_name + 'variables')))
1540ee81e68SLisandro Dalcin        self.have_fortran = int(self.conf.get('PETSC_HAVE_FORTRAN', '0'))
1550ee81e68SLisandro Dalcin
1560ee81e68SLisandro Dalcin    def inconf(self, key, val):
1570ee81e68SLisandro Dalcin        if key in ['package', 'function', 'define']:
1580ee81e68SLisandro Dalcin            return self.conf.get(val)
1590ee81e68SLisandro Dalcin        elif key == 'precision':
1600ee81e68SLisandro Dalcin            return val == self.conf['PETSC_PRECISION']
1610ee81e68SLisandro Dalcin        elif key == 'scalar':
1620ee81e68SLisandro Dalcin            return val == self.conf['PETSC_SCALAR']
1630ee81e68SLisandro Dalcin        elif key == 'language':
1640ee81e68SLisandro Dalcin            return val == self.conf['PETSC_LANGUAGE']
1650ee81e68SLisandro Dalcin        raise RuntimeError('Unknown conf check: %s %s' % (key, val))
1660ee81e68SLisandro Dalcin
1670ee81e68SLisandro Dalcin    def relpath(self, root, src):
168add6df95SStefano Zampini        return os.path.relpath(os.path.join(root, src), self.pkg_dir)
1690ee81e68SLisandro Dalcin
1705a7ab478SBarry Smith    def get_sources_from_files(self, files):
1710ee81e68SLisandro Dalcin        """Return dict {lang: list_of_source_files}"""
1720ee81e68SLisandro Dalcin        source = dict()
1730ee81e68SLisandro Dalcin        for lang, sourcelang in LANGS.items():
1745a7ab478SBarry Smith            source[lang] = [f for f in files if f.endswith('.'+lang.replace('_','.'))]
1755a7ab478SBarry Smith            files = [f for f in files if not f.endswith('.'+lang.replace('_','.'))]
1760ee81e68SLisandro Dalcin        return source
1770ee81e68SLisandro Dalcin
1780ee81e68SLisandro Dalcin    def gen_pkg(self, pkg):
1790ee81e68SLisandro Dalcin        pkgsrcs = dict()
1800ee81e68SLisandro Dalcin        for lang in LANGS:
1810ee81e68SLisandro Dalcin            pkgsrcs[lang] = []
182add6df95SStefano Zampini        for root, dirs, files in os.walk(os.path.join(self.pkg_dir, 'src', pkg)):
183*b75c6efcSBarry Smith            if SKIPDIRS.intersection(pathsplit(root)): continue
18409a6cbfcSBernhard M. Wiedemann            dirs.sort()
18509a6cbfcSBernhard M. Wiedemann            files.sort()
1860ee81e68SLisandro Dalcin            makefile = os.path.join(root,'makefile')
1870ee81e68SLisandro Dalcin            if not os.path.exists(makefile):
1880ee81e68SLisandro Dalcin                dirs[:] = []
1890ee81e68SLisandro Dalcin                continue
190021a2b48SJed Brown            with open(makefile) as mklines:
1910ee81e68SLisandro Dalcin                conditions = set(tuple(stripsplit(line)) for line in mklines if line.startswith('#requires'))
1920ee81e68SLisandro Dalcin            if not all(self.inconf(key, val) for key, val in conditions):
1930ee81e68SLisandro Dalcin                dirs[:] = []
1940ee81e68SLisandro Dalcin                continue
1950ee81e68SLisandro Dalcin            makevars = parse_makefile(makefile)
1960ee81e68SLisandro Dalcin            mdirs = makevars.get('DIRS','').split() # Directories specified in the makefile
1970ee81e68SLisandro Dalcin            self.mistakes.compareDirLists(root, mdirs, dirs) # diagnostic output to find unused directories
1980ee81e68SLisandro Dalcin            candidates = set(mdirs).union(AUTODIRS).difference(SKIPDIRS)
1990ee81e68SLisandro Dalcin            dirs[:] = list(candidates.intersection(dirs))
2000ee81e68SLisandro Dalcin            allsource = []
2010ee81e68SLisandro Dalcin            def mkrel(src):
2020ee81e68SLisandro Dalcin                return self.relpath(root, src)
2035a7ab478SBarry Smith            source = self.get_sources_from_files(files)
2040ee81e68SLisandro Dalcin            for lang, s in source.items():
2052b757757SJed Brown                pkgsrcs[lang] += [mkrel(t) for t in s]
2060ee81e68SLisandro Dalcin            self.gendeps.append(self.relpath(root, 'makefile'))
2070ee81e68SLisandro Dalcin        return pkgsrcs
2080ee81e68SLisandro Dalcin
209b0790570SJed Brown    def gen_gnumake(self, fd):
2100ee81e68SLisandro Dalcin        def write(stem, srcs):
2110ee81e68SLisandro Dalcin            for lang in LANGS:
212c0558f20SBarry Smith                fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang.replace('_','.'), srcs=' '.join(srcs[lang])))
21347fd361eSStefano Zampini        for pkg in self.pkg_pkgs:
2140ee81e68SLisandro Dalcin            srcs = self.gen_pkg(pkg)
215b0790570SJed Brown            write('srcs-' + pkg, srcs)
2160ee81e68SLisandro Dalcin        return self.gendeps
2170ee81e68SLisandro Dalcin
2180ee81e68SLisandro Dalcin    def gen_ninja(self, fd):
2190ee81e68SLisandro Dalcin        libobjs = []
22047fd361eSStefano Zampini        for pkg in self.pkg_pkgs:
2210ee81e68SLisandro Dalcin            srcs = self.gen_pkg(pkg)
2220ee81e68SLisandro Dalcin            for lang in LANGS:
2230ee81e68SLisandro Dalcin                for src in srcs[lang]:
2240ee81e68SLisandro Dalcin                    obj = '$objdir/%s.o' % src
225add6df95SStefano 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)))
2260ee81e68SLisandro Dalcin                    libobjs.append(obj)
2270ee81e68SLisandro Dalcin        fd.write('\n')
2280ee81e68SLisandro Dalcin        fd.write('build $libdir/libpetsc.so : %s_LINK_SHARED %s\n\n' % ('CF'[self.have_fortran], ' '.join(libobjs)))
2290ee81e68SLisandro Dalcin        fd.write('build petsc : phony || $libdir/libpetsc.so\n\n')
2300ee81e68SLisandro Dalcin
2310ee81e68SLisandro Dalcin    def summary(self):
2320ee81e68SLisandro Dalcin        self.mistakes.summary()
2330ee81e68SLisandro Dalcin
2340ee81e68SLisandro Dalcindef WriteGnuMake(petsc):
235add6df95SStefano Zampini    arch_files = petsc.pkg_arch_path('lib',petsc.pkg_name,'conf', 'files')
236021a2b48SJed Brown    with open(arch_files, 'w') as fd:
2370ee81e68SLisandro Dalcin        gendeps = petsc.gen_gnumake(fd)
2380ee81e68SLisandro Dalcin        fd.write('\n')
2390ee81e68SLisandro Dalcin        fd.write('# Dependency to regenerate this file\n')
240add6df95SStefano Zampini        fd.write('%s : %s %s\n' % (os.path.relpath(arch_files, petsc.pkg_dir),
241add6df95SStefano Zampini                                   os.path.relpath(__file__, os.path.realpath(petsc.pkg_dir)),
2420ee81e68SLisandro Dalcin                                   ' '.join(gendeps)))
2430ee81e68SLisandro Dalcin        fd.write('\n')
2440ee81e68SLisandro Dalcin        fd.write('# Dummy dependencies in case makefiles are removed\n')
2450ee81e68SLisandro Dalcin        fd.write(''.join([dep + ':\n' for dep in gendeps]))
2460ee81e68SLisandro Dalcin
2470ee81e68SLisandro Dalcindef WriteNinja(petsc):
2480ee81e68SLisandro Dalcin    conf = dict()
249af0996ceSBarry Smith    parse_makefile(os.path.join(petsc.petsc_dir, 'lib', 'petsc','conf', 'variables'), conf)
250af0996ceSBarry Smith    parse_makefile(petsc.arch_path('lib','petsc','conf', 'petscvariables'), conf)
2510ee81e68SLisandro Dalcin    build_ninja = petsc.arch_path('build.ninja')
252021a2b48SJed Brown    with open(build_ninja, 'w') as fd:
2530ee81e68SLisandro Dalcin        fd.write('objdir = obj-ninja\n')
2540ee81e68SLisandro Dalcin        fd.write('libdir = lib\n')
2550ee81e68SLisandro Dalcin        fd.write('c_compile = %(PCC)s\n' % conf)
2560ee81e68SLisandro Dalcin        fd.write('c_flags = %(PETSC_CC_INCLUDES)s %(PCC_FLAGS)s %(CCPPFLAGS)s\n' % conf)
2570ee81e68SLisandro Dalcin        fd.write('c_link = %(PCC_LINKER)s\n' % conf)
2580ee81e68SLisandro Dalcin        fd.write('c_link_flags = %(PCC_LINKER_FLAGS)s\n' % conf)
2590ee81e68SLisandro Dalcin        if petsc.have_fortran:
2600ee81e68SLisandro Dalcin            fd.write('f_compile = %(FC)s\n' % conf)
2610ee81e68SLisandro Dalcin            fd.write('f_flags = %(PETSC_FC_INCLUDES)s %(FC_FLAGS)s %(FCPPFLAGS)s\n' % conf)
2620ee81e68SLisandro Dalcin            fd.write('f_link = %(FC_LINKER)s\n' % conf)
2630ee81e68SLisandro Dalcin            fd.write('f_link_flags = %(FC_LINKER_FLAGS)s\n' % conf)
2640ee81e68SLisandro Dalcin        fd.write('petsc_external_lib = %(PETSC_EXTERNAL_LIB_BASIC)s\n' % conf)
2650ee81e68SLisandro Dalcin        fd.write('python = %(PYTHON)s\n' % conf)
2660ee81e68SLisandro Dalcin        fd.write('\n')
2670ee81e68SLisandro Dalcin        fd.write('rule C_COMPILE\n'
2680ee81e68SLisandro Dalcin                 '  command = $c_compile -MMD -MF $out.d $c_flags -c $in -o $out\n'
2690ee81e68SLisandro Dalcin                 '  description = CC $out\n'
2700ee81e68SLisandro Dalcin                 '  depfile = $out.d\n'
2710ee81e68SLisandro Dalcin                 # '  deps = gcc\n') # 'gcc' is default, 'msvc' only recognized by newer versions of ninja
2720ee81e68SLisandro Dalcin                 '\n')
2730ee81e68SLisandro Dalcin        fd.write('rule C_LINK_SHARED\n'
2740ee81e68SLisandro Dalcin                 '  command = $c_link $c_link_flags -shared -o $out $in $petsc_external_lib\n'
2750ee81e68SLisandro Dalcin                 '  description = CLINK_SHARED $out\n'
2760ee81e68SLisandro Dalcin                 '\n')
2770ee81e68SLisandro Dalcin        if petsc.have_fortran:
2780ee81e68SLisandro Dalcin            fd.write('rule F_COMPILE\n'
2790ee81e68SLisandro Dalcin                     '  command = $f_compile -MMD -MF $out.d $f_flags -c $in -o $out\n'
2800ee81e68SLisandro Dalcin                     '  description = FC $out\n'
2810ee81e68SLisandro Dalcin                     '  depfile = $out.d\n'
2820ee81e68SLisandro Dalcin                     '\n')
2830ee81e68SLisandro Dalcin            fd.write('rule F_LINK_SHARED\n'
2840ee81e68SLisandro Dalcin                     '  command = $f_link $f_link_flags -shared -o $out $in $petsc_external_lib\n'
2850ee81e68SLisandro Dalcin                     '  description = FLINK_SHARED $out\n'
2860ee81e68SLisandro Dalcin                     '\n')
2870ee81e68SLisandro Dalcin        fd.write('rule GEN_NINJA\n'
2880ee81e68SLisandro Dalcin                 '  command = $python $in --output=ninja\n'
2890ee81e68SLisandro Dalcin                 '  generator = 1\n'
2900ee81e68SLisandro Dalcin                 '\n')
2910ee81e68SLisandro Dalcin        petsc.gen_ninja(fd)
2920ee81e68SLisandro Dalcin        fd.write('\n')
2930ee81e68SLisandro Dalcin        fd.write('build %s : GEN_NINJA | %s %s %s %s\n' % (build_ninja,
2940ee81e68SLisandro Dalcin                                                           os.path.abspath(__file__),
295af0996ceSBarry Smith                                                           os.path.join(petsc.petsc_dir, 'lib','petsc','conf', 'variables'),
296af0996ceSBarry Smith                                                           petsc.arch_path('lib','petsc','conf', 'petscvariables'),
297add6df95SStefano Zampini                                                       ' '.join(os.path.join(petsc.pkg_dir, dep) for dep in petsc.gendeps)))
2980ee81e68SLisandro Dalcin
29947fd361eSStefano Zampinidef main(petsc_dir=None, petsc_arch=None, pkg_dir=None, pkg_name=None, pkg_arch=None, pkg_pkgs=None, output=None, verbose=False):
3000ee81e68SLisandro Dalcin    if output is None:
3010ee81e68SLisandro Dalcin        output = 'gnumake'
3020ee81e68SLisandro Dalcin    writer = dict(gnumake=WriteGnuMake, ninja=WriteNinja)
30347fd361eSStefano 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)
3040ee81e68SLisandro Dalcin    writer[output](petsc)
3050ee81e68SLisandro Dalcin    petsc.summary()
3060ee81e68SLisandro Dalcin
3070ee81e68SLisandro Dalcinif __name__ == '__main__':
3080ee81e68SLisandro Dalcin    import optparse
3090ee81e68SLisandro Dalcin    parser = optparse.OptionParser()
3100ee81e68SLisandro Dalcin    parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False)
3110ee81e68SLisandro Dalcin    parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH'))
312add6df95SStefano 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)
313add6df95SStefano Zampini    parser.add_option('--pkg-name', help='Set the name of the package you want to generate the makefile rules for', default=None)
314c4bccdb5SStefano Zampini    parser.add_option('--pkg-arch', help='Set the package arch name you want to generate the makefile rules for', default=None)
31547fd361eSStefano 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)
3160ee81e68SLisandro Dalcin    parser.add_option('--output', help='Location to write output file', default=None)
3170ee81e68SLisandro Dalcin    opts, extra_args = parser.parse_args()
3180ee81e68SLisandro Dalcin    if extra_args:
3190ee81e68SLisandro Dalcin        import sys
3200ee81e68SLisandro Dalcin        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
3210ee81e68SLisandro Dalcin        exit(1)
32247fd361eSStefano 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)
323