aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/backends.py29
-rw-r--r--mesonbuild/backend/vs2010backend.py49
-rw-r--r--mesonbuild/build.py24
-rw-r--r--mesonbuild/dependencies.py187
-rw-r--r--mesonbuild/environment.py3
-rw-r--r--mesonbuild/interpreter.py17
-rw-r--r--mesonbuild/mesonmain.py9
-rw-r--r--mesonbuild/modules/windows.py2
-rw-r--r--test cases/common/115 spaces backslash/asm output/meson.build2
-rw-r--r--test cases/common/115 spaces backslash/comparer-end-notstring.c20
-rw-r--r--test cases/common/115 spaces backslash/comparer-end.c16
-rw-r--r--test cases/common/115 spaces backslash/comparer.c16
-rw-r--r--test cases/common/115 spaces backslash/include/comparer.h4
-rw-r--r--test cases/common/115 spaces backslash/meson.build28
-rw-r--r--test cases/failing/24 backslash/comparer.c10
-rw-r--r--test cases/failing/24 backslash/meson.build3
-rw-r--r--test cases/windows/9 find program/meson.build4
-rw-r--r--test cases/windows/9 find program/test-script3
-rwxr-xr-xtools/ac_converter.py1
19 files changed, 307 insertions, 120 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index d2693b2..1f1c3ca 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -296,6 +296,33 @@ class Backend():
args = includeargs + args
return args
+ @staticmethod
+ def escape_extra_args(compiler, args):
+ # No extra escaping/quoting needed when not running on Windows
+ if not mesonlib.is_windows():
+ return args
+ extra_args = []
+ # Compiler-specific escaping is needed for -D args but not for any others
+ if compiler.get_id() == 'msvc':
+ # MSVC needs escaping when a -D argument ends in \ or \"
+ for arg in args:
+ if arg.startswith('-D') or arg.startswith('/D'):
+ # Without extra escaping for these two, the next character
+ # gets eaten
+ if arg.endswith('\\'):
+ arg += '\\'
+ elif arg.endswith('\\"'):
+ arg = arg[:-2] + '\\\\"'
+ extra_args.append(arg)
+ else:
+ # MinGW GCC needs all backslashes in defines to be doubly-escaped
+ # FIXME: Not sure about Cygwin or Clang
+ for arg in args:
+ if arg.startswith('-D') or arg.startswith('/D'):
+ arg = arg.replace('\\', '\\\\')
+ extra_args.append(arg)
+ return extra_args
+
def generate_basic_compiler_args(self, target, compiler):
commands = []
commands += self.get_cross_stdlib_args(target, compiler)
@@ -304,7 +331,7 @@ class Backend():
commands += compiler.get_option_compile_args(self.environment.coredata.compiler_options)
commands += self.build.get_global_args(compiler)
commands += self.environment.coredata.external_args[compiler.get_language()]
- commands += target.get_extra_args(compiler.get_language())
+ commands += self.escape_extra_args(compiler, target.get_extra_args(compiler.get_language()))
commands += compiler.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
if self.environment.coredata.get_builtin_option('werror'):
commands += compiler.get_werror_args()
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')
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index b610bb8..6a4f375 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -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:
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index 2b77706..b4f825b 100644
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -122,56 +122,66 @@ class PkgConfigDependency(Dependency):
if self.required:
raise DependencyException('%s dependency %s not found.' % (self.type_string, name))
self.modversion = 'none'
+ return
+ self.modversion = out.decode().strip()
+ found_msg = ['%s dependency' % self.type_string, mlog.bold(name), 'found:']
+ self.version_requirement = kwargs.get('version', None)
+ if self.version_requirement is None:
+ self.is_found = True
else:
- self.modversion = out.decode().strip()
- mlog.log('%s dependency' % self.type_string, mlog.bold(name), 'found:',
- mlog.green('YES'), self.modversion)
- self.version_requirement = kwargs.get('version', None)
- if self.version_requirement is None:
- self.is_found = True
- else:
- if not isinstance(self.version_requirement, str):
- raise DependencyException('Version argument must be string.')
- self.is_found = mesonlib.version_compare(self.modversion, self.version_requirement)
- if not self.is_found and self.required:
+ if not isinstance(self.version_requirement, str):
+ raise DependencyException('Version argument must be string.')
+ self.is_found = mesonlib.version_compare(self.modversion, self.version_requirement)
+ if not self.is_found:
+ found_msg += [mlog.red('NO'), 'found {!r}'.format(self.modversion),
+ 'but need {!r}'.format(self.version_requirement)]
+ mlog.log(*found_msg)
+ if self.required:
raise DependencyException(
'Invalid version of a dependency, needed %s %s found %s.' %
(name, self.version_requirement, self.modversion))
- if not self.is_found:
return
- p = subprocess.Popen([pkgbin, '--cflags', name], stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out = p.communicate()[0]
- if p.returncode != 0:
- raise DependencyException('Could not generate cargs for %s:\n\n%s' % \
- (name, out.decode(errors='ignore')))
- self.cargs = out.decode().split()
-
- libcmd = [pkgbin, '--libs']
- if self.static:
- libcmd.append('--static')
- p = subprocess.Popen(libcmd + [name], stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out = p.communicate()[0]
- if p.returncode != 0:
- raise DependencyException('Could not generate libs for %s:\n\n%s' % \
- (name, out.decode(errors='ignore')))
- self.libs = []
- for lib in out.decode().split():
- if lib.endswith(".la"):
- shared_libname = self.extract_libtool_shlib(lib)
- shared_lib = os.path.join(os.path.dirname(lib), shared_libname)
- if not os.path.exists(shared_lib):
- shared_lib = os.path.join(os.path.dirname(lib), ".libs", shared_libname)
-
- if not os.path.exists(shared_lib):
- raise DependencyException('Got a libtools specific "%s" dependencies'
- 'but we could not compute the actual shared'
- 'library path' % lib)
- lib = shared_lib
- self.is_libtool = True
-
- self.libs.append(lib)
+ found_msg += [mlog.green('YES'), self.modversion]
+ mlog.log(*found_msg)
+ # Fetch cargs to be used while using this dependency
+ self._set_cargs()
+ # Fetch the libraries and library paths needed for using this
+ self._set_libs()
+
+ def _set_cargs(self):
+ p = subprocess.Popen([self.pkgbin, '--cflags', self.name],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out = p.communicate()[0]
+ if p.returncode != 0:
+ raise DependencyException('Could not generate cargs for %s:\n\n%s' % \
+ (name, out.decode(errors='ignore')))
+ self.cargs = out.decode().split()
+
+ def _set_libs(self):
+ libcmd = [self.pkgbin, '--libs']
+ if self.static:
+ libcmd.append('--static')
+ p = subprocess.Popen(libcmd + [self.name],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out = p.communicate()[0]
+ if p.returncode != 0:
+ raise DependencyException('Could not generate libs for %s:\n\n%s' % \
+ (name, out.decode(errors='ignore')))
+ self.libs = []
+ for lib in out.decode().split():
+ if lib.endswith(".la"):
+ shared_libname = self.extract_libtool_shlib(lib)
+ shared_lib = os.path.join(os.path.dirname(lib), shared_libname)
+ if not os.path.exists(shared_lib):
+ shared_lib = os.path.join(os.path.dirname(lib), ".libs", shared_libname)
+
+ if not os.path.exists(shared_lib):
+ raise DependencyException('Got a libtools specific "%s" dependencies'
+ 'but we could not compute the actual shared'
+ 'library path' % lib)
+ lib = shared_lib
+ self.is_libtool = True
+ self.libs.append(lib)
def get_variable(self, variable_name):
p = subprocess.Popen([self.pkgbin, '--variable=%s' % variable_name, self.name],
@@ -343,37 +353,13 @@ class WxDependency(Dependency):
class ExternalProgram():
def __init__(self, name, fullpath=None, silent=False, search_dir=None):
self.name = name
- self.fullpath = None
if fullpath is not None:
if not isinstance(fullpath, list):
self.fullpath = [fullpath]
else:
self.fullpath = fullpath
else:
- self.fullpath = [shutil.which(name)]
- if self.fullpath[0] is None and search_dir is not None:
- trial = os.path.join(search_dir, name)
- suffix = os.path.splitext(trial)[-1].lower()[1:]
- if mesonlib.is_windows() and (suffix == 'exe' or suffix == 'com'\
- or suffix == 'bat'):
- self.fullpath = [trial]
- elif not mesonlib.is_windows() and os.access(trial, os.X_OK):
- self.fullpath = [trial]
- else:
- # Now getting desperate. Maybe it is a script file that is a) not chmodded
- # executable or b) we are on windows so they can't be directly executed.
- try:
- first_line = open(trial).readline().strip()
- if first_line.startswith('#!'):
- commands = first_line[2:].split('#')[0].strip().split()
- if mesonlib.is_windows():
- # Windows does not have /usr/bin.
- commands[0] = commands[0].split('/')[-1]
- if commands[0] == 'env':
- commands = commands[1:]
- self.fullpath = commands + [trial]
- except Exception:
- pass
+ self.fullpath = self._search(name, search_dir)
if not silent:
if self.found():
mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'),
@@ -381,6 +367,67 @@ class ExternalProgram():
else:
mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO'))
+ @staticmethod
+ def _shebang_to_cmd(script):
+ """
+ Windows does not understand shebangs, so we check if the file has a
+ shebang and manually parse it to figure out the interpreter to use
+ """
+ try:
+ first_line = open(script).readline().strip()
+ if first_line.startswith('#!'):
+ commands = first_line[2:].split('#')[0].strip().split()
+ if mesonlib.is_windows():
+ # Windows does not have /usr/bin.
+ commands[0] = commands[0].split('/')[-1]
+ if commands[0] == 'env':
+ commands = commands[1:]
+ return commands + [script]
+ except Exception:
+ pass
+ return False
+
+ @staticmethod
+ def _is_executable(path):
+ suffix = os.path.splitext(path)[-1].lower()[1:]
+ if mesonlib.is_windows():
+ if suffix == 'exe' or suffix == 'com' or suffix == 'bat':
+ return True
+ elif os.access(path, os.X_OK):
+ return True
+ return False
+
+ def _search_dir(self, name, search_dir):
+ if search_dir is None:
+ return False
+ trial = os.path.join(search_dir, name)
+ if not os.path.exists(trial):
+ return False
+ if self._is_executable(trial):
+ return [trial]
+ # Now getting desperate. Maybe it is a script file that is a) not chmodded
+ # executable or b) we are on windows so they can't be directly executed.
+ return self._shebang_to_cmd(trial)
+
+ def _search(self, name, search_dir):
+ commands = self._search_dir(name, search_dir)
+ if commands:
+ return commands
+ # Do a standard search in PATH
+ fullpath = shutil.which(name)
+ if fullpath or not mesonlib.is_windows():
+ # On UNIX-like platforms, the standard PATH search is enough
+ return [fullpath]
+ # On Windows, interpreted scripts must have an extension otherwise they
+ # cannot be found by a standard PATH search. So we do a custom search
+ # where we manually search for a script with a shebang in PATH.
+ search_dirs = os.environ.get('PATH', '').split(';')
+ for search_dir in search_dirs:
+ commands = self._search_dir(name, search_dir)
+ if commands:
+ return commands
+ return [None]
+
def found(self):
return self.fullpath[0] is not None
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 6375938..404ed3e 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -171,9 +171,10 @@ class Environment():
def is_cross_build(self):
return self.cross_info is not None
- def dump_coredata(self):
+ def dump_coredata(self, mtime):
cdf = os.path.join(self.get_build_dir(), Environment.coredata_file)
coredata.save(self.coredata, cdf)
+ os.utime(cdf, times=(mtime, mtime))
def get_script_dir(self):
import mesonbuild.scripts
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 51c40c9..5201be2 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -1683,21 +1683,29 @@ class Interpreter():
dep = dependencies.find_external_dependency(name, self.environment, kwargs)
except dependencies.DependencyException:
if 'fallback' in kwargs:
- dep = self.dependency_fallback(kwargs)
+ dep = self.dependency_fallback(name, kwargs)
self.coredata.deps[identifier] = dep.held_object
return dep
raise
self.coredata.deps[identifier] = dep
return DependencyHolder(dep)
- def dependency_fallback(self, kwargs):
+ def dependency_fallback(self, name, kwargs):
fbinfo = kwargs['fallback']
check_stringlist(fbinfo)
if len(fbinfo) != 2:
raise InterpreterException('Fallback info must have exactly two items.')
dirname, varname = fbinfo
- self.do_subproject(dirname, {})
+ try:
+ self.do_subproject(dirname, {})
+ except:
+ mlog.log('Also couldn\'t find a fallback subproject in',
+ mlog.bold(os.path.join(self.subproject_dir, dirname)),
+ 'for the dependency', mlog.bold(name))
+ raise
dep = self.subprojects[dirname].get_variable_method([varname], {})
+ if not isinstance(dep, (DependencyHolder, InternalDependencyHolder)):
+ raise InterpreterException('Fallback variable is not a dependency object.')
# Check if the version of the declared dependency matches what we want
if 'version' in kwargs:
wanted = kwargs['version']
@@ -1705,6 +1713,9 @@ class Interpreter():
if found == 'undefined' or not mesonlib.version_compare(found, wanted):
m = 'Subproject "{0}" dependency "{1}" version is "{2}" but "{3}" is required.'
raise InterpreterException(m.format(dirname, varname, found, wanted))
+ mlog.log('Found a', mlog.green('fallback'), 'subproject',
+ mlog.bold(os.path.join(self.subproject_dir, dirname)), 'for',
+ mlog.bold(name))
return dep
def func_executable(self, node, args, kwargs):
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index e61c602..e002d9a 100644
--- a/mesonbuild/mesonmain.py
+++ b/mesonbuild/mesonmain.py
@@ -15,7 +15,7 @@
# limitations under the License.
import sys, stat, traceback, pickle, argparse
-import datetime
+import time, datetime
import os.path
from . import environment, interpreter, mesonlib
from . import build
@@ -164,6 +164,7 @@ itself as required.'''
mlog.log('Build machine cpu family:', mlog.bold(intr.builtin['build_machine'].cpu_family_method([], {})))
mlog.log('Build machine cpu:', mlog.bold(intr.builtin['build_machine'].cpu_method([], {})))
intr.run()
+ coredata_mtime = time.time()
g.generate(intr)
g.run_postconf_scripts()
dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat')
@@ -173,7 +174,11 @@ itself as required.'''
# that pops up during generation, post-conf scripts, etc to cause us to
# incorrectly signal a successful meson run which will cause an error
# about an already-configured build directory when the user tries again.
- env.dump_coredata()
+ #
+ # However, we set the mtime to an earlier value to ensure that doing an
+ # mtime comparison between the coredata dump and other build files
+ # shows the build files to be newer, not older.
+ env.dump_coredata(coredata_mtime)
def run_script_command(args):
cmdname = args[0]
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
index 7bf0319..cd4e343 100644
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -38,6 +38,8 @@ class WindowsModule:
rescomp = dependencies.ExternalProgram(rescomp_name, silent=True)
res_args = extra_args + ['@INPUT@', '@OUTPUT@']
suffix = 'o'
+ if not rescomp.found():
+ raise MesonException('Could not find Windows resource compiler %s.' % ' '.join(rescomp.get_command()))
res_files = mesonlib.stringlistify(args)
res_kwargs = {'output' : '@BASENAME@.' + suffix,
'arguments': res_args}
diff --git a/test cases/common/115 spaces backslash/asm output/meson.build b/test cases/common/115 spaces backslash/asm output/meson.build
new file mode 100644
index 0000000..b5f13f5
--- /dev/null
+++ b/test cases/common/115 spaces backslash/asm output/meson.build
@@ -0,0 +1,2 @@
+configure_file(output : 'blank.txt', configuration : configuration_data())
+
diff --git a/test cases/common/115 spaces backslash/comparer-end-notstring.c b/test cases/common/115 spaces backslash/comparer-end-notstring.c
new file mode 100644
index 0000000..65bf8bc
--- /dev/null
+++ b/test cases/common/115 spaces backslash/comparer-end-notstring.c
@@ -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;
+}
diff --git a/test cases/common/115 spaces backslash/comparer-end.c b/test cases/common/115 spaces backslash/comparer-end.c
new file mode 100644
index 0000000..fef25a5
--- /dev/null
+++ b/test cases/common/115 spaces backslash/comparer-end.c
@@ -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;
+}
diff --git a/test cases/common/115 spaces backslash/comparer.c b/test cases/common/115 spaces backslash/comparer.c
new file mode 100644
index 0000000..937cb47
--- /dev/null
+++ b/test cases/common/115 spaces backslash/comparer.c
@@ -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;
+}
diff --git a/test cases/common/115 spaces backslash/include/comparer.h b/test cases/common/115 spaces backslash/include/comparer.h
new file mode 100644
index 0000000..624d96c
--- /dev/null
+++ b/test cases/common/115 spaces backslash/include/comparer.h
@@ -0,0 +1,4 @@
+#include <string.h>
+#include <stdio.h>
+
+#define COMPARER_INCLUDED
diff --git a/test cases/common/115 spaces backslash/meson.build b/test cases/common/115 spaces backslash/meson.build
new file mode 100644
index 0000000..bf614e8
--- /dev/null
+++ b/test cases/common/115 spaces backslash/meson.build
@@ -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\\']))
diff --git a/test cases/failing/24 backslash/comparer.c b/test cases/failing/24 backslash/comparer.c
deleted file mode 100644
index f562f5e..0000000
--- a/test cases/failing/24 backslash/comparer.c
+++ /dev/null
@@ -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;
-}
diff --git a/test cases/failing/24 backslash/meson.build b/test cases/failing/24 backslash/meson.build
deleted file mode 100644
index dba891e..0000000
--- a/test cases/failing/24 backslash/meson.build
+++ /dev/null
@@ -1,3 +0,0 @@
-project('comparer', 'c')
-
-test('backslash quoting', executable('comparer', 'comparer.c', c_args : '-DDEF_WITH_BACKSLASH="foo\\bar"'))
diff --git a/test cases/windows/9 find program/meson.build b/test cases/windows/9 find program/meson.build
new file mode 100644
index 0000000..ef34586
--- /dev/null
+++ b/test cases/windows/9 find program/meson.build
@@ -0,0 +1,4 @@
+project('find program', 'c')
+
+prog = find_program('test-script')
+test('script', prog)
diff --git a/test cases/windows/9 find program/test-script b/test cases/windows/9 find program/test-script
new file mode 100644
index 0000000..d105a81
--- /dev/null
+++ b/test cases/windows/9 find program/test-script
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+
+print('1')
diff --git a/tools/ac_converter.py b/tools/ac_converter.py
index c7dbd37..2f1b4c3 100755
--- a/tools/ac_converter.py
+++ b/tools/ac_converter.py
@@ -116,6 +116,7 @@ function_data = \
'HAVE_READLINK': ('readlink', 'unistd.h'),
'HAVE_RES_INIT': ('res_init', 'resolv.h'),
'HAVE_SENDMMSG': ('sendmmsg', 'sys/socket.h'),
+ 'HAVE_SOCKET' : ('socket',' sys/socket.h'),
'HAVE_GETENV': ('getenv', 'stdlib.h'),
'HAVE_SETENV': ('setenv', 'stdlib.h'),
'HAVE_PUTENV': ('putenv', 'stdlib.h'),