#!/usr/bin/env python """Ninja build generator""" import argparse import os import pipes import sys import platform import toolchain import syntax class Generator(object): def __init__(self, project, includepaths = [], dependlibs = [], libpaths = [], variables = None): parser = argparse.ArgumentParser(description = 'Ninja build generator') parser.add_argument('-t', '--target', help = 'Target platform', choices = platform.supported_platforms()) parser.add_argument('--host', help = 'Host platform', choices = platform.supported_platforms()) parser.add_argument('--toolchain', help = 'Toolchain to use', choices = toolchain.supported_toolchains()) parser.add_argument('-c', '--config', action = 'append', help = 'Build configuration', choices = ['debug', 'release', 'profile', 'deploy'], default = []) parser.add_argument('-a', '--arch', action = 'append', help = 'Add architecture', choices = toolchain.supported_architectures(), default = []) parser.add_argument('-i', '--includepath', action = 'append', help = 'Add include path', default = []) parser.add_argument('--monolithic', action='store_true', help = 'Build monolithic test suite', default = False) parser.add_argument('--coverage', action='store_true', help = 'Build with code coverage', default = False) parser.add_argument('--subninja', action='store', help = 'Build as subproject (exclude rules and pools) with the given subpath', default = '') parser.add_argument('--buildprefs', action='store', help = 'Read the given build preferences file', default = '') parser.add_argument('--updatebuild', action='store_true', help = 'Update submodule build scripts', default = '') parser.add_argument('--lto', action='store_true', help = 'Build with Link Time Optimization', default = False) options = parser.parse_args() self.project = project self.target = platform.Platform(options.target) self.host = platform.Platform(options.host) self.subninja = options.subninja archs = options.arch configs = options.config if includepaths is None: includepaths = [] if not options.includepath is None: includepaths += options.includepath buildfile = open('build.ninja', 'w') self.writer = syntax.Writer(buildfile) self.writer.variable('ninja_required_version', '1.3') self.writer.newline() self.writer.comment('configure.py arguments') self.writer.variable('configure_args', ' '.join(sys.argv[1:])) self.writer.newline() self.writer.comment('configure options') self.writer.variable('configure_target', self.target.platform) self.writer.variable('configure_host', self.host.platform) env_keys = set(['CC', 'AR', 'LINK', 'CFLAGS', 'ARFLAGS', 'LINKFLAGS']) configure_env = dict((key, os.environ[key]) for key in os.environ if key in env_keys) if configure_env: config_str = ' '.join([key + '=' + pipes.quote(configure_env[key]) for key in configure_env]) self.writer.variable('configure_env', config_str + '$ ') if variables is None: variables = {} if not isinstance(variables, dict): variables = dict(variables) if options.monolithic: variables['monolithic'] = True if options.coverage: variables['coverage'] = True if options.lto: variables['lto'] = True if self.subninja != '': variables['internal_deps'] = True self.toolchain = toolchain.make_toolchain(self.host, self.target, options.toolchain) self.toolchain.buildprefs = options.buildprefs self.toolchain.initialize(project, archs, configs, includepaths, dependlibs, libpaths, variables, self.subninja) self.writer.variable('configure_toolchain', self.toolchain.name()) self.writer.variable('configure_archs', archs) self.writer.variable('configure_configs', configs) self.writer.newline() self.toolchain.write_variables(self.writer) if self.subninja == '': self.toolchain.write_rules(self.writer) def target(self): return self.target def host(self): return self.host def toolchain(self): return self.toolchain def writer(self): return self.writer def is_subninja(self): return self.subninja != '' def lib(self, module, sources, libname = None, basepath = None, configs = None, includepaths = None, variables = None): return self.toolchain.lib(self.writer, module, sources, libname, basepath, configs, includepaths, variables) def sharedlib(self, module, sources, libname = None, basepath = None, configs = None, includepaths = None, libpaths = None, implicit_deps = None, dependlibs = None, libs = None, frameworks = None, variables = None): return self.toolchain.sharedlib(self.writer, module, sources, libname, basepath, configs, includepaths, libpaths, implicit_deps, dependlibs, libs, frameworks, variables) def bin(self, module, sources, binname, basepath = None, configs = None, includepaths = None, libpaths = None, implicit_deps = None, dependlibs = None, libs = None, frameworks = None, variables = None): return self.toolchain.bin(self.writer, module, sources, binname, basepath, configs, includepaths, libpaths, implicit_deps, dependlibs, libs, frameworks, variables) def app(self, module, sources, binname, basepath = None, configs = None, includepaths = None, libpaths = None, implicit_deps = None, dependlibs = None, libs = None, frameworks = None, variables = None, resources = None): return self.toolchain.app(self.writer, module, sources, binname, basepath, configs, includepaths, libpaths, implicit_deps, dependlibs, libs, frameworks, variables, resources) def test_includepaths(self): #TODO: This is ugly if self.project == "foundation": return ['test'] foundation_path = os.path.join('..', 'foundation_lib') if not os.path.isfile(os.path.join(foundation_path, 'foundation', 'foundation.h')): foundation_path = os.path.join('..', 'foundation') return ['test', os.path.join(foundation_path, 'test')] def test_monolithic(self): return self.toolchain.is_monolithic()