Repository: mesonbuild/meson

Issue:
LDC can't parse RSP file issued by Meson
**Describe the bug**
When the command line length hits a threshold, it is converted to a RSP file. In this file, some of the arguments are quoted using python `shlex.quote`.
`shlex.quote` happens to quote using single quotes `'` (at least on Windows).

In my case, the RSP file contains among many other `'-L=/PDB:lib\\doptest.pdb'` and LDC fails to parse with `Error: unrecognized file extension pdb'`. (note the `'` in the file extension).

LDC forwards expansion of RSP file directly to LLVM ([implementation](https://llvm.org/doxygen/CommandLine_8cpp_source.html#l00930))

So who's to blame here? `shlex` ? LLVM? Meson (for using shlex)?

**To Reproduce**
you may set `MESON_RSP_THRESHOLD` to a low value and compile a D project with LDC.

**Expected behavior**
No failure

**system parameters**
* plain native build 
* Windows 10
* Python 3.9.0
* Meson 0.57.1
* Ninja 1.10.1



Discussion:
Hmmm, we shouldn't be using shlex on windows, we have a separate meson implemented method for windows
With my build on Windows with LDC I have meson choosing gcc style quote for rsp for the following rules:
 - `depscan`
 - `d_COMPILER_FOR_BUILD`
 - `d_COMPILER`
 - `STATIC_LINKER_FOR_BUILD`
 - `STATIC_LINKER`
 - `d_LINKER_FOR_BUILD`
 - `d_LINKER`
 - `SHSYM`
 - `CUSTOM_COMMAND`
 - `CUSTOM_COMMAND_DEP`
 - `REGENERATE_BUILD`

The RSP only kicks in for the `d_LINKER` however.

at least for the compile and link rules, the logic is the following:
```python
        rspfile_quote_style='cl' if (compiler.get_argument_syntax() == 'msvc' or
                                     isinstance(compiler, DmdDCompiler)) else 'gcc',
```
I guess this should be more general like
```python
        rspfile_quote_style='cl' if (is_msvc() or is_dlang() and is_windows()) else 'gcc',
```
or even maybe
```python
        rspfile_quote_style='cl' if is_windows() else 'gcc',
```


Resolving patch:
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -33,7 +33,9 @@
 from ..compilers import (
     Compiler, CCompiler,
     DmdDCompiler,
-    FortranCompiler, PGICCompiler,
+    FortranCompiler,
+    LLVMDCompiler,
+    PGICCompiler,
     VisualStudioCsCompiler,
     VisualStudioLikeCompiler,
 )
@@ -89,6 +91,13 @@ def gcc_rsp_quote(s):
     execute_wrapper = []
     rmfile_prefix = ['rm', '-f', '{}', '&&']
 
+
+def dlang_cl_rsp(compiler: Compiler) -> bool:
+    '''Return whether the D compiler accepts cl style RSP quote'''
+    return (isinstance(compiler, DmdDCompiler) or
+        mesonlib.is_windows() and isinstance(compiler, LLVMDCompiler))
+
+
 def get_rsp_threshold():
     '''Return a conservative estimate of the commandline size in bytes
     above which a response file should be used.  May be overridden for
@@ -1887,7 +1896,7 @@ def generate_dynamic_link_rules(self):
                 self.add_rule(NinjaRule(rule, command, args, description,
                                         rspable=compiler.can_linker_accept_rsp(),
                                         rspfile_quote_style='cl' if (compiler.get_argument_syntax() == 'msvc' or
-                                                                     isinstance(compiler, DmdDCompiler)) else 'gcc',
+                                                                     dlang_cl_rsp(compiler)) else 'gcc',
                                         extra=pool))
 
         args = self.environment.get_build_command() + \
@@ -2011,7 +2020,7 @@ def generate_compile_rule_for(self, langname, compiler):
         self.add_rule(NinjaRule(rule, command, args, description,
                                 rspable=compiler.can_linker_accept_rsp(),
                                 rspfile_quote_style='cl' if (compiler.get_argument_syntax() == 'msvc' or
-                                                             isinstance(compiler, DmdDCompiler)) else 'gcc',
+                                                             dlang_cl_rsp(compiler)) else 'gcc',
                                 deps=deps, depfile=depfile))
 
     def generate_pch_rule_for(self, langname, compiler):


Test patch: