Ninja now supports backslash in command args, so we can too

At the same time, this also adds a bunch of tests that document and keep
track of how we expect quoting to pass through via Ninja to the
compiler.

We need at least Ninja 1.6.0 for this.

This fixes https://github.com/mesonbuild/meson/issues/489
pull/641/head
Nirbheek Chauhan 9 years ago
parent 4a92b78e6e
commit d8b9b12adb
  1. 24
      mesonbuild/build.py
  2. 2
      test cases/common/115 spaces backslash/asm output/meson.build
  3. 20
      test cases/common/115 spaces backslash/comparer-end-notstring.c
  4. 16
      test cases/common/115 spaces backslash/comparer-end.c
  5. 16
      test cases/common/115 spaces backslash/comparer.c
  6. 4
      test cases/common/115 spaces backslash/include/comparer.h
  7. 28
      test cases/common/115 spaces backslash/meson.build
  8. 10
      test cases/failing/24 backslash/comparer.c
  9. 3
      test cases/failing/24 backslash/meson.build

@ -50,28 +50,6 @@ known_shlib_kwargs.update({'version' : True,
'name_suffix' : True,
'vs_module_defs' : True})
backslash_explanation = \
'''Compiler arguments have a backslash "\\" character. This is unfortunately not
permitted. The reason for this is that backslash is a shell quoting character
that behaves differently across different systems. Because of this is it not
possible to make it work reliably across all the platforms Meson needs to
support.
There are several different ways of working around this issue. Most of the time
you are using this to provide a -D define to your compiler. Try instead to
create a config.h file and put all of your definitions in it using
configure_file().
Another approach is to move the backslashes into the source and have the other
bits in the def. So you would have an arg -DPLAIN_TEXT="foo" and then in your
C sources something like this:
const char *fulltext = "\\\\" PLAIN_TEXT;
We are fully aware that these are not really usable or pleasant ways to do
this but it's the best we can do given the way shell quoting works.
'''
def sources_are_suffix(sources, suffix):
for source in sources:
if source.endswith('.' + suffix):
@ -606,8 +584,6 @@ class BuildTarget():
for a in args:
if not isinstance(a, (str, File)):
raise InvalidArguments('A non-string passed to compiler args.')
if isinstance(a, str) and '\\' in a:
raise InvalidArguments(backslash_explanation)
if language in self.extra_args:
self.extra_args[language] += args
else:

@ -0,0 +1,2 @@
configure_file(output : 'blank.txt', configuration : configuration_data())

@ -0,0 +1,20 @@
#include "comparer.h"
#ifndef COMPARER_INCLUDED
#error "comparer.h not included"
#endif
/* This converts foo\\\\bar\\\\ to "foo\\bar\\" (string literal) */
#define Q(x) #x
#define QUOTE(x) Q(x)
#define COMPARE_WITH "foo\\bar\\" /* This is the literal `foo\bar\` */
int main(int argc, char **argv) {
if(strcmp(QUOTE(DEF_WITH_BACKSLASH), COMPARE_WITH)) {
printf("Arg string is quoted incorrectly: %s instead of %s\n",
QUOTE(DEF_WITH_BACKSLASH), COMPARE_WITH);
return 1;
}
return 0;
}

@ -0,0 +1,16 @@
#include "comparer.h"
#ifndef COMPARER_INCLUDED
#error "comparer.h not included"
#endif
#define COMPARE_WITH "foo\\bar\\" /* This is `foo\bar\` */
int main (int argc, char **argv) {
if (strcmp (DEF_WITH_BACKSLASH, COMPARE_WITH)) {
printf ("Arg string is quoted incorrectly: %s vs %s\n",
DEF_WITH_BACKSLASH, COMPARE_WITH);
return 1;
}
return 0;
}

@ -0,0 +1,16 @@
#include "comparer.h"
#ifndef COMPARER_INCLUDED
#error "comparer.h not included"
#endif
#define COMPARE_WITH "foo\\bar" /* This is the literal `foo\bar` */
int main (int argc, char **argv) {
if (strcmp (DEF_WITH_BACKSLASH, COMPARE_WITH)) {
printf ("Arg string is quoted incorrectly: %s instead of %s\n",
DEF_WITH_BACKSLASH, COMPARE_WITH);
return 1;
}
return 0;
}

@ -0,0 +1,4 @@
#include <string.h>
#include <stdio.h>
#define COMPARER_INCLUDED

@ -0,0 +1,28 @@
project('comparer', 'c')
# Added manually as a c_arg to test handling of include paths with backslashes
# and spaces. This is especially useful on Windows in vcxproj files since it
# stores include directories in a separate element that has its own
# context-specific escaping/quoting.
include_dir = meson.current_source_dir() + '/include'
default_c_args = ['-I' + include_dir]
if meson.get_compiler('c').get_id() == 'msvc'
default_c_args += ['/Faasm output\\']
# Hack to create the 'asm output' directory in the builddir
subdir('asm output')
endif
# Path can contain \. Here we're sending `"foo\bar"`.
test('backslash quoting',
executable('comparer', 'comparer.c',
c_args : default_c_args + ['-DDEF_WITH_BACKSLASH="foo\\bar"']))
# Path can end in \ without any special quoting. Here we send `"foo\bar\"`.
test('backslash end quoting',
executable('comparer-end', 'comparer-end.c',
c_args : default_c_args + ['-DDEF_WITH_BACKSLASH="foo\\bar\\"']))
# Path can (really) end in \ if we're not passing a string literal without any
# special quoting. Here we're sending `foo\bar\`.
test('backslash end quoting when not a string literal',
executable('comparer-end-notstring', 'comparer-end-notstring.c',
c_args : default_c_args + ['-DDEF_WITH_BACKSLASH=foo\\bar\\']))

@ -1,10 +0,0 @@
#include<string.h>
#include<stdio.h>
int main(int argc, char **argv) {
if(strcmp(DEF_WITH_BACKSLASH, "foo\\bar")) {
printf("Arg string is quoted incorrectly: %s\n", DEF_WITH_BACKSLASH);
return 1;
}
return 0;
}

@ -1,3 +0,0 @@
project('comparer', 'c')
test('backslash quoting', executable('comparer', 'comparer.c', c_args : '-DDEF_WITH_BACKSLASH="foo\\bar"'))
Loading…
Cancel
Save