Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(993)

Unified Diff: pylib/gyp/generator/ninja.py

Issue 9460049: Next level of changes to get more of Chrome building (Closed) Base URL: https://gyp.googlecode.com/svn/trunk
Patch Set: wip Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pylib/gyp/MSVSVersion.py ('k') | pylib/gyp/msvs_emulation.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pylib/gyp/generator/ninja.py
diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py
index 7c66a1d0a7544eef40a0d46917fc5cb8ed274226..46c41f60d9a1180ae3d379f8b68ce615700b4cf9 100644
--- a/pylib/gyp/generator/ninja.py
+++ b/pylib/gyp/generator/ninja.py
@@ -8,6 +8,7 @@ import gyp.common
import gyp.msvs_emulation
import gyp.system_test
import gyp.xcode_emulation
+import json
import os.path
import re
import subprocess
@@ -216,7 +217,11 @@ class NinjaWriter:
if self.flavor == 'win':
# Don't use os.path.normpath here. Callers pass in './foo' and expect
- # the result to be runnable, but normpath removes the prefix.
+ # the result to be runnable, but normpath removes the prefix. If the
+ # variable is $! prefixed on Windows, don't modify it (used for compiler
+ # flags, etc.)
+ if path.startswith('$!'):
+ return path[2:]
return path.replace('/', '\\')
return path
@@ -303,10 +308,11 @@ class NinjaWriter:
self.target = Target(spec['type'])
self.is_mac_bundle = gyp.xcode_emulation.IsMacBundle(self.flavor, spec)
+ self.xcode_settings = self.msvs_settings = None
if self.flavor == 'mac':
self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec)
- else:
- self.xcode_settings = None
+ if self.flavor == 'win':
+ self.msvs_settings = gyp.msvs_emulation.MsvsSettings(spec)
# Compute predepends for all rules.
# actions_depends is the dependencies this target depends on before running
@@ -351,7 +357,7 @@ class NinjaWriter:
sources = spec.get('sources', []) + extra_sources
if sources:
link_deps = self.WriteSources(
- config_name, config, sources, compile_depends_stamp,
+ config_name, config, sources, compile_depends_stamp, spec,
gyp.xcode_emulation.MacPrefixHeader(
self.xcode_settings, self.GypPathToNinja,
lambda path, lang: self.GypPathToUniqueOutput(path + '-' + lang)))
@@ -435,14 +441,24 @@ class NinjaWriter:
action.get('message', None),
name)
rule_name = self.WriteNewNinjaRule(name, action['action'], description,
- env=env)
+ env=env, rule=action)
- inputs = [self.GypPathToNinja(i, env) for i in action['inputs']]
+ if self.flavor == 'win':
+ inputs = [self.msvs_settings.ConvertVSMacros(i)
+ for i in action['inputs']]
+ else:
+ inputs = actions['inputs']
+ inputs = [self.GypPathToNinja(i, env) for i in inputs]
if int(action.get('process_outputs_as_sources', False)):
extra_sources += action['outputs']
if int(action.get('process_outputs_as_mac_bundle_resources', False)):
extra_mac_bundle_resources += action['outputs']
- outputs = [self.GypPathToNinja(o, env) for o in action['outputs']]
+ if self.flavor == 'win':
+ outputs = [self.msvs_settings.ConvertVSMacros(i)
+ for i in action['outputs']]
+ else:
+ outputs = action['outputs']
+ outputs = [self.GypPathToNinja(o, env) for o in outputs]
# Then write out an edge using the rule.
self.ninja.build(outputs, rule_name, inputs,
@@ -464,7 +480,7 @@ class NinjaWriter:
'RULE',
rule.get('message', None),
('%s ' + generator_default_variables['RULE_INPUT_PATH']) % name)
- rule_name = self.WriteNewNinjaRule(name, args, description)
+ rule_name = self.WriteNewNinjaRule(name, args, description, rule=rule)
# TODO: if the command references the outputs directly, we should
# simplify it to just use $out.
@@ -479,6 +495,12 @@ class NinjaWriter:
if ('${%s}' % var) in argument:
needed_variables.add(var)
+ is_cygwin = gyp.msvs_emulation.IsRuleRunUnderCygwin(rule)
+ def cygwin_munge(path):
+ if is_cygwin:
+ return path.replace('\\', '/')
+ return path
+
# For each source file, write an edge that generates all the outputs.
for source in rule.get('rule_sources', []):
dirname, basename = os.path.split(source)
@@ -498,23 +520,27 @@ class NinjaWriter:
extra_bindings = []
for var in needed_variables:
if var == 'root':
- extra_bindings.append(('root', root))
+ extra_bindings.append(('root', cygwin_munge(root)))
elif var == 'dirname':
- extra_bindings.append(('dirname', dirname))
+ extra_bindings.append(('dirname', cygwin_munge(dirname)))
elif var == 'source':
# '$source' is a parameter to the rule action, which means
# it shouldn't be converted to a Ninja path. But we don't
# want $!PRODUCT_DIR in there either.
source_expanded = self.ExpandSpecial(source, self.base_to_build)
- extra_bindings.append(('source', source_expanded))
+ extra_bindings.append(('source', cygwin_munge(source_expanded)))
elif var == 'ext':
- extra_bindings.append(('ext', ext))
+ extra_bindings.append(('ext', cygwin_munge(ext)))
elif var == 'name':
extra_bindings.append(('name', basename))
else:
assert var == None, repr(var)
- inputs = map(self.GypPathToNinja, rule.get('inputs', []))
+ inputs = []
+ for input in rule.get('inputs', []):
+ inputs.append(self.ExpandRuleVariables(input, root, dirname, source,
+ ext, basename))
+ inputs = map(self.GypPathToNinja, inputs)
outputs = map(self.GypPathToNinja, outputs)
self.ninja.build(outputs, rule_name, self.GypPathToNinja(source),
implicit=inputs,
@@ -574,7 +600,7 @@ class NinjaWriter:
('env', env)])
bundle_depends.append(out)
- def WriteSources(self, config_name, config, sources, predepends,
+ def WriteSources(self, config_name, config, sources, predepends, spec,
precompiled_header):
"""Write build rules to compile all of |sources|."""
if self.toolset == 'target':
@@ -583,6 +609,7 @@ class NinjaWriter:
self.ninja.variable('cxx', '$cxx_target')
self.ninja.variable('ld', '$ld_target')
+ extra_defines = []
if self.flavor == 'mac':
cflags = self.xcode_settings.GetCflags(config_name)
cflags_c = self.xcode_settings.GetCflagsC(config_name)
@@ -591,17 +618,32 @@ class NinjaWriter:
self.xcode_settings.GetCflagsObjC(config_name)
cflags_objcc = ['$cflags_cc'] + \
self.xcode_settings.GetCflagsObjCC(config_name)
+ elif self.flavor == 'win':
+ cflags = self.msvs_settings.GetCflags(config_name)
+ cflags_c = self.msvs_settings.GetCflagsC(config_name)
+ cflags_cc = self.msvs_settings.GetCflagsCC(config_name)
+ extra_defines = self.msvs_settings.GetComputedDefines(config_name)
+ self.msvs_settings.HandleIdlFiles(
+ self.ninja, spec, sources, config_name,
+ self.GypPathToNinja,
+ self.GypPathToUniqueOutput,
+ self.ExpandRuleVariables)
else:
cflags = config.get('cflags', [])
cflags_c = config.get('cflags_c', [])
cflags_cc = config.get('cflags_cc', [])
+ defines = config.get('defines', []) + extra_defines
self.WriteVariableList('defines',
[QuoteShellArgument(ninja_syntax.escape('-D' + d), self.flavor)
- for d in config.get('defines', [])])
+ for d in defines])
+ include_dirs = config.get('include_dirs', [])
+ if self.flavor == 'win':
+ include_dirs = self.msvs_settings.AdjustIncludeDirs(include_dirs,
+ config_name)
self.WriteVariableList('includes',
- ['-I' + self.GypPathToNinja(i)
- for i in config.get('include_dirs', [])])
+ [QuoteShellArgument('-I' + self.GypPathToNinja(i), self.flavor)
+ for i in include_dirs])
pch_commands = precompiled_header.GetGchBuildCommands()
if self.flavor == 'mac':
@@ -636,7 +678,6 @@ class NinjaWriter:
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)
@@ -711,6 +752,14 @@ class NinjaWriter:
ldflags = self.xcode_settings.GetLdflags(config_name,
self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
self.GypPathToNinja)
+ elif self.flavor == 'win':
+ ldflags = self.msvs_settings.GetLdflags(config_name, spec,
+ self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
+ self.GypPathToNinja)
+ libflags = self.msvs_settings.GetLibFlags(config_name, spec)
+ self.WriteVariableList('libflags',
+ gyp.common.uniquer(map(self.ExpandSpecial,
+ libflags)))
else:
ldflags = config.get('ldflags', [])
self.WriteVariableList('ldflags',
@@ -721,6 +770,8 @@ class NinjaWriter:
spec.get('libraries', [])))
if self.flavor == 'mac':
libraries = self.xcode_settings.AdjustLibraries(libraries)
+ elif self.flavor == 'win':
+ libraries = self.msvs_settings.AdjustLibraries(libraries)
self.WriteVariableList('libs', libraries)
self.target.binary = output
@@ -731,8 +782,8 @@ class NinjaWriter:
import_lib = output + '.lib'
extra_bindings.append(('dll', output))
extra_bindings.append(('implib', import_lib))
- self.target.binary = import_lib
output = [output, import_lib]
+ self.target.binary = import_lib
self.ninja.build(output, command, link_deps,
implicit=list(implicit_deps),
@@ -934,7 +985,7 @@ class NinjaWriter:
values = []
self.ninja.variable(var, ' '.join(values))
- def WriteNewNinjaRule(self, name, args, description, env={}):
+ def WriteNewNinjaRule(self, name, args, description, env={}, rule=None):
"""Write out a new ninja "rule" statement for a given command.
Returns the name of the new rule."""
@@ -950,19 +1001,26 @@ class NinjaWriter:
args = args[:]
+ is_cygwin = rule and int(rule.get('msvs_cygwin_shell', 1))
+
# 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
+ cd = 'cmd /s /c "'
+ if not is_cygwin:
+ cd += '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): Respect msvs_cygwin setting here.
- # If there's no command, fake one to match the dangling |&&| above.
- command = gyp.msvs_emulation.EncodeCmdExeList(args) or 'cmd /c'
+ if is_cygwin:
+ command = gyp.msvs_emulation.BuildCygwinBashCommandLine(
+ self.msvs_settings, rule, args, self.build_to_base, self.config_name)
+ else:
+ # If there's no command, fake one to match the dangling |&&| above.
+ command = self.msvs_settings.EncodeCmdExeList(args) or 'cmd /c'
else:
command = gyp.common.EncodePOSIXShellList(args)
if env:
@@ -1011,6 +1069,21 @@ def CalculateVariables(default_variables, params):
default_variables['STATIC_LIB_SUFFIX'] = '.lib'
default_variables['SHARED_LIB_PREFIX'] = ''
default_variables['SHARED_LIB_SUFFIX'] = '.dll'
+ generator_flags = params.get('generator_flags', {})
+ msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
+
+ # Set a variable so conditions can be based on msvs_version.
+ default_variables['MSVS_VERSION'] = msvs_version.ShortName()
+
+ # To determine processor word size on Windows, in addition to checking
+ # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
+ # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
+ # contains the actual word size of the system when running thru WOW64).
+ if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or
+ '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')):
+ default_variables['MSVS_OS_BITS'] = 64
+ else:
+ default_variables['MSVS_OS_BITS'] = 32
else:
operating_system = flavor
if flavor == 'android':
@@ -1033,6 +1106,7 @@ def OpenOutput(path):
def GenerateOutputForConfig(target_list, target_dicts, data, params,
config_name):
+ print "Generating ninja build files for %s..." % config_name
options = params['options']
flavor = gyp.common.GetFlavor(params)
generator_flags = params.get('generator_flags', {})
@@ -1042,16 +1116,17 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
build_dir = os.path.join(generator_flags.get('output_dir', 'out'),
config_name)
+ top_build_dir = os.path.join(options.toplevel_dir, build_dir)
master_ninja = ninja_syntax.Writer(
- OpenOutput(os.path.join(options.toplevel_dir, build_dir, 'build.ninja')),
+ OpenOutput(os.path.join(top_build_dir, 'build.ninja')),
width=120)
# Put build-time support tools in out/{config_name}.
- gyp.common.CopyTool(flavor, os.path.join(options.toplevel_dir, build_dir))
+ gyp.common.CopyTool(flavor, top_build_dir)
# Grab make settings for CC/CXX.
if flavor == 'win':
- cc = cxx = 'cl'
+ cc = cxx = gyp.msvs_emulation.GetCLPath(generator_flags)
else:
cc, cxx = 'gcc', 'g++'
build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
@@ -1068,7 +1143,9 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
master_ninja.variable('cc', os.environ.get('CC', cc))
master_ninja.variable('cxx', os.environ.get('CXX', cxx))
if flavor == 'win':
- master_ninja.variable('ld', 'link')
+ master_ninja.variable('ld', gyp.msvs_emulation.GetLinkPath(generator_flags))
+ master_ninja.variable('idl',
+ gyp.msvs_emulation.GetMidlPath(generator_flags))
else:
master_ninja.variable('ld', flock + ' linker.lock $cxx')
@@ -1076,7 +1153,8 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
master_ninja.variable('cc_target', os.environ.get('CC_target', '$cc'))
master_ninja.variable('cxx_target', os.environ.get('CXX_target', '$cxx'))
if flavor == 'win':
- master_ninja.variable('ld_target', 'link')
+ master_ninja.variable('ld_target', gyp.msvs_emulation.GetLinkPath(
+ generator_flags))
else:
master_ninja.variable('ld_target', flock + ' linker.lock $cxx_target')
@@ -1103,19 +1181,29 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
master_ninja.rule(
'cc',
description='CC $out',
- command=('cmd /c $cc /nologo /showIncludes '
- '$defines $includes $cflags $cflags_c '
- '$cflags_pch_c /c $in /Fo$out '
- '| ninja-deplist-helper -f cl -o $out.dl'),
- deplist='$out.dl')
+ command=('cmd /s /c "$cc /nologo /showIncludes '
+ '@$out.rsp '
+ '$cflags_pch_c /c $in /Fo$out /Fd$out.pdb '
+ '| ninja-deplist-helper -d .ninja_depdb -q -f cl -o $in"'),
+ depdb='$in',
+ rspfile='$out.rsp',
+ rspfile_content='$defines $includes $cflags $cflags_c')
master_ninja.rule(
'cxx',
description='CXX $out',
- command=('cmd /c $cxx /nologo /showIncludes '
- '$defines $includes $cflags $cflags_cc '
- '$cflags_pch_cc /c $in /Fo$out '
- '| ninja-deplist-helper -f cl -o $out.dl'),
- deplist='$out.dl')
+ command=('cmd /s /c "$cxx /nologo /showIncludes '
+ '@$out.rsp '
+ '$cflags_pch_cc /c $in /Fo$out /Fd$out.pdb '
+ '| ninja-deplist-helper -d .ninja_depdb -q -f cl -o $in"'),
+ depdb='$in',
+ rspfile='$out.rsp',
+ rspfile_content='$defines $includes $cflags $cflags_cc')
+ master_ninja.rule(
+ 'idl',
+ description='IDL $outdir',
+ command=('python gyp-win-tool quiet-midl $outdir '
+ '$tlb $h $dlldata $iid $proxy $in '
+ '$idlflags'))
if flavor != 'mac' and flavor != 'win':
master_ninja.rule(
@@ -1141,19 +1229,29 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
master_ninja.rule(
'alink',
description='LIB $out',
- command='lib /nologo /OUT:$out $in')
- master_ninja.rule(
- 'solink',
- description='LINK(DLL) $dll',
- command=('$ld /nologo /IMPLIB:$implib /DLL $ldflags /OUT:$dll $in $libs'))
- master_ninja.rule(
- 'solink_module',
- description='LINK(DLL) $dll',
- command=('$ld /nologo /IMPLIB:$implib /DLL $ldflags /OUT:$dll $in $libs'))
+ command='lib /nologo /ignore:4221 $libflags /OUT:$out @$out.rsp',
+ rspfile='$out.rsp',
+ rspfile_content='$in')
+ # TODO(scottmg): The lib is the main output, rather than the dll. link
+ # doesn't create the import lib unless there's exports from the dll,
+ # however. This means the dependencies are wrong and the dll will always
+ # relink if it has no exports. We could touch a dummy file, but we don't
+ # want to do && touch, because that would mean we'd have to prepend cmd,
+ # which would impose a short line length on the link command line. That
+ # can be resolved by adding support for @rsp files, but neither ninja or
+ # gyp takes care of that right now. So, currently, we force the export
+ # of the entry point, and then ignore the warning that we're doing so,
+ # which causes the lib to always get generated.
+ dlldesc = 'LINK(DLL) $dll and $implib'
+ dllcmd = ('$ld /nologo /IMPLIB:$implib /DLL $ldflags /OUT:$dll '
+ '/PDB:$dll.pdb $libs @$dll.rsp')
+ master_ninja.rule('solink', description=dlldesc, command=dllcmd,
+ rspfile='$dll.rsp', rspfile_content='$in')
+ master_ninja.rule('solink_module', description=dlldesc, command=dllcmd)
master_ninja.rule(
'link',
description='LINK $out',
- command=('$ld /nologo $ldflags /OUT:$out $in $libs'))
+ command=('$ld /nologo $ldflags /OUT:$out /PDB:$out.pdb $in $libs'))
else:
master_ninja.rule(
'objc',
@@ -1212,8 +1310,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
master_ninja.rule(
'copy',
description='COPY $in $out',
- command='cmd /c mklink /h $out $in >nul || mklink /h /j $out $in >nul || '
- 'python gyp-win-tool recursive-mirror $in $out')
+ command='python gyp-win-tool recursive-mirror $in $out')
else:
master_ninja.rule(
'stamp',
@@ -1256,11 +1353,9 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
obj += '.' + toolset
output_file = os.path.join(obj, base_path, name + '.ninja')
- abs_build_dir=os.path.abspath(os.path.join(options.toplevel_dir, build_dir))
+ abs_build_dir=os.path.abspath(top_build_dir)
writer = NinjaWriter(target_outputs, base_path, build_dir,
- OpenOutput(os.path.join(options.toplevel_dir,
- build_dir,
- output_file)),
+ OpenOutput(os.path.join(top_build_dir, output_file)),
flavor, abs_build_dir=abs_build_dir)
master_ninja.subninja(output_file)
« no previous file with comments | « pylib/gyp/MSVSVersion.py ('k') | pylib/gyp/msvs_emulation.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698