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

Side by Side Diff: pylib/gyp/msvs_emulation.py

Issue 10384100: ninja windows: support msvs_quote_cmd support (Closed) Base URL: http://git.chromium.org/external/gyp.git@master
Patch Set: use namedtuple instead Created 8 years, 7 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 unified diff | Download patch
« no previous file with comments | « pylib/gyp/generator/ninja.py ('k') | test/win/gyptest-no-quotes.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2012 Google Inc. All rights reserved. 1 # Copyright (c) 2012 Google Inc. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """ 5 """
6 This module helps emulate Visual Studio 2008 behavior on top of other 6 This module helps emulate Visual Studio 2008 behavior on top of other
7 build systems, primarily ninja. 7 build systems, primarily ninja.
8 """ 8 """
9 9
10 import collections
10 import os 11 import os
11 import re 12 import re
12 import subprocess 13 import subprocess
13 import sys 14 import sys
14 15
15 import gyp.MSVSVersion 16 import gyp.MSVSVersion
16 17
17 windows_quoter_regex = re.compile(r'(\\*)"') 18 windows_quoter_regex = re.compile(r'(\\*)"')
18 19
19 def QuoteForRspFile(arg): 20 def QuoteForRspFile(arg, quote_cmd=True):
20 """Quote a command line argument so that it appears as one argument when 21 """Quote a command line argument so that it appears as one argument when
21 processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for 22 processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for
22 Windows programs).""" 23 Windows programs)."""
23 # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment 24 # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment
24 # threads. This is actually the quoting rules for CommandLineToArgvW, not 25 # threads. This is actually the quoting rules for CommandLineToArgvW, not
25 # for the shell, because the shell doesn't do anything in Windows. This 26 # for the shell, because the shell doesn't do anything in Windows. This
26 # works more or less because most programs (including the compiler, etc.) 27 # works more or less because most programs (including the compiler, etc.)
27 # use that function to handle command line arguments. 28 # use that function to handle command line arguments.
28 29
29 # For a literal quote, CommandLineToArgvW requires 2n+1 backslashes 30 # For a literal quote, CommandLineToArgvW requires 2n+1 backslashes
30 # preceding it, and results in n backslashes + the quote. So we substitute 31 # preceding it, and results in n backslashes + the quote. So we substitute
31 # in 2* what we match, +1 more, plus the quote. 32 # in 2* what we match, +1 more, plus the quote.
32 arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg) 33 if quote_cmd:
34 arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg)
33 35
34 # %'s also need to be doubled otherwise they're interpreted as batch 36 # %'s also need to be doubled otherwise they're interpreted as batch
35 # positional arguments. Also make sure to escape the % so that they're 37 # positional arguments. Also make sure to escape the % so that they're
36 # passed literally through escaping so they can be singled to just the 38 # passed literally through escaping so they can be singled to just the
37 # original %. Otherwise, trying to pass the literal representation that 39 # original %. Otherwise, trying to pass the literal representation that
38 # looks like an environment variable to the shell (e.g. %PATH%) would fail. 40 # looks like an environment variable to the shell (e.g. %PATH%) would fail.
39 arg = arg.replace('%', '%%') 41 arg = arg.replace('%', '%%')
40 42
41 # These commands are used in rsp files, so no escaping for the shell (via ^) 43 # These commands are used in rsp files, so no escaping for the shell (via ^)
42 # is necessary. 44 # is necessary.
43 45
44 # Finally, wrap the whole thing in quotes so that the above quote rule 46 # As a workaround for programs that don't use CommandLineToArgvW, gyp
45 # applies and whitespace isn't a word break. 47 # supports msvs_quote_cmd=0, which simply disables all quoting.
46 return '"' + arg + '"' 48 if quote_cmd:
49 # Finally, wrap the whole thing in quotes so that the above quote rule
50 # applies and whitespace isn't a word break.
51 arg = '"' + arg + '"'
47 52
53 return arg
48 54
49 def EncodeRspFileList(args): 55 def EncodeRspFileList(args, quote_cmd):
50 """Process a list of arguments using QuoteCmdExeArgument.""" 56 """Process a list of arguments using QuoteCmdExeArgument."""
51 # Note that the first argument is assumed to be the command. Don't add 57 # Note that the first argument is assumed to be the command. Don't add
52 # quotes around it because then built-ins like 'echo', etc. won't work. 58 # quotes around it because then built-ins like 'echo', etc. won't work.
53 # Take care to normpath only the path in the case of 'call ../x.bat' because 59 # Take care to normpath only the path in the case of 'call ../x.bat' because
54 # otherwise the whole thing is incorrectly interpreted as a path and not 60 # otherwise the whole thing is incorrectly interpreted as a path and not
55 # normalized correctly. 61 # normalized correctly.
56 if not args: return '' 62 if not args: return ''
57 if args[0].startswith('call '): 63 if args[0].startswith('call '):
58 call, program = args[0].split(' ', 1) 64 call, program = args[0].split(' ', 1)
59 program = call + ' ' + os.path.normpath(program) 65 program = call + ' ' + os.path.normpath(program)
60 else: 66 else:
61 program = os.path.normpath(args[0]) 67 program = os.path.normpath(args[0])
62 return program + ' ' + ' '.join(QuoteForRspFile(arg) for arg in args[1:]) 68 return (program + ' ' +
69 ' '.join(QuoteForRspFile(arg, quote_cmd) for arg in args[1:]))
63 70
64 71
65 def _GenericRetrieve(root, default, path): 72 def _GenericRetrieve(root, default, path):
66 """Given a list of dictionary keys |path| and a tree of dicts |root|, find 73 """Given a list of dictionary keys |path| and a tree of dicts |root|, find
67 value at path, or return |default| if any of the path doesn't exist.""" 74 value at path, or return |default| if any of the path doesn't exist."""
68 if not root: 75 if not root:
69 return default 76 return default
70 if not path: 77 if not path:
71 return root 78 return root
72 return _GenericRetrieve(root.get(path[0]), default, path[1:]) 79 return _GenericRetrieve(root.get(path[0]), default, path[1:])
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 os.path.join(path_to_base, self.msvs_cygwin_dirs[0])) 398 os.path.join(path_to_base, self.msvs_cygwin_dirs[0]))
392 cd = ('cd %s' % path_to_base).replace('\\', '/') 399 cd = ('cd %s' % path_to_base).replace('\\', '/')
393 args = [a.replace('\\', '/') for a in args] 400 args = [a.replace('\\', '/') for a in args]
394 args = ["'%s'" % a.replace("'", "\\'") for a in args] 401 args = ["'%s'" % a.replace("'", "\\'") for a in args]
395 bash_cmd = ' '.join(args) 402 bash_cmd = ' '.join(args)
396 cmd = ( 403 cmd = (
397 'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir + 404 'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir +
398 'bash -c "%s ; %s"' % (cd, bash_cmd)) 405 'bash -c "%s ; %s"' % (cd, bash_cmd))
399 return cmd 406 return cmd
400 407
401 def IsRuleRunUnderCygwin(self, rule): 408 RuleShellFlags = collections.namedtuple('RuleShellFlags', ['cygwin', 'quote'])
402 """Determine if an action should be run under cygwin. If the variable is 409
403 unset, or set to 1 we use cygwin.""" 410 def GetRuleShellFlags(self, rule):
404 return int(rule.get('msvs_cygwin_shell', 411 """Return RuleShellFlags about how the given rule should be run. This
405 self.spec.get('msvs_cygwin_shell', 1))) != 0 412 includes whether it should run under cygwin (msvs_cygwin_shell), and
413 whether the commands should be quoted (msvs_quote_cmd)."""
414 # If the variable is unset, or set to 1 we use cygwin
415 cygwin = int(rule.get('msvs_cygwin_shell',
416 self.spec.get('msvs_cygwin_shell', 1))) != 0
417 # Default to quoting. There's only a few special instances where the
418 # target command uses non-standard command line parsing and handle quotes
419 # and quote escaping differently.
420 quote_cmd = int(rule.get('msvs_quote_cmd', 1))
421 assert not (quote_cmd == 0 and cygwin == 1), \
422 'msvs_quote_cmd=0 only applicable for msvs_cygwin_shell=0'
423 return MsvsSettings.RuleShellFlags(cygwin, quote_cmd)
406 424
407 def HasExplicitIdlRules(self, spec): 425 def HasExplicitIdlRules(self, spec):
408 """Determine if there's an explicit rule for idl files. When there isn't we 426 """Determine if there's an explicit rule for idl files. When there isn't we
409 need to generate implicit rules to build MIDL .idl files.""" 427 need to generate implicit rules to build MIDL .idl files."""
410 for rule in spec.get('rules', []): 428 for rule in spec.get('rules', []):
411 if rule['extension'] == 'idl' and int(rule.get('msvs_external_rule', 0)): 429 if rule['extension'] == 'idl' and int(rule.get('msvs_external_rule', 0)):
412 return True 430 return True
413 return False 431 return False
414 432
415 def GetIdlBuildData(self, source, config): 433 def GetIdlBuildData(self, source, config):
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 return vs.SetupScript() 486 return vs.SetupScript()
469 487
470 def ExpandMacros(string, expansions): 488 def ExpandMacros(string, expansions):
471 """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv 489 """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
472 for the canonical way to retrieve a suitable dict.""" 490 for the canonical way to retrieve a suitable dict."""
473 if '$' in string: 491 if '$' in string:
474 for old, new in expansions.iteritems(): 492 for old, new in expansions.iteritems():
475 assert '$(' not in new, new 493 assert '$(' not in new, new
476 string = string.replace(old, new) 494 string = string.replace(old, new)
477 return string 495 return string
OLDNEW
« no previous file with comments | « pylib/gyp/generator/ninja.py ('k') | test/win/gyptest-no-quotes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698