ninja: Use shlex.quote for quoting on non-Windows

This is more reliable, and more accurate. For instance, this means
arguments in commands aren't surrounded by `'` on Linux unless that
is actually needed by that specific argument.

There is no equivalent helper for Windows, so we keep the old
behaviour for that.
pull/1545/head
Nirbheek Chauhan 8 years ago
parent ae9b23832e
commit 4b428053f4
  1. 46
      mesonbuild/backend/ninjabackend.py
  2. 16
      run_unittests.py

@ -12,6 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import shlex
import os, sys, pickle, re
import subprocess, shutil
from collections import OrderedDict
from . import backends
from .. import modules
from .. import environment, mesonlib
@ -24,16 +29,13 @@ from ..mesonlib import File, MesonException, OrderedSet
from ..mesonlib import get_meson_script, get_compiler_for_source
from .backends import CleanTrees, InstallData
from ..build import InvalidArguments
import os, sys, pickle, re
import subprocess, shutil
from collections import OrderedDict
if mesonlib.is_windows():
quote_char = '"'
quote_func = lambda s: '"{}"'.format(s)
execute_wrapper = 'cmd /c'
rmfile_prefix = 'del /f /s /q {} &&'
else:
quote_char = "'"
quote_func = shlex.quote
execute_wrapper = ''
rmfile_prefix = 'rm -f {} &&'
@ -105,18 +107,17 @@ class NinjaBuildElement:
(name, elems) = e
should_quote = name not in raw_names
line = ' %s = ' % name
q_templ = quote_char + "%s" + quote_char
noq_templ = "%s"
newelems = []
for i in elems:
if not should_quote or i == '&&': # Hackety hack hack
templ = noq_templ
quoter = ninja_quote
else:
templ = q_templ
quoter = lambda x: ninja_quote(quote_func(x))
i = i.replace('\\', '\\\\')
if quote_char == '"':
if quote_func('') == '""':
i = i.replace('"', '\\"')
newelems.append(templ % ninja_quote(i))
newelems.append(quoter(i))
line += ' '.join(newelems)
line += '\n'
outfile.write(line)
@ -854,12 +855,12 @@ int dummy;
outfile.write(' depfile = $DEPFILE\n')
outfile.write(' restat = 1\n\n')
outfile.write('rule REGENERATE_BUILD\n')
c = (quote_char + ninja_quote(sys.executable) + quote_char,
quote_char + ninja_quote(self.environment.get_build_command()) + quote_char,
c = (ninja_quote(quote_func(sys.executable)),
ninja_quote(quote_func(self.environment.get_build_command())),
'--internal',
'regenerate',
quote_char + ninja_quote(self.environment.get_source_dir()) + quote_char,
quote_char + ninja_quote(self.environment.get_build_dir()) + quote_char)
ninja_quote(quote_func(self.environment.get_source_dir())),
ninja_quote(quote_func(self.environment.get_build_dir())))
outfile.write(" command = %s %s %s %s %s %s --backend ninja\n" % c)
outfile.write(' description = Regenerating build files.\n')
outfile.write(' generator = 1\n\n')
@ -1515,7 +1516,7 @@ rule FORTRAN_DEP_HACK
pass
return []
def generate_compile_rule_for(self, langname, compiler, qstr, is_cross, outfile):
def generate_compile_rule_for(self, langname, compiler, is_cross, outfile):
if langname == 'java':
if not is_cross:
self.generate_java_compile_rule(compiler, outfile)
@ -1547,7 +1548,7 @@ rule FORTRAN_DEP_HACK
quoted_depargs = []
for d in depargs:
if d != '$out' and d != '$in':
d = qstr % d
d = quote_func(d)
quoted_depargs.append(d)
cross_args = self.get_cross_info_lang_args(langname, is_cross)
if mesonlib.is_windows():
@ -1576,7 +1577,7 @@ rule FORTRAN_DEP_HACK
outfile.write(description)
outfile.write('\n')
def generate_pch_rule_for(self, langname, compiler, qstr, is_cross, outfile):
def generate_pch_rule_for(self, langname, compiler, is_cross, outfile):
if langname != 'c' and langname != 'cpp':
return
if is_cross:
@ -1595,7 +1596,7 @@ rule FORTRAN_DEP_HACK
quoted_depargs = []
for d in depargs:
if d != '$out' and d != '$in':
d = qstr % d
d = quote_func(d)
quoted_depargs.append(d)
if compiler.get_id() == 'msvc':
output = ''
@ -1621,12 +1622,11 @@ rule FORTRAN_DEP_HACK
outfile.write('\n')
def generate_compile_rules(self, outfile):
qstr = quote_char + "%s" + quote_char
for langname, compiler in self.build.compilers.items():
if compiler.get_id() == 'clang':
self.generate_llvm_ir_compile_rule(compiler, False, outfile)
self.generate_compile_rule_for(langname, compiler, qstr, False, outfile)
self.generate_pch_rule_for(langname, compiler, qstr, False, outfile)
self.generate_compile_rule_for(langname, compiler, False, outfile)
self.generate_pch_rule_for(langname, compiler, False, outfile)
if self.environment.is_cross_build():
# In case we are going a target-only build, make the native compilers
# masquerade as cross compilers.
@ -1637,8 +1637,8 @@ rule FORTRAN_DEP_HACK
for langname, compiler in cclist.items():
if compiler.get_id() == 'clang':
self.generate_llvm_ir_compile_rule(compiler, True, outfile)
self.generate_compile_rule_for(langname, compiler, qstr, True, outfile)
self.generate_pch_rule_for(langname, compiler, qstr, True, outfile)
self.generate_compile_rule_for(langname, compiler, True, outfile)
self.generate_pch_rule_for(langname, compiler, True, outfile)
outfile.write('\n')
def generate_generator_list_rules(self, target, outfile):

@ -1266,15 +1266,15 @@ class LinuxlikeTests(BasePlatformTests):
self.assertIsNotNone(vala_command)
self.assertIsNotNone(c_command)
# -w suppresses all warnings, should be there in Vala but not in C
self.assertIn("'-w'", vala_command)
self.assertNotIn("'-w'", c_command)
self.assertIn(" -w ", vala_command)
self.assertNotIn(" -w ", c_command)
# -Wall enables all warnings, should be there in C but not in Vala
self.assertNotIn("'-Wall'", vala_command)
self.assertIn("'-Wall'", c_command)
self.assertNotIn(" -Wall ", vala_command)
self.assertIn(" -Wall ", c_command)
# -Werror converts warnings to errors, should always be there since it's
# injected by an unrelated piece of code and the project has werror=true
self.assertIn("'-Werror'", vala_command)
self.assertIn("'-Werror'", c_command)
self.assertIn(" -Werror ", vala_command)
self.assertIn(" -Werror ", c_command)
def test_qt5dependency_pkgconfig_detection(self):
'''
@ -1405,7 +1405,7 @@ class LinuxlikeTests(BasePlatformTests):
self.init(testdir, ['-D' + std_opt])
cmd = self.get_compdb()[0]['command']
if v != 'none':
cmd_std = "'-std={}'".format(v)
cmd_std = " -std={} ".format(v)
self.assertIn(cmd_std, cmd)
try:
self.build()
@ -1420,7 +1420,7 @@ class LinuxlikeTests(BasePlatformTests):
os.environ[env_flags] = cmd_std
self.init(testdir)
cmd = self.get_compdb()[0]['command']
qcmd_std = "'{}'".format(cmd_std)
qcmd_std = " {} ".format(cmd_std)
self.assertIn(qcmd_std, cmd)
with self.assertRaises(subprocess.CalledProcessError,
msg='{} should have failed'.format(qcmd_std)):

Loading…
Cancel
Save