aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/backend/vs2010backend.py
diff options
context:
space:
mode:
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')