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')
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)
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)
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])
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)
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))
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)
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
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)
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)
def RunBuildScripts(self, files, vars={}): if util.IsString(files): self.generator.evalScript(files, vars) else: for script in files: self.generator.evalScript(script, vars)