xref: /petsc/config/gmakegen.py (revision 5a7ab478d68915ac7719a50d8dd16b5f3e87e23f)
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
11f22bedf1SBarry SmithSKIPDIRS = set('benchmarks build'.split())               # Skip these during the build
12dc0529c6SBarry SmithNOWARNDIRS = set('tests tutorials'.split())              # Do not warn about mismatch in these
13dc0529c6SBarry Smith
14dc0529c6SBarry Smithdef pathsplit(path):
15dc0529c6SBarry Smith    """Recursively split a path, returns a tuple"""
16dc0529c6SBarry Smith    stem, basename = os.path.split(path)
17dc0529c6SBarry Smith    if stem == '':
18dc0529c6SBarry Smith        return (basename,)
19dc0529c6SBarry Smith    if stem == path:            # fixed point, likely '/'
20dc0529c6SBarry Smith        return (path,)
21dc0529c6SBarry Smith    return pathsplit(stem) + (basename,)
22dc0529c6SBarry Smith
23c0558f20SBarry Smithdef getlangext(name):
24c0558f20SBarry Smith    """Returns everything after the first . in the filename, including the ."""
25c0558f20SBarry Smith    file = os.path.basename(name)
26c0558f20SBarry Smith    loc = file.find('.')
27c0558f20SBarry Smith    if loc > -1: return file[loc:]
28c0558f20SBarry Smith    else: return ''
29c0558f20SBarry Smith
30c0558f20SBarry Smithdef getlangsplit(name):
31c0558f20SBarry Smith    """Returns everything before the first . in the filename, excluding the ."""
32c0558f20SBarry Smith    file = os.path.basename(name)
33c0558f20SBarry Smith    loc = file.find('.')
34c0558f20SBarry Smith    if loc > -1: return os.path.join(os.path.dirname(name),file[:loc])
35c0558f20SBarry Smith    raise RuntimeError("No . in filename")
36c0558f20SBarry Smith
37dc0529c6SBarry Smithclass Mistakes(object):
38dc0529c6SBarry Smith    def __init__(self, log, verbose=False):
39dc0529c6SBarry Smith        self.mistakes = []
40dc0529c6SBarry Smith        self.verbose = verbose
41dc0529c6SBarry Smith        self.log = log
42dc0529c6SBarry Smith
43dc0529c6SBarry Smith    def compareDirLists(self,root, mdirs, dirs):
44dc0529c6SBarry Smith        if NOWARNDIRS.intersection(pathsplit(root)):
45dc0529c6SBarry Smith            return
46dc0529c6SBarry Smith        smdirs = set(mdirs)
47dc0529c6SBarry Smith        sdirs  = set(dirs).difference(AUTODIRS)
48dc0529c6SBarry Smith        if not smdirs.issubset(sdirs):
49cca3327aSJed Brown            self.mistakes.append('%s/makefile contains a directory not on the filesystem: %r' % (root, sorted(smdirs - sdirs)))
50dc0529c6SBarry Smith        if not self.verbose: return
51dc0529c6SBarry Smith        if smdirs != sdirs:
52dc0529c6SBarry Smith            from sys import stderr
53dc0529c6SBarry Smith            stderr.write('Directory mismatch at %s:\n\t%s: %r\n\t%s: %r\n\t%s: %r\n'
54dc0529c6SBarry Smith                         % (root,
55dc0529c6SBarry Smith                            'in makefile   ',sorted(smdirs),
56dc0529c6SBarry Smith                            'on filesystem ',sorted(sdirs),
57dc0529c6SBarry Smith                            'symmetric diff',sorted(smdirs.symmetric_difference(sdirs))))
58dc0529c6SBarry Smith
59dc0529c6SBarry Smith    def summary(self):
60dc0529c6SBarry Smith        for m in self.mistakes:
61dc0529c6SBarry Smith            self.log.write(m + '\n')
62dc0529c6SBarry Smith        if self.mistakes:
63a943032dSBarry 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)))
64dc0529c6SBarry Smith
65dc0529c6SBarry Smithdef stripsplit(line):
66dc0529c6SBarry Smith  return line[len('#requires'):].replace("'","").split()
67dc0529c6SBarry Smith
6847fd361eSStefano ZampiniPetscPKGS = 'sys vec mat dm ksp snes ts tao'.split()
69c0558f20SBarry 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 .
70*5a7ab478SBarry 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')
710ee81e68SLisandro Dalcin
720ee81e68SLisandro Dalcinclass debuglogger(object):
730ee81e68SLisandro Dalcin    def __init__(self, log):
740ee81e68SLisandro Dalcin        self._log = log
750ee81e68SLisandro Dalcin
760ee81e68SLisandro Dalcin    def write(self, string):
770ee81e68SLisandro Dalcin        self._log.debug(string)
780ee81e68SLisandro Dalcin
790ee81e68SLisandro Dalcinclass Petsc(object):
8047fd361eSStefano Zampini    def __init__(self, petsc_dir=None, petsc_arch=None, pkg_dir=None, pkg_name=None, pkg_arch=None, pkg_pkgs=None, verbose=False):
810ee81e68SLisandro Dalcin        if petsc_dir is None:
820ee81e68SLisandro Dalcin            petsc_dir = os.environ.get('PETSC_DIR')
830ee81e68SLisandro Dalcin            if petsc_dir is None:
840ee81e68SLisandro Dalcin                try:
85af0996ceSBarry Smith                    petsc_dir = parse_makefile(os.path.join('lib','petsc','conf', 'petscvariables')).get('PETSC_DIR')
860ee81e68SLisandro Dalcin                finally:
870ee81e68SLisandro Dalcin                    if petsc_dir is None:
880ee81e68SLisandro Dalcin                        raise RuntimeError('Could not determine PETSC_DIR, please set in environment')
890ee81e68SLisandro Dalcin        if petsc_arch is None:
900ee81e68SLisandro Dalcin            petsc_arch = os.environ.get('PETSC_ARCH')
910ee81e68SLisandro Dalcin            if petsc_arch is None:
920ee81e68SLisandro Dalcin                try:
93af0996ceSBarry Smith                    petsc_arch = parse_makefile(os.path.join(petsc_dir, 'lib','petsc','conf', 'petscvariables')).get('PETSC_ARCH')
940ee81e68SLisandro Dalcin                finally:
950ee81e68SLisandro Dalcin                    if petsc_arch is None:
960ee81e68SLisandro Dalcin                        raise RuntimeError('Could not determine PETSC_ARCH, please set in environment')
97add6df95SStefano Zampini        self.petsc_dir = os.path.normpath(petsc_dir)
98add6df95SStefano Zampini        self.petsc_arch = petsc_arch.rstrip(os.sep)
99add6df95SStefano Zampini        self.pkg_dir = pkg_dir
100add6df95SStefano Zampini        self.pkg_name = pkg_name
101c4bccdb5SStefano Zampini        self.pkg_arch = pkg_arch
102add6df95SStefano Zampini        if self.pkg_dir is None:
103add6df95SStefano Zampini          self.pkg_dir = petsc_dir
104add6df95SStefano Zampini          self.pkg_name = 'petsc'
105c4bccdb5SStefano Zampini          self.pkg_arch = self.petsc_arch
106add6df95SStefano Zampini        if self.pkg_name is None:
107add6df95SStefano Zampini          self.pkg_name = os.path.basename(os.path.normpath(self.pkg_dir))
108c4bccdb5SStefano Zampini        if self.pkg_arch is None:
109c4bccdb5SStefano Zampini          self.pkg_arch = self.petsc_arch
11047fd361eSStefano Zampini        self.pkg_pkgs = PetscPKGS
11147fd361eSStefano Zampini        if pkg_pkgs is not None:
11247fd361eSStefano Zampini          self.pkg_pkgs += list(set(pkg_pkgs.split(','))-set(self.pkg_pkgs))
11347fd361eSStefano Zampini        self.read_conf()
1148e69c5ecSJed Brown        try:
115add6df95SStefano Zampini            logging.basicConfig(filename=self.pkg_arch_path('lib',self.pkg_name,'conf', 'gmake.log'), level=logging.DEBUG)
1168e69c5ecSJed Brown        except IOError:
1178e69c5ecSJed Brown            # Disable logging if path is not writeable (e.g., prefix install)
1188e69c5ecSJed Brown            logging.basicConfig(filename='/dev/null', level=logging.DEBUG)
1190ee81e68SLisandro Dalcin        self.log = logging.getLogger('gmakegen')
1200ee81e68SLisandro Dalcin        self.mistakes = Mistakes(debuglogger(self.log), verbose=verbose)
1210ee81e68SLisandro Dalcin        self.gendeps = []
1220ee81e68SLisandro Dalcin
1230ee81e68SLisandro Dalcin    def arch_path(self, *args):
1240ee81e68SLisandro Dalcin        return os.path.join(self.petsc_dir, self.petsc_arch, *args)
1250ee81e68SLisandro Dalcin
126add6df95SStefano Zampini    def pkg_arch_path(self, *args):
127c4bccdb5SStefano Zampini        return os.path.join(self.pkg_dir, self.pkg_arch, *args)
128add6df95SStefano Zampini
1290ee81e68SLisandro Dalcin    def read_conf(self):
1300ee81e68SLisandro Dalcin        self.conf = dict()
131021a2b48SJed Brown        with open(self.arch_path('include', 'petscconf.h')) as petscconf_h:
132021a2b48SJed Brown            for line in petscconf_h:
1330ee81e68SLisandro Dalcin                if line.startswith('#define '):
1340ee81e68SLisandro Dalcin                    define = line[len('#define '):]
1350ee81e68SLisandro Dalcin                    space = define.find(' ')
1360ee81e68SLisandro Dalcin                    key = define[:space]
1370ee81e68SLisandro Dalcin                    val = define[space+1:]
1380ee81e68SLisandro Dalcin                    self.conf[key] = val
139af0996ceSBarry Smith        self.conf.update(parse_makefile(self.arch_path('lib','petsc','conf', 'petscvariables')))
14047fd361eSStefano Zampini        # allow parsing package additional configurations (if any)
14147fd361eSStefano Zampini        if self.pkg_name != 'petsc' :
14247fd361eSStefano Zampini            f = self.pkg_arch_path('include', self.pkg_name + 'conf.h')
14347fd361eSStefano Zampini            if os.path.isfile(f):
144021a2b48SJed Brown                with open(self.pkg_arch_path('include', self.pkg_name + 'conf.h')) as pkg_conf_h:
145021a2b48SJed Brown                    for line in pkg_conf_h:
14647fd361eSStefano Zampini                        if line.startswith('#define '):
14747fd361eSStefano Zampini                            define = line[len('#define '):]
14847fd361eSStefano Zampini                            space = define.find(' ')
14947fd361eSStefano Zampini                            key = define[:space]
15047fd361eSStefano Zampini                            val = define[space+1:]
15147fd361eSStefano Zampini                            self.conf[key] = val
15247fd361eSStefano Zampini            f = self.pkg_arch_path('lib',self.pkg_name,'conf', self.pkg_name + 'variables')
15347fd361eSStefano Zampini            if os.path.isfile(f):
15447fd361eSStefano Zampini                self.conf.update(parse_makefile(self.pkg_arch_path('lib',self.pkg_name,'conf', self.pkg_name + 'variables')))
1550ee81e68SLisandro Dalcin        self.have_fortran = int(self.conf.get('PETSC_HAVE_FORTRAN', '0'))
1560ee81e68SLisandro Dalcin
1570ee81e68SLisandro Dalcin    def inconf(self, key, val):
1580ee81e68SLisandro Dalcin        if key in ['package', 'function', 'define']:
1590ee81e68SLisandro Dalcin            return self.conf.get(val)
1600ee81e68SLisandro Dalcin        elif key == 'precision':
1610ee81e68SLisandro Dalcin            return val == self.conf['PETSC_PRECISION']
1620ee81e68SLisandro Dalcin        elif key == 'scalar':
1630ee81e68SLisandro Dalcin            return val == self.conf['PETSC_SCALAR']
1640ee81e68SLisandro Dalcin        elif key == 'language':
1650ee81e68SLisandro Dalcin            return val == self.conf['PETSC_LANGUAGE']
1660ee81e68SLisandro Dalcin        raise RuntimeError('Unknown conf check: %s %s' % (key, val))
1670ee81e68SLisandro Dalcin
1680ee81e68SLisandro Dalcin    def relpath(self, root, src):
169add6df95SStefano Zampini        return os.path.relpath(os.path.join(root, src), self.pkg_dir)
1700ee81e68SLisandro Dalcin
171*5a7ab478SBarry Smith    def get_sources_from_files(self, files):
1720ee81e68SLisandro Dalcin        """Return dict {lang: list_of_source_files}"""
1730ee81e68SLisandro Dalcin        source = dict()
1740ee81e68SLisandro Dalcin        for lang, sourcelang in LANGS.items():
175*5a7ab478SBarry Smith            source[lang] = [f for f in files if f.endswith('.'+lang.replace('_','.'))]
176*5a7ab478SBarry Smith            files = [f for f in files if not f.endswith('.'+lang.replace('_','.'))]
1770ee81e68SLisandro Dalcin        return source
1780ee81e68SLisandro Dalcin
1790ee81e68SLisandro Dalcin    def gen_pkg(self, pkg):
1800ee81e68SLisandro Dalcin        pkgsrcs = dict()
1810ee81e68SLisandro Dalcin        for lang in LANGS:
1820ee81e68SLisandro Dalcin            pkgsrcs[lang] = []
183add6df95SStefano Zampini        for root, dirs, files in os.walk(os.path.join(self.pkg_dir, 'src', pkg)):
184*5a7ab478SBarry Smith            if NOWARNDIRS.intersection(pathsplit(root)): continue
18509a6cbfcSBernhard M. Wiedemann            dirs.sort()
18609a6cbfcSBernhard M. Wiedemann            files.sort()
1870ee81e68SLisandro Dalcin            makefile = os.path.join(root,'makefile')
1880ee81e68SLisandro Dalcin            if not os.path.exists(makefile):
1890ee81e68SLisandro Dalcin                dirs[:] = []
1900ee81e68SLisandro Dalcin                continue
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)
204*5a7ab478SBarry Smith            source = self.get_sources_from_files(files)
2050ee81e68SLisandro Dalcin            for lang, s in source.items():
2062b757757SJed Brown                pkgsrcs[lang] += [mkrel(t) for t in s]
2070ee81e68SLisandro Dalcin            self.gendeps.append(self.relpath(root, 'makefile'))
2080ee81e68SLisandro Dalcin        return pkgsrcs
2090ee81e68SLisandro Dalcin
210b0790570SJed Brown    def gen_gnumake(self, fd):
2110ee81e68SLisandro Dalcin        def write(stem, srcs):
2120ee81e68SLisandro Dalcin            for lang in LANGS:
213c0558f20SBarry Smith                fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang.replace('_','.'), srcs=' '.join(srcs[lang])))
21447fd361eSStefano Zampini        for pkg in self.pkg_pkgs:
2150ee81e68SLisandro Dalcin            srcs = self.gen_pkg(pkg)
216b0790570SJed Brown            write('srcs-' + pkg, srcs)
2170ee81e68SLisandro Dalcin        return self.gendeps
2180ee81e68SLisandro Dalcin
2190ee81e68SLisandro Dalcin    def gen_ninja(self, fd):
2200ee81e68SLisandro Dalcin        libobjs = []
22147fd361eSStefano Zampini        for pkg in self.pkg_pkgs:
2220ee81e68SLisandro Dalcin            srcs = self.gen_pkg(pkg)
2230ee81e68SLisandro Dalcin            for lang in LANGS:
2240ee81e68SLisandro Dalcin                for src in srcs[lang]:
2250ee81e68SLisandro Dalcin                    obj = '$objdir/%s.o' % src
226add6df95SStefano 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)))
2270ee81e68SLisandro Dalcin                    libobjs.append(obj)
2280ee81e68SLisandro Dalcin        fd.write('\n')
2290ee81e68SLisandro Dalcin        fd.write('build $libdir/libpetsc.so : %s_LINK_SHARED %s\n\n' % ('CF'[self.have_fortran], ' '.join(libobjs)))
2300ee81e68SLisandro Dalcin        fd.write('build petsc : phony || $libdir/libpetsc.so\n\n')
2310ee81e68SLisandro Dalcin
2320ee81e68SLisandro Dalcin    def summary(self):
2330ee81e68SLisandro Dalcin        self.mistakes.summary()
2340ee81e68SLisandro Dalcin
2350ee81e68SLisandro Dalcindef WriteGnuMake(petsc):
236add6df95SStefano Zampini    arch_files = petsc.pkg_arch_path('lib',petsc.pkg_name,'conf', 'files')
237021a2b48SJed Brown    with open(arch_files, 'w') as fd:
2380ee81e68SLisandro Dalcin        gendeps = petsc.gen_gnumake(fd)
2390ee81e68SLisandro Dalcin        fd.write('\n')
2400ee81e68SLisandro Dalcin        fd.write('# Dependency to regenerate this file\n')
241add6df95SStefano Zampini        fd.write('%s : %s %s\n' % (os.path.relpath(arch_files, petsc.pkg_dir),
242add6df95SStefano Zampini                                   os.path.relpath(__file__, os.path.realpath(petsc.pkg_dir)),
2430ee81e68SLisandro Dalcin                                   ' '.join(gendeps)))
2440ee81e68SLisandro Dalcin        fd.write('\n')
2450ee81e68SLisandro Dalcin        fd.write('# Dummy dependencies in case makefiles are removed\n')
2460ee81e68SLisandro Dalcin        fd.write(''.join([dep + ':\n' for dep in gendeps]))
2470ee81e68SLisandro Dalcin
2480ee81e68SLisandro Dalcindef WriteNinja(petsc):
2490ee81e68SLisandro Dalcin    conf = dict()
250af0996ceSBarry Smith    parse_makefile(os.path.join(petsc.petsc_dir, 'lib', 'petsc','conf', 'variables'), conf)
251af0996ceSBarry Smith    parse_makefile(petsc.arch_path('lib','petsc','conf', 'petscvariables'), conf)
2520ee81e68SLisandro Dalcin    build_ninja = petsc.arch_path('build.ninja')
253021a2b48SJed Brown    with open(build_ninja, 'w') as fd:
2540ee81e68SLisandro Dalcin        fd.write('objdir = obj-ninja\n')
2550ee81e68SLisandro Dalcin        fd.write('libdir = lib\n')
2560ee81e68SLisandro Dalcin        fd.write('c_compile = %(PCC)s\n' % conf)
2570ee81e68SLisandro Dalcin        fd.write('c_flags = %(PETSC_CC_INCLUDES)s %(PCC_FLAGS)s %(CCPPFLAGS)s\n' % conf)
2580ee81e68SLisandro Dalcin        fd.write('c_link = %(PCC_LINKER)s\n' % conf)
2590ee81e68SLisandro Dalcin        fd.write('c_link_flags = %(PCC_LINKER_FLAGS)s\n' % conf)
2600ee81e68SLisandro Dalcin        if petsc.have_fortran:
2610ee81e68SLisandro Dalcin            fd.write('f_compile = %(FC)s\n' % conf)
2620ee81e68SLisandro Dalcin            fd.write('f_flags = %(PETSC_FC_INCLUDES)s %(FC_FLAGS)s %(FCPPFLAGS)s\n' % conf)
2630ee81e68SLisandro Dalcin            fd.write('f_link = %(FC_LINKER)s\n' % conf)
2640ee81e68SLisandro Dalcin            fd.write('f_link_flags = %(FC_LINKER_FLAGS)s\n' % conf)
2650ee81e68SLisandro Dalcin        fd.write('petsc_external_lib = %(PETSC_EXTERNAL_LIB_BASIC)s\n' % conf)
2660ee81e68SLisandro Dalcin        fd.write('python = %(PYTHON)s\n' % conf)
2670ee81e68SLisandro Dalcin        fd.write('\n')
2680ee81e68SLisandro Dalcin        fd.write('rule C_COMPILE\n'
2690ee81e68SLisandro Dalcin                 '  command = $c_compile -MMD -MF $out.d $c_flags -c $in -o $out\n'
2700ee81e68SLisandro Dalcin                 '  description = CC $out\n'
2710ee81e68SLisandro Dalcin                 '  depfile = $out.d\n'
2720ee81e68SLisandro Dalcin                 # '  deps = gcc\n') # 'gcc' is default, 'msvc' only recognized by newer versions of ninja
2730ee81e68SLisandro Dalcin                 '\n')
2740ee81e68SLisandro Dalcin        fd.write('rule C_LINK_SHARED\n'
2750ee81e68SLisandro Dalcin                 '  command = $c_link $c_link_flags -shared -o $out $in $petsc_external_lib\n'
2760ee81e68SLisandro Dalcin                 '  description = CLINK_SHARED $out\n'
2770ee81e68SLisandro Dalcin                 '\n')
2780ee81e68SLisandro Dalcin        if petsc.have_fortran:
2790ee81e68SLisandro Dalcin            fd.write('rule F_COMPILE\n'
2800ee81e68SLisandro Dalcin                     '  command = $f_compile -MMD -MF $out.d $f_flags -c $in -o $out\n'
2810ee81e68SLisandro Dalcin                     '  description = FC $out\n'
2820ee81e68SLisandro Dalcin                     '  depfile = $out.d\n'
2830ee81e68SLisandro Dalcin                     '\n')
2840ee81e68SLisandro Dalcin            fd.write('rule F_LINK_SHARED\n'
2850ee81e68SLisandro Dalcin                     '  command = $f_link $f_link_flags -shared -o $out $in $petsc_external_lib\n'
2860ee81e68SLisandro Dalcin                     '  description = FLINK_SHARED $out\n'
2870ee81e68SLisandro Dalcin                     '\n')
2880ee81e68SLisandro Dalcin        fd.write('rule GEN_NINJA\n'
2890ee81e68SLisandro Dalcin                 '  command = $python $in --output=ninja\n'
2900ee81e68SLisandro Dalcin                 '  generator = 1\n'
2910ee81e68SLisandro Dalcin                 '\n')
2920ee81e68SLisandro Dalcin        petsc.gen_ninja(fd)
2930ee81e68SLisandro Dalcin        fd.write('\n')
2940ee81e68SLisandro Dalcin        fd.write('build %s : GEN_NINJA | %s %s %s %s\n' % (build_ninja,
2950ee81e68SLisandro Dalcin                                                           os.path.abspath(__file__),
296af0996ceSBarry Smith                                                           os.path.join(petsc.petsc_dir, 'lib','petsc','conf', 'variables'),
297af0996ceSBarry Smith                                                           petsc.arch_path('lib','petsc','conf', 'petscvariables'),
298add6df95SStefano Zampini                                                       ' '.join(os.path.join(petsc.pkg_dir, dep) for dep in petsc.gendeps)))
2990ee81e68SLisandro Dalcin
30047fd361eSStefano Zampinidef main(petsc_dir=None, petsc_arch=None, pkg_dir=None, pkg_name=None, pkg_arch=None, pkg_pkgs=None, output=None, verbose=False):
3010ee81e68SLisandro Dalcin    if output is None:
3020ee81e68SLisandro Dalcin        output = 'gnumake'
3030ee81e68SLisandro Dalcin    writer = dict(gnumake=WriteGnuMake, ninja=WriteNinja)
30447fd361eSStefano 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)
3050ee81e68SLisandro Dalcin    writer[output](petsc)
3060ee81e68SLisandro Dalcin    petsc.summary()
3070ee81e68SLisandro Dalcin
3080ee81e68SLisandro Dalcinif __name__ == '__main__':
3090ee81e68SLisandro Dalcin    import optparse
3100ee81e68SLisandro Dalcin    parser = optparse.OptionParser()
3110ee81e68SLisandro Dalcin    parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False)
3120ee81e68SLisandro Dalcin    parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH'))
313add6df95SStefano 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)
314add6df95SStefano Zampini    parser.add_option('--pkg-name', help='Set the name of the package you want to generate the makefile rules for', default=None)
315c4bccdb5SStefano Zampini    parser.add_option('--pkg-arch', help='Set the package arch name you want to generate the makefile rules for', default=None)
31647fd361eSStefano 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)
3170ee81e68SLisandro Dalcin    parser.add_option('--output', help='Location to write output file', default=None)
3180ee81e68SLisandro Dalcin    opts, extra_args = parser.parse_args()
3190ee81e68SLisandro Dalcin    if extra_args:
3200ee81e68SLisandro Dalcin        import sys
3210ee81e68SLisandro Dalcin        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
3220ee81e68SLisandro Dalcin        exit(1)
32347fd361eSStefano 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)
324