def GetPostbuildCommand(self, spec, output, output_binary, is_command_start=False): """Returns a shell command that runs all the postbuilds, and removes |output| if any of them fails. If |is_command_start| is False, then the returned string will start with ' && '.""" if not self.xcode_settings or spec['type'] == 'none' or not output: return '' output = QuoteShellArgument(output) target_postbuilds = self.xcode_settings.GetTargetPostbuilds( self.config_name, output, QuoteShellArgument(output_binary), quiet=True) postbuilds = gyp.xcode_emulation.GetSpecPostbuildCommands( spec, self.GypPathToNinja, quiet=True) postbuilds = target_postbuilds + postbuilds if not postbuilds: return '' env = self.ComputeExportEnvString(self.GetXcodePostbuildEnv()) commands = env + ' F=0; ' + \ ' '.join([ninja_syntax.escape(command) + ' || F=$$?;' for command in postbuilds]) command_string = env + commands + ' ((exit $$F) || rm -rf %s) ' % output + \ '&& exit $$F)' if is_command_start: return '(' + command_string + ' && ' else: return '$ && (' + command_string
def WriteSources(self, config, sources, predepends): """Write build rules to compile all of |sources|.""" if self.toolset == "host": self.ninja.variable("cc", "$cc_host") self.ninja.variable("cxx", "$cxx_host") self.WriteVariableList( "defines", ["-D" + MaybeQuoteShellArgument(ninja_syntax.escape(d)) for d in config.get("defines", [])] ) self.WriteVariableList("includes", ["-I" + self.GypPathToNinja(i) for i in config.get("include_dirs", [])]) self.WriteVariableList("cflags", config.get("cflags")) self.WriteVariableList("cflags_c", config.get("cflags_c")) self.WriteVariableList("cflags_cc", config.get("cflags_cc")) self.ninja.newline() outputs = [] for source in sources: filename, ext = os.path.splitext(source) ext = ext[1:] if ext in ("cc", "cpp", "cxx"): command = "cxx" elif ext in ("c", "s", "S"): command = "cc" else: # TODO: should we assert here on unexpected extensions? continue input = self.GypPathToNinja(source) output = self.GypPathToUniqueOutput(filename + ".o") self.ninja.build(output, command, input, order_only=predepends) outputs.append(output) self.ninja.newline() return outputs
def WriteSources(self, config, sources, predepends): """Write build rules to compile all of |sources|.""" if self.toolset == 'host': self.ninja.variable('cc', '$cc_host') self.ninja.variable('cxx', '$cxx_host') self.WriteVariableList('defines', ['-D' + MaybeQuoteShellArgument(ninja_syntax.escape(d)) for d in config.get('defines', [])]) self.WriteVariableList('includes', ['-I' + self.GypPathToNinja(i) for i in config.get('include_dirs', [])]) self.WriteVariableList('cflags', config.get('cflags')) self.WriteVariableList('cflags_c', config.get('cflags_c')) self.WriteVariableList('cflags_cc', config.get('cflags_cc')) self.ninja.newline() outputs = [] for source in sources: filename, ext = os.path.splitext(source) ext = ext[1:] if ext in ('cc', 'cpp', 'cxx'): command = 'cxx' elif ext in ('c', 's', 'S'): command = 'cc' else: # TODO: should we assert here on unexpected extensions? continue input = self.GypPathToNinja(source) output = self.GypPathToUniqueOutput(filename + '.o') self.ninja.build(output, command, input, order_only=predepends) outputs.append(output) self.ninja.newline() return outputs
def GetPostbuildCommand(self, spec, output, output_binary, is_command_start=False): """Returns a shell command that runs all the postbuilds, and removes |output| if any of them fails. If |is_command_start| is False, then the returned string will start with ' && '.""" if not self.xcode_settings or spec['type'] == 'none' or not output: return '' output = QuoteShellArgument(output, self.flavor) target_postbuilds = self.xcode_settings.GetTargetPostbuilds( self.config_name, output, QuoteShellArgument(output_binary, self.flavor), quiet=True) postbuilds = gyp.xcode_emulation.GetSpecPostbuildCommands( spec, self.GypPathToNinja, quiet=True) postbuilds = target_postbuilds + postbuilds if not postbuilds: return '' env = self.ComputeExportEnvString(self.GetXcodePostbuildEnv()) commands = env + ' F=0; ' + \ ' '.join([ninja_syntax.escape(command) + ' || F=$$?;' for command in postbuilds]) command_string = env + commands + ' ((exit $$F) || rm -rf %s) ' % output + \ '&& exit $$F)' if is_command_start: return '(' + command_string + ' && ' else: return '$ && (' + command_string
def Define(d, flavor): """Takes a preprocessor define and returns a -D parameter that's ninja- and shell-escaped.""" if flavor == 'win': # cl.exe replaces literal # characters with = in preprocesor definitions for # some reason. Octal-encode to work around that. d = d.replace('#', '\\%03o' % ord('#')) return QuoteShellArgument(ninja_syntax.escape('-D' + d), flavor)
def ComputeExportEnvString(self, env): """Given an environment, returns a string looking like 'export FOO=foo; export BAR="${FOO} bar;' that exports |env| to the shell.""" export_str = [] for k in gyp.xcode_emulation.TopologicallySortedEnvVarKeys(env): export_str.append('export %s=%s;' % (k, ninja_syntax.escape(gyp.common.EncodePOSIXShellArgument(env[k])))) return ' '.join(export_str)
def WriteSources(self, config, sources, predepends): """Write build rules to compile all of |sources|.""" if self.toolset == 'host': self.ninja.variable('cc', '$cc_host') self.ninja.variable('cxx', '$cxx_host') if self.flavor == 'mac': # TODO(jeremya/thakis): Extract these from XcodeSettings instead. cflags = [] cflags_c = [] cflags_cc = [] cflags_objc = [] cflags_objcc = [] else: cflags = config.get('cflags', []) cflags_c = config.get('cflags_c', []) cflags_cc = config.get('cflags_cc', []) self.WriteVariableList('defines', [QuoteShellArgument(ninja_syntax.escape('-D' + d)) for d in config.get('defines', [])]) self.WriteVariableList('includes', ['-I' + self.GypPathToNinja(i) for i in config.get('include_dirs', [])]) self.WriteVariableList('cflags', map(self.ExpandSpecial, cflags)) self.WriteVariableList('cflags_c', map(self.ExpandSpecial, cflags_c)) self.WriteVariableList('cflags_cc', map(self.ExpandSpecial, cflags_cc)) if self.flavor == 'mac': self.WriteVariableList('cflags_objc', map(self.ExpandSpecial, cflags_objc)) self.WriteVariableList('cflags_objcc', map(self.ExpandSpecial, cflags_objcc)) self.ninja.newline() outputs = [] for source in sources: filename, ext = os.path.splitext(source) ext = ext[1:] if ext in ('cc', 'cpp', 'cxx'): command = 'cxx' elif ext in ('c', 's', 'S'): command = 'cc' elif self.flavor == 'mac' and ext == 'm': command = 'objc' elif self.flavor == 'mac' and ext == 'mm': command = 'objcxx' else: # TODO: should we assert here on unexpected extensions? continue input = self.GypPathToNinja(source) output = self.GypPathToUniqueOutput(filename + '.o') self.ninja.build(output, command, input, order_only=predepends) outputs.append(output) self.ninja.newline() return outputs
def WriteNewNinjaRule(self, name, args, description, env={}): """Write out a new ninja "rule" statement for a given command. Returns the name of the new rule.""" # TODO: we shouldn't need to qualify names; we do it because # currently the ninja rule namespace is global, but it really # should be scoped to the subninja. rule_name = self.name if self.toolset == 'target': rule_name += '.' + self.toolset rule_name += '.' + name rule_name = rule_name.replace(' ', '_') args = args[:] # gyp dictates that commands are run from the base directory. # cd into the directory before running, and adjust paths in # the arguments to point to the proper locations. if self.flavor == 'win': cd = 'cmd /s /c "cd %s && ' % self.build_to_base else: cd = 'cd %s; ' % self.build_to_base args = [self.ExpandSpecial(arg, self.base_to_build) for arg in args] env = self.ComputeExportEnvString(env) if self.flavor == 'win': # TODO(scottmg): Really don't want encourage cygwin, but I'm not sure # how much sh is depended upon. For now, double quote args to make most # things work. command = args[0] + ' "' + '" "'.join(args[1:]) + '""' else: command = gyp.common.EncodePOSIXShellList(args) if env: # If an environment is passed in, variables in the command should be # read from it, instead of from ninja's internal variables. command = ninja_syntax.escape(command) command = cd + env + command # GYP rules/actions express being no-ops by not touching their outputs. # Avoid executing downstream dependencies in this case by specifying # restat=1 to ninja. self.ninja.rule(rule_name, command, description, restat=True) self.ninja.newline() return rule_name
def WriteMacInfoPlist(self, bundle_depends): """Write build rules for bundle Info.plist files.""" info_plist, out, defines, extra_env = gyp.xcode_emulation.GetMacInfoPlist( self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']), self.xcode_settings, self.GypPathToNinja) if not info_plist: return if defines: # Create an intermediate file to store preprocessed results. intermediate_plist = self.GypPathToUniqueOutput( os.path.basename(info_plist)) defines = ' '.join( [QuoteShellArgument(ninja_syntax.escape('-D' + d)) for d in defines]) info_plist = self.ninja.build(intermediate_plist, 'infoplist', info_plist, variables=[('defines',defines)]) env = self.GetXcodeEnv(additional_settings=extra_env) env = self.ComputeExportEnvString(env) self.ninja.build(out, 'mac_tool', info_plist, variables=[('mactool_cmd', 'copy-info-plist'), ('env', env)]) bundle_depends.append(out)
def WriteNewNinjaRule(self, name, args, description, env={}): """Write out a new ninja "rule" statement for a given command. Returns the name of the new rule.""" # TODO: we shouldn't need to qualify names; we do it because # currently the ninja rule namespace is global, but it really # should be scoped to the subninja. rule_name = self.name if self.toolset == 'target': rule_name += '.' + self.toolset rule_name += '.' + name rule_name = rule_name.replace(' ', '_') args = args[:] # gyp dictates that commands are run from the base directory. # cd into the directory before running, and adjust paths in # the arguments to point to the proper locations. cd = 'cd %s; ' % self.build_to_base args = [self.ExpandSpecial(arg, self.base_to_build) for arg in args] env = self.ComputeExportEnvString(env) command = gyp.common.EncodePOSIXShellList(args) if env: # If an environment is passed in, variables in the command should be # read from it, instead of from ninja's internal variables. command = ninja_syntax.escape(command) command = cd + env + command # GYP rules/actions express being no-ops by not touching their outputs. # Avoid executing downstream dependencies in this case by specifying # restat=1 to ninja. self.ninja.rule(rule_name, command, description, restat=True) self.ninja.newline() return rule_name
def WriteSources(self, config_name, config, sources, predepends, precompiled_header): """Write build rules to compile all of |sources|.""" if self.toolset == 'host': self.ninja.variable('cc', '$cc_host') self.ninja.variable('cxx', '$cxx_host') if self.flavor == 'mac': cflags = self.xcode_settings.GetCflags(config_name) cflags_c = self.xcode_settings.GetCflagsC(config_name) cflags_cc = self.xcode_settings.GetCflagsCC(config_name) cflags_objc = ['$cflags_c'] + \ self.xcode_settings.GetCflagsObjC(config_name) cflags_objcc = ['$cflags_cc'] + \ self.xcode_settings.GetCflagsObjCC(config_name) else: cflags = config.get('cflags', []) cflags_c = config.get('cflags_c', []) cflags_cc = config.get('cflags_cc', []) self.WriteVariableList('defines', [QuoteShellArgument(ninja_syntax.escape('-D' + d), self.flavor) for d in config.get('defines', [])]) self.WriteVariableList('includes', ['-I' + self.GypPathToNinja(i) for i in config.get('include_dirs', [])]) pch_commands = precompiled_header.GetGchBuildCommands() if self.flavor == 'mac': self.WriteVariableList('cflags_pch_c', [precompiled_header.GetInclude('c')]) self.WriteVariableList('cflags_pch_cc', [precompiled_header.GetInclude('cc')]) self.WriteVariableList('cflags_pch_objc', [precompiled_header.GetInclude('m')]) self.WriteVariableList('cflags_pch_objcc', [precompiled_header.GetInclude('mm')]) self.WriteVariableList('cflags', map(self.ExpandSpecial, cflags)) self.WriteVariableList('cflags_c', map(self.ExpandSpecial, cflags_c)) self.WriteVariableList('cflags_cc', map(self.ExpandSpecial, cflags_cc)) if self.flavor == 'mac': self.WriteVariableList('cflags_objc', map(self.ExpandSpecial, cflags_objc)) self.WriteVariableList('cflags_objcc', map(self.ExpandSpecial, cflags_objcc)) self.ninja.newline() outputs = [] for source in sources: filename, ext = os.path.splitext(source) ext = ext[1:] if ext in ('cc', 'cpp', 'cxx'): command = 'cxx' elif ext in ('c', 's', 'S'): command = 'cc' elif self.flavor == 'mac' and ext == 'm': command = 'objc' elif self.flavor == 'mac' and ext == 'mm': command = 'objcxx' else: # TODO: should we assert here on unexpected extensions? continue input = self.GypPathToNinja(source) output = self.GypPathToUniqueOutput(filename + self.obj_ext) implicit = precompiled_header.GetObjDependencies([input], [output]) self.ninja.build(output, command, input, implicit=[gch for _, _, gch in implicit], order_only=predepends) outputs.append(output) self.WritePchTargets(pch_commands) self.ninja.newline() return outputs
def WriteSources(self, config_name, config, sources, predepends, precompiled_header): """Write build rules to compile all of |sources|.""" if self.toolset == 'host': self.ninja.variable('cc', '$cc_host') self.ninja.variable('cxx', '$cxx_host') if self.flavor == 'mac': cflags = self.xcode_settings.GetCflags(config_name) cflags_c = self.xcode_settings.GetCflagsC(config_name) cflags_cc = self.xcode_settings.GetCflagsCC(config_name) cflags_objc = ['$cflags_c'] + \ self.xcode_settings.GetCflagsObjC(config_name) cflags_objcc = ['$cflags_cc'] + \ self.xcode_settings.GetCflagsObjCC(config_name) else: cflags = config.get('cflags', []) cflags_c = config.get('cflags_c', []) cflags_cc = config.get('cflags_cc', []) self.WriteVariableList('defines', [QuoteShellArgument(ninja_syntax.escape('-D' + d)) for d in config.get('defines', [])]) self.WriteVariableList('includes', ['-I' + self.GypPathToNinja(i) for i in config.get('include_dirs', [])]) pch_commands = precompiled_header.GetGchBuildCommands() if self.flavor == 'mac': self.WriteVariableList('cflags_pch_c', [precompiled_header.GetInclude('c')]) self.WriteVariableList('cflags_pch_cc', [precompiled_header.GetInclude('cc')]) self.WriteVariableList('cflags_pch_objc', [precompiled_header.GetInclude('m')]) self.WriteVariableList('cflags_pch_objcc', [precompiled_header.GetInclude('mm')]) self.WriteVariableList('cflags', map(self.ExpandSpecial, cflags)) self.WriteVariableList('cflags_c', map(self.ExpandSpecial, cflags_c)) self.WriteVariableList('cflags_cc', map(self.ExpandSpecial, cflags_cc)) if self.flavor == 'mac': self.WriteVariableList('cflags_objc', map(self.ExpandSpecial, cflags_objc)) self.WriteVariableList('cflags_objcc', map(self.ExpandSpecial, cflags_objcc)) self.ninja.newline() outputs = [] for source in sources: filename, ext = os.path.splitext(source) ext = ext[1:] if ext in ('cc', 'cpp', 'cxx'): command = 'cxx' elif ext in ('c', 's', 'S'): command = 'cc' elif self.flavor == 'mac' and ext == 'm': command = 'objc' elif self.flavor == 'mac' and ext == 'mm': command = 'objcxx' else: # TODO: should we assert here on unexpected extensions? continue input = self.GypPathToNinja(source) output = self.GypPathToUniqueOutput(filename + self.obj_ext) implicit = precompiled_header.GetObjDependencies([input], [output]) self.ninja.build(output, command, input, implicit=[gch for _, _, gch in implicit], order_only=predepends) outputs.append(output) self.WritePchTargets(pch_commands) self.ninja.newline() return outputs