aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MANIFEST.in2
-rw-r--r--man/meson.12
-rw-r--r--man/mesonconf.12
-rw-r--r--man/mesonintrospect.12
-rw-r--r--man/wraptool.12
-rw-r--r--manual tests/1 wrap/meson.build13
-rw-r--r--manual tests/1 wrap/subprojects/sqlite.wrap6
-rw-r--r--manual tests/4 standalone binaries/readme.txt2
-rw-r--r--mesonbuild/backend/backends.py49
-rw-r--r--mesonbuild/backend/ninjabackend.py40
-rw-r--r--mesonbuild/backend/vs2010backend.py281
-rw-r--r--mesonbuild/backend/vs2015backend.py1
-rw-r--r--mesonbuild/backend/xcodebackend.py8
-rw-r--r--mesonbuild/build.py326
-rw-r--r--mesonbuild/compilers.py49
-rw-r--r--mesonbuild/coredata.py8
-rw-r--r--mesonbuild/dependencies.py193
-rw-r--r--mesonbuild/environment.py105
-rw-r--r--mesonbuild/interpreter.py46
-rw-r--r--mesonbuild/mesonlib.py10
-rw-r--r--mesonbuild/mesonmain.py22
-rw-r--r--mesonbuild/modules/gnome.py2
-rw-r--r--mesonbuild/modules/windows.py7
-rw-r--r--mesonbuild/mparser.py20
-rw-r--r--mesonbuild/scripts/depfixer.py30
-rw-r--r--mesonbuild/scripts/gtkdochelper.py36
-rw-r--r--mesonbuild/scripts/meson_install.py24
-rw-r--r--mesonbuild/scripts/regen_checker.py11
-rwxr-xr-xrun_cross_test.py2
-rwxr-xr-xrun_tests.py138
-rw-r--r--test cases/common/114 multiple dir configure file/meson.build7
-rw-r--r--test cases/common/114 multiple dir configure file/subdir/meson.build4
-rw-r--r--test cases/common/114 multiple dir configure file/subdir/someinput.in0
-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/common/116 ternary/meson.build7
-rw-r--r--test cases/common/27 library versions/installed_files.txt4
-rw-r--r--test cases/common/27 library versions/meson.build11
-rw-r--r--test cases/common/27 library versions/subdir/meson.build8
-rw-r--r--test cases/common/46 library chain/installed_files.txt5
-rw-r--r--test cases/common/46 library chain/subdir/meson.build2
-rw-r--r--test cases/common/46 library chain/subdir/subdir2/meson.build2
-rw-r--r--test cases/common/46 library chain/subdir/subdir3/meson.build2
-rw-r--r--test cases/common/49 subproject/installed_files.txt3
-rw-r--r--test cases/common/49 subproject/subprojects/sublib/meson.build2
-rw-r--r--test cases/common/51 pkgconfig-gen/installed_files.txt1
-rw-r--r--test cases/common/51 pkgconfig-gen/meson.build2
-rw-r--r--test cases/common/52 custom install dirs/installed_files.txt2
-rw-r--r--test cases/common/6 linkshared/installed_files.txt3
-rw-r--r--test cases/common/6 linkshared/meson.build2
-rw-r--r--test cases/common/60 install script/installed_files.txt2
-rw-r--r--test cases/common/60 install script/meson.build4
-rw-r--r--test cases/common/60 install script/myinstall.bat3
-rwxr-xr-xtest cases/common/60 install script/myinstall.sh4
-rw-r--r--test cases/common/60 install script/no-installed-files0
-rw-r--r--test cases/common/67 foreach/installed_files.txt6
-rw-r--r--test cases/common/76 configure file in custom target/src/meson.build16
-rw-r--r--test cases/common/8 install/installed_files.txt5
-rw-r--r--test cases/common/8 install/meson.build3
-rw-r--r--test cases/common/8 install/shar.c1
-rw-r--r--test cases/common/86 same basename/meson.build7
-rw-r--r--test cases/common/86 same basename/sub/meson.build1
-rw-r--r--test cases/csharp/2 library/installed_files.txt2
-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/failing/30 nested ternary/meson.build3
-rw-r--r--test cases/linuxlike/7 library versions/installed_files.txt9
-rw-r--r--test cases/linuxlike/7 library versions/lib.c3
-rw-r--r--test cases/linuxlike/7 library versions/meson.build18
-rw-r--r--test cases/linuxlike/8 subproject library install/installed_files.txt3
-rw-r--r--test cases/linuxlike/8 subproject library install/meson.build6
-rw-r--r--test cases/linuxlike/8 subproject library install/subprojects/sublib/include/subdefs.h21
-rw-r--r--test cases/linuxlike/8 subproject library install/subprojects/sublib/meson.build10
-rw-r--r--test cases/linuxlike/8 subproject library install/subprojects/sublib/sublib.c5
-rw-r--r--test cases/osx/2 library versions/installed_files.txt4
-rw-r--r--test cases/osx/2 library versions/lib.c3
-rw-r--r--test cases/osx/2 library versions/meson.build18
-rw-r--r--test cases/prebuilt/1 object/main.c (renamed from test cases/prebuilt object/1 basic/main.c)0
-rw-r--r--test cases/prebuilt/1 object/meson.build (renamed from test cases/prebuilt object/1 basic/meson.build)0
-rw-r--r--test cases/prebuilt/1 object/source.c (renamed from test cases/prebuilt object/1 basic/source.c)0
-rw-r--r--test cases/prebuilt/2 static/libdir/best.c3
-rw-r--r--test cases/prebuilt/2 static/libdir/best.h3
-rw-r--r--test cases/prebuilt/2 static/libdir/meson.build5
-rw-r--r--test cases/prebuilt/2 static/main.c7
-rw-r--r--test cases/prebuilt/2 static/meson.build5
-rw-r--r--test cases/rust/1 basic/installed_files.txt2
-rw-r--r--test cases/rust/2 sharedlib/installed_files.txt2
-rw-r--r--test cases/rust/3 staticlib/installed_files.txt2
-rw-r--r--test cases/windows/7 mingw dll versioning/installed_files.txt4
-rw-r--r--test cases/windows/7 mingw dll versioning/lib.c6
-rw-r--r--test cases/windows/7 mingw dll versioning/meson.build17
-rw-r--r--test cases/windows/7 mingw dll versioning/no-installed-files0
-rw-r--r--test cases/windows/8 msvc dll versioning/installed_files.txt4
-rw-r--r--test cases/windows/8 msvc dll versioning/lib.c6
-rw-r--r--test cases/windows/8 msvc dll versioning/meson.build16
-rw-r--r--test cases/windows/8 msvc dll versioning/no-installed-files0
-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.py8
103 files changed, 1405 insertions, 454 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index 6df696f..234c773 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -8,7 +8,7 @@ graft tools
include authors.txt
include contributing.txt
include COPYING
-include readme.txt
+include README.md
include run_cross_test.py
include run_tests.py
include ghwt.py
diff --git a/man/meson.1 b/man/meson.1
index 8432321..83ac397 100644
--- a/man/meson.1
+++ b/man/meson.1
@@ -1,4 +1,4 @@
-.TH MESON "1" "June 2016" "meson 0.32.0" "User Commands"
+.TH MESON "1" "July 2016" "meson 0.33.0" "User Commands"
.SH NAME
meson - a high productivity build system
.SH DESCRIPTION
diff --git a/man/mesonconf.1 b/man/mesonconf.1
index e1cef24..35f8486 100644
--- a/man/mesonconf.1
+++ b/man/mesonconf.1
@@ -1,4 +1,4 @@
-.TH MESONCONF "1" "June 2016" "mesonconf 0.32.0" "User Commands"
+.TH MESONCONF "1" "July 2016" "mesonconf 0.33.0" "User Commands"
.SH NAME
mesonconf - a tool to configure Meson builds
.SH DESCRIPTION
diff --git a/man/mesonintrospect.1 b/man/mesonintrospect.1
index 39392e3..307b99a 100644
--- a/man/mesonintrospect.1
+++ b/man/mesonintrospect.1
@@ -1,4 +1,4 @@
-.TH MESONCONF "1" "June 2016" "mesonintrospect 0.32.0" "User Commands"
+.TH MESONCONF "1" "July 2016" "mesonintrospect 0.33.0" "User Commands"
.SH NAME
mesonintrospect - a tool to extract information about a Meson build
.SH DESCRIPTION
diff --git a/man/wraptool.1 b/man/wraptool.1
index 780b8e2..26d942f 100644
--- a/man/wraptool.1
+++ b/man/wraptool.1
@@ -1,4 +1,4 @@
-.TH WRAPTOOL "1" "June 2016" "meson 0.32.0" "User Commands"
+.TH WRAPTOOL "1" "July 2016" "meson 0.33.0" "User Commands"
.SH NAME
wraptool - source dependency downloader
.SH DESCRIPTION
diff --git a/manual tests/1 wrap/meson.build b/manual tests/1 wrap/meson.build
index 99ea260..aee358d 100644
--- a/manual tests/1 wrap/meson.build
+++ b/manual tests/1 wrap/meson.build
@@ -1,14 +1,13 @@
project('downloader', 'c')
-s = subproject('sqlite')
+cc = meson.get_compiler('c')
-libdl = find_library('dl', required : false)
+s = subproject('sqlite').get_variable('sqlite_dep')
+th = dependency('threads')
+
+libdl = cc.find_library('dl', required : false)
e = executable('dtest', 'main.c',
- include_directories : s.get_variable('sqinc'),
- link_args : ['-pthread'],
- c_args : '-pthread',
- dependencies : libdl,
- link_with : s.get_variable('sqlib'))
+ dependencies : [th, libdl, s])
test('dltest', e)
diff --git a/manual tests/1 wrap/subprojects/sqlite.wrap b/manual tests/1 wrap/subprojects/sqlite.wrap
index cf6ff7a..6d14949 100644
--- a/manual tests/1 wrap/subprojects/sqlite.wrap
+++ b/manual tests/1 wrap/subprojects/sqlite.wrap
@@ -5,6 +5,6 @@ source_url = http://sqlite.com/2015/sqlite-amalgamation-3080802.zip
source_filename = sqlite-amalgamation-3080802.zip
source_hash = 5ebeea0dfb75d090ea0e7ff84799b2a7a1550db3fe61eb5f6f61c2e971e57663
-patch_url = http://wrapdb.mesonbuild.com/v1/projects/sqlite/3080802/2/get_zip
-patch_filename = sqlite-3080802-2-wrap.zip
-patch_hash = 300eb0e16cf7d32e873f16617de959c0a3e914614c5fddcff858fc010db10688
+patch_url = https://wrapdb.mesonbuild.com/v1/projects/sqlite/3080802/5/get_zip
+patch_filename = sqlite-3080802-5-wrap.zip
+patch_hash = d66469a73fa1344562d56a1d7627d5d0ee4044a77b32d16cf4bbb85741d4c9fd
diff --git a/manual tests/4 standalone binaries/readme.txt b/manual tests/4 standalone binaries/readme.txt
index 5a3604d..991b5c6 100644
--- a/manual tests/4 standalone binaries/readme.txt
+++ b/manual tests/4 standalone binaries/readme.txt
@@ -1,6 +1,6 @@
This directory shows how you can build redistributable binaries. On
OSX this menans building an app bundle and a .dmg installer. On Linux
-it means building a binary that bundles its dependencies. On Windows
+it means building an archive that bundles its dependencies. On Windows
it means building an .exe installer.
To build each package you run the corresponding build_ARCH.sh build
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
index fcc3d3b..1f1c3ca 100644
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -110,9 +110,13 @@ class Backend():
# On some platforms (msvc for instance), the file that is used for
# dynamic linking is not the same as the dynamic library itself. This
# file is called an import library, and we want to link against that.
- # On platforms where this distinction is not important, the import
- # library is the same as the dynamic library itself.
- return os.path.join(self.get_target_dir(target), target.get_import_filename())
+ # On all other platforms, we link to the library directly.
+ if isinstance(target, build.SharedLibrary):
+ link_lib = target.get_import_filename() or target.get_filename()
+ return os.path.join(self.get_target_dir(target), link_lib)
+ elif isinstance(target, build.StaticLibrary):
+ return os.path.join(self.get_target_dir(target), target.get_filename())
+ raise AssertionError('BUG: Tried to link to something that\'s not a library')
def get_target_dir(self, target):
if self.environment.coredata.get_builtin_option('layout') == 'mirror':
@@ -292,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)
@@ -300,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()
@@ -496,11 +527,19 @@ class Backend():
if isinstance(i, build.Executable):
cmd += self.exe_object_to_cmd_array(i)
continue
- if isinstance(i, build.CustomTarget):
+ elif isinstance(i, build.CustomTarget):
# GIR scanner will attempt to execute this binary but
# it assumes that it is in path, so always give it a full path.
tmp = i.get_filename()[0]
i = os.path.join(self.get_target_dir(i), tmp)
+ elif isinstance(i, mesonlib.File):
+ i = os.path.join(i.subdir, i.fname)
+ if absolute_paths:
+ i = os.path.join(self.environment.get_build_dir(), i)
+ # FIXME: str types are blindly added and ignore the 'absolute_paths' argument
+ elif not isinstance(i, str):
+ err_msg = 'Argument {0} is of unknown type {1}'
+ raise RuntimeError(err_msg.format(str(i), str(type(i))))
for (j, src) in enumerate(srcs):
i = i.replace('@INPUT%d@' % j, src)
for (j, res) in enumerate(ofilenames):
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index a1bccc2..15f298b 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -496,18 +496,33 @@ int dummy;
pickle.dump(d, ofile)
def generate_target_install(self, d):
- libdir = self.environment.get_libdir()
- bindir = self.environment.get_bindir()
-
should_strip = self.environment.coredata.get_builtin_option('strip')
for t in self.build.get_targets().values():
if t.should_install():
+ # Find the installation directory
outdir = t.get_custom_install_dir()
- if outdir is None:
- if isinstance(t, build.Executable):
- outdir = bindir
- else:
- outdir = libdir
+ if outdir is not None:
+ pass
+ elif isinstance(t, build.SharedLibrary):
+ # For toolchains/platforms that need an import library for
+ # linking (separate from the shared library with all the
+ # code), we need to install the import library (dll.a/.lib)
+ if t.get_import_filename():
+ # Install the import library.
+ i = [self.get_target_filename_for_linking(t),
+ self.environment.get_import_lib_dir(),
+ # It has no aliases, should not be stripped, and
+ # doesn't have an install_rpath
+ [], False, '']
+ d.targets.append(i)
+ outdir = self.environment.get_shared_lib_dir()
+ elif isinstance(t, build.StaticLibrary):
+ outdir = self.environment.get_static_lib_dir()
+ elif isinstance(t, build.Executable):
+ outdir = self.environment.get_bindir()
+ else:
+ # XXX: Add BuildTarget-specific install dir cases here
+ outdir = self.environment.get_libdir()
i = [self.get_target_filename(t), outdir, t.get_aliaslist(),\
should_strip, t.install_rpath]
d.targets.append(i)
@@ -1665,8 +1680,12 @@ rule FORTRAN_DEP_HACK
else:
soversion = None
commands += linker.get_soname_args(target.name, abspath, soversion)
+ # This is only visited when using the Visual Studio toolchain
if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'):
commands += linker.gen_vs_module_defs_args(target.vs_module_defs.rel_to_builddir(self.build_to_src))
+ # This is only visited when building for Windows using either MinGW/GCC or Visual Studio
+ if target.import_filename:
+ commands += linker.gen_import_library_args(os.path.join(target.subdir, target.import_filename))
elif isinstance(target, build.StaticLibrary):
commands += linker.get_std_link_args()
else:
@@ -1684,8 +1703,7 @@ rule FORTRAN_DEP_HACK
commands += linker.thread_link_flags()
if not isinstance(target, build.StaticLibrary):
commands += target.link_args
- # External deps must be last because target link libraries may depend on them.
- if not(isinstance(target, build.StaticLibrary)):
+ # External deps must be last because target link libraries may depend on them.
for dep in target.get_external_deps():
commands += dep.get_link_args()
for d in target.get_dependencies():
@@ -1803,7 +1821,7 @@ rule FORTRAN_DEP_HACK
ninja_command = environment.detect_ninja()
if ninja_command is None:
- raise MesonException('Could not detect ninja command')
+ raise MesonException('Could not detect Ninja v1.6 or newer)')
elem = NinjaBuildElement(self.all_outputs, 'clean', 'CUSTOM_COMMAND', 'PHONY')
elem.add_item('COMMAND', [ninja_command, '-t', 'clean'])
elem.add_item('description', 'Cleaning')
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index d262e6b..669bcf8 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -28,6 +28,27 @@ import xml.dom.minidom
from ..mesonlib import MesonException
from ..environment import Environment
+def split_o_flags_args(args):
+ """
+ Splits any /O args and returns them. Does not take care of flags overriding
+ previous ones. Skips non-O flag arguments.
+
+ ['/Ox', '/Ob1'] returns ['/Ox', '/Ob1']
+ ['/Oxj', '/MP'] returns ['/Ox', '/Oj']
+ """
+ o_flags = []
+ for arg in args:
+ if not arg.startswith('/O'):
+ continue
+ flags = list(arg[2:])
+ # Assume that this one can't be clumped with the others since it takes
+ # an argument itself
+ if 'b' in flags:
+ o_flags.append(arg)
+ else:
+ o_flags += ['/O' + f for f in flags]
+ return o_flags
+
class RegenInfo():
def __init__(self, source_dir, build_dir, depfiles):
self.source_dir = source_dir
@@ -40,6 +61,7 @@ class Vs2010Backend(backends.Backend):
self.project_file_version = '10.0.30319.1'
self.sources_conflicts = {}
self.platform_toolset = None
+ self.vs_version = '2010'
def object_filename_from_source(self, target, source):
basename = os.path.basename(source.fname)
@@ -76,9 +98,14 @@ class Vs2010Backend(backends.Backend):
outputs = []
custom_target_include_dirs = []
custom_target_output_files = []
+ target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))
+ down = self.target_to_build_root(target)
for genlist in target.get_generated_sources():
if isinstance(genlist, build.CustomTarget):
- custom_target_output_files += [os.path.join(self.get_target_dir(genlist), i) for i in genlist.output]
+ for i in genlist.output:
+ # Path to the generated source from the current vcxproj dir via the build root
+ ipath = os.path.join(down, self.get_target_dir(genlist), i)
+ custom_target_output_files.append(ipath)
idir = self.relpath(self.get_target_dir(genlist), self.get_target_dir(target))
if idir not in custom_target_include_dirs:
custom_target_include_dirs.append(idir)
@@ -89,7 +116,6 @@ class Vs2010Backend(backends.Backend):
outfilelist = genlist.get_outfilelist()
exe_arr = self.exe_object_to_cmd_array(exe)
base_args = generator.get_arglist()
- target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))
for i in range(len(infilelist)):
if len(infilelist) == len(outfilelist):
sole_output = os.path.join(target_private_dir, outfilelist[i])
@@ -123,7 +149,17 @@ class Vs2010Backend(backends.Backend):
def generate(self, interp):
self.resolve_source_conflicts()
self.interpreter = interp
- self.platform = 'Win32'
+ target_machine = self.interpreter.builtin['target_machine'].cpu_family_method(None, None)
+ if target_machine.endswith('64'):
+ # amd64 or x86_64
+ self.platform = 'x64'
+ elif target_machine == 'x86':
+ # x86
+ self.platform = 'Win32'
+ elif 'arm' in target_machine.lower():
+ self.platform = 'ARM'
+ else:
+ raise MesonException('Unsupported Visual Studio platform: ' + target_machine)
self.buildtype = self.environment.coredata.get_builtin_option('buildtype')
sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln')
projlist = self.generate_projects()
@@ -183,7 +219,7 @@ class Vs2010Backend(backends.Backend):
def generate_solution(self, sln_filename, projlist):
ofile = open(sln_filename, 'w')
ofile.write('Microsoft Visual Studio Solution File, Format Version 11.00\n')
- ofile.write('# Visual Studio 2010\n')
+ ofile.write('# Visual Studio ' + self.vs_version + '\n')
prj_templ = prj_line = 'Project("{%s}") = "%s", "%s", "{%s}"\n'
for p in projlist:
prj_line = prj_templ % (self.environment.coredata.guid, p[0], p[1], p[2])
@@ -400,9 +436,61 @@ 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):
+ """
+ Split a list of link arguments into three lists:
+ * library search paths
+ * library filenames (or paths)
+ * other link arguments
+ """
+ lpaths = []
+ libs = []
+ other = []
+ for arg in args:
+ if arg.startswith('/LIBPATH:'):
+ lpath = arg[9:]
+ # De-dup library search paths by removing older entries when
+ # a new one is found. This is necessary because unlike other
+ # search paths such as the include path, the library is
+ # searched for in the newest (right-most) search path first.
+ if lpath in lpaths:
+ lpaths.remove(lpath)
+ lpaths.append(lpath)
+ # It's ok if we miss libraries with non-standard extensions here.
+ # They will go into the general link arguments.
+ elif arg.endswith('.lib') or arg.endswith('.a'):
+ # De-dup
+ if arg not in libs:
+ libs.append(arg)
+ else:
+ other.append(arg)
+ return (lpaths, libs, other)
def gen_vcxproj(self, target, ofname, guid, compiler):
mlog.debug('Generating vcxproj %s.' % target.name)
@@ -424,11 +512,15 @@ class Vs2010Backend(backends.Backend):
return self.gen_run_target_vcxproj(target, ofname, guid)
else:
raise MesonException('Unknown target type for %s' % target.get_basename())
+ # Prefix to use to access the build root from the vcxproj dir
down = self.target_to_build_root(target)
+ # Prefix to use to access the source tree's root from the vcxproj dir
proj_to_src_root = os.path.join(down, self.build_to_src)
+ # Prefix to use to access the source tree's subdir from the vcxproj dir
proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir)
(sources, headers, objects, languages) = self.split_sources(target.sources)
- buildtype = self.buildtype
+ buildtype_args = compiler.get_buildtype_args(self.buildtype)
+ buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype)
project_name = target.name
target_name = target.name
root = ET.Element('Project', {'DefaultTargets' : "Build",
@@ -438,9 +530,10 @@ class Vs2010Backend(backends.Backend):
prjconf = ET.SubElement(confitems, 'ProjectConfiguration',
{'Include' : self.buildtype + '|' + self.platform})
p = ET.SubElement(prjconf, 'Configuration')
- p.text= buildtype
+ p.text= self.buildtype
pl = ET.SubElement(prjconf, 'Platform')
pl.text = self.platform
+ # Globals
globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals')
guidelem = ET.SubElement(globalgroup, 'ProjectGuid')
guidelem.text = guid
@@ -453,13 +546,68 @@ class Vs2010Backend(backends.Backend):
pname= ET.SubElement(globalgroup, 'ProjectName')
pname.text = project_name
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
+ # Start configuration
type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration')
ET.SubElement(type_config, 'ConfigurationType').text = conftype
ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte'
if self.platform_toolset:
ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset
+ # FIXME: Meson's LTO support needs to be integrated here
ET.SubElement(type_config, 'WholeProgramOptimization').text = 'false'
- ET.SubElement(type_config, 'UseDebugLibraries').text = 'true'
+ # Let VS auto-set the RTC level
+ ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'Default'
+ o_flags = split_o_flags_args(buildtype_args)
+ if '/Oi' in o_flags:
+ ET.SubElement(type_config, 'IntrinsicFunctions').text = 'true'
+ if '/Ob1' in o_flags:
+ ET.SubElement(type_config, 'InlineFunctionExpansion').text = 'OnlyExplicitInline'
+ elif '/Ob2' in o_flags:
+ ET.SubElement(type_config, 'InlineFunctionExpansion').text = 'AnySuitable'
+ # Size-preserving flags
+ if '/Os' in o_flags:
+ ET.SubElement(type_config, 'FavorSizeOrSpeed').text = 'Size'
+ else:
+ ET.SubElement(type_config, 'FavorSizeOrSpeed').text = 'Speed'
+ # Incremental linking increases code size
+ if '/INCREMENTAL:NO' in buildtype_link_args:
+ ET.SubElement(type_config, 'LinkIncremental').text = 'false'
+ # CRT type; debug or release
+ if '/MDd' in buildtype_args:
+ ET.SubElement(type_config, 'UseDebugLibraries').text = 'true'
+ ET.SubElement(type_config, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL'
+ else:
+ ET.SubElement(type_config, 'UseDebugLibraries').text = 'false'
+ ET.SubElement(type_config, 'RuntimeLibrary').text = 'MultiThreadedDLL'
+ # Debug format
+ if '/ZI' in buildtype_args:
+ ET.SubElement(type_config, 'DebugInformationFormat').text = 'EditAndContinue'
+ elif '/Zi' in buildtype_args:
+ ET.SubElement(type_config, 'DebugInformationFormat').text = 'ProgramDatabase'
+ elif '/Z7' in buildtype_args:
+ ET.SubElement(type_config, 'DebugInformationFormat').text = 'OldStyle'
+ # Generate Debug info
+ if '/DEBUG' in buildtype_link_args:
+ ET.SubElement(type_config, 'GenerateDebugInformation').text = 'true'
+ # Runtime checks
+ if '/RTC1' in buildtype_args:
+ ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'EnableFastChecks'
+ elif '/RTCu' in buildtype_args:
+ ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'UninitializedLocalUsageCheck'
+ elif '/RTCs' in buildtype_args:
+ ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'StackFrameRuntimeCheck'
+ # Optimization flags
+ if '/Ox' in o_flags:
+ ET.SubElement(type_config, 'Optimization').text = 'Full'
+ elif '/O2' in o_flags:
+ ET.SubElement(type_config, 'Optimization').text = 'MaxSpeed'
+ elif '/O1' in o_flags:
+ ET.SubElement(type_config, 'Optimization').text = 'MinSpace'
+ elif '/Od' in o_flags:
+ ET.SubElement(type_config, 'Optimization').text = 'Disabled'
+ # Warning level
+ warning_level = self.environment.coredata.get_builtin_option('warning_level')
+ ET.SubElement(type_config, 'WarningLevel').text = 'Level' + warning_level
+ # End configuration
ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props')
generated_files, custom_target_output_files, generated_files_include_dirs = self.generate_custom_generator_commands(target, root)
(gen_src, gen_hdrs, gen_objs, gen_langs) = self.split_sources(generated_files)
@@ -467,6 +615,7 @@ class Vs2010Backend(backends.Backend):
gen_src += custom_src
gen_hdrs += custom_hdrs
gen_langs += custom_langs
+ # Project information
direlem = ET.SubElement(root, 'PropertyGroup')
fver = ET.SubElement(direlem, '_ProjectFileVersion')
fver.text = self.project_file_version
@@ -474,15 +623,13 @@ class Vs2010Backend(backends.Backend):
outdir.text = '.\\'
intdir = ET.SubElement(direlem, 'IntDir')
intdir.text = target.get_id() + '\\'
- tname = ET.SubElement(direlem, 'TargetName')
- tname.text = target_name
- inclinc = ET.SubElement(direlem, 'LinkIncremental')
- inclinc.text = 'true'
+ tfilename = os.path.splitext(target.get_filename())
+ ET.SubElement(direlem, 'TargetName').text = tfilename[0]
+ ET.SubElement(direlem, 'TargetExt').text = tfilename[1]
+ # Build information
compiles = ET.SubElement(root, 'ItemDefinitionGroup')
clconf = ET.SubElement(compiles, 'ClCompile')
- opt = ET.SubElement(clconf, 'Optimization')
- opt.text = 'disabled'
inc_dirs = ['.', self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)),
proj_to_src_dir] + generated_files_include_dirs
@@ -496,21 +643,43 @@ class Vs2010Backend(backends.Backend):
for l, args in target.extra_args.items():
if l in extra_args:
extra_args[l] += compiler.unix_compile_flags_to_native(args)
- general_args = compiler.get_buildtype_args(self.buildtype).copy()
# FIXME all the internal flags of VS (optimization etc) are represented
# by their own XML elements. In theory we should split all flags to those
# that have an XML element and those that don't and serialise them
# properly. This is a crapton of work for no real gain, so just dump them
# here.
- general_args += compiler.get_option_compile_args(self.environment.coredata.compiler_options)
+ general_args = compiler.get_option_compile_args(self.environment.coredata.compiler_options)
for d in target.get_external_deps():
- try:
- general_args += d.compile_args
- except AttributeError:
- pass
-
+ # Cflags required by external deps might have UNIX-specific flags,
+ # 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') or arg.startswith('/I'):
+ inc_dir = arg[2:]
+ # De-dup
+ if inc_dir not in inc_dirs:
+ inc_dirs.append(inc_dir)
+ 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())
@@ -537,11 +706,9 @@ 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'
- rtlib = ET.SubElement(clconf, 'RuntimeLibrary')
- rtlib.text = 'MultiThreadedDebugDLL'
funclink = ET.SubElement(clconf, 'FunctionLevelLinking')
funclink.text = 'true'
pch_node = ET.SubElement(clconf, 'PrecompiledHeader')
@@ -564,28 +731,39 @@ class Vs2010Backend(backends.Backend):
pch_out = ET.SubElement(clconf, 'PrecompiledHeaderOutputFile')
pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % pch_source[2]
- warnings = ET.SubElement(clconf, 'WarningLevel')
- warnings.text = 'Level3'
- debinfo = ET.SubElement(clconf, 'DebugInformationFormat')
- debinfo.text = 'EditAndContinue'
resourcecompile = ET.SubElement(compiles, 'ResourceCompile')
ET.SubElement(resourcecompile, 'PreprocessorDefinitions')
link = ET.SubElement(compiles, 'Link')
# Put all language args here, too.
extra_link_args = compiler.get_option_link_args(self.environment.coredata.compiler_options)
+ # FIXME: Can these buildtype linker args be added as tags in the
+ # vcxproj file (similar to buildtype compiler args) instead of in
+ # AdditionalOptions?
extra_link_args += compiler.get_buildtype_linker_args(self.buildtype)
for l in self.environment.coredata.external_link_args.values():
- extra_link_args += compiler.unix_link_flags_to_native(l)
- extra_link_args += compiler.unix_link_flags_to_native(target.link_args)
+ extra_link_args += l
+ if not isinstance(target, build.StaticLibrary):
+ extra_link_args += target.link_args
+ # External deps must be last because target link libraries may depend on them.
+ for dep in target.get_external_deps():
+ extra_link_args += dep.get_link_args()
+ for d in target.get_dependencies():
+ if isinstance(d, build.StaticLibrary):
+ for dep in d.get_external_deps():
+ extra_link_args += dep.get_link_args()
+ extra_link_args = compiler.unix_link_flags_to_native(extra_link_args)
+ (additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args)
if len(extra_link_args) > 0:
extra_link_args.append('%(AdditionalOptions)')
ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_link_args)
+ if len(additional_libpaths) > 0:
+ additional_libpaths.insert(0, '%(AdditionalLibraryDirectories)')
+ ET.SubElement(link, 'AdditionalLibraryDirectories').text = ';'.join(additional_libpaths)
- additional_links = []
+ # Add more libraries to be linked if needed
for t in target.get_dependencies():
lobj = self.build.targets[t.get_id()]
- rel_path = self.relpath(lobj.subdir, target.subdir)
- linkname = os.path.join(rel_path, lobj.get_import_filename())
+ linkname = os.path.join(down, self.get_target_filename_for_linking(lobj))
additional_links.append(linkname)
for lib in self.get_custom_target_provided_libraries(target):
additional_links.append(self.relpath(lib, self.get_target_dir(target)))
@@ -600,26 +778,37 @@ class Vs2010Backend(backends.Backend):
ET.SubElement(link, 'AdditionalDependencies').text = ';'.join(additional_links)
ofile = ET.SubElement(link, 'OutputFile')
ofile.text = '$(OutDir)%s' % target.get_filename()
- addlibdir = ET.SubElement(link, 'AdditionalLibraryDirectories')
- addlibdir.text = '%(AdditionalLibraryDirectories)'
subsys = ET.SubElement(link, 'SubSystem')
subsys.text = subsystem
- gendeb = ET.SubElement(link, 'GenerateDebugInformation')
- gendeb.text = 'true'
if isinstance(target, build.SharedLibrary):
+ # DLLs built with MSVC always have an import library except when
+ # they're data-only DLLs, but we don't support those yet.
ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename()
- pdb = ET.SubElement(link, 'ProgramDataBaseFileName')
- pdb.text = '$(OutDir}%s.pdb' % target_name
+ # Add module definitions file, if provided
+ if target.vs_module_defs:
+ relpath = os.path.join(down, target.vs_module_defs.rel_to_builddir(self.build_to_src))
+ ET.SubElement(link, 'ModuleDefinitionFile').text = relpath
+ if '/ZI' in buildtype_args or '/Zi' in buildtype_args:
+ pdb = ET.SubElement(link, 'ProgramDataBaseFileName')
+ pdb.text = '$(OutDir}%s.pdb' % target_name
if isinstance(target, build.Executable):
ET.SubElement(link, 'EntryPointSymbol').text = entrypoint
targetmachine = ET.SubElement(link, 'TargetMachine')
- targetmachine.text = 'MachineX86'
+ targetplatform = self.platform.lower()
+ if targetplatform == 'win32':
+ targetmachine.text = 'MachineX86'
+ elif targetplatform == 'x64':
+ targetmachine.text = 'MachineX64'
+ elif targetplatform == 'arm':
+ targetmachine.text = 'MachineARM'
+ else:
+ raise MesonException('Unsupported Visual Studio target machine: ' + targetmachine)
extra_files = target.extra_files
if len(headers) + len(gen_hdrs) + len(extra_files) > 0:
inc_hdrs = ET.SubElement(root, 'ItemGroup')
for h in headers:
- relpath = h.rel_to_builddir(proj_to_src_root)
+ relpath = os.path.join(down, h.rel_to_builddir(self.build_to_src))
ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath)
for h in gen_hdrs:
ET.SubElement(inc_hdrs, 'CLInclude', Include=h)
@@ -630,7 +819,7 @@ class Vs2010Backend(backends.Backend):
if len(sources) + len(gen_src) + len(pch_sources) > 0:
inc_src = ET.SubElement(root, 'ItemGroup')
for s in sources:
- relpath = s.rel_to_builddir(proj_to_src_root)
+ relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src))
inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath)
self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s)
self.add_additional_options(s, inc_cl, extra_args, additional_options_set)
@@ -658,7 +847,7 @@ class Vs2010Backend(backends.Backend):
if self.has_objects(objects, additional_objects, gen_objs):
inc_objs = ET.SubElement(root, 'ItemGroup')
for s in objects:
- relpath = s.rel_to_builddir(proj_to_src_root)
+ relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src))
ET.SubElement(inc_objs, 'Object', Include=relpath)
for s in additional_objects:
ET.SubElement(inc_objs, 'Object', Include=s)
diff --git a/mesonbuild/backend/vs2015backend.py b/mesonbuild/backend/vs2015backend.py
index c138cb5..8d4ff45 100644
--- a/mesonbuild/backend/vs2015backend.py
+++ b/mesonbuild/backend/vs2015backend.py
@@ -20,6 +20,7 @@ class Vs2015Backend(Vs2010Backend):
def __init__(self, build):
super().__init__(build)
self.platform_toolset = 'v140'
+ self.vs_version = '2015'
@staticmethod
def has_objects(objects, additional_objects, generated_objects):
diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py
index 0ce90ce..e64866d 100644
--- a/mesonbuild/backend/xcodebackend.py
+++ b/mesonbuild/backend/xcodebackend.py
@@ -292,12 +292,10 @@ class XCodeBackend(backends.Backend):
reftype = 0
if isinstance(t, build.Executable):
typestr = 'compiled.mach-o.executable'
- path = t.get_filename()
+ path = fname
elif isinstance(t, build.SharedLibrary):
- # OSX has a completely different shared library
- # naming scheme so do this manually.
typestr = self.get_xcodetype('dummy.dylib')
- path = t.get_osx_filename()
+ path = fname
else:
typestr = self.get_xcodetype(fname)
path = '"%s"' % t.get_filename()
@@ -626,7 +624,7 @@ class XCodeBackend(backends.Backend):
headerdirs.append(os.path.join(self.environment.get_build_dir(), cd))
for l in target.link_targets:
abs_path = os.path.join(self.environment.get_build_dir(),
- l.subdir, buildtype, l.get_osx_filename())
+ l.subdir, buildtype, l.get_filename())
dep_libs.append("'%s'" % abs_path)
if isinstance(l, build.SharedLibrary):
links_dylib = True
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index c60f37f..6a4f375 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -16,8 +16,9 @@ from . import coredata
from . import environment
from . import dependencies
from . import mlog
-import copy, os
+import copy, os, re
from .mesonlib import File, flatten, MesonException
+from .environment import for_windows, for_darwin
known_basic_kwargs = {'install' : True,
'c_pch' : True,
@@ -49,27 +50,37 @@ 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.
+def sources_are_suffix(sources, suffix):
+ for source in sources:
+ if source.endswith('.' + suffix):
+ return True
+ return False
-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:
+def compiler_is_msvc(sources, is_cross, env):
+ """
+ Since each target does not currently have the compiler information attached
+ to it, we must do this detection manually here.
-const char *fulltext = "\\\\" PLAIN_TEXT;
+ This detection is purposely incomplete and will cause bugs if other code is
+ extended and this piece of code is forgotten.
+ """
+ compiler = None
+ if sources_are_suffix(sources, 'c'):
+ try:
+ compiler = env.detect_c_compiler(is_cross)
+ except MesonException:
+ return False
+ elif sources_are_suffix(sources, 'cxx') or \
+ sources_are_suffix(sources, 'cpp') or \
+ sources_are_suffix(sources, 'cc'):
+ try:
+ compiler = env.detect_cpp_compiler(is_cross)
+ except MesonException:
+ return False
+ if compiler and compiler.get_id() == 'msvc':
+ return True
+ return False
-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.
-'''
class InvalidArguments(MesonException):
pass
@@ -209,6 +220,10 @@ class BuildTarget():
raise InvalidArguments('Build target %s has no sources.' % name)
self.validate_sources()
+ def __repr__(self):
+ repr_str = "<{0} {1}: {2}>"
+ return repr_str.format(self.__class__.__name__, self.get_id(), self.filename)
+
def get_id(self):
# This ID must also be a valid file name on all OSs.
# It should also avoid shell metacharacters for obvious
@@ -569,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:
@@ -593,6 +606,10 @@ class Generator():
self.exe = exe
self.process_kwargs(kwargs)
+ def __repr__(self):
+ repr_str = "<{0}: {1}>"
+ return repr_str.format(self.__class__.__name__, self.exe)
+
def get_exe(self):
return self.exe
@@ -670,15 +687,19 @@ class GeneratedList():
class Executable(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
- self.prefix = ''
- self.suffix = environment.get_exe_suffix()
- suffix = environment.get_exe_suffix()
- if len(self.sources) > 0 and self.sources[0].endswith('.cs'):
- suffix = 'exe'
- if suffix != '':
- self.filename = self.name + '.' + suffix
- else:
- self.filename = self.name
+ # Unless overriden, executables have no suffix or prefix. Except on
+ # Windows and with C#/Mono executables where the suffix is 'exe'
+ if not hasattr(self, 'prefix'):
+ self.prefix = ''
+ if not hasattr(self, 'suffix'):
+ # Executable for Windows or C#/Mono
+ if for_windows(is_cross, environment) or sources_are_suffix(self.sources, 'cs'):
+ self.suffix = 'exe'
+ else:
+ self.suffix = ''
+ self.filename = self.name
+ if self.suffix:
+ self.filename += '.' + self.suffix
def type_suffix(self):
return "@exe"
@@ -686,52 +707,161 @@ class Executable(BuildTarget):
class StaticLibrary(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
- if len(self.sources) > 0 and self.sources[0].endswith('.cs'):
+ if sources_are_suffix(self.sources, 'cs'):
raise InvalidArguments('Static libraries not supported for C#.')
+ # By default a static library is named libfoo.a even on Windows because
+ # MSVC does not have a consistent convention for what static libraries
+ # are called. The MSVC CRT uses libfoo.lib syntax but nothing else uses
+ # it and GCC only looks for static libraries called foo.lib and
+ # libfoo.a. However, we cannot use foo.lib because that's the same as
+ # the import library. Using libfoo.a is ok because people using MSVC
+ # always pass the library filename while linking anyway.
if not hasattr(self, 'prefix'):
- self.prefix = environment.get_static_lib_prefix()
- self.suffix = environment.get_static_lib_suffix()
- if len(self.sources) > 0 and self.sources[0].endswith('.rs'):
- self.suffix = 'rlib'
+ self.prefix = 'lib'
+ if not hasattr(self, 'suffix'):
+ # Rust static library crates have .rlib suffix
+ if sources_are_suffix(self.sources, 'rs'):
+ self.suffix = 'rlib'
+ else:
+ self.suffix = 'a'
self.filename = self.prefix + self.name + '.' + self.suffix
- def get_import_filename(self):
- return self.filename
-
- def get_osx_filename(self):
- return self.get_filename()
-
def type_suffix(self):
return "@sta"
class SharedLibrary(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
- self.version = None
self.soversion = None
+ self.ltversion = None
self.vs_module_defs = None
- super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs);
- if len(self.sources) > 0 and self.sources[0].endswith('.cs'):
+ # The import library this target will generate
+ self.import_filename = None
+ # The import library that Visual Studio would generate (and accept)
+ self.vs_import_filename = None
+ # The import library that GCC would generate (and prefer)
+ self.gcc_import_filename = None
+ super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
+ if not hasattr(self, 'prefix'):
+ self.prefix = None
+ if not hasattr(self, 'suffix'):
+ self.suffix = None
+ self.basic_filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ self.determine_filenames(is_cross, environment)
+
+ def determine_filenames(self, is_cross, env):
+ """
+ See https://github.com/mesonbuild/meson/pull/417 for details.
+
+ First we determine the filename template (self.filename_tpl), then we
+ set the output filename (self.filename).
+
+ The template is needed while creating aliases (self.get_aliaslist),
+ which are needed while generating .so shared libraries for Linux.
+
+ Besides this, there's also the import library name, which is only used
+ on Windows since on that platform the linker uses a separate library
+ called the "import library" during linking instead of the shared
+ library (DLL). The toolchain will output an import library in one of
+ two formats: GCC or Visual Studio.
+
+ When we're building with Visual Studio, the import library that will be
+ generated by the toolchain is self.vs_import_filename, and with
+ MinGW/GCC, it's self.gcc_import_filename. self.import_filename will
+ always contain the import library name this target will generate.
+ """
+ prefix = ''
+ suffix = ''
+ self.filename_tpl = self.basic_filename_tpl
+ # If the user already provided the prefix and suffix to us, we don't
+ # need to do any filename suffix/prefix detection.
+ # NOTE: manual prefix/suffix override is currently only tested for C/C++
+ if self.prefix != None and self.suffix != None:
+ pass
+ # C# and Mono
+ elif sources_are_suffix(self.sources, 'cs'):
+ prefix = ''
+ suffix = 'dll'
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ # Rust
+ elif sources_are_suffix(self.sources, 'rs'):
+ # Currently, we always build --crate-type=rlib
prefix = 'lib'
+ suffix = 'rlib'
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ # C, C++, Swift, Vala
+ # Only Windows uses a separate import library for linking
+ # For all other targets/platforms import_filename stays None
+ elif for_windows(is_cross, env):
suffix = 'dll'
+ self.vs_import_filename = '{0}.lib'.format(self.name)
+ self.gcc_import_filename = 'lib{0}.dll.a'.format(self.name)
+ if compiler_is_msvc(self.sources, is_cross, env):
+ # Shared library is of the form foo.dll
+ prefix = ''
+ # Import library is called foo.lib
+ self.import_filename = self.vs_import_filename
+ # Assume GCC-compatible naming
+ else:
+ # Shared library is of the form libfoo.dll
+ prefix = 'lib'
+ # Import library is called libfoo.dll.a
+ self.import_filename = self.gcc_import_filename
+ # Shared library has the soversion if it is defined
+ if self.soversion:
+ self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}'
+ else:
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ elif for_darwin(is_cross, env):
+ prefix = 'lib'
+ suffix = 'dylib'
+ if self.soversion:
+ # libfoo.X.dylib
+ self.filename_tpl = '{0.prefix}{0.name}.{0.soversion}.{0.suffix}'
+ else:
+ # libfoo.dylib
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
else:
- prefix = environment.get_shared_lib_prefix()
- suffix = environment.get_shared_lib_suffix()
- if not hasattr(self, 'prefix'):
- self.prefix = prefix
- if not hasattr(self, 'suffix'):
- if len(self.sources) > 0 and self.sources[0].endswith('.rs'):
- self.suffix = 'rlib'
+ prefix = 'lib'
+ suffix = 'so'
+ if self.ltversion:
+ # libfoo.so.X[.Y[.Z]] (.Y and .Z are optional)
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.ltversion}'
+ elif self.soversion:
+ # libfoo.so.X
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.soversion}'
else:
- self.suffix = suffix
- self.importsuffix = environment.get_import_lib_suffix()
- self.filename = self.prefix + self.name + '.' + self.suffix
+ # No versioning, libfoo.so
+ self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
+ if self.prefix == None:
+ self.prefix = prefix
+ if self.suffix == None:
+ self.suffix = suffix
+ self.filename = self.filename_tpl.format(self)
def process_kwargs(self, kwargs, environment):
super().process_kwargs(kwargs, environment)
+ # Shared library version
if 'version' in kwargs:
- self.set_version(kwargs['version'])
+ self.ltversion = kwargs['version']
+ if not isinstance(self.ltversion, str):
+ raise InvalidArguments('Shared library version needs to be a string, not ' + type(self.ltversion).__name__)
+ if not re.fullmatch(r'[0-9]+(\.[0-9]+){0,2}', self.ltversion):
+ raise InvalidArguments('Invalid Shared library version "{0}". Must be of the form X.Y.Z where all three are numbers. Y and Z are optional.'.format(self.ltversion))
+ # Try to extract/deduce the soversion
if 'soversion' in kwargs:
- self.set_soversion(kwargs['soversion'])
+ self.soversion = kwargs['soversion']
+ if isinstance(self.soversion, int):
+ self.soversion = str(self.soversion)
+ if not isinstance(self.soversion, str):
+ raise InvalidArguments('Shared library soversion is not a string or integer.')
+ try:
+ int(self.soversion)
+ except ValueError:
+ raise InvalidArguments('Shared library soversion must be a valid integer')
+ elif self.ltversion:
+ # library version is defined, get the soversion from that
+ self.soversion = self.ltversion.split('.')[0]
+ # Visual Studio module-definitions file
if 'vs_module_defs' in kwargs:
path = kwargs['vs_module_defs']
if (os.path.isabs(path)):
@@ -742,46 +872,41 @@ class SharedLibrary(BuildTarget):
def check_unknown_kwargs(self, kwargs):
self.check_unknown_kwargs_int(kwargs, known_shlib_kwargs)
- def get_shbase(self):
- return self.prefix + self.name + '.' + self.suffix
-
def get_import_filename(self):
- return self.prefix + self.name + '.' + self.importsuffix
-
- def get_all_link_deps(self):
- return [self] + self.get_transitive_link_deps()
-
- def get_filename(self):
- '''Works on all platforms except OSX, which does its own thing.'''
- fname = self.get_shbase()
- if self.version is None:
- return fname
- else:
- return fname + '.' + self.version
+ """
+ The name of the import library that will be outputted by the compiler
- def get_osx_filename(self):
- if self.version is None:
- return self.get_shbase()
- return self.prefix + self.name + '.' + self.version + '.' + self.suffix
+ Returns None if there is no import library required for this platform
+ """
+ return self.import_filename
- def set_version(self, version):
- if not isinstance(version, str):
- raise InvalidArguments('Shared library version is not a string.')
- self.version = version
+ def get_import_filenameslist(self):
+ if self.import_filename:
+ return [self.vs_import_filename, self.gcc_import_filename]
+ return []
- def set_soversion(self, version):
- if isinstance(version, int):
- version = str(version)
- if not isinstance(version, str):
- raise InvalidArguments('Shared library soversion is not a string or integer.')
- self.soversion = version
+ def get_all_link_deps(self):
+ return [self] + self.get_transitive_link_deps()
def get_aliaslist(self):
- aliases = []
- if self.soversion is not None:
- aliases.append(self.get_shbase() + '.' + self.soversion)
- if self.version is not None:
- aliases.append(self.get_shbase())
+ """
+ If the versioned library name is libfoo.so.0.100.0, aliases are:
+ * libfoo.so.0 (soversion)
+ * libfoo.so (unversioned; for linking)
+ """
+ # Aliases are only useful with .so libraries. Also if the .so library
+ # ends with .so (no versioning), we don't need aliases.
+ if self.suffix != 'so' or self.filename.endswith('.so'):
+ return []
+ # Unversioned alias: libfoo.so
+ aliases = [self.basic_filename_tpl.format(self)]
+ # If ltversion != soversion we create an soversion alias: libfoo.so.X
+ if self.ltversion and self.ltversion != self.soversion:
+ if not self.soversion:
+ # This is done in self.process_kwargs()
+ raise AssertionError('BUG: If library version is defined, soversion must have been defined')
+ alias_tpl = self.filename_tpl.replace('ltversion', 'soversion')
+ aliases.append(alias_tpl.format(self))
return aliases
def type_suffix(self):
@@ -815,6 +940,10 @@ class CustomTarget:
mlog.log(mlog.bold('Warning:'), 'Unknown keyword arguments in target %s: %s' %
(self.name, ', '.join(unknowns)))
+ def __repr__(self):
+ repr_str = "<{0} {1}: {2}>"
+ return repr_str.format(self.__class__.__name__, self.get_id(), self.command)
+
def get_id(self):
return self.name + self.type_suffix()
@@ -851,7 +980,7 @@ class CustomTarget:
for i, c in enumerate(cmd):
if hasattr(c, 'held_object'):
c = c.held_object
- if isinstance(c, str):
+ if isinstance(c, str) or isinstance(c, File):
final_cmd.append(c)
elif isinstance(c, dependencies.ExternalProgram):
if not c.found():
@@ -867,8 +996,6 @@ class CustomTarget:
if not isinstance(s, str):
raise InvalidArguments('Array as argument %d contains a non-string.' % i)
final_cmd.append(s)
- elif isinstance(c, File):
- final_cmd.append(os.path.join(c.subdir, c.fname))
else:
raise InvalidArguments('Argument %s in "command" is invalid.' % i)
self.command = final_cmd
@@ -944,6 +1071,10 @@ class RunTarget:
self.dependencies = dependencies
self.subdir = subdir
+ def __repr__(self):
+ repr_str = "<{0} {1}: {2}>"
+ return repr_str.format(self.__class__.__name__, self.get_id(), self.command)
+
def get_id(self):
return self.name + self.type_suffix()
@@ -994,6 +1125,12 @@ class ConfigureFile():
self.targetname = targetname
self.configuration_data = configuration_data
+ def __repr__(self):
+ repr_str = "<{0}: {1} -> {2}>"
+ src = os.path.join(self.subdir, self.sourcename)
+ dst = os.path.join(self.subdir, self.targetname)
+ return repr_str.format(self.__class__.__name__, src, dst)
+
def get_configuration_data(self):
return self.configuration_data
@@ -1011,6 +1148,9 @@ class ConfigurationData():
super().__init__()
self.values = {}
+ def __repr__(self):
+ return repr(self.values)
+
def get(self, name):
return self.values[name]
diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py
index 8ee86bc..30eecec 100644
--- a/mesonbuild/compilers.py
+++ b/mesonbuild/compilers.py
@@ -142,6 +142,7 @@ base_options = {
['none', 'address', 'thread', 'undefined', 'memory'],
'none'),
'b_lundef': coredata.UserBooleanOption('b_lundef', 'Use -Wl,--no-undefined when linking', True),
+ 'b_asneeded': coredata.UserBooleanOption('b_asneeded', 'Use -Wl,--as-needed when linking', True),
'b_pgo': coredata.UserComboOption('b_pgo', 'Use profile guide optimization',
['off', 'generate', 'use'],
'off'),
@@ -224,6 +225,11 @@ def get_base_link_args(options, linker):
except KeyError:
pass
try:
+ if options['b_asneeded'].value:
+ args.append('-Wl,--as-needed')
+ except KeyError:
+ pass
+ try:
if options['b_coverage'].value:
args += linker.get_coverage_link_args()
except KeyError:
@@ -274,6 +280,13 @@ class Compiler():
def get_linker_always_args(self):
return []
+ def gen_import_library_args(self, implibname):
+ """
+ Used only on Windows for libraries that need an import library.
+ This currently means C, C++, Fortran.
+ """
+ return []
+
def get_options(self):
return {} # build afresh every time
@@ -473,6 +486,14 @@ class CCompiler(Compiler):
def get_linker_search_args(self, dirname):
return ['-L'+dirname]
+ def gen_import_library_args(self, implibname):
+ """
+ The name of the outputted import library
+
+ This implementation is used only on Windows by compilers that use GNU ld
+ """
+ return ['-Wl,--out-implib=' + implibname]
+
def sanity_check_impl(self, work_dir, environment, sname, code):
mlog.debug('Sanity testing ' + self.language + ' compiler:', ' '.join(self.exelist))
mlog.debug('Is cross compiler: %s.' % str(self.is_cross))
@@ -1499,6 +1520,10 @@ class VisualStudioCCompiler(CCompiler):
objname = os.path.splitext(pchname)[0] + '.obj'
return (objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname ])
+ def gen_import_library_args(self, implibname):
+ "The name of the outputted import library"
+ return ['/IMPLIB:' + implibname]
+
def build_rpath_args(self, build_dir, rpath_paths, install_rpath):
return []
@@ -1642,6 +1667,7 @@ class GnuCCompiler(CCompiler):
'b_colorout']
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
+ self.base_options.append('b_asneeded')
def get_colorout_args(self, colortype):
if mesonlib.version_compare(self.version, '>=4.9.0'):
@@ -1712,6 +1738,7 @@ class GnuObjCCompiler(ObjCCompiler):
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
+ self.base_options.append('b_asneeded')
def get_buildtype_args(self, buildtype):
return gnulike_buildtype_args[buildtype]
@@ -1740,6 +1767,7 @@ class GnuObjCPPCompiler(ObjCPPCompiler):
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
+ self.base_options.append('b_asneeded')
def get_buildtype_args(self, buildtype):
return gnulike_buildtype_args[buildtype]
@@ -1761,6 +1789,7 @@ class ClangObjCCompiler(GnuObjCCompiler):
self.clang_type = cltype
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
+ self.base_options.append('b_asneeded')
class ClangObjCPPCompiler(GnuObjCPPCompiler):
def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None):
@@ -1770,6 +1799,7 @@ class ClangObjCPPCompiler(GnuObjCPPCompiler):
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
+ self.base_options.append('b_asneeded')
class ClangCCompiler(CCompiler):
def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None):
@@ -1782,6 +1812,7 @@ class ClangCCompiler(CCompiler):
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
+ self.base_options.append('b_asneeded')
def get_buildtype_args(self, buildtype):
return gnulike_buildtype_args[buildtype]
@@ -1831,6 +1862,7 @@ class GnuCPPCompiler(CPPCompiler):
'b_colorout']
if self.gcc_type != GCC_OSX:
self.base_options.append('b_lundef')
+ self.base_options.append('b_asneeded')
def get_colorout_args(self, colortype):
if mesonlib.version_compare(self.version, '>=4.9.0'):
@@ -1892,6 +1924,7 @@ class ClangCPPCompiler(CPPCompiler):
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage']
if self.clang_type != CLANG_OSX:
self.base_options.append('b_lundef')
+ self.base_options.append('b_asneeded')
def get_buildtype_args(self, buildtype):
return gnulike_buildtype_args[buildtype]
@@ -2057,6 +2090,14 @@ class GnuFortranCompiler(FortranCompiler):
def get_always_args(self):
return ['-pipe']
+ def gen_import_library_args(self, implibname):
+ """
+ The name of the outputted import library
+
+ Used only on Windows
+ """
+ return ['-Wl,--out-implib=' + implibname]
+
class G95FortranCompiler(FortranCompiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
super().__init__(exelist, version, is_cross, exe_wrapper=None)
@@ -2068,6 +2109,14 @@ class G95FortranCompiler(FortranCompiler):
def get_always_args(self):
return ['-pipe']
+ def gen_import_library_args(self, implibname):
+ """
+ The name of the outputted import library
+
+ Used only on Windows
+ """
+ return ['-Wl,--out-implib=' + implibname]
+
class SunFortranCompiler(FortranCompiler):
def __init__(self, exelist, version, is_cross, exe_wrapper=None):
super().__init__(exelist, version, is_cross, exe_wrapper=None)
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 21b907e..7c8e458 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -15,7 +15,7 @@
import pickle, os, uuid
from .mesonlib import MesonException, default_libdir, default_libexecdir, default_prefix
-version = '0.33.0.dev1'
+version = '0.34.0.dev1'
backendlist = ['ninja', 'vs2010', 'vs2015', 'xcode']
class UserOption:
@@ -100,10 +100,10 @@ class UserStringArrayOption(UserOption):
raise MesonException('Valuestring does not define an array: ' + newvalue)
newvalue = eval(newvalue, {}, {}) # Yes, it is unsafe.
if not isinstance(newvalue, list):
- raise MesonException('String array value is not an array.')
+ raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue)))
for i in newvalue:
if not isinstance(i, str):
- raise MesonException('String array element not a string.')
+ raise MesonException('String array element "{0}" is not a string.'.format(str(newvalue)))
self.value = newvalue
# This class contains all data that must persist over multiple
@@ -133,6 +133,8 @@ class CoreData():
self.cross_compilers = {}
self.deps = {}
self.modules = {}
+ # Only to print a warning if it changes between Meson invocations.
+ self.pkgconf_envvar = os.environ.get('PKG_CONFIG_PATH', '')
def init_builtins(self, options):
self.builtins = {}
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index 544291b..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
@@ -1105,11 +1152,13 @@ class Python3Dependency(Dependency):
super().__init__()
self.name = 'python3'
self.is_found = False
+ self.version = "3.something_maybe"
try:
pkgdep = PkgConfigDependency('python3', environment, kwargs)
if pkgdep.found():
self.cargs = pkgdep.cargs
self.libs = pkgdep.libs
+ self.version = pkgdep.get_version()
self.is_found = True
return
except Exception:
@@ -1127,6 +1176,7 @@ class Python3Dependency(Dependency):
self.libs = ['-L{}/libs'.format(basedir),
'-lpython{}'.format(vernum)]
self.is_found = True
+ self.version = sysconfig.get_config_var('py_version_short')
elif mesonlib.is_osx():
# In OSX the Python 3 framework does not have a version
# number in its name.
@@ -1146,6 +1196,9 @@ class Python3Dependency(Dependency):
def get_link_args(self):
return self.libs
+ def get_version(self):
+ return self.version
+
def get_dep_identifier(name, kwargs):
elements = [name]
modlist = kwargs.get('modules', [])
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 3868301..404ed3e 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -45,11 +45,13 @@ def find_valgrind():
def detect_ninja():
for n in ['ninja', 'ninja-build']:
try:
- p = subprocess.Popen([n, '--version'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+ p = subprocess.Popen([n, '--version'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
except FileNotFoundError:
continue
- p.communicate()
- if p.returncode == 0:
+ version = p.communicate()[0].decode(errors='ignore')
+ # Perhaps we should add a way for the caller to know the failure mode
+ # (not found or too old)
+ if p.returncode == 0 and mesonlib.version_compare(version, ">=1.6"):
return n
def detect_cpu_family():
@@ -80,11 +82,37 @@ def detect_system():
return platform.system().lower()
+def for_windows(is_cross, env):
+ """
+ Host machine is windows?
+
+ Note: 'host' is the machine on which compiled binaries will run
+ """
+ if not is_cross:
+ return mesonlib.is_windows()
+ elif env.cross_info.has_host():
+ return env.cross_info.config['host_machine']['system'] == 'windows'
+ return False
+
+def for_darwin(is_cross, env):
+ """
+ Host machine is Darwin (iOS/OS X)?
+
+ Note: 'host' is the machine on which compiled binaries will run
+ """
+ if not is_cross:
+ return mesonlib.is_osx()
+ elif env.cross_info.has_host():
+ return env.cross_info.config['host_machine']['system'] == 'darwin'
+ return False
+
+
class Environment():
private_dir = 'meson-private'
log_dir = 'meson-logs'
coredata_file = os.path.join(private_dir, 'coredata.dat')
version_regex = '\d+(\.\d+)+(-[a-zA-Z0-9]+)?'
+
def __init__(self, source_dir, build_dir, main_script_file, options, original_cmd_line_args):
assert(os.path.isabs(main_script_file))
assert(not os.path.islink(main_script_file))
@@ -100,7 +128,11 @@ class Environment():
self.coredata = coredata.load(cdf)
self.first_invocation = False
except FileNotFoundError:
+ # WARNING: Don't use any values from coredata in __init__. It gets
+ # re-initialized with project options by the interpreter during
+ # build file parsing.
self.coredata = coredata.CoreData(options)
+ self.coredata.meson_script_file = self.meson_script_file
self.first_invocation = True
if self.coredata.cross_file:
self.cross_info = CrossBuildInfo(self.coredata.cross_file)
@@ -122,40 +154,27 @@ class Environment():
self.default_static_linker = 'ar'
self.vs_static_linker = 'lib'
+ # Various prefixes and suffixes for import libraries, shared libraries,
+ # static libraries, and executables.
+ # Versioning is added to these names in the backends as-needed.
cross = self.is_cross_build()
if (not cross and mesonlib.is_windows()) \
or (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'windows'):
self.exe_suffix = 'exe'
- if self.detect_c_compiler(cross).get_id() == 'msvc':
- self.import_lib_suffix = 'lib'
- else:
- # MinGW-GCC doesn't generate and can't link with a .lib
- # It uses the DLL file as the import library
- self.import_lib_suffix = 'dll'
- self.shared_lib_suffix = 'dll'
- self.shared_lib_prefix = ''
- self.static_lib_suffix = 'lib'
- self.static_lib_prefix = ''
self.object_suffix = 'obj'
+ self.win_libdir_layout = True
else:
self.exe_suffix = ''
- if (not cross and mesonlib.is_osx()) or \
- (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'darwin'):
- self.shared_lib_suffix = 'dylib'
- else:
- self.shared_lib_suffix = 'so'
- self.shared_lib_prefix = 'lib'
- self.static_lib_suffix = 'a'
- self.static_lib_prefix = 'lib'
self.object_suffix = 'o'
- self.import_lib_suffix = self.shared_lib_suffix
+ self.win_libdir_layout = False
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
@@ -641,22 +660,19 @@ class Environment():
def get_exe_suffix(self):
return self.exe_suffix
- # On Windows (MSVC) the library has suffix dll
- # but you link against a file that has suffix lib.
- def get_import_lib_suffix(self):
- return self.import_lib_suffix
-
- def get_shared_lib_prefix(self):
- return self.shared_lib_prefix
+ def get_import_lib_dir(self):
+ "Install dir for the import library (library used for linking)"
+ return self.get_libdir()
- def get_shared_lib_suffix(self):
- return self.shared_lib_suffix
+ def get_shared_lib_dir(self):
+ "Install dir for the shared library"
+ if self.win_libdir_layout:
+ return self.get_bindir()
+ return self.get_libdir()
- def get_static_lib_prefix(self):
- return self.static_lib_prefix
-
- def get_static_lib_suffix(self):
- return self.static_lib_suffix
+ def get_static_lib_dir(self):
+ "Install dir for the static library"
+ return self.get_libdir()
def get_object_suffix(self):
return self.object_suffix
@@ -682,17 +698,6 @@ class Environment():
def get_datadir(self):
return self.coredata.get_builtin_option('datadir')
- def find_library(self, libname, dirs):
- if dirs is None:
- dirs = mesonlib.get_library_dirs()
- suffixes = [self.get_shared_lib_suffix(), self.get_static_lib_suffix()]
- prefix = self.get_shared_lib_prefix()
- for d in dirs:
- for suffix in suffixes:
- trial = os.path.join(d, prefix + libname + '.' + suffix)
- if os.path.isfile(trial):
- return trial
-
def get_args_from_envvars(lang):
if lang == 'c':
@@ -721,14 +726,12 @@ def get_args_from_envvars(lang):
class CrossBuildInfo():
def __init__(self, filename):
- self.config = {}
+ self.config = {'properties': {}}
self.parse_datafile(filename)
if 'target_machine' in self.config:
return
if not 'host_machine' in self.config:
raise mesonlib.MesonException('Cross info file must have either host or a target machine.')
- if not 'properties' in self.config:
- raise mesonlib.MesonException('Cross file is missing "properties".')
if not 'binaries' in self.config:
raise mesonlib.MesonException('Cross file is missing "binaries".')
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index df4cb0d..9c2a74c 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -120,8 +120,14 @@ class RunProcess(InterpreterObject):
pc = self.run_command(command_array, source_dir, build_dir, subdir, in_builddir)
(stdout, stderr) = pc.communicate()
self.returncode = pc.returncode
- self.stdout = stdout.decode().replace('\r\n', '\n')
- self.stderr = stderr.decode().replace('\r\n', '\n')
+ if sys.stdout.encoding:
+ self.stdout = stdout.decode(encoding=sys.stdout.encoding, errors='ignore').replace('\r\n', '\n')
+ else:
+ self.stdout = stdout.decode(errors='ignore').replace('\r\n', '\n')
+ if sys.stderr.encoding:
+ self.stderr = stderr.decode(encoding=sys.stderr.encoding, errors='ignore').replace('\r\n', '\n')
+ else:
+ self.stderr = stderr.decode(errors='ignore').replace('\r\n', '\n')
self.methods.update({'returncode' : self.returncode_method,
'stdout' : self.stdout_method,
'stderr' : self.stderr_method,
@@ -1317,6 +1323,8 @@ class Interpreter():
return self.evaluate_plusassign(cur)
elif isinstance(cur, mparser.IndexNode):
return self.evaluate_indexing(cur)
+ elif isinstance(cur, mparser.TernaryNode):
+ return self.evaluate_ternary(cur)
elif self.is_elementary_type(cur):
return cur
else:
@@ -1381,7 +1389,8 @@ class Interpreter():
r = wrap.Resolver(os.path.join(self.build.environment.get_source_dir(), self.subproject_dir))
resolved = r.resolve(dirname)
if resolved is None:
- raise InterpreterException('Subproject directory does not exist and can not be downloaded.')
+ msg = 'Subproject directory {!r} does not exist and can not be downloaded.'
+ raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname)))
subdir = os.path.join(self.subproject_dir, resolved)
os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
self.global_args_frozen = True
@@ -1677,21 +1686,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']
@@ -1699,6 +1716,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):
@@ -1987,7 +2007,9 @@ class Interpreter():
raise InterpreterException('Argument "configuration" is not of type configuration_data')
ofile_abs = os.path.join(self.environment.build_dir, self.subdir, output)
if inputfile is not None:
- conffile = os.path.join(self.subdir, inputfile)
+ # Normalize the path of the conffile to avoid duplicates
+ # This is especially important to convert '/' to '\' on Windows
+ conffile = os.path.normpath(os.path.join(self.subdir, inputfile))
if conffile not in self.build_def_files:
self.build_def_files.append(conffile)
os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True)
@@ -2382,6 +2404,16 @@ class Interpreter():
if not isinstance(node.elseblock, mparser.EmptyNode):
self.evaluate_codeblock(node.elseblock)
+ def evaluate_ternary(self, node):
+ assert(isinstance(node, mparser.TernaryNode))
+ result = self.evaluate_statement(node.condition)
+ if not isinstance(result, bool):
+ raise InterpreterException('Ternary condition is not boolean.')
+ if result:
+ return self.evaluate_statement(node.trueblock)
+ else:
+ return self.evaluate_statement(node.falseblock)
+
def evaluate_foreach(self, node):
assert(isinstance(node, mparser.ForeachClauseNode))
varname = node.varname.value
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index 837f78a..1672d95 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -28,6 +28,16 @@ class File:
self.subdir = subdir
self.fname = fname
+ def __str__(self):
+ return os.path.join(self.subdir, self.fname)
+
+ def __repr__(self):
+ ret = '<File: {0}'
+ if not self.is_built:
+ ret += ' (not built)'
+ ret += '>'
+ return ret.format(os.path.join(self.subdir, self.fname))
+
@staticmethod
def from_source_file(source_root, subdir, fname):
if not os.path.isfile(os.path.join(source_root, subdir, fname)):
diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py
index 3f5612b..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
@@ -117,6 +117,13 @@ itself as required.'''
raise RuntimeError('Something went terribly wrong. Please file a bug.')
return (src_dir, build_dir)
+ def check_pkgconfig_envvar(self, env):
+ curvar = os.environ.get('PKG_CONFIG_PATH', '')
+ if curvar != env.coredata.pkgconf_envvar:
+ mlog.log(mlog.red("WARNING:"), 'PKG_CONFIG_PATH has changed between invocations from "%s" to "%s".' %
+ (env.coredata.pkgconf_envvar, curvar))
+ env.coredata.pkgconf_envvar = curvar
+
def generate(self):
env = environment.Environment(self.source_dir, self.build_dir, self.meson_script_file, self.options, self.original_cmd_line_args)
mlog.initialize(env.get_log_dir())
@@ -124,6 +131,7 @@ itself as required.'''
mlog.debug('Python binary:', sys.executable)
mlog.debug('Python system:', platform.system())
mlog.log(mlog.bold('The Meson build system'))
+ self.check_pkgconfig_envvar(env)
mlog.log('Version:', coredata.version)
mlog.log('Source dir:', mlog.bold(self.source_dir))
mlog.log('Build dir:', mlog.bold(self.build_dir))
@@ -156,11 +164,21 @@ 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()
- env.dump_coredata()
+ coredata_mtime = time.time()
g.generate(intr)
g.run_postconf_scripts()
dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat')
pickle.dump(b, open(dumpfile, 'wb'))
+ # Write this last since we use the existence of this file to check if
+ # we generated the build file successfully, so we don't want an error
+ # 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.
+ #
+ # 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/gnome.py b/mesonbuild/modules/gnome.py
index 037b1f5..be3c3ac 100644
--- a/mesonbuild/modules/gnome.py
+++ b/mesonbuild/modules/gnome.py
@@ -288,7 +288,7 @@ class GnomeModule:
args += self.unpack_args('--htmlargs=', 'html_args', kwargs)
args += self.unpack_args('--scanargs=', 'scan_args', kwargs)
args += self.unpack_args('--fixxrefargs=', 'fixxref_args', kwargs)
- res = [build.RunTarget(targetname, command[0], command[1:] + args, state.subdir)]
+ res = [build.RunTarget(targetname, command[0], command[1:] + args, [], state.subdir)]
if kwargs.get('install', True):
res.append(build.InstallScript(command + args))
return res
diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py
index 29d6236..cd4e343 100644
--- a/mesonbuild/modules/windows.py
+++ b/mesonbuild/modules/windows.py
@@ -32,9 +32,14 @@ class WindowsModule:
res_args = extra_args + ['/nologo', '/fo@OUTPUT@', '@INPUT@']
suffix = 'res'
else:
- rescomp = dependencies.ExternalProgram('windres', silent=True)
+ # Pick-up env var WINDRES if set. This is often used for specifying
+ # an arch-specific windres.
+ rescomp_name = os.environ.get('WINDRES', 'windres')
+ 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/mesonbuild/mparser.py b/mesonbuild/mparser.py
index fd720fb..2f0eb2d 100644
--- a/mesonbuild/mparser.py
+++ b/mesonbuild/mparser.py
@@ -67,6 +67,7 @@ class Lexer:
('lt', re.compile(r'<')),
('ge', re.compile(r'>=')),
('gt', re.compile(r'>')),
+ ('questionmark', re.compile(r'\?')),
]
def lex(self, code):
@@ -282,6 +283,14 @@ class IfNode():
self.condition = condition
self.block = block
+class TernaryNode():
+ def __init__(self, lineno, colno, condition, trueblock, falseblock):
+ self.lineno = lineno
+ self.colno = colno
+ self.condition = condition
+ self.trueblock = trueblock
+ self.falseblock = falseblock
+
class ArgumentNode():
def __init__(self, token):
self.lineno = token.lineno
@@ -344,6 +353,7 @@ class Parser:
def __init__(self, code):
self.stream = Lexer().lex(code)
self.getsym()
+ self.in_ternary = False
def getsym(self):
try:
@@ -383,6 +393,16 @@ class Parser:
raise ParseException('Assignment target must be an id.',
left.lineno, left.colno)
return AssignmentNode(left.lineno, left.colno, left.value, value)
+ elif self.accept('questionmark'):
+ if self.in_ternary:
+ raise ParseException('Nested ternary operators are not allowed.',
+ left.lineno, left.colno)
+ self.in_ternary = True
+ trueblock = self.e1()
+ self.expect('colon')
+ falseblock = self.e1()
+ self.in_ternary = False
+ return TernaryNode(left.lineno, left.colno, left, trueblock, falseblock)
return left
def e2(self):
diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py
index 8ff0dd1..cb136f4 100644
--- a/mesonbuild/scripts/depfixer.py
+++ b/mesonbuild/scripts/depfixer.py
@@ -20,6 +20,7 @@ import sys, struct
SHT_STRTAB = 3
DT_NEEDED = 1
DT_RPATH = 15
+DT_RUNPATH = 29
DT_STRTAB = 5
DT_SONAME = 14
@@ -211,21 +212,29 @@ class Elf(DataSizes):
self.bf.seek(strtab.val + soname.val)
print(self.read_str())
- def get_rpath_offset(self):
+ def get_entry_offset(self, entrynum):
sec = self.find_section(b'.dynstr')
for i in self.dynamic:
- if i.d_tag == DT_RPATH:
+ if i.d_tag == entrynum:
return sec.sh_offset + i.val
return None
def print_rpath(self):
- offset = self.get_rpath_offset()
+ offset = self.get_entry_offset(DT_RPATH)
if offset is None:
print("This file does not have an rpath.")
else:
self.bf.seek(offset)
print(self.read_str())
+ def print_runpath(self):
+ offset = self.get_entry_offset(DT_RUNPATH)
+ if offset is None:
+ print("This file does not have a runpath.")
+ else:
+ self.bf.seek(offset)
+ print(self.read_str())
+
def print_deps(self):
sec = self.find_section(b'.dynstr')
deps = []
@@ -257,9 +266,15 @@ class Elf(DataSizes):
self.bf.write(newname)
def fix_rpath(self, new_rpath):
+ # The path to search for can be either rpath or runpath.
+ # Fix both of them to be sure.
+ self.fix_rpathtype_entry(new_rpath, DT_RPATH)
+ self.fix_rpathtype_entry(new_rpath, DT_RUNPATH)
+
+ def fix_rpathtype_entry(self, new_rpath, entrynum):
if isinstance(new_rpath, str):
new_rpath = new_rpath.encode('utf8')
- rp_off = self.get_rpath_offset()
+ rp_off = self.get_entry_offset(entrynum)
if rp_off is None:
if self.verbose:
print('File does not have rpath. It should be a fully static executable.')
@@ -272,12 +287,12 @@ class Elf(DataSizes):
self.bf.write(new_rpath)
self.bf.write(b'\0'*(len(old_rpath) - len(new_rpath) + 1))
if len(new_rpath) == 0:
- self.remove_rpath_entry()
+ self.remove_rpath_entry(entrynum)
- def remove_rpath_entry(self):
+ def remove_rpath_entry(self, entrynum):
sec = self.find_section(b'.dynamic')
for (i, entry) in enumerate(self.dynamic):
- if entry.d_tag == DT_RPATH:
+ if entry.d_tag == entrynum:
rpentry = self.dynamic[i]
rpentry.d_tag = 0
self.dynamic = self.dynamic[:i] + self.dynamic[i+1:] + [rpentry]
@@ -296,6 +311,7 @@ def run(args):
e = Elf(args[0])
if len(args) == 1:
e.print_rpath()
+ e.print_runpath()
else:
new_rpath = args[1]
e.fix_rpath(new_rpath)
diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py
index cc06f7b..0c87717 100644
--- a/mesonbuild/scripts/gtkdochelper.py
+++ b/mesonbuild/scripts/gtkdochelper.py
@@ -17,6 +17,7 @@ import sys, os
import subprocess
import shutil
import argparse
+from mesonbuild.mesonlib import MesonException
from mesonbuild.scripts import destdir_join
parser = argparse.ArgumentParser()
@@ -31,6 +32,18 @@ parser.add_argument('--htmlargs', dest='htmlargs', default='')
parser.add_argument('--scanargs', dest='scanargs', default='')
parser.add_argument('--fixxrefargs', dest='fixxrefargs', default='')
+def gtkdoc_run_check(cmd, cwd):
+ p = subprocess.Popen(cmd, cwd=cwd,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stde, stdo) = p.communicate()
+ if p.returncode != 0:
+ err_msg = ["{!r} failed with status {:d}".format(cmd[0], p.returncode)]
+ if stde:
+ err_msg.append(stde.decode(errors='ignore'))
+ if stdo:
+ err_msg.append(stdo.decode(errors='ignore'))
+ raise MesonException('\n'.join(err_msg))
+
def build_gtkdoc(source_root, build_root, doc_subdir, src_subdir,
main_file, module, html_args, scan_args, fixxref_args):
abs_src = os.path.join(source_root, src_subdir)
@@ -39,10 +52,9 @@ def build_gtkdoc(source_root, build_root, doc_subdir, src_subdir,
scan_cmd = ['gtkdoc-scan',
'--module=' + module,
'--source-dir=' + abs_src] + scan_args
-# print(scan_cmd)
-# sys.exit(1)
- subprocess.check_call(scan_cmd,
- cwd=abs_out)
+ gtkdoc_run_check(scan_cmd, abs_out)
+
+ # Make docbook files
if main_file.endswith('sgml'):
modeflag = '--sgml-mode'
else:
@@ -56,9 +68,9 @@ def build_gtkdoc(source_root, build_root, doc_subdir, src_subdir,
if len(main_file) > 0:
# Yes, this is the flag even if the file is in xml.
mkdb_cmd.append('--main-sgml-file=' + main_file)
-# print(mkdb_cmd)
-# sys.exit(1)
- subprocess.check_call(mkdb_cmd, cwd=abs_out)
+ gtkdoc_run_check(mkdb_cmd, abs_out)
+
+ # Make HTML documentation
shutil.rmtree(htmldir, ignore_errors=True)
try:
os.mkdir(htmldir)
@@ -73,15 +85,13 @@ def build_gtkdoc(source_root, build_root, doc_subdir, src_subdir,
else:
mkhtml_cmd.append('%s-docs.xml' % module)
# html gen must be run in the HTML dir
-# print(mkhtml_cmd)
-# sys.exit(1)
- subprocess.check_call(mkhtml_cmd, cwd=os.path.join(abs_out, 'html'), shell=False)
+ gtkdoc_run_check(mkhtml_cmd, os.path.join(abs_out, 'html'))
+
+ # Fix cross-references in HTML files
fixref_cmd = ['gtkdoc-fixxref',
'--module=' + module,
'--module-dir=html'] + fixxref_args
-# print(fixref_cmd)
-# sys.exit(1)
- subprocess.check_call(fixref_cmd, cwd=abs_out)
+ gtkdoc_run_check(fixref_cmd, abs_out)
def install_gtkdoc(build_root, doc_subdir, install_prefix, datadir, module):
source = os.path.join(build_root, doc_subdir, 'html')
diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py
index 3a87f2d..1924b95 100644
--- a/mesonbuild/scripts/meson_install.py
+++ b/mesonbuild/scripts/meson_install.py
@@ -19,6 +19,14 @@ from glob import glob
from mesonbuild.scripts import depfixer
from mesonbuild.scripts import destdir_join
+install_log_file = None
+
+def append_to_log(line):
+ install_log_file.write(line)
+ if not line.endswith('\n'):
+ install_log_file.write('\n')
+ install_log_file.flush()
+
def do_copy(from_file, to_file):
try:
# Python's copyfile fails if the target file already exists.
@@ -27,6 +35,7 @@ def do_copy(from_file, to_file):
pass
shutil.copyfile(from_file, to_file)
shutil.copystat(from_file, to_file)
+ append_to_log(to_file)
def do_install(datafilename):
ifile = open(datafilename, 'rb')
@@ -43,7 +52,7 @@ def do_install(datafilename):
def install_subdirs(data):
for (src_dir, inst_dir, dst_dir) in data.install_subdirs:
- if src_dir.endswith('/'):
+ if src_dir.endswith('/') or src_dir.endswith('\\'):
src_dir = src_dir[:-1]
src_prefix = os.path.join(src_dir, inst_dir)
print('Installing subdir %s to %s.' % (src_prefix, dst_dir))
@@ -78,6 +87,7 @@ def install_subdirs(data):
os.mkdir(parent_dir)
shutil.copystat(os.path.split(abs_src)[0], parent_dir)
shutil.copy2(abs_src, abs_dst, follow_symlinks=False)
+ append_to_log(abs_dst)
def install_data(d):
for i in d.data:
@@ -104,6 +114,7 @@ def install_man(d):
if outfilename.endswith('.gz') and not full_source_filename.endswith('.gz'):
open(outfilename, 'wb').write(gzip.compress(open(full_source_filename, 'rb').read()))
shutil.copystat(full_source_filename, outfilename)
+ append_to_log(outfilename)
else:
do_copy(full_source_filename, outfilename)
@@ -209,6 +220,7 @@ def install_targets(d):
except FileNotFoundError:
pass
os.symlink(os.path.split(fname)[-1], symlinkfilename)
+ append_to_log(symlinkfilename)
except (NotImplementedError, OSError):
if not printed_symlink_error:
print("Symlink creation does not work on this platform.")
@@ -224,11 +236,19 @@ def install_targets(d):
raise
def run(args):
+ global install_log_file
if len(args) != 1:
print('Installer script for Meson. Do not run on your own, mmm\'kay?')
print('meson_install.py [install info file]')
datafilename = args[0]
- do_install(datafilename)
+ private_dir = os.path.split(datafilename)[0]
+ log_dir = os.path.join(private_dir, '../meson-logs')
+ with open(os.path.join(log_dir, 'install-log.txt'), 'w') as lf:
+ install_log_file = lf
+ append_to_log('# List of files installed by Meson')
+ append_to_log('# Does not contain files installed by custom scripts.')
+ do_install(datafilename)
+ install_log_file = None
return 0
if __name__ == '__main__':
diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py
index 2e974d8..f65f3bd 100644
--- a/mesonbuild/scripts/regen_checker.py
+++ b/mesonbuild/scripts/regen_checker.py
@@ -33,25 +33,28 @@ def need_regen(regeninfo, regen_timestamp):
Vs2010Backend.touch_regen_timestamp(regeninfo.build_dir)
return False
-def regen(regeninfo):
+def regen(regeninfo, mesonscript, backend):
scriptdir = os.path.split(__file__)[0]
- mesonscript = os.path.join(scriptdir, '../../', 'meson')
cmd = [sys.executable,
mesonscript,
'--internal',
'regenerate',
regeninfo.build_dir,
regeninfo.source_dir,
- '--backend=vs2010']
+ '--backend=' + backend]
subprocess.check_call(cmd)
def run(args):
private_dir = args[0]
dumpfile = os.path.join(private_dir, 'regeninfo.dump')
+ coredata = os.path.join(private_dir, 'coredata.dat')
regeninfo = pickle.load(open(dumpfile, 'rb'))
+ coredata = pickle.load(open(coredata, 'rb'))
+ mesonscript = coredata.meson_script_file
+ backend = coredata.get_builtin_option('backend')
regen_timestamp = os.stat(dumpfile).st_mtime
if need_regen(regeninfo, regen_timestamp):
- regen(regeninfo)
+ regen(regeninfo, mesonscript, backend)
sys.exit(0)
if __name__ == '__main__':
diff --git a/run_cross_test.py b/run_cross_test.py
index a788850..3abd288 100755
--- a/run_cross_test.py
+++ b/run_cross_test.py
@@ -34,7 +34,7 @@ meson_command = './meson.py'
extra_flags = ['--cross-file', sys.argv[1]]
ninja_command = environment.detect_ninja()
if ninja_command is None:
- raise RuntimeError('Could not find Ninja executable.')
+ raise RuntimeError('Could not find Ninja v1.6 or newer')
compile_commands = [ninja_command]
test_commands = [ninja_command, 'test']
install_commands = [ninja_command, 'install']
diff --git a/run_tests.py b/run_tests.py
index 6f51a19..34258d8 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -116,52 +116,61 @@ def setup_commands(backend):
backend_flags = []
ninja_command = environment.detect_ninja()
if ninja_command is None:
- raise RuntimeError('Could not find Ninja executable.')
+ raise RuntimeError('Could not find Ninja v1.6 or newer')
if print_debug:
compile_commands = [ninja_command, '-v']
else:
compile_commands = [ninja_command]
+ compile_commands += ['-w', 'dupbuild=err']
test_commands = [ninja_command, 'test', 'benchmark']
install_commands = [ninja_command, 'install']
-def platform_fix_filename(fname):
- if mesonlib.is_osx():
- if fname.endswith('.so'):
- return fname[:-2] + 'dylib'
- return fname.replace('.so.', '.dylib.')
- elif mesonlib.is_windows():
- if fname.endswith('.so'):
- (p, f) = os.path.split(fname)
- f = f[3:-2] + 'dll'
- return os.path.join(p, f)
- if fname.endswith('.a'):
- return fname[:-1] + 'lib'
+def get_relative_files_list_from_dir(fromdir):
+ paths = []
+ for (root, _, files) in os.walk(fromdir):
+ reldir = os.path.relpath(root, start=fromdir)
+ for f in files:
+ path = os.path.join(reldir, f).replace('\\', '/')
+ if path.startswith('./'):
+ path = path[2:]
+ paths.append(path)
+ return paths
+
+def platform_fix_exe_name(fname):
+ if not fname.endswith('?exe'):
+ return fname
+ fname = fname[:-4]
+ if mesonlib.is_windows():
+ return fname + '.exe'
return fname
def validate_install(srcdir, installdir):
- if mesonlib.is_windows():
- # Don't really know how Windows installs should work
- # so skip.
- return ''
+ # List of installed files
info_file = os.path.join(srcdir, 'installed_files.txt')
+ # If this exists, the test does not install any other files
+ noinst_file = 'usr/no-installed-files'
expected = {}
found = {}
- if os.path.exists(info_file):
+ ret_msg = ''
+ # Generate list of expected files
+ if os.path.exists(os.path.join(installdir, noinst_file)):
+ expected[noinst_file] = False
+ elif os.path.exists(info_file):
for line in open(info_file):
- expected[platform_fix_filename(line.strip())] = True
- for root, _, files in os.walk(installdir):
- for fname in files:
- found_name = os.path.join(root, fname)[len(installdir)+1:]
- found[found_name] = True
- expected = set(expected)
- found = set(found)
- missing = expected - found
- for fname in missing:
- return 'Expected file %s missing.' % fname
- extra = found - expected
- for fname in extra:
- return 'Found extra file %s.' % fname
- return ''
+ expected[platform_fix_exe_name(line.strip())] = False
+ # Check if expected files were found
+ for fname in expected:
+ if os.path.exists(os.path.join(installdir, fname)):
+ expected[fname] = True
+ for (fname, found) in expected.items():
+ if not found:
+ ret_msg += 'Expected file {0} missing.\n'.format(fname)
+ # Check if there are any unexpected files
+ found = get_relative_files_list_from_dir(installdir)
+ for fname in found:
+ if fname not in expected:
+ ret_msg += 'Extra file {0} found.\n'.format(fname)
+ return ret_msg
def log_text_file(logfile, testdir, stdo, stde):
global stop, executor, futures
@@ -299,7 +308,7 @@ def detect_tests_to_run():
all_tests = []
all_tests.append(('common', gather_tests('test cases/common'), False))
all_tests.append(('failing', gather_tests('test cases/failing'), False))
- all_tests.append(('prebuilt object', gather_tests('test cases/prebuilt object'), False))
+ all_tests.append(('prebuilt', gather_tests('test cases/prebuilt'), False))
all_tests.append(('platform-osx', gather_tests('test cases/osx'), False if mesonlib.is_osx() else True))
all_tests.append(('platform-windows', gather_tests('test cases/windows'), False if mesonlib.is_windows() else True))
@@ -396,27 +405,51 @@ def check_format():
fullname = os.path.join(root, file)
check_file(fullname)
-def generate_prebuilt_object():
- source = 'test cases/prebuilt object/1 basic/source.c'
- objectbase = 'test cases/prebuilt object/1 basic/prebuilt.'
- if shutil.which('cl'):
- objectfile = objectbase + 'obj'
- cmd = ['cl', '/nologo', '/Fo'+objectfile, '/c', source]
+def pbcompile(compiler, source, objectfile):
+ if compiler == 'cl':
+ cmd = [compiler, '/nologo', '/Fo'+objectfile, '/c', source]
else:
- if mesonlib.is_windows():
- objectfile = objectbase + 'obj'
- else:
- objectfile = objectbase + 'o'
- if shutil.which('cc'):
- cmd = 'cc'
- elif shutil.which('gcc'):
- cmd = 'gcc'
- else:
- raise RuntimeError("Could not find C compiler.")
- cmd = [cmd, '-c', source, '-o', objectfile]
+ cmd = [compiler, '-c', source, '-o', objectfile]
subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+
+def generate_pb_object(compiler, object_suffix):
+ source = 'test cases/prebuilt/1 object/source.c'
+ objectfile = 'test cases/prebuilt/1 object/prebuilt.' + object_suffix
+ pbcompile(compiler, source, objectfile)
return objectfile
+def generate_pb_static(compiler, object_suffix, static_suffix):
+ source = 'test cases/prebuilt/2 static/libdir/best.c'
+ objectfile = 'test cases/prebuilt/2 static/libdir/best.' + object_suffix
+ stlibfile = 'test cases/prebuilt/2 static/libdir/libbest.' + static_suffix
+ pbcompile(compiler, source, objectfile)
+ if compiler == 'cl':
+ linker = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile]
+ else:
+ linker = ['ar', 'csr', stlibfile, objectfile]
+ subprocess.check_call(linker)
+ os.unlink(objectfile)
+ return stlibfile
+
+def generate_prebuilt():
+ static_suffix = 'a'
+ if shutil.which('cl'):
+ compiler = 'cl'
+ static_suffix = 'lib'
+ elif shutil.which('cc'):
+ compiler = 'cc'
+ elif shutil.which('gcc'):
+ compiler = 'gcc'
+ else:
+ raise RuntimeError("Could not find C compiler.")
+ if mesonlib.is_windows():
+ object_suffix = 'obj'
+ else:
+ object_suffix = 'o'
+ objectfile = generate_pb_object(compiler, object_suffix)
+ stlibfile = generate_pb_static(compiler, object_suffix, static_suffix)
+ return (objectfile, stlibfile)
+
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
parser.add_argument('extra_args', nargs='*',
@@ -430,12 +463,13 @@ if __name__ == '__main__':
if script_dir != '':
os.chdir(script_dir)
check_format()
- pbfile = generate_prebuilt_object()
+ pbfiles = generate_prebuilt()
try:
run_tests(options.extra_args)
except StopException:
pass
- os.unlink(pbfile)
+ for f in pbfiles:
+ os.unlink(f)
print('\nTotal passed tests:', passing_tests)
print('Total failed tests:', failing_tests)
print('Total skipped tests:', skipped_tests)
diff --git a/test cases/common/114 multiple dir configure file/meson.build b/test cases/common/114 multiple dir configure file/meson.build
new file mode 100644
index 0000000..180227c
--- /dev/null
+++ b/test cases/common/114 multiple dir configure file/meson.build
@@ -0,0 +1,7 @@
+project('multiple dir configure file', 'c')
+
+subdir('subdir')
+
+configure_file(input : 'subdir/someinput.in',
+ output : 'outputhere',
+ configuration : configuration_data())
diff --git a/test cases/common/114 multiple dir configure file/subdir/meson.build b/test cases/common/114 multiple dir configure file/subdir/meson.build
new file mode 100644
index 0000000..a8f731d
--- /dev/null
+++ b/test cases/common/114 multiple dir configure file/subdir/meson.build
@@ -0,0 +1,4 @@
+configure_file(input : 'someinput.in',
+ output : 'outputsubdir',
+ install : false,
+ configuration : configuration_data())
diff --git a/test cases/common/114 multiple dir configure file/subdir/someinput.in b/test cases/common/114 multiple dir configure file/subdir/someinput.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/common/114 multiple dir configure file/subdir/someinput.in
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/common/116 ternary/meson.build b/test cases/common/116 ternary/meson.build
new file mode 100644
index 0000000..3e65046
--- /dev/null
+++ b/test cases/common/116 ternary/meson.build
@@ -0,0 +1,7 @@
+project('ternary operator', 'c')
+
+one = true ? 1 : error('False branch should not be evaluated')
+two = false ? error('True branch should not be evaluated.') : 2
+
+assert(one == 1, 'Return value from ternary true is wrong.')
+assert(two == 2, 'Return value from ternary false is wrong.')
diff --git a/test cases/common/27 library versions/installed_files.txt b/test cases/common/27 library versions/installed_files.txt
index a218d29..e10d1dd 100644
--- a/test cases/common/27 library versions/installed_files.txt
+++ b/test cases/common/27 library versions/installed_files.txt
@@ -1,3 +1 @@
-usr/lib/libsomelib.so
-usr/lib/libsomelib.so.0
-usr/lib/libsomelib.so.1.2.3
+usr/lib/prefixsomelib.suffix
diff --git a/test cases/common/27 library versions/meson.build b/test cases/common/27 library versions/meson.build
index cebcd64..2e2bef7 100644
--- a/test cases/common/27 library versions/meson.build
+++ b/test cases/common/27 library versions/meson.build
@@ -1,6 +1,9 @@
project('library versions', 'c')
-lib = shared_library('somelib', 'lib.c', \
-version : '1.2.3', \
-soversion : '0', \
-install : true)
+shared_library('somelib', 'lib.c',
+ name_prefix : 'prefix',
+ name_suffix : 'suffix',
+ install_dir : 'lib',
+ install : true)
+
+subdir('subdir')
diff --git a/test cases/common/27 library versions/subdir/meson.build b/test cases/common/27 library versions/subdir/meson.build
new file mode 100644
index 0000000..b51033d
--- /dev/null
+++ b/test cases/common/27 library versions/subdir/meson.build
@@ -0,0 +1,8 @@
+# Test that using files generated with configure_file as sources works.
+# We do this inside a subdir so that the path isn't accidentally correct
+# because there is no structure in the build dir.
+genlib = configure_file(input : '../lib.c',
+ output : 'genlib.c',
+ configuration : configuration_data())
+shared_library('genlib', genlib,
+ install : false)
diff --git a/test cases/common/46 library chain/installed_files.txt b/test cases/common/46 library chain/installed_files.txt
index 8d38fd9..c7dab9f 100644
--- a/test cases/common/46 library chain/installed_files.txt
+++ b/test cases/common/46 library chain/installed_files.txt
@@ -1,4 +1 @@
-usr/bin/prog
-usr/lib/liblib1.so
-usr/lib/liblib2.so
-usr/lib/liblib3.so
+usr/bin/prog?exe
diff --git a/test cases/common/46 library chain/subdir/meson.build b/test cases/common/46 library chain/subdir/meson.build
index c165abe..ab71bda 100644
--- a/test cases/common/46 library chain/subdir/meson.build
+++ b/test cases/common/46 library chain/subdir/meson.build
@@ -1,4 +1,4 @@
subdir('subdir2')
subdir('subdir3')
-lib1 = shared_library('lib1', 'lib1.c', install : true, link_with : [lib2, lib3])
+lib1 = shared_library('lib1', 'lib1.c', install : false, link_with : [lib2, lib3])
diff --git a/test cases/common/46 library chain/subdir/subdir2/meson.build b/test cases/common/46 library chain/subdir/subdir2/meson.build
index 2281e4b..befd94d 100644
--- a/test cases/common/46 library chain/subdir/subdir2/meson.build
+++ b/test cases/common/46 library chain/subdir/subdir2/meson.build
@@ -1 +1 @@
-lib2 = shared_library('lib2', 'lib2.c', install : true)
+lib2 = shared_library('lib2', 'lib2.c', install : false)
diff --git a/test cases/common/46 library chain/subdir/subdir3/meson.build b/test cases/common/46 library chain/subdir/subdir3/meson.build
index f049c79..7bd249a 100644
--- a/test cases/common/46 library chain/subdir/subdir3/meson.build
+++ b/test cases/common/46 library chain/subdir/subdir3/meson.build
@@ -1 +1 @@
-lib3 = shared_library('lib3', 'lib3.c', install : true)
+lib3 = shared_library('lib3', 'lib3.c', install : false)
diff --git a/test cases/common/49 subproject/installed_files.txt b/test cases/common/49 subproject/installed_files.txt
index f2e1e27..dc09fb7 100644
--- a/test cases/common/49 subproject/installed_files.txt
+++ b/test cases/common/49 subproject/installed_files.txt
@@ -1,3 +1,2 @@
-usr/bin/user
-usr/lib/libsublib.so
+usr/bin/user?exe
usr/share/sublib/sublib.depmf
diff --git a/test cases/common/49 subproject/subprojects/sublib/meson.build b/test cases/common/49 subproject/subprojects/sublib/meson.build
index 269f815..acaf1bf 100644
--- a/test cases/common/49 subproject/subprojects/sublib/meson.build
+++ b/test cases/common/49 subproject/subprojects/sublib/meson.build
@@ -13,7 +13,7 @@ if meson.project_version() != '1.0.0'
endif
i = include_directories('include')
-l = shared_library('sublib', 'sublib.c', include_directories : i, install : true,
+l = shared_library('sublib', 'sublib.c', include_directories : i, install : false,
c_args : '-DBUILDING_SUB=2')
t = executable('simpletest', 'simpletest.c', include_directories : i, link_with : l)
test('plain', t)
diff --git a/test cases/common/51 pkgconfig-gen/installed_files.txt b/test cases/common/51 pkgconfig-gen/installed_files.txt
index cc5d34b..d6a23d7 100644
--- a/test cases/common/51 pkgconfig-gen/installed_files.txt
+++ b/test cases/common/51 pkgconfig-gen/installed_files.txt
@@ -1,3 +1,2 @@
usr/include/simple.h
-usr/lib/libsimple.so
usr/lib/pkgconfig/simple.pc
diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build
index 4044b3d..b5f6921 100644
--- a/test cases/common/51 pkgconfig-gen/meson.build
+++ b/test cases/common/51 pkgconfig-gen/meson.build
@@ -2,7 +2,7 @@ project('pkgconfig-gen', 'c')
pkgg = import('pkgconfig')
-lib = shared_library('simple', 'simple.c', install : true)
+lib = shared_library('simple', 'simple.c')
libver = '1.0'
h = install_headers('simple.h')
diff --git a/test cases/common/52 custom install dirs/installed_files.txt b/test cases/common/52 custom install dirs/installed_files.txt
index dc495e2..1b8b561 100644
--- a/test cases/common/52 custom install dirs/installed_files.txt
+++ b/test cases/common/52 custom install dirs/installed_files.txt
@@ -1,4 +1,4 @@
-usr/dib/dab/dub/prog
+usr/dib/dab/dub/prog?exe
usr/some/dir/sample.h
usr/woman/prog.1.gz
usr/meow/datafile.cat
diff --git a/test cases/common/6 linkshared/installed_files.txt b/test cases/common/6 linkshared/installed_files.txt
index 2a4c330..c7dab9f 100644
--- a/test cases/common/6 linkshared/installed_files.txt
+++ b/test cases/common/6 linkshared/installed_files.txt
@@ -1,2 +1 @@
-usr/bin/prog
-usr/lib/libmylib.so
+usr/bin/prog?exe
diff --git a/test cases/common/6 linkshared/meson.build b/test cases/common/6 linkshared/meson.build
index 1ecb052..846b4a0 100644
--- a/test cases/common/6 linkshared/meson.build
+++ b/test cases/common/6 linkshared/meson.build
@@ -2,7 +2,7 @@ project('shared library linking test', 'c', 'cpp')
lib = shared_library('mylib',
'libfile.c' # Split to different lines before and after the comma to test parser.
- , install : true)
+ , install : false) # Don't install libraries in common tests; the path is platform-specific
exe = executable('prog', 'main.c', link_with : lib, install : true)
test('runtest', exe)
diff --git a/test cases/common/60 install script/installed_files.txt b/test cases/common/60 install script/installed_files.txt
index 58315f9..94e3164 100644
--- a/test cases/common/60 install script/installed_files.txt
+++ b/test cases/common/60 install script/installed_files.txt
@@ -1,2 +1,2 @@
-usr/bin/prog
+usr/bin/prog?exe
usr/diiba/daaba/file.dat
diff --git a/test cases/common/60 install script/meson.build b/test cases/common/60 install script/meson.build
index 66db0a7..6cab840 100644
--- a/test cases/common/60 install script/meson.build
+++ b/test cases/common/60 install script/meson.build
@@ -1,8 +1,8 @@
project('custom install script', 'c')
if meson.get_compiler('c').get_id() == 'msvc'
- meson.add_install_script('myinstall.bat')
+ install_data('no-installed-files', install_dir : '')
else
meson.add_install_script('myinstall.sh')
+ executable('prog', 'prog.c', install : true)
endif
-executable('prog', 'prog.c', install : true)
diff --git a/test cases/common/60 install script/myinstall.bat b/test cases/common/60 install script/myinstall.bat
deleted file mode 100644
index 7036077..0000000
--- a/test cases/common/60 install script/myinstall.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-@ECHO OFF
-
-echo At this point we could do something.
diff --git a/test cases/common/60 install script/myinstall.sh b/test cases/common/60 install script/myinstall.sh
index 42a415e..79512c9 100755
--- a/test cases/common/60 install script/myinstall.sh
+++ b/test cases/common/60 install script/myinstall.sh
@@ -4,9 +4,7 @@ set -eu
echo Starting custom installation step
-# These commands fail on Windows, but we don't really care.
-
mkdir -p "${DESTDIR}${MESON_INSTALL_PREFIX}/diiba/daaba"
touch "${DESTDIR}${MESON_INSTALL_PREFIX}/diiba/daaba/file.dat"
-echo Finishing custom install step
+echo Finished custom install step
diff --git a/test cases/common/60 install script/no-installed-files b/test cases/common/60 install script/no-installed-files
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/common/60 install script/no-installed-files
diff --git a/test cases/common/67 foreach/installed_files.txt b/test cases/common/67 foreach/installed_files.txt
index 36c6386..2930ff0 100644
--- a/test cases/common/67 foreach/installed_files.txt
+++ b/test cases/common/67 foreach/installed_files.txt
@@ -1,3 +1,3 @@
-usr/bin/prog1
-usr/bin/prog2
-usr/bin/prog3
+usr/bin/prog1?exe
+usr/bin/prog2?exe
+usr/bin/prog3?exe
diff --git a/test cases/common/76 configure file in custom target/src/meson.build b/test cases/common/76 configure file in custom target/src/meson.build
index b049e95..cbbce5c 100644
--- a/test cases/common/76 configure file in custom target/src/meson.build
+++ b/test cases/common/76 configure file in custom target/src/meson.build
@@ -2,3 +2,19 @@ custom_target('thing',
output : 'final.dat',
input : cfile,
command : [find_program('mycompiler.py'), '@INPUT@', '@OUTPUT@'])
+
+# Test usage of a `configure_file` as part of the command list
+py3 = find_program('python3', required : false)
+if not py3.found()
+ # Maybe 'python' is Python 3
+ py3 = find_program('python')
+endif
+
+compiler = configure_file(input : 'mycompiler.py',
+ output : 'mycompiler2.py',
+ configuration : configuration_data())
+
+custom_target('thing2',
+output : 'final2.dat',
+input : cfile,
+command : [py3, compiler, '@INPUT@', '@OUTPUT@'])
diff --git a/test cases/common/8 install/installed_files.txt b/test cases/common/8 install/installed_files.txt
index 1e9166b..cbbdc03 100644
--- a/test cases/common/8 install/installed_files.txt
+++ b/test cases/common/8 install/installed_files.txt
@@ -1,3 +1,2 @@
-usr/bin/prog
-usr/lib/libshar.so
-usr/lib/libstat.a
+usr/bin/prog?exe
+usr/libtest/libstat.a
diff --git a/test cases/common/8 install/meson.build b/test cases/common/8 install/meson.build
index 677a2ee..12ad389 100644
--- a/test cases/common/8 install/meson.build
+++ b/test cases/common/8 install/meson.build
@@ -1,5 +1,4 @@
-project('install test', 'c')
+project('install test', 'c', default_options : ['libdir=libtest'])
stlib = static_library('stat', 'stat.c', install : true)
-shlib = shared_library('shar', 'shar.c', install : true)
exe = executable('prog', 'prog.c', install : true)
diff --git a/test cases/common/8 install/shar.c b/test cases/common/8 install/shar.c
deleted file mode 100644
index 9c816a6..0000000
--- a/test cases/common/8 install/shar.c
+++ /dev/null
@@ -1 +0,0 @@
-int func() { return 15; }
diff --git a/test cases/common/86 same basename/meson.build b/test cases/common/86 same basename/meson.build
index e320f95..3dc384e 100644
--- a/test cases/common/86 same basename/meson.build
+++ b/test cases/common/86 same basename/meson.build
@@ -5,10 +5,9 @@ project('same basename', 'c')
# then the .o files will clobber each other.
shlib = shared_library('name', 'lib.c', c_args : '-DSHAR')
-# On Windows a static lib is a foo.lib but a share library
-# is both a foo.dll and a foo.lib. Put static in subdir to avoid
-# name clashes.
-subdir('sub')
+# On Windows a static lib is now libfoo.a, so it does not conflict with foo.lib
+# from the shared library above
+stlib = static_library('name', 'lib.c', c_args : '-DSTAT')
exe1 = executable('name', 'exe1.c', link_with : stlib)
exe2 = executable('name2', 'exe2.c', link_with : shlib)
diff --git a/test cases/common/86 same basename/sub/meson.build b/test cases/common/86 same basename/sub/meson.build
deleted file mode 100644
index 07250a5..0000000
--- a/test cases/common/86 same basename/sub/meson.build
+++ /dev/null
@@ -1 +0,0 @@
-stlib = static_library('name', '../lib.c', c_args : '-DSTAT')
diff --git a/test cases/csharp/2 library/installed_files.txt b/test cases/csharp/2 library/installed_files.txt
index b830634..4ebea55 100644
--- a/test cases/csharp/2 library/installed_files.txt
+++ b/test cases/csharp/2 library/installed_files.txt
@@ -1,2 +1,2 @@
usr/bin/prog.exe
-usr/lib/libhelper.dll
+usr/lib/helper.dll
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/failing/30 nested ternary/meson.build b/test cases/failing/30 nested ternary/meson.build
new file mode 100644
index 0000000..f9c2e5f
--- /dev/null
+++ b/test cases/failing/30 nested ternary/meson.build
@@ -0,0 +1,3 @@
+project('nested ternary', 'c')
+
+x = true ? (false ? 1 : 0) : 2
diff --git a/test cases/linuxlike/7 library versions/installed_files.txt b/test cases/linuxlike/7 library versions/installed_files.txt
new file mode 100644
index 0000000..b997e53
--- /dev/null
+++ b/test cases/linuxlike/7 library versions/installed_files.txt
@@ -0,0 +1,9 @@
+usr/lib/libsome.so
+usr/lib/libsome.so.0
+usr/lib/libsome.so.1.2.3
+usr/lib/libnoversion.so
+usr/lib/libonlyversion.so
+usr/lib/libonlyversion.so.1
+usr/lib/libonlyversion.so.1.4.5
+usr/lib/libonlysoversion.so
+usr/lib/libonlysoversion.so.5
diff --git a/test cases/linuxlike/7 library versions/lib.c b/test cases/linuxlike/7 library versions/lib.c
new file mode 100644
index 0000000..67b6f4d
--- /dev/null
+++ b/test cases/linuxlike/7 library versions/lib.c
@@ -0,0 +1,3 @@
+int myFunc() {
+ return 55;
+}
diff --git a/test cases/linuxlike/7 library versions/meson.build b/test cases/linuxlike/7 library versions/meson.build
new file mode 100644
index 0000000..504aa4e
--- /dev/null
+++ b/test cases/linuxlike/7 library versions/meson.build
@@ -0,0 +1,18 @@
+project('library versions', 'c')
+
+shared_library('some', 'lib.c',
+ version : '1.2.3',
+ soversion : '0',
+ install : true)
+
+shared_library('noversion', 'lib.c',
+ install : true)
+
+shared_library('onlyversion', 'lib.c',
+ version : '1.4.5',
+ install : true)
+
+shared_library('onlysoversion', 'lib.c',
+ # Also test that int soversion is acceptable
+ soversion : 5,
+ install : true)
diff --git a/test cases/linuxlike/8 subproject library install/installed_files.txt b/test cases/linuxlike/8 subproject library install/installed_files.txt
new file mode 100644
index 0000000..5c4a301
--- /dev/null
+++ b/test cases/linuxlike/8 subproject library install/installed_files.txt
@@ -0,0 +1,3 @@
+usr/lib/libsublib.so
+usr/lib/libsublib.so.5
+usr/lib/libsublib.so.2.1.0
diff --git a/test cases/linuxlike/8 subproject library install/meson.build b/test cases/linuxlike/8 subproject library install/meson.build
new file mode 100644
index 0000000..63e57cf
--- /dev/null
+++ b/test cases/linuxlike/8 subproject library install/meson.build
@@ -0,0 +1,6 @@
+project('subproj lib install', 'c',
+ version : '2.3.4',
+ license : 'mylicense')
+
+# Test that the subproject library gets installed
+subproject('sublib', version : '1.0.0')
diff --git a/test cases/linuxlike/8 subproject library install/subprojects/sublib/include/subdefs.h b/test cases/linuxlike/8 subproject library install/subprojects/sublib/include/subdefs.h
new file mode 100644
index 0000000..681c7b8
--- /dev/null
+++ b/test cases/linuxlike/8 subproject library install/subprojects/sublib/include/subdefs.h
@@ -0,0 +1,21 @@
+#ifndef SUBDEFS_H_
+#define SUBDEFS_H_
+
+#if defined _WIN32 || defined __CYGWIN__
+#if defined BUILDING_SUB
+ #define DLL_PUBLIC __declspec(dllexport)
+#else
+ #define DLL_PUBLIC __declspec(dllimport)
+#endif
+#else
+ #if defined __GNUC__
+ #define DLL_PUBLIC __attribute__ ((visibility("default")))
+ #else
+ #pragma message ("Compiler does not support symbol visibility.")
+ #define DLL_PUBLIC
+ #endif
+#endif
+
+int DLL_PUBLIC subfunc();
+
+#endif
diff --git a/test cases/linuxlike/8 subproject library install/subprojects/sublib/meson.build b/test cases/linuxlike/8 subproject library install/subprojects/sublib/meson.build
new file mode 100644
index 0000000..97658fa
--- /dev/null
+++ b/test cases/linuxlike/8 subproject library install/subprojects/sublib/meson.build
@@ -0,0 +1,10 @@
+project('subproject', 'c',
+ version : '1.0.0',
+ license : ['sublicense1', 'sublicense2'])
+
+i = include_directories('include')
+shared_library('sublib', 'sublib.c',
+ version : '2.1.0',
+ soversion : 5,
+ include_directories : i, install : true,
+ c_args : '-DBUILDING_SUB=2')
diff --git a/test cases/linuxlike/8 subproject library install/subprojects/sublib/sublib.c b/test cases/linuxlike/8 subproject library install/subprojects/sublib/sublib.c
new file mode 100644
index 0000000..c13326b
--- /dev/null
+++ b/test cases/linuxlike/8 subproject library install/subprojects/sublib/sublib.c
@@ -0,0 +1,5 @@
+#include<subdefs.h>
+
+int DLL_PUBLIC subfunc() {
+ return 42;
+}
diff --git a/test cases/osx/2 library versions/installed_files.txt b/test cases/osx/2 library versions/installed_files.txt
new file mode 100644
index 0000000..66470ab
--- /dev/null
+++ b/test cases/osx/2 library versions/installed_files.txt
@@ -0,0 +1,4 @@
+usr/lib/libsome.0.dylib
+usr/lib/libnoversion.dylib
+usr/lib/libonlyversion.1.dylib
+usr/lib/libonlysoversion.5.dylib
diff --git a/test cases/osx/2 library versions/lib.c b/test cases/osx/2 library versions/lib.c
new file mode 100644
index 0000000..67b6f4d
--- /dev/null
+++ b/test cases/osx/2 library versions/lib.c
@@ -0,0 +1,3 @@
+int myFunc() {
+ return 55;
+}
diff --git a/test cases/osx/2 library versions/meson.build b/test cases/osx/2 library versions/meson.build
new file mode 100644
index 0000000..504aa4e
--- /dev/null
+++ b/test cases/osx/2 library versions/meson.build
@@ -0,0 +1,18 @@
+project('library versions', 'c')
+
+shared_library('some', 'lib.c',
+ version : '1.2.3',
+ soversion : '0',
+ install : true)
+
+shared_library('noversion', 'lib.c',
+ install : true)
+
+shared_library('onlyversion', 'lib.c',
+ version : '1.4.5',
+ install : true)
+
+shared_library('onlysoversion', 'lib.c',
+ # Also test that int soversion is acceptable
+ soversion : 5,
+ install : true)
diff --git a/test cases/prebuilt object/1 basic/main.c b/test cases/prebuilt/1 object/main.c
index 480bda5..480bda5 100644
--- a/test cases/prebuilt object/1 basic/main.c
+++ b/test cases/prebuilt/1 object/main.c
diff --git a/test cases/prebuilt object/1 basic/meson.build b/test cases/prebuilt/1 object/meson.build
index 92f966b..92f966b 100644
--- a/test cases/prebuilt object/1 basic/meson.build
+++ b/test cases/prebuilt/1 object/meson.build
diff --git a/test cases/prebuilt object/1 basic/source.c b/test cases/prebuilt/1 object/source.c
index f39b4f3..f39b4f3 100644
--- a/test cases/prebuilt object/1 basic/source.c
+++ b/test cases/prebuilt/1 object/source.c
diff --git a/test cases/prebuilt/2 static/libdir/best.c b/test cases/prebuilt/2 static/libdir/best.c
new file mode 100644
index 0000000..ab774e1
--- /dev/null
+++ b/test cases/prebuilt/2 static/libdir/best.c
@@ -0,0 +1,3 @@
+const char *msg() {
+ return "I am the best.";
+}
diff --git a/test cases/prebuilt/2 static/libdir/best.h b/test cases/prebuilt/2 static/libdir/best.h
new file mode 100644
index 0000000..063017f
--- /dev/null
+++ b/test cases/prebuilt/2 static/libdir/best.h
@@ -0,0 +1,3 @@
+#pragma once
+
+const char *msg();
diff --git a/test cases/prebuilt/2 static/libdir/meson.build b/test cases/prebuilt/2 static/libdir/meson.build
new file mode 100644
index 0000000..8d74ccf
--- /dev/null
+++ b/test cases/prebuilt/2 static/libdir/meson.build
@@ -0,0 +1,5 @@
+cc = meson.get_compiler('c')
+stlib = cc.find_library('best', dirs : meson.current_source_dir())
+
+best_dep = declare_dependency(dependencies : stlib,
+ include_directories : include_directories('.'))
diff --git a/test cases/prebuilt/2 static/main.c b/test cases/prebuilt/2 static/main.c
new file mode 100644
index 0000000..d172625
--- /dev/null
+++ b/test cases/prebuilt/2 static/main.c
@@ -0,0 +1,7 @@
+#include<stdio.h>
+#include<best.h>
+
+int main(int argc, char **argv) {
+ printf("%s\n", msg());
+ return 0;
+}
diff --git a/test cases/prebuilt/2 static/meson.build b/test cases/prebuilt/2 static/meson.build
new file mode 100644
index 0000000..9ea1d0d
--- /dev/null
+++ b/test cases/prebuilt/2 static/meson.build
@@ -0,0 +1,5 @@
+project('prebuilt static lib', 'c')
+
+subdir('libdir')
+
+test('static', executable('mainprog', 'main.c', dependencies : best_dep))
diff --git a/test cases/rust/1 basic/installed_files.txt b/test cases/rust/1 basic/installed_files.txt
index 61eda27..c7dab9f 100644
--- a/test cases/rust/1 basic/installed_files.txt
+++ b/test cases/rust/1 basic/installed_files.txt
@@ -1 +1 @@
-usr/bin/prog
+usr/bin/prog?exe
diff --git a/test cases/rust/2 sharedlib/installed_files.txt b/test cases/rust/2 sharedlib/installed_files.txt
index 5a7c7d6..85acff2 100644
--- a/test cases/rust/2 sharedlib/installed_files.txt
+++ b/test cases/rust/2 sharedlib/installed_files.txt
@@ -1,2 +1,2 @@
-usr/bin/prog
+usr/bin/prog?exe
usr/lib/libstuff.rlib
diff --git a/test cases/rust/3 staticlib/installed_files.txt b/test cases/rust/3 staticlib/installed_files.txt
index 5a7c7d6..85acff2 100644
--- a/test cases/rust/3 staticlib/installed_files.txt
+++ b/test cases/rust/3 staticlib/installed_files.txt
@@ -1,2 +1,2 @@
-usr/bin/prog
+usr/bin/prog?exe
usr/lib/libstuff.rlib
diff --git a/test cases/windows/7 mingw dll versioning/installed_files.txt b/test cases/windows/7 mingw dll versioning/installed_files.txt
new file mode 100644
index 0000000..8c2a8f2
--- /dev/null
+++ b/test cases/windows/7 mingw dll versioning/installed_files.txt
@@ -0,0 +1,4 @@
+usr/bin/libsome-0.dll
+usr/lib/libsome.dll.a
+usr/bin/libnoversion.dll
+usr/lib/libnoversion.dll.a
diff --git a/test cases/windows/7 mingw dll versioning/lib.c b/test cases/windows/7 mingw dll versioning/lib.c
new file mode 100644
index 0000000..cf7dfdd
--- /dev/null
+++ b/test cases/windows/7 mingw dll versioning/lib.c
@@ -0,0 +1,6 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int myFunc() {
+ return 55;
+}
diff --git a/test cases/windows/7 mingw dll versioning/meson.build b/test cases/windows/7 mingw dll versioning/meson.build
new file mode 100644
index 0000000..23a3343
--- /dev/null
+++ b/test cases/windows/7 mingw dll versioning/meson.build
@@ -0,0 +1,17 @@
+project('mingw dll versioning', 'c')
+
+cc = meson.get_compiler('c')
+
+# Test that MinGW/GCC creates correctly-named dll files and dll.a files,
+# and also installs them in the right place
+if cc.get_id() != 'msvc'
+ shared_library('some', 'lib.c',
+ version : '1.2.3',
+ soversion : '0',
+ install : true)
+
+ shared_library('noversion', 'lib.c',
+ install : true)
+else
+ install_data('no-installed-files', install_dir : '')
+endif
diff --git a/test cases/windows/7 mingw dll versioning/no-installed-files b/test cases/windows/7 mingw dll versioning/no-installed-files
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/windows/7 mingw dll versioning/no-installed-files
diff --git a/test cases/windows/8 msvc dll versioning/installed_files.txt b/test cases/windows/8 msvc dll versioning/installed_files.txt
new file mode 100644
index 0000000..5f6e26a
--- /dev/null
+++ b/test cases/windows/8 msvc dll versioning/installed_files.txt
@@ -0,0 +1,4 @@
+usr/bin/some-0.dll
+usr/lib/some.lib
+usr/bin/noversion.dll
+usr/lib/noversion.lib
diff --git a/test cases/windows/8 msvc dll versioning/lib.c b/test cases/windows/8 msvc dll versioning/lib.c
new file mode 100644
index 0000000..cf7dfdd
--- /dev/null
+++ b/test cases/windows/8 msvc dll versioning/lib.c
@@ -0,0 +1,6 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int myFunc() {
+ return 55;
+}
diff --git a/test cases/windows/8 msvc dll versioning/meson.build b/test cases/windows/8 msvc dll versioning/meson.build
new file mode 100644
index 0000000..0c36173
--- /dev/null
+++ b/test cases/windows/8 msvc dll versioning/meson.build
@@ -0,0 +1,16 @@
+project('msvc dll versioning', 'c')
+
+cc = meson.get_compiler('c')
+
+# Test that MSVC creates foo-0.dll and bar.dll
+if cc.get_id() == 'msvc'
+ shared_library('some', 'lib.c',
+ version : '1.2.3',
+ soversion : '0',
+ install : true)
+
+ shared_library('noversion', 'lib.c',
+ install : true)
+else
+ install_data('no-installed-files', install_dir : '')
+endif
diff --git a/test cases/windows/8 msvc dll versioning/no-installed-files b/test cases/windows/8 msvc dll versioning/no-installed-files
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test cases/windows/8 msvc dll versioning/no-installed-files
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..571481e 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'),
@@ -161,6 +162,11 @@ function_data = \
'HAVE_GETPWUID_R': ('getpwuid_r', 'pwd.h'),
'HAVE_GETUID': ('getuid', 'unistd.h'),
'HAVE_LRINTF': ('lrintf', 'math.h'),
+ 'HAVE_DECL_ISNAN': ('isnan', 'math.h'),
+ 'HAVE_DECL_ISINF': ('isinf', 'math.h'),
+ 'HAVE_ROUND': ('round', 'math.h'),
+ 'HAVE_NEARBYINT': ('nearbyint', 'math.h'),
+ 'HAVE_RINT': ('rint', 'math.h'),
'HAVE_MKFIFO': ('mkfifo', 'sys/stat.h'),
'HAVE_MLOCK': ('mlock', 'sys/mman.h'),
'HAVE_NANOSLEEP': ('nanosleep', 'time.h'),
@@ -269,6 +275,6 @@ for line in open(sys.argv[1]):
print("cdata.set('%s', cc.sizeof('%s'))" % (elem, typename))
print('''
-configure_file(input : 'config.h.in',
+configure_file(input : 'config.h.meson',
output : 'config.h',
configuration : cdata)''')