diff options
author | Nirbheek Chauhan <nirbheek@centricular.com> | 2016-07-29 18:25:43 +0530 |
---|---|---|
committer | Nirbheek Chauhan <nirbheek@centricular.com> | 2016-07-29 19:51:10 +0530 |
commit | 2d05008956dedbfb4b6c8b690c4f025451aea587 (patch) | |
tree | 01b066f628a7c8779167d54edb0397a36402b7cf /mesonbuild/backend/vs2010backend.py | |
parent | d8b9b12adbd2fa04f40ea2823929acc41f0a8003 (diff) | |
download | meson-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.py | 49 |
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') |