Пример #1
0
    def parseInput(self, context, source):
        if util.IsString(source):
            if not os.path.isabs(source):
                source = os.path.join(context.currentSourcePath, source)
            source = os.path.normpath(source)

            entry = self.db.query_path(source)
            if not entry:
                return self.db.add_source(source)

            # Otherwise, we have to valid the node.
            source = entry

        if source.type == nodetypes.Source or source.type == nodetypes.Output:
            return source

        if source.type == nodetypes.Mkdir:
            if source not in self.bad_outputs_:
                util.con_err(util.ConsoleRed, 'Tried to use folder path ',
                             util.ConsoleBlue, source.path, util.ConsoleRed,
                             ' as a file path.', util.ConsoleNormal)
                raise Exception('Tried to use folder path as a file path')

        util.con_err(util.ConsoleRed,
                     'Tried to use incompatible node "', util.ConsoleBlue,
                     source.format(), util.ConsoleRed, '" as a file path.',
                     util.ConsoleNormal)
        raise Exception('Tried to use non-file node as a file path')
Пример #2
0
def Join(*nodes):
  paths = []
  for node in nodes:
    if node is None:
      continue
    if util.IsString(node):
      paths.append(node)
    else:
      paths.append(node.path)
  return os.path.join(*paths)
Пример #3
0
def ComputeSourcePath(context, localFolderNode, item):
    # This is a path into the source tree.
    if util.IsString(item):
        if os.path.isabs(item):
            sourceFile = item
        else:
            sourceFile = os.path.join(context.currentSourcePath, item)
        return os.path.normpath(sourceFile)

    # This is a node computed by a previous step. Compute a relative path.
    return os.path.relpath(item.path, localFolderNode.path)
Пример #4
0
    def addFileOp(self, cmd, context, source, output_path):
        # Try to detect if our output_path is actually a folder, via trailing
        # slash or '.'/'' indicating the context folder.
        detected_folder = None
        if util.IsString(output_path):
            if output_path[-1] == os.sep or output_path[-1] == os.altsep:
                detected_folder = os.path.join(context.buildFolder,
                                               os.path.normpath(output_path))
            elif output_path == '.' or output_path == '':
                detected_folder = context.buildFolder

            # Since we're building something relative to the context folder, ensure
            # that the context folder exists.
            self.getLocalFolder(context)
        else:
            assert output_path.type != nodetypes.Source
            local_path = os.path.relpath(output_path.path, context.buildFolder)
            detected_folder = os.path.join(context.buildFolder, local_path)
            detected_folder = os.path.normpath(detected_folder)

        source_entry = self.parseInput(context, source)

        # This is similar to a "cp a b/", so we append to get "b/a" as the path.
        if detected_folder is not None:
            base, output_path = os.path.split(source_entry.path)
            assert len(output_path)

            output_folder = detected_folder
        else:
            output_folder = context.buildFolder

        output_path = nodetypes.combine(output_folder, output_path)

        # For copy operations, it's okay to use the path from the current folder.
        # However, when performing symlinks, we always want an absolute path.
        if cmd == nodetypes.Symlink:
            if source_entry.type == nodetypes.Source:
                source_path = source_entry.path
            else:
                source_path = os.path.join(context.buildPath,
                                           source_entry.path)
        else:
            source_path = source_entry.path

        # For clarity of spew, we always execute file operations in the root of
        # the build folder. This means that no matter what context we're in,
        # we can use absolute-ish folders and get away with it.
        return self.addCommand(context=context,
                               node_type=cmd,
                               folder=None,
                               data=(source_path, output_path),
                               inputs=[source_entry],
                               outputs=[output_path])
Пример #5
0
    def parseCxxDeps(self, context, binary, inputs, items):
        for val in items:
            if util.IsString(val):
                continue

            if type(val) is nodetypes.Entry:
                item = val
            elif util.IsLambda(val.node):
                item = val.node(context, binary)
            elif val.node is None:
                item = self.parseInput(context, val.text).path
            else:
                item = val.node

            if type(item) is list:
                inputs.extend(item)
            else:
                inputs.append(item)
Пример #6
0
def export_configuration_options(node, xml, builder):
    compiler = builder.compiler

    includes = ['%(AdditionalIncludeDirectories)'
                ] + compiler.includes + compiler.cxxincludes
    all_defines = compiler.defines + compiler.cxxdefines
    simple_defines = ['%(PreprocessorDefinitions)'] + [
        option for option in all_defines if '=' not in option
    ]
    val_defines = [
        '/D{0}'.format(option) for option in all_defines if '=' in option
    ]

    with xml.block('ClCompile'):
        flags = compiler.cflags + compiler.cxxflags

        # Filter out options we handle specially.
        other_flags = val_defines + flags
        other_flags = [
            flag for flag in other_flags if not flag.startswith('/O')
        ]
        other_flags = [
            flag for flag in other_flags if not flag.startswith('/RTC')
        ]
        other_flags = [
            flag for flag in other_flags if not flag.startswith('/EH')
        ]
        other_flags = [
            flag for flag in other_flags if not flag.startswith('/MT')
        ]
        other_flags = [
            flag for flag in other_flags if not flag.startswith('/MD')
        ]
        other_flags = [
            flag for flag in other_flags if not flag.startswith('/W')
        ]
        other_flags = [
            flag for flag in other_flags if not flag.startswith('/GR')
        ]

        if len(other_flags):
            xml.tag('AdditionalOptions', ' '.join(other_flags))

        xml.tag('AdditionalIncludeDirectories', ';'.join(includes))
        xml.tag('PreprocessorDefinitions', ';'.join(simple_defines))

        if '/Ox' in flags:
            xml.tag('Optimization', 'Full')
        elif '/O2' in flags:
            xml.tag('Optimization', 'MaxSpeed')
        elif '/O1' in flags:
            xml.tag('Optimization', 'MinSpace')
        else:
            xml.tag('Optimization', 'Disabled')

        if '/Os' in flags:
            xml.tag('FavorSizeOrSpeed', 'Size')
        elif '/Ot' in flags:
            xml.tag('FavorSizeOrSpeed', 'Speed')

        xml.tag('MinimalRebuild', 'true')

        if '/RTC1' in flags or '/RTCsu' in flags:
            xml.tag('BasicRuntimeChecks', 'EnableFastChecks')
        elif '/RTCs' in flags:
            xml.tag('BasicRuntimeChecks', 'StackFrame')
        elif '/RTCu' in flags:
            xml.tag('BasicRuntimeChecks', 'UninitVariables')

        if '/Oy-' in flags:
            xml.tag('OmitFramePointer', 'true')
        if '/EHsc' in flags:
            xml.tag('ExceptionHandling', 'Sync')

        if '/MT' in flags:
            xml.tag('RuntimeLibrary', 'MultiThreaded')
        elif '/MTd' in flags:
            xml.tag('RuntimeLibrary', 'MultiThreadedDebug')
        elif '/MD' in flags:
            xml.tag('RuntimeLibrary', 'MultiThreadedDLL')
        elif '/MDd' in flags:
            xml.tag('RuntimeLibrary', 'MultiThreadedDebugDLL')

        if '/W0' in flags:
            xml.tag('WarningLevel', 'Level0')
        elif '/W1' in flags:
            xml.tag('WarningLevel', 'Level1')
        elif '/W2' in flags:
            xml.tag('WarningLevel', 'Level2')
        elif '/W3' in flags:
            xml.tag('WarningLevel', 'Level3')
        elif '/W4' in flags:
            xml.tag('WarningLevel', 'Level4')

        if '/Od' in flags:
            xml.tag('DebugInformationFormat', 'EditAndContinue')
        else:
            xml.tag('DebugInformationFormat', 'ProgramDatabase')

        if '/GR-' in flags:
            xml.tag('RuntimeTypeInfo', 'false')
        elif '/GR' in flags:
            xml.tag('RuntimeTypeInfo', 'true')

        with xml.block('PrecompiledHeader'):
            pass
        xml.tag('MultiProcessorCompilation', 'true')

    with xml.block('ResourceCompile'):
        defines = [
            '%(PreprocessorDefinitions)'
        ] + compiler.defines + compiler.cxxdefines + compiler.rcdefines
        defines = sanitize_val_defines(defines)
        xml.tag('PreprocessorDefinitions', ';'.join(defines))
        xml.tag('AdditionalIncludeDirectories',
                ';'.join(includes[1:] + includes[0:1]))

    with xml.block('Link'):
        link_flags = compiler.linkflags + compiler.postlink

        # Parse link flags.
        libs = ['%(AdditionalDependencies)']
        ignore_libs = ['%(IgnoreSpecificDefaultLibraries)']
        machine = 'X86'
        subsystem = 'Windows'
        for flag in link_flags:
            if util.IsString(flag):
                if flag == '/SUBSYSTEM:CONSOLE':
                    subsystem = 'Console'
                    continue

                if '.lib' in flag:
                    libs.append(flag)
                    continue

                m = re.match('/NODEFAULTLIB:(.+)', flag)
                if m is not None:
                    ignore_libs.append(m.group(1))
                    continue

                m = re.match('/MACHINE:(.+)', flag)
                if m is not None:
                    machine = m.group(1)
            else:
                libs.append(Dep.resolve(node.context, builder, flag))

        xml.tag('AdditionalDependencies', ';'.join(libs))
        xml.tag('OutputFile', '$(OutDir)$(TargetFileName)')
        xml.tag('IgnoreSpecificDefaultLibraries', ';'.join(ignore_libs))
        if compiler.debuginfo is None:
            xml.tag('GenerateDebugInformation', 'false')
        else:
            xml.tag('GenerateDebugInformation', 'true')
        if '/OPT:REF' in link_flags:
            xml.tag('OptimizeReferences', 'true')
        elif '/OPT:NOREF' in link_flags:
            xml.tag('OptimizeReferences', 'false')
        if '/OPT:ICF' in link_flags:
            xml.tag('EnableCOMDATFolding', 'true')
        elif '/OPT:NOICF' in link_flags:
            xml.tag('EnableCOMDATFolding', 'true')
        xml.tag('TargetMachine', 'Machine{0}'.format(machine))
Пример #7
0
    def Configure(self):
        args = self.options.parse_args()

        # In order to support pickling, we need to rewrite |options| to not use
        # optparse.Values, since its implementation changes across Python versions.
        options = util.Expando()
        for attr in vars(args):
            setattr(options, attr, getattr(args, attr))

        if options.list_gen:
            print('Available build system generators:')
            print('  {0:24} - AMBuild 2 (default)'.format('ambuild2'))
            print('  {0:24} - Visual Studio'.format('vs'))
            print('')
            print('Extra options:')
            print(
                '  --vs-version=N        Visual Studio: IDE version (2015 or 14 default)'
            )
            print(
                '  --vs-split            Visual Studio: generate one project file per configuration'
            )
            sys.exit(0)

        if options.no_color:
            util.DisableConsoleColors()

        source_abspath = os.path.normpath(os.path.abspath(self.sourcePath))
        build_abspath = os.path.normpath(os.path.abspath(self.buildPath))
        if source_abspath == build_abspath:
            if util.IsString(self.default_build_folder):
                objfolder = self.default_build_folder
            else:
                objfolder = self.default_build_folder(self)
            new_buildpath = os.path.join(self.buildPath, objfolder)

            util.con_err(
                util.ConsoleHeader,
                'Warning: build is being configured in the source tree.',
                util.ConsoleNormal)
            if os.path.exists(os.path.join(new_buildpath)):
                has_amb2 = os.path.exists(
                    os.path.join(new_buildpath, '.ambuild2'))
                if not has_amb2 and len(os.listdir(
                        new_buildpath)) and options.generator == 'ambuild2':
                    util.con_err(util.ConsoleRed, 'Tried to use ',
                                 util.ConsoleBlue, objfolder, util.ConsoleRed,
                                 ' as a build folder, but it is not empty!',
                                 util.ConsoleNormal)
                    raise Exception('build folder has unrecognized files')

                util.con_err(util.ConsoleHeader, 'Re-using build folder: ',
                             util.ConsoleBlue, '{0}'.format(objfolder),
                             util.ConsoleNormal)
            else:
                util.con_err(util.ConsoleHeader, 'Creating "',
                             util.ConsoleBlue, '{0}'.format(objfolder),
                             util.ConsoleHeader, '" as a build folder.',
                             util.ConsoleNormal)
                os.mkdir(new_buildpath)
            self.buildPath = new_buildpath

        from ambuild2.frontend.v2_2.context_manager import ContextManager

        cm = ContextManager(self.sourcePath, self.buildPath, os.getcwd(),
                            options, args)

        with util.FolderChanger(self.buildPath):
            try:
                if not cm.generate(options.generator):
                    sys.stderr.write('Configure failed.\n')
                    sys.exit(1)
            except Exception as e:
                traceback.print_exc()
                util.con_err(util.ConsoleRed, 'Configure failed: {}'.format(e),
                             util.ConsoleNormal)
Пример #8
0
    def buildModule(self, cx, module):
        localFolder, outputFolder, outputPath = self.computeModuleFolders(
            cx, module)
        localFolderNode = cx.AddFolder(localFolder)

        must_include_builddir = False

        # Run custom tools attached to this module.
        addl_source_deps = []
        for custom in module.custom:
            cmd = CustomToolCommand(cx=cx,
                                    module=module,
                                    localFolderNode=localFolderNode,
                                    data=custom)
            custom.tool.evaluate(cmd)

            # Integrate any additional outputs.
            module.sources += cmd.sources
            if cmd.sourcedeps:
                addl_source_deps += cmd.sourcedeps
                must_include_builddir = True

        # If custom tools run, they may place new headers in the objdir. For now
        # we put them implicitly in the include path. We might need to make this
        # explicit (or the path customizable) later.
        if must_include_builddir:
            addl_include_dirs = [outputPath]
        else:
            addl_include_dirs = []

        builder = ObjectArgvBuilder()
        builder.setOutputs(localFolderNode, outputFolder, outputPath)
        builder.setCompiler(module.compiler, addl_include_dirs,
                            addl_source_deps)

        # Parse all source file entries.
        for entry in module.sources:
            if isinstance(entry, CustomSource):
                item = entry.source
                extra_weak_deps = entry.weak_deps
            else:
                item = entry
                extra_weak_deps = None

            sourceFile = ComputeSourcePath(module.context, localFolderNode,
                                           item)

            # If the item is a string, use the computed source path as the dependent
            # item. Otherwise, use the raw item, since it's probably an output from
            # a precursor step.
            #
            # For the short-form name, which is used to compute an object file name,
            # we use the given source string. If the item is a dependent step then
            # use the path to its output.
            if util.IsString(item):
                inputObj = sourceFile
                sourceName = item
            else:
                inputObj = item
                sourceName = sourceFile

            # Build the object we pass to the generator. Include any extra source deps
            # if the file has extended requirements.
            obj_item = builder.buildItem(inputObj, sourceName, sourceFile)
            if extra_weak_deps is not None:
                obj_item.sourcedeps += extra_weak_deps

            self.objects.append(obj_item)

        # Propagate the used_cxx bit.
        if builder.used_cxx:
            self.used_cxx_ = True
        if builder.has_code:
            self.has_code_ = True
Пример #9
0
    def Configure(self):
        if self.target_arch is None:
            self.options.add_option("--target-arch",
                                    type="string",
                                    dest="target_arch",
                                    default=None,
                                    help="Override the target architecture.")

        v_options, args = self.options.parse_args()

        # In order to support pickling, we need to rewrite |options| to not use
        # optparse.Values, since its implementation changes across Python versions.
        options = util.Expando()
        ignore_attrs = set(dir(Values))
        for attr in dir(v_options):
            if attr in ignore_attrs:
                continue
            setattr(options, attr, getattr(v_options, attr))

        # Propagate the overridden architecture.
        if self.target_arch is not None:
            assert getattr(options, 'target_arch', None) is None
            options.target_arch = self.target_arch

        if options.list_gen:
            print('Available build system generators:')
            print('  {0:24} - AMBuild 2 (default)'.format('ambuild2'))
            print('  {0:24} - Visual Studio'.format('vs'))
            print('')
            print('Extra options:')
            print(
                '  --vs-version=N        Visual Studio: IDE version (2010 or 10 default)'
            )
            print(
                '  --vs-split            Visual Studio: generate one project file per configuration'
            )
            sys.exit(0)

        if options.no_color:
            util.DisableConsoleColors()

        source_abspath = os.path.normpath(os.path.abspath(self.sourcePath))
        build_abspath = os.path.normpath(os.path.abspath(self.buildPath))
        if source_abspath == build_abspath:
            if util.IsString(self.default_build_folder):
                objfolder = self.default_build_folder
            else:
                objfolder = self.default_build_folder(self)
            new_buildpath = os.path.join(self.buildPath, objfolder)

            util.con_err(
                util.ConsoleHeader,
                'Warning: build is being configured in the source tree.',
                util.ConsoleNormal)
            if os.path.exists(os.path.join(new_buildpath)):
                has_amb2 = os.path.exists(
                    os.path.join(new_buildpath, '.ambuild2'))
                if not has_amb2 and len(os.listdir(new_buildpath)):
                    util.con_err(util.ConsoleRed, 'Tried to use ',
                                 util.ConsoleBlue, objfolder, util.ConsoleRed,
                                 ' as a build folder, but it is not empty!',
                                 util.ConsoleNormal)
                    raise Exception('build folder has unrecognized files')

                util.con_err(util.ConsoleHeader, 'Re-using build folder: ',
                             util.ConsoleBlue, '{0}'.format(objfolder),
                             util.ConsoleNormal)
            else:
                util.con_err(util.ConsoleHeader, 'Creating "',
                             util.ConsoleBlue, '{0}'.format(objfolder),
                             util.ConsoleHeader, '" as a build folder.',
                             util.ConsoleNormal)
                os.mkdir(new_buildpath)
            self.buildPath = new_buildpath

        if options.generator == 'ambuild2':
            from ambuild2.frontend.v2_1.amb2 import gen
            builder = gen.Generator(self.sourcePath, self.buildPath,
                                    os.getcwd(), options, args)
        elif options.generator == 'vs':
            from ambuild2.frontend.v2_1.vs import gen
            builder = gen.Generator(self.sourcePath, self.buildPath,
                                    os.getcwd(), options, args)
        else:
            sys.stderr.write('Unrecognized build generator: ' +
                             options.generator + '\n')
            sys.exit(1)

        with util.FolderChanger(self.buildPath):
            if not builder.generate():
                sys.stderr.write('Configure failed.\n')
                sys.exit(1)
Пример #10
0
 def RunBuildScripts(self, files, vars=None):
     if util.IsString(files):
         self.cm.evalScript(files, vars or {})
     else:
         for script in files:
             self.cm.evalScript(script, vars)
Пример #11
0
 def RunBuildScripts(self, files, vars={}):
     if util.IsString(files):
         self.generator.evalScript(files, vars)
     else:
         for script in files:
             self.generator.evalScript(script, vars)