aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/backend/vs2010backend.py
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2016-07-29 18:25:43 +0530
committerNirbheek Chauhan <nirbheek@centricular.com>2016-07-29 19:51:10 +0530
commit2d05008956dedbfb4b6c8b690c4f025451aea587 (patch)
tree01b066f628a7c8779167d54edb0397a36402b7cf /mesonbuild/backend/vs2010backend.py
parentd8b9b12adbd2fa04f40ea2823929acc41f0a8003 (diff)
downloadmeson-2d05008956dedbfb4b6c8b690c4f025451aea587.zip
meson-2d05008956dedbfb4b6c8b690c4f025451aea587.tar.gz
meson-2d05008956dedbfb4b6c8b690c4f025451aea587.tar.bz2
vs: Fix quoting and escaping of compiler options
Target-specific compiler options should be split into pre-processor defines, include directories, and additional options, then escaped/quoted and added to the appropriate portions of the project file. The "115 spaces backslash" test now checks that backslashes and spaces now work properly in all three places.
Diffstat (limited to 'mesonbuild/backend/vs2010backend.py')
-rw-r--r--mesonbuild/backend/vs2010backend.py49
1 files changed, 43 insertions, 6 deletions
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index f7eb147..669bcf8 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -436,9 +436,30 @@ class Vs2010Backend(backends.Backend):
# they are part of the CustomBuildStep Outputs.
return
- @classmethod
- def quote_define_cmdline(cls, arg):
- return re.sub(r'^([-/])D(.*?)="(.*)"$', r'\1D\2=\"\3\"', arg)
+ @staticmethod
+ def escape_preprocessor_define(define):
+ # See: https://msdn.microsoft.com/en-us/library/bb383819.aspx
+ table = str.maketrans({'%': '%25', '$': '%24', '@': '%40',
+ "'": '%27', ';': '%3B', '?': '%3F', '*': '%2A',
+ # We need to escape backslash because it'll be un-escaped by
+ # Windows during process creation when it parses the arguments
+ # Basically, this converts `\` to `\\`.
+ '\\': '\\\\'})
+ return define.translate(table)
+
+ @staticmethod
+ def escape_additional_option(option):
+ # See: https://msdn.microsoft.com/en-us/library/bb383819.aspx
+ table = str.maketrans({'%': '%25', '$': '%24', '@': '%40',
+ "'": '%27', ';': '%3B', '?': '%3F', '*': '%2A', ' ': '%20',})
+ option = option.translate(table)
+ # Since we're surrounding the option with ", if it ends in \ that will
+ # escape the " when the process arguments are parsed and the starting
+ # " will not terminate. So we escape it if that's the case. I'm not
+ # kidding, this is how escaping works for process args on Windows.
+ if option.endswith('\\'):
+ option += '\\'
+ return '"{}"'.format(option)
@staticmethod
def split_link_args(args):
@@ -633,7 +654,7 @@ class Vs2010Backend(backends.Backend):
# so filter them out if needed
d_compile_args = compiler.unix_compile_flags_to_native(d.get_compile_args())
for arg in d_compile_args:
- if arg.startswith('-I'):
+ if arg.startswith('-I') or arg.startswith('/I'):
inc_dir = arg[2:]
# De-dup
if inc_dir not in inc_dirs:
@@ -641,8 +662,24 @@ class Vs2010Backend(backends.Backend):
else:
general_args.append(arg)
+ defines = []
+ # Split preprocessor defines and include directories out of the list of
+ # all extra arguments. The rest go into %(AdditionalOptions).
for l, args in extra_args.items():
- extra_args[l] = [Vs2010Backend.quote_define_cmdline(x) for x in args]
+ extra_args[l] = []
+ for arg in args:
+ if arg.startswith('-D') or arg.startswith('/D'):
+ define = self.escape_preprocessor_define(arg[2:])
+ # De-dup
+ if define not in defines:
+ defines.append(define)
+ elif arg.startswith('-I') or arg.startswith('/I'):
+ inc_dir = arg[2:]
+ # De-dup
+ if inc_dir not in inc_dirs:
+ inc_dirs.append(inc_dir)
+ else:
+ extra_args[l].append(self.escape_additional_option(arg))
languages += gen_langs
has_language_specific_args = any(l != extra_args['c'] for l in extra_args.values())
@@ -669,7 +706,7 @@ class Vs2010Backend(backends.Backend):
inc_dirs.append('%(AdditionalIncludeDirectories)')
ET.SubElement(clconf, 'AdditionalIncludeDirectories').text = ';'.join(inc_dirs)
- preproc = ET.SubElement(clconf, 'PreprocessorDefinitions')
+ ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(defines)
rebuild = ET.SubElement(clconf, 'MinimalRebuild')
rebuild.text = 'true'
funclink = ET.SubElement(clconf, 'FunctionLevelLinking')