diff options
68 files changed, 562 insertions, 233 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 9264f49..c79e250 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -38,6 +38,10 @@ environment: compiler: msys2-mingw backend: ninja + - arch: x64 + compiler: cygwin + backend: ninja + platform: - x64 @@ -55,15 +59,22 @@ install: - cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% ) - cmd: if %compiler%==msvc2017 ( call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=%arch% ) - cmd: if %compiler%==msys2-mingw (if %arch%==x86 (set "PATH=C:\msys64\mingw32\bin;%PATH%") else (set "PATH=C:\msys64\mingw64\bin;%PATH%")) + - cmd: if %compiler%==cygwin ( call ci\appveyor-install.bat ) build_script: - cmd: echo No build step. - - cmd: if %backend%==ninja ( ninja.exe --version ) else ( MSBuild /version & echo. ) + - cmd: if not %compiler%==cygwin if %backend%==ninja ( ninja.exe --version ) else ( MSBuild /version & echo. ) test_script: - cmd: echo Running tests for %arch% and %compiler% with the %backend% backend - - cmd: PATH=%cd%;%MESON_PYTHON_PATH%;%PATH%; && python run_tests.py --backend=%backend% + - cmd: set "ORIG_PATH=%PATH%" + - cmd: if %compiler%==cygwin ( set "PATH=%CYGWIN_ROOT%\bin;%SYSTEMROOT%\system32" && bash -lc "cd $APPVEYOR_BUILD_FOLDER && ci/appveyor-test.sh" ) + - cmd: if not %compiler%==cygwin ( set "PATH=%cd%;%MESON_PYTHON_PATH%;%PATH%;" && python run_tests.py --backend=%backend% ) on_finish: + - set "PATH=%ORIG_PATH%" - appveyor PushArtifact meson-test-run.txt -DeploymentName "Text test logs" - appveyor PushArtifact meson-test-run.xml -DeploymentName "XML test logs" + +cache: + - C:\cache diff --git a/authors.txt b/authors.txt index 0c575e7..467ab75 100644 --- a/authors.txt +++ b/authors.txt @@ -73,3 +73,9 @@ Joe Baldino Peter Harris Roger Boerdijk melak47 +Philipp Ittershagen +Dylan Baker +Aaron Plattner +Jon Turney +Wade Berrier +Richard Hughes diff --git a/ci/appveyor-install.bat b/ci/appveyor-install.bat new file mode 100644 index 0000000..0c1ce44 --- /dev/null +++ b/ci/appveyor-install.bat @@ -0,0 +1,11 @@ +set CACHE=C:\cache +set CYGWIN_MIRROR="http://cygwin.mirror.constant.com" + +if _%arch%_ == _x64_ set SETUP=setup-x86_64.exe && set CYGWIN_ROOT=C:\cygwin64 +if _%arch%_ == _x86_ set SETUP=setup-x86.exe && set CYGWIN_ROOT=C:\cygwin + +if not exist %CACHE% mkdir %CACHE% + +echo Updating Cygwin and installing ninja and test prerequisites +%CYGWIN_ROOT%\%SETUP% -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -l "%CACHE%" -g -P "ninja,gcc-objc,gcc-objc++,libglib2.0-devel,zlib-devel" +echo Install done diff --git a/ci/appveyor-test.sh b/ci/appveyor-test.sh new file mode 100755 index 0000000..2f29630 --- /dev/null +++ b/ci/appveyor-test.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +echo ninja $(ninja --version) +python3 --version -V + +python3 run_tests.py --backend=${backend} diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 9b541e9..2e630bd 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -20,7 +20,8 @@ from .. import mlog from .. import compilers import json import subprocess -from ..mesonlib import MesonException, get_compiler_for_source, classify_unity_sources +from ..mesonlib import MesonException, get_meson_script +from ..mesonlib import get_compiler_for_source, classify_unity_sources from ..compilers import CompilerArgs class CleanTrees: @@ -33,7 +34,7 @@ class CleanTrees: self.trees = trees class InstallData: - def __init__(self, source_dir, build_dir, prefix, strip_bin): + def __init__(self, source_dir, build_dir, prefix, strip_bin, mesonintrospect): self.source_dir = source_dir self.build_dir = build_dir self.prefix = prefix @@ -46,6 +47,7 @@ class InstallData: self.po = [] self.install_scripts = [] self.install_subdirs = [] + self.mesonintrospect = mesonintrospect class ExecutableSerialisation: def __init__(self, name, fname, cmd_args, env, is_cross, exe_wrapper, @@ -252,7 +254,7 @@ class Backend: exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None) else: exe_wrapper = None - if mesonlib.is_windows(): + if mesonlib.is_windows() or mesonlib.is_cygwin(): extra_paths = self.determine_windows_extra_paths(exe) else: extra_paths = [] @@ -481,7 +483,7 @@ class Backend: exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None) else: exe_wrapper = None - if mesonlib.is_windows(): + if mesonlib.is_windows() or mesonlib.is_cygwin(): extra_paths = self.determine_windows_extra_paths(exe) else: extra_paths = [] @@ -714,7 +716,7 @@ class Backend: def run_postconf_scripts(self): env = {'MESON_SOURCE_ROOT': self.environment.get_source_dir(), 'MESON_BUILD_ROOT': self.environment.get_build_dir(), - } + 'MESONINTROSPECT': get_meson_script(self.environment, 'mesonintrospect')} child_env = os.environ.copy() child_env.update(env) diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 9378a56..4c87951 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -20,7 +20,8 @@ from .. import mlog from .. import dependencies from .. import compilers from ..compilers import CompilerArgs -from ..mesonlib import File, MesonException, get_compiler_for_source, Popen_safe +from ..mesonlib import File, MesonException +from ..mesonlib import get_meson_script, get_compiler_for_source, Popen_safe from .backends import CleanTrees, InstallData from ..build import InvalidArguments import os, sys, pickle, re @@ -492,7 +493,7 @@ int dummy; # the project, we need to set PATH so the DLLs are found. We use # a serialized executable wrapper for that and check if the # CustomTarget command needs extra paths first. - if target.capture or (mesonlib.is_windows() and + if target.capture or ((mesonlib.is_windows() or mesonlib.is_cygwin()) and self.determine_windows_extra_paths(target.command[0])): exe_data = self.serialise_executable(target.command[0], cmd[1:], # All targets are built from the build dir @@ -515,7 +516,7 @@ int dummy; self.processed_targets[target.name + target.type_suffix()] = True def generate_run_target(self, target, outfile): - runnerscript = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner'] + cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner'] deps = self.unwrap_dep_list(target) arg_strings = [] for i in target.args: @@ -531,7 +532,10 @@ int dummy; else: raise AssertionError('Unreachable code in generate_run_target: ' + str(i)) elem = NinjaBuildElement(self.all_outputs, target.name, 'CUSTOM_COMMAND', []) - cmd = runnerscript + [self.environment.get_source_dir(), self.environment.get_build_dir(), target.subdir] + cmd += [self.environment.get_source_dir(), + self.environment.get_build_dir(), + target.subdir, + get_meson_script(self.environment, 'mesonintrospect')] texe = target.command try: texe = texe.held_object @@ -608,7 +612,8 @@ int dummy; d = InstallData(self.environment.get_source_dir(), self.environment.get_build_dir(), self.environment.get_prefix(), - strip_bin) + strip_bin, + get_meson_script(self.environment, 'mesonintrospect')) elem = NinjaBuildElement(self.all_outputs, 'install', 'CUSTOM_COMMAND', 'PHONY') elem.add_dep('all') elem.add_item('DESC', 'Installing files.') @@ -775,9 +780,7 @@ int dummy; def generate_tests(self, outfile): self.serialise_tests() - meson_exe = self.environment.get_build_command() - (base, ext) = os.path.splitext(meson_exe) - test_exe = base + 'test' + ext + test_exe = get_meson_script(self.environment, 'mesontest') cmd = [sys.executable, test_exe, '--no-rebuild'] if not self.environment.coredata.get_builtin_option('stdsplit'): cmd += ['--no-stdsplit'] diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 7afbc0d..139360c 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -24,7 +24,7 @@ from .. import mlog from .. import compilers from ..build import BuildTarget from ..compilers import CompilerArgs -from ..mesonlib import MesonException, File +from ..mesonlib import MesonException, File, get_meson_script from ..environment import Environment def autodetect_vs_version(build): @@ -409,8 +409,10 @@ class Vs2010Backend(backends.Backend): customstep = ET.SubElement(action, 'PostBuildEvent') cmd_raw = [target.command] + target.args cmd = [sys.executable, os.path.join(self.environment.get_script_dir(), 'commandrunner.py'), - self.environment.get_build_dir(), self.environment.get_source_dir(), - self.get_target_dir(target)] + self.environment.get_build_dir(), + self.environment.get_source_dir(), + self.get_target_dir(target), + get_meson_script(self.environment, 'mesonintrospect')] for i in cmd_raw: if isinstance(i, build.BuildTarget): cmd.append(os.path.join(self.environment.get_build_dir(), self.get_target_filename(i))) @@ -1164,11 +1166,8 @@ if %%errorlevel%% neq 0 goto :VCEnd''' postbuild = ET.SubElement(action, 'PostBuildEvent') ET.SubElement(postbuild, 'Message') # FIXME: No benchmarks? - meson_py = self.environment.get_build_command() - (base, ext) = os.path.splitext(meson_py) - mesontest_py = base + 'test' + ext test_command = [sys.executable, - mesontest_py, + get_meson_script(self.environment, 'mesontest'), '--no-rebuild'] if not self.environment.coredata.get_builtin_option('stdsplit'): test_command += ['--no-stdsplit'] diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 973d8e9..df3f37b 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -21,7 +21,7 @@ from . import mlog from .mesonlib import File, MesonException from .mesonlib import flatten, typeslistify, stringlistify, classify_unity_sources from .mesonlib import get_filenames_templates_dict, substitute_values -from .environment import for_windows, for_darwin +from .environment import for_windows, for_darwin, for_cygwin from .compilers import is_object, clike_langs, sort_clike, lang_suffixes known_basic_kwargs = {'install': True, @@ -1000,7 +1000,8 @@ class Executable(BuildTarget): self.prefix = '' if not hasattr(self, 'suffix'): # Executable for Windows or C#/Mono - if for_windows(is_cross, environment) or 'cs' in self.compilers: + if (for_windows(is_cross, environment) or + for_cygwin(is_cross, environment) or 'cs' in self.compilers): self.suffix = 'exe' else: self.suffix = '' @@ -1125,6 +1126,18 @@ class SharedLibrary(BuildTarget): self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}' else: self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' + elif for_cygwin(is_cross, env): + suffix = 'dll' + self.gcc_import_filename = 'lib{0}.dll.a'.format(self.name) + # Shared library is of the form cygfoo.dll + # (ld --dll-search-prefix=cyg is the default) + prefix = 'cyg' + # Import library is called libfoo.dll.a + self.import_filename = self.gcc_import_filename + 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' diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index 5e7db24..e6be8b1 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -550,11 +550,11 @@ class Compiler: def get_exelist(self): return self.exelist[:] - def get_define(self, *args, **kwargs): - raise EnvironmentException('%s does not support get_define.' % self.id) + def get_builtin_define(self, *args, **kwargs): + raise EnvironmentException('%s does not support get_builtin_define.' % self.id) - def has_define(self, *args, **kwargs): - raise EnvironmentException('%s does not support has_define.' % self.id) + def has_builtin_define(self, *args, **kwargs): + raise EnvironmentException('%s does not support has_builtin_define.' % self.id) def get_always_args(self): return [] @@ -906,8 +906,6 @@ class CCompiler(Compiler): return self.sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code) def has_header(self, hname, prefix, env, extra_args=None, dependencies=None): - if extra_args is None: - extra_args = [] fargs = {'prefix': prefix, 'header': hname} code = '''{prefix} #ifdef __has_include @@ -921,8 +919,6 @@ class CCompiler(Compiler): dependencies, 'preprocess') def has_header_symbol(self, hname, symbol, prefix, env, extra_args=None, dependencies=None): - if extra_args is None: - extra_args = [] fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol} t = '''{prefix} #include <{header}> @@ -934,7 +930,7 @@ class CCompiler(Compiler): }}''' return self.compiles(t.format(**fargs), env, extra_args, dependencies) - def compiles(self, code, env, extra_args=None, dependencies=None, mode='compile'): + def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): if extra_args is None: extra_args = [] elif isinstance(extra_args, str): @@ -943,49 +939,43 @@ class CCompiler(Compiler): dependencies = [] elif not isinstance(dependencies, list): dependencies = [dependencies] - # Add compile flags needed by dependencies + # Collect compiler arguments args = CompilerArgs(self) for d in dependencies: + # Add compile flags needed by dependencies args += d.get_compile_args() + if mode == 'link': + # Add link flags needed to find dependencies + args += d.get_link_args() + # Select a CRT if needed since we're linking + if mode == 'link': + args += self.get_linker_debug_crt_args() # Read c_args/cpp_args/etc from the cross-info file (if needed) - args += self.get_cross_extra_flags(env, compile=True, link=False) - # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS from the env - # We assume that the user has ensured these are compiler-specific - args += env.coredata.external_args[self.language] + args += self.get_cross_extra_flags(env, compile=(mode != 'preprocess'), + link=(mode == 'link')) + if mode == 'preprocess': + # Add CPPFLAGS from the env. + args += env.coredata.external_preprocess_args[self.language] + elif mode == 'compile': + # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS from the env + args += env.coredata.external_args[self.language] + elif mode == 'link': + # Add LDFLAGS from the env + args += env.coredata.external_link_args[self.language] args += self.get_compiler_check_args() # extra_args must override all other arguments, so we add them last args += extra_args + return args + + def compiles(self, code, env, extra_args=None, dependencies=None, mode='compile'): + args = self._get_compiler_check_args(env, extra_args, dependencies, mode) # We only want to compile; not link with self.compile(code, args.to_native(), mode) as p: return p.returncode == 0 def _links_wrapper(self, code, env, extra_args, dependencies): "Shares common code between self.links and self.run" - if extra_args is None: - extra_args = [] - elif isinstance(extra_args, str): - extra_args = [extra_args] - if dependencies is None: - dependencies = [] - elif not isinstance(dependencies, list): - dependencies = [dependencies] - # Add compile and link flags needed by dependencies - args = CompilerArgs(self) - for d in dependencies: - args += d.get_compile_args() - args += d.get_link_args() - # Select a CRT if needed since we're linking - args += self.get_linker_debug_crt_args() - # Read c_args/c_link_args/cpp_args/cpp_link_args/etc from the - # cross-info file (if needed) - args += self.get_cross_extra_flags(env, compile=True, link=True) - # Add LDFLAGS from the env. We assume that the user has ensured these - # are compiler-specific - args += env.coredata.external_link_args[self.language] - # Add compiler check args such that they override - args += self.get_compiler_check_args() - # extra_args must override all other arguments, so we add them last - args += extra_args + args = self._get_compiler_check_args(env, extra_args, dependencies, mode='link') return self.compile(code, args.to_native()) def links(self, code, env, extra_args=None, dependencies=None): @@ -1141,6 +1131,24 @@ class CCompiler(Compiler): raise EnvironmentException('Could not determine alignment of %s. Sorry. You might want to file a bug.' % typename) return align + def get_define(self, dname, prefix, env, extra_args, dependencies): + delim = '"MESON_GET_DEFINE_DELIMITER"' + fargs = {'prefix': prefix, 'define': dname, 'delim': delim} + code = ''' + #ifndef {define} + # define {define} + #endif + {prefix} + {delim}\n{define}''' + args = self._get_compiler_check_args(env, extra_args, dependencies, + mode='preprocess').to_native() + with self.compile(code.format(**fargs), args, 'preprocess') as p: + if p.returncode != 0: + raise EnvironmentException('Could not get define {!r}'.format(dname)) + # Get the preprocessed value after the delimiter, + # minus the extra newline at the end + return p.stdo.split(delim + '\n')[-1][:-1] + @staticmethod def _no_prototype_templ(): """ @@ -2301,6 +2309,7 @@ class VisualStudioCPPCompiler(VisualStudioCCompiler, CPPCompiler): GCC_STANDARD = 0 GCC_OSX = 1 GCC_MINGW = 2 +GCC_CYGWIN = 3 CLANG_STANDARD = 0 CLANG_OSX = 1 @@ -2316,7 +2325,7 @@ def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, i sostr = '' else: sostr = '.' + soversion - if gcc_type == GCC_STANDARD or gcc_type == GCC_MINGW: + if gcc_type in (GCC_STANDARD, GCC_MINGW, GCC_CYGWIN): # Might not be correct for mingw but seems to work. return ['-Wl,-soname,%s%s.%s%s' % (prefix, shlib_name, suffix, sostr)] elif gcc_type == GCC_OSX: @@ -2382,15 +2391,15 @@ class GnuCompiler: args[args.index('-Wpedantic')] = '-pedantic' return args - def has_define(self, define): + def has_builtin_define(self, define): return define in self.defines - def get_define(self, define): + def get_builtin_define(self, define): if define in self.defines: return self.defines[define] def get_pic_args(self): - if self.gcc_type in (GCC_MINGW, GCC_OSX): + if self.gcc_type in (GCC_CYGWIN, GCC_MINGW, GCC_OSX): return [] # On Window and OS X, pic is always on. return ['-fPIC'] @@ -2788,7 +2797,7 @@ class FortranCompiler(Compiler): return ' '.join(self.exelist) def get_pic_args(self): - if self.gcc_type in (GCC_MINGW, GCC_OSX): + if self.gcc_type in (GCC_CYGWIN, GCC_MINGW, GCC_OSX): return [] # On Window and OS X, pic is always on. return ['-fPIC'] @@ -2896,10 +2905,10 @@ class GnuFortranCompiler(FortranCompiler): self.defines = defines or {} self.id = 'gcc' - def has_define(self, define): + def has_builtin_define(self, define): return define in self.defines - def get_define(self, define): + def get_builtin_define(self, define): if define in self.defines: return self.defines[define] diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 67516e7..27f1dd7 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -148,10 +148,11 @@ class CoreData: self.user_options = {} self.compiler_options = {} self.base_options = {} - # These two, external_*args, are set via env vars CFLAGS, LDFLAGS, etc + # These external_*args, are set via env vars CFLAGS, LDFLAGS, etc # but only when not cross-compiling. - self.external_args = {} - self.external_link_args = {} + self.external_preprocess_args = {} # CPPFLAGS only + self.external_args = {} # CPPFLAGS + CFLAGS + self.external_link_args = {} # CFLAGS + LDFLAGS (with MSVC: only LDFLAGS) if options.cross_file is not None: self.cross_file = os.path.join(os.getcwd(), options.cross_file) else: diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py index eacb15b..2b110bb 100644 --- a/mesonbuild/dependencies.py +++ b/mesonbuild/dependencies.py @@ -598,12 +598,18 @@ class BoostDependency(Dependency): self.boost_root = None if self.boost_root is None: if self.want_cross: - raise DependencyException('BOOST_ROOT is needed while cross-compiling') + if 'BOOST_INCLUDEDIR' in os.environ: + self.incdir = os.environ['BOOST_INCLUDEDIR'] + else: + raise DependencyException('BOOST_ROOT or BOOST_INCLUDEDIR is needed while cross-compiling') if mesonlib.is_windows(): self.boost_root = self.detect_win_root() self.incdir = self.boost_root else: - self.incdir = '/usr/include' + if 'BOOST_INCLUDEDIR' in os.environ: + self.incdir = os.environ['BOOST_INCLUDEDIR'] + else: + self.incdir = '/usr/include' else: self.incdir = os.path.join(self.boost_root, 'include') self.boost_inc_subdir = os.path.join(self.incdir, 'boost') @@ -727,7 +733,9 @@ class BoostDependency(Dependency): libsuffix = 'so' globber = 'libboost_*.{}'.format(libsuffix) - if self.boost_root is None: + if 'BOOST_LIBRARYDIR' in os.environ: + libdirs = [os.environ['BOOST_LIBRARYDIR']] + elif self.boost_root is None: libdirs = mesonlib.get_library_dirs() else: libdirs = [os.path.join(self.boost_root, 'lib')] @@ -758,6 +766,8 @@ class BoostDependency(Dependency): args = [] if self.boost_root: args.append('-L' + os.path.join(self.boost_root, 'lib')) + elif 'BOOST_LIBRARYDIR' in os.environ: + args.append('-L' + os.environ['BOOST_LIBRARYDIR']) for module in self.requested_modules: module = BoostDependency.name2lib.get(module, module) libname = 'boost_' + module @@ -1483,6 +1493,14 @@ class Python3Dependency(Dependency): def get_version(self): return self.version +class ValgrindDependency(PkgConfigDependency): + + def __init__(self, environment, kwargs): + PkgConfigDependency.__init__(self, 'valgrind', environment, kwargs) + + def get_link_args(self): + return [] + def get_dep_identifier(name, kwargs): elements = [name] modlist = kwargs.get('modules', []) @@ -1544,4 +1562,5 @@ packages = {'boost': BoostDependency, 'gl': GLDependency, 'threads': ThreadDependency, 'python3': Python3Dependency, + 'valgrind': ValgrindDependency, } diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 92040c4..7861612 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -102,7 +102,7 @@ def detect_windows_arch(compilers): platform = os.environ.get('Platform', 'x86').lower() if platform == 'x86': return platform - if compiler.id == 'gcc' and compiler.has_define('__i386__'): + if compiler.id == 'gcc' and compiler.has_builtin_define('__i386__'): return 'x86' return os_arch @@ -129,10 +129,10 @@ def detect_cpu_family(compilers): # to know is to check the compiler defines. for c in compilers.values(): try: - if c.has_define('__i386__'): + if c.has_builtin_define('__i386__'): return 'x86' except mesonlib.MesonException: - # Ignore compilers that do not support has_define. + # Ignore compilers that do not support has_builtin_define. pass return 'x86_64' # Add fixes here as bugs are reported. @@ -149,7 +149,7 @@ def detect_cpu(compilers): # Same check as above for cpu_family for c in compilers.values(): try: - if c.has_define('__i386__'): + if c.has_builtin_define('__i386__'): return 'i686' # All 64 bit cpus have at least this level of x86 support. except mesonlib.MesonException: pass @@ -158,7 +158,10 @@ def detect_cpu(compilers): return trial def detect_system(): - return platform.system().lower() + system = platform.system().lower() + if system.startswith('cygwin'): + return 'cygwin' + return system def for_windows(is_cross, env): @@ -173,6 +176,20 @@ def for_windows(is_cross, env): return env.cross_info.config['host_machine']['system'] == 'windows' return False + +def for_cygwin(is_cross, env): + """ + Host machine is cygwin? + + Note: 'host' is the machine on which compiled binaries will run + """ + if not is_cross: + return mesonlib.is_cygwin() + elif env.cross_info.has_host(): + return env.cross_info.config['host_machine']['system'] == 'cygwin' + return False + + def for_darwin(is_cross, env): """ Host machine is Darwin (iOS/OS X)? @@ -257,6 +274,11 @@ class Environment: self.exe_suffix = 'exe' self.object_suffix = 'obj' self.win_libdir_layout = True + elif (not cross and mesonlib.is_cygwin()) \ + or (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'cygwin'): + self.exe_suffix = 'exe' + self.object_suffix = 'o' + self.win_libdir_layout = True else: self.exe_suffix = '' self.object_suffix = 'o' @@ -368,7 +390,8 @@ class Environment: return GCC_OSX elif '__MINGW32__' in defines or '__MINGW64__' in defines: return GCC_MINGW - # We ignore Cygwin for now, and treat it as a standard GCC + elif '__CYGWIN__' in defines: + return GCC_CYGWIN return GCC_STANDARD def _get_compilers(self, lang, evar, want_cross): @@ -770,7 +793,7 @@ def get_args_from_envvars(compiler): compiler_is_linker = (compiler.get_exelist() == compiler.get_linker_exelist()) if lang not in ('c', 'cpp', 'objc', 'objcpp', 'fortran', 'd'): - return [], [] + return [], [], [] # Compile flags cflags_mapping = {'c': 'CFLAGS', @@ -781,12 +804,12 @@ def get_args_from_envvars(compiler): 'd': 'DFLAGS'} compile_flags = os.environ.get(cflags_mapping[lang], '') log_var(cflags_mapping[lang], compile_flags) - compile_flags = compile_flags.split() + compile_flags = shlex.split(compile_flags) # Link flags (same for all languages) link_flags = os.environ.get('LDFLAGS', '') log_var('LDFLAGS', link_flags) - link_flags = link_flags.split() + link_flags = shlex.split(link_flags) if compiler_is_linker: # When the compiler is used as a wrapper around the linker (such as # with GCC and Clang), the compile flags can be needed while linking @@ -794,14 +817,15 @@ def get_args_from_envvars(compiler): # this when the linker is stand-alone such as with MSVC C/C++, etc. link_flags = compile_flags + link_flags - # Pre-processof rlags (not for fortran) + # Pre-processor flags (not for fortran or D) preproc_flags = '' if lang in ('c', 'cpp', 'objc', 'objcpp'): preproc_flags = os.environ.get('CPPFLAGS', '') log_var('CPPFLAGS', preproc_flags) - compile_flags += preproc_flags.split() + preproc_flags = shlex.split(preproc_flags) + compile_flags += preproc_flags - return compile_flags, link_flags + return preproc_flags, compile_flags, link_flags class CrossBuildInfo: def __init__(self, filename): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 945de6b..2f8e5f6 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -22,7 +22,7 @@ from . import optinterpreter from . import compilers from .wrap import wrap, WrapMode from . import mesonlib -from .mesonlib import FileMode, Popen_safe +from .mesonlib import FileMode, Popen_safe, get_meson_script from .dependencies import InternalDependency, Dependency from .interpreterbase import InterpreterBase from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs @@ -72,20 +72,21 @@ class TryRunResultHolder(InterpreterObject): class RunProcess(InterpreterObject): - def __init__(self, command_array, source_dir, build_dir, subdir, in_builddir=False): + def __init__(self, command_array, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False): super().__init__() - pc, self.stdout, self.stderr = self.run_command(command_array, source_dir, build_dir, subdir, in_builddir) + pc, self.stdout, self.stderr = self.run_command(command_array, source_dir, build_dir, subdir, mesonintrospect, in_builddir) self.returncode = pc.returncode self.methods.update({'returncode': self.returncode_method, 'stdout': self.stdout_method, 'stderr': self.stderr_method, }) - def run_command(self, command_array, source_dir, build_dir, subdir, in_builddir): + def run_command(self, command_array, source_dir, build_dir, subdir, mesonintrospect, in_builddir): cmd_name = command_array[0] env = {'MESON_SOURCE_ROOT': source_dir, 'MESON_BUILD_ROOT': build_dir, - 'MESON_SUBDIR': subdir} + 'MESON_SUBDIR': subdir, + 'MESONINTROSPECT': mesonintrospect} if in_builddir: cwd = os.path.join(build_dir, subdir) else: @@ -634,6 +635,7 @@ class CompilerHolder(InterpreterObject): 'get_id': self.get_id_method, 'compute_int': self.compute_int_method, 'sizeof': self.sizeof_method, + 'get_define': self.get_define_method, 'has_header': self.has_header_method, 'has_header_symbol': self.has_header_symbol_method, 'run': self.run_method, @@ -865,6 +867,20 @@ class CompilerHolder(InterpreterObject): mlog.log('Checking for size of "%s": %d' % (element, esize)) return esize + def get_define_method(self, args, kwargs): + if len(args) != 1: + raise InterpreterException('get_define() takes exactly one argument.') + check_stringlist(args) + element = args[0] + prefix = kwargs.get('prefix', '') + if not isinstance(prefix, str): + raise InterpreterException('Prefix argument of get_define() must be a string.') + extra_args = self.determine_args(kwargs) + deps = self.determine_dependencies(kwargs) + value = self.compiler.get_define(element, prefix, self.environment, extra_args, deps) + mlog.log('Checking for value of define "%s": %s' % (element, value)) + return value + def compiles_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('compiles method takes exactly one argument.') @@ -1224,7 +1240,8 @@ class Interpreter(InterpreterBase): self.builtin.update({'meson': MesonMain(build, self)}) self.generators = [] self.visited_subdirs = {} - self.args_frozen = False + self.project_args_frozen = False + self.global_args_frozen = False # implies self.project_args_frozen self.subprojects = {} self.subproject_stack = [] self.default_project_options = default_project_options[:] # Passed from the outside, only used in subprojects. @@ -1474,8 +1491,8 @@ class Interpreter(InterpreterBase): in_builddir = kwargs.get('in_builddir', False) if not isinstance(in_builddir, bool): raise InterpreterException('in_builddir must be boolean.') - return RunProcess(args, self.environment.source_dir, self.environment.build_dir, - self.subdir, in_builddir) + return RunProcess(args, self.environment.source_dir, self.environment.build_dir, self.subdir, + get_meson_script(self.environment, 'mesonintrospect'), in_builddir) @stringArgs def func_gettext(self, nodes, args, kwargs): @@ -1507,7 +1524,7 @@ class Interpreter(InterpreterBase): raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e)) subdir = os.path.join(self.subproject_dir, resolved) os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True) - self.args_frozen = True + self.global_args_frozen = True mlog.log('\nExecuting subproject ', mlog.bold(dirname), '.\n', sep='') subi = Interpreter(self.build, self.backend, dirname, subdir, self.subproject_dir, mesonlib.stringlistify(kwargs.get('default_options', []))) @@ -1615,25 +1632,29 @@ class Interpreter(InterpreterBase): def func_project(self, node, args, kwargs): if len(args) < 1: raise InvalidArguments('Not enough arguments to project(). Needs at least the project name.') + proj_name = args[0] + proj_langs = args[1:] + if ':' in proj_name: + raise InvalidArguments("Project name {!r} must not contain ':'".format(proj_name)) default_options = kwargs.get('default_options', []) if self.environment.first_invocation and (len(default_options) > 0 or len(self.default_project_options) > 0): self.parse_default_options(default_options) if not self.is_subproject(): - self.build.project_name = args[0] + self.build.project_name = proj_name if os.path.exists(self.option_file): oi = optinterpreter.OptionInterpreter(self.subproject, self.build.environment.cmd_line_options.projectoptions, ) oi.process(self.option_file) self.build.environment.merge_options(oi.options) - self.active_projectname = args[0] + self.active_projectname = proj_name self.project_version = kwargs.get('version', 'undefined') if self.build.project_version is None: self.build.project_version = self.project_version proj_license = mesonlib.stringlistify(kwargs.get('license', 'unknown')) - self.build.dep_manifest[args[0]] = {'version': self.project_version, - 'license': proj_license} + self.build.dep_manifest[proj_name] = {'version': self.project_version, + 'license': proj_license} if self.subproject in self.build.projects: raise InvalidCode('Second call to project().') if not self.is_subproject() and 'subproject_dir' in kwargs: @@ -1644,9 +1665,9 @@ class Interpreter(InterpreterBase): pv = kwargs['meson_version'] if not mesonlib.version_compare(cv, pv): raise InterpreterException('Meson version is %s but project requires %s.' % (cv, pv)) - self.build.projects[self.subproject] = args[0] - mlog.log('Project name: ', mlog.bold(args[0]), sep='') - self.add_languages(args[1:], True) + self.build.projects[self.subproject] = proj_name + mlog.log('Project name: ', mlog.bold(proj_name), sep='') + self.add_languages(proj_langs, True) langs = self.coredata.compilers.keys() if 'vala' in langs: if 'c' not in langs: @@ -1772,9 +1793,10 @@ class Interpreter(InterpreterBase): raise mlog.log('Native %s compiler: ' % lang, mlog.bold(' '.join(comp.get_exelist())), ' (%s %s)' % (comp.id, comp.version), sep='') if not comp.get_language() in self.coredata.external_args: - (ext_compile_args, ext_link_args) = environment.get_args_from_envvars(comp) - self.coredata.external_args[comp.get_language()] = ext_compile_args - self.coredata.external_link_args[comp.get_language()] = ext_link_args + (preproc_args, compile_args, link_args) = environment.get_args_from_envvars(comp) + self.coredata.external_preprocess_args[comp.get_language()] = preproc_args + self.coredata.external_args[comp.get_language()] = compile_args + self.coredata.external_link_args[comp.get_language()] = link_args self.build.add_compiler(comp) if need_cross_compiler: mlog.log('Cross %s compiler: ' % lang, mlog.bold(' '.join(cross_comp.get_exelist())), ' (%s %s)' % (cross_comp.id, cross_comp.version), sep='') @@ -2290,7 +2312,11 @@ class Interpreter(InterpreterBase): inputfile = inputfile[0] if not isinstance(inputfile, (str, mesonlib.File)): raise InterpreterException('Input must be a string or a file') - ifile_abs = os.path.join(self.environment.source_dir, self.subdir, inputfile) + if isinstance(inputfile, str): + inputfile = os.path.join(self.subdir, inputfile) + else: + inputfile = inputfile.relative_name() + ifile_abs = os.path.join(self.environment.source_dir, inputfile) elif 'command' in kwargs and '@INPUT@' in kwargs['command']: raise InterpreterException('@INPUT@ used as command argument, but no input file specified.') # Validate output @@ -2309,7 +2335,7 @@ class Interpreter(InterpreterBase): if inputfile is not None: # 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)) + conffile = os.path.normpath(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) @@ -2415,83 +2441,51 @@ different subdirectory. @stringArgs def func_add_global_arguments(self, node, args, kwargs): - if self.subproject != '': - msg = 'Global arguments can not be set in subprojects because ' \ - 'there is no way to make that reliable.\nPlease only call ' \ - 'this if is_subproject() returns false. Alternatively, ' \ - 'define a variable that\ncontains your language-specific ' \ - 'arguments and add it to the appropriate *_args kwarg ' \ - 'in each target.' - raise InvalidCode(msg) - if self.args_frozen: - msg = 'Tried to set global arguments after a build target has ' \ - 'been declared.\nThis is not permitted. Please declare all ' \ - 'global arguments before your targets.' - raise InvalidCode(msg) - if 'language' not in kwargs: - raise InvalidCode('Missing language definition in add_global_arguments') - lang = kwargs['language'].lower() - if lang in self.build.global_args: - self.build.global_args[lang] += args - else: - self.build.global_args[lang] = args + self.add_global_arguments(node, self.build.global_args, args, kwargs) @stringArgs def func_add_global_link_arguments(self, node, args, kwargs): + self.add_global_arguments(node, self.build.global_link_args, args, kwargs) + + @stringArgs + def func_add_project_arguments(self, node, args, kwargs): + self.add_project_arguments(node, self.build.projects_args, args, kwargs) + + @stringArgs + def func_add_project_link_arguments(self, node, args, kwargs): + self.add_project_arguments(node, self.build.projects_link_args, args, kwargs) + + def add_global_arguments(self, node, argsdict, args, kwargs): if self.subproject != '': - msg = 'Global link arguments can not be set in subprojects because ' \ + msg = 'Function \'{}\' cannot be used in subprojects because ' \ 'there is no way to make that reliable.\nPlease only call ' \ 'this if is_subproject() returns false. Alternatively, ' \ 'define a variable that\ncontains your language-specific ' \ 'arguments and add it to the appropriate *_args kwarg ' \ - 'in each target.' + 'in each target.'.format(node.func_name) raise InvalidCode(msg) - if self.args_frozen: - msg = 'Tried to set global link arguments after a build target has ' \ - 'been declared.\nThis is not permitted. Please declare all ' \ - 'global arguments before your targets.' + frozen = self.project_args_frozen or self.global_args_frozen + self.add_arguments(node, argsdict, frozen, args, kwargs) + + def add_project_arguments(self, node, argsdict, args, kwargs): + if self.subproject not in argsdict: + argsdict[self.subproject] = {} + self.add_arguments(node, argsdict[self.subproject], + self.project_args_frozen, args, kwargs) + + def add_arguments(self, node, argsdict, args_frozen, args, kwargs): + if args_frozen: + msg = 'Tried to use \'{}\' after a build target has been declared.\n' \ + 'This is not permitted. Please declare all ' \ + 'arguments before your targets.'.format(node.func_name) raise InvalidCode(msg) - if 'language' not in kwargs: - raise InvalidCode('Missing language definition in add_global_link_arguments') - lang = kwargs['language'].lower() - if lang in self.build.global_link_args: - self.build.global_link_args[lang] += args - else: - self.build.global_link_args[lang] = args - @stringArgs - def func_add_project_link_arguments(self, node, args, kwargs): - if self.args_frozen: - msg = 'Tried to set project link arguments after a build target has ' \ - 'been declared.\nThis is not permitted. Please declare all ' \ - 'project link arguments before your targets.' - raise InvalidCode(msg) if 'language' not in kwargs: - raise InvalidCode('Missing language definition in add_project_link_arguments') - lang = kwargs['language'].lower() - if self.subproject not in self.build.projects_link_args: - self.build.projects_link_args[self.subproject] = {} + raise InvalidCode('Missing language definition in {}'.format(node.func_name)) - args = self.build.projects_link_args[self.subproject].get(lang, []) + args - self.build.projects_link_args[self.subproject][lang] = args - - @stringArgs - def func_add_project_arguments(self, node, args, kwargs): - if self.args_frozen: - msg = 'Tried to set project arguments after a build target has ' \ - 'been declared.\nThis is not permitted. Please declare all ' \ - 'project arguments before your targets.' - raise InvalidCode(msg) - - if 'language' not in kwargs: - raise InvalidCode('Missing language definition in add_project_arguments') - - if self.subproject not in self.build.projects_args: - self.build.projects_args[self.subproject] = {} - - lang = kwargs['language'].lower() - args = self.build.projects_args[self.subproject].get(lang, []) + args - self.build.projects_args[self.subproject][lang] = args + for lang in mesonlib.stringlistify(kwargs['language']): + lang = lang.lower() + argsdict[lang] = argsdict.get(lang, []) + args def func_environment(self, node, args, kwargs): return EnvironmentVariablesHolder() @@ -2576,7 +2570,7 @@ different subdirectory. self.add_cross_stdlib_info(target) l = targetholder(target, self) self.add_target(name, l.held_object) - self.args_frozen = True + self.project_args_frozen = True return l def get_used_languages(self, target): diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index ef169c1..5377d8e 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -125,14 +125,14 @@ class File: assert(isinstance(self.fname, str)) def __str__(self): - return os.path.join(self.subdir, self.fname) + return self.relative_name() 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)) + return ret.format(self.relative_name()) @staticmethod def from_source_file(source_root, subdir, fname): @@ -150,15 +150,15 @@ class File: def rel_to_builddir(self, build_to_src): if self.is_built: - return os.path.join(self.subdir, self.fname) + return self.relative_name() else: return os.path.join(build_to_src, self.subdir, self.fname) def absolute_path(self, srcdir, builddir): + absdir = srcdir if self.is_built: - return os.path.join(builddir, self.subdir, self.fname) - else: - return os.path.join(srcdir, self.subdir, self.fname) + absdir = builddir + return os.path.join(absdir, self.relative_name()) def endswith(self, ending): return self.fname.endswith(ending) @@ -175,6 +175,15 @@ class File: def relative_name(self): return os.path.join(self.subdir, self.fname) +def get_meson_script(env, script): + ''' + Given the path of `meson.py`/`meson`, get the path of a meson script such + as `mesonintrospect` or `mesontest`. + ''' + meson_py = env.get_build_command() + (base, ext) = os.path.splitext(meson_py) + return os.path.join(os.path.dirname(base), script + ext) + def get_compiler_for_source(compilers, src): for comp in compilers: if comp.can_compile(src): @@ -212,6 +221,10 @@ def is_windows(): platname = platform.system().lower() return platname == 'windows' or 'mingw' in platname +def is_cygwin(): + platname = platform.system().lower() + return platname.startswith('cygwin') + def is_debianlike(): return os.path.isfile('/etc/debian_version') diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 2f5bfb9..adb6fa8 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -766,6 +766,8 @@ class GnomeModule(ExtensionModule): cmd += ['--interface-prefix', kwargs.pop('interface_prefix')] if 'namespace' in kwargs: cmd += ['--c-namespace', kwargs.pop('namespace')] + if kwargs.get('object_manager', False): + cmd += ['--c-generate-object-manager'] # https://git.gnome.org/browse/glib/commit/?id=ee09bb704fe9ccb24d92dd86696a0e6bb8f0dc1a if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.51.3'): diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index c233d90..3fb0107 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -51,9 +51,17 @@ class WindowsModule(ExtensionModule): for arg in extra_args: if ' ' in arg: mlog.warning(m.format(arg)) - # 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_name = None + # FIXME: Does not handle `native: true` executables, see + # https://github.com/mesonbuild/meson/issues/1531 + if state.environment.is_cross_build(): + # If cross compiling see if windres has been specified in the + # cross file before trying to find it another way. + rescomp_name = state.environment.cross_info.config['binaries'].get('windres') + if rescomp_name is None: + # 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' diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 7a91539..a9f25b1 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -407,6 +407,7 @@ class Parser: def __init__(self, code, subdir): self.lexer = Lexer(code) self.stream = self.lexer.lex(subdir) + self.current = Token('eof', '', 0, 0, 0, (0, 0), None) self.getsym() self.in_ternary = False diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index 10b8fab..f9e7f26 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -75,15 +75,16 @@ class OptionInterpreter: self.cmd_line_options = {} for o in command_line_options: if self.subproject != '': # Strip the beginning. + # Ignore options that aren't for this subproject if not o.startswith(self.sbprefix): continue - else: - if ':' in o: - continue try: (key, value) = o.split('=', 1) except ValueError: raise OptionException('Option {!r} must have a value separated by equals sign.'.format(o)) + # Ignore subproject options if not fetching subproject options + if self.subproject == '' and ':' in key: + continue self.cmd_line_options[key] = value def process(self, option_file): diff --git a/mesonbuild/scripts/commandrunner.py b/mesonbuild/scripts/commandrunner.py index cf2770d..87e3b8b 100644 --- a/mesonbuild/scripts/commandrunner.py +++ b/mesonbuild/scripts/commandrunner.py @@ -17,11 +17,11 @@ what to run, sets up the environment and executes the command.""" import sys, os, subprocess, shutil -def run_command(source_dir, build_dir, subdir, command, arguments): +def run_command(source_dir, build_dir, subdir, mesonintrospect, command, arguments): env = {'MESON_SOURCE_ROOT': source_dir, 'MESON_BUILD_ROOT': build_dir, 'MESON_SUBDIR': subdir, - } + 'MESONINTROSPECT': mesonintrospect} cwd = os.path.join(source_dir, subdir) child_env = os.environ.copy() child_env.update(env) @@ -47,9 +47,10 @@ def run(args): src_dir = args[0] build_dir = args[1] subdir = args[2] - command = args[3] - arguments = args[4:] - pc = run_command(src_dir, build_dir, subdir, command, arguments) + mesonintrospect = args[3] + command = args[4] + arguments = args[5:] + pc = run_command(src_dir, build_dir, subdir, mesonintrospect, command, arguments) pc.wait() return pc.returncode diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py index 5c5c317..643e1af 100644 --- a/mesonbuild/scripts/meson_exe.py +++ b/mesonbuild/scripts/meson_exe.py @@ -29,8 +29,12 @@ def is_windows(): platname = platform.system().lower() return platname == 'windows' or 'mingw' in platname +def is_cygwin(): + platname = platform.system().lower() + return 'cygwin' in platname + def run_with_mono(fname): - if fname.endswith('.exe') and not is_windows(): + if fname.endswith('.exe') and not (is_windows() or is_cygwin()): return True return False diff --git a/mesonbuild/scripts/meson_install.py b/mesonbuild/scripts/meson_install.py index 8fb9e04..2205f1a 100644 --- a/mesonbuild/scripts/meson_install.py +++ b/mesonbuild/scripts/meson_install.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys, pickle, os, shutil, subprocess, gzip, platform +import sys, pickle, os, shutil, subprocess, gzip, platform, errno from glob import glob from . import depfixer from . import destdir_join @@ -34,6 +34,15 @@ def set_mode(path, mode): except PermissionError as e: msg = '{!r}: Unable to set owner {!r} and group {!r}: {}, ignoring...' print(msg.format(path, mode.owner, mode.group, e.strerror)) + except LookupError as e: + msg = '{!r}: Non-existent owner {!r} or group {!r}: ignoring...' + print(msg.format(path, mode.owner, mode.group)) + except OSError as e: + if e.errno == errno.EINVAL: + msg = '{!r}: Non-existent numeric owner {!r} or group {!r}: ignoring...' + print(msg.format(path, mode.owner, mode.group)) + else: + raise # Must set permissions *after* setting owner/group otherwise the # setuid/setgid bits will get wiped by chmod # NOTE: On Windows you can set read/write perms; the rest are ignored @@ -174,7 +183,7 @@ def run_install_script(d): 'MESON_BUILD_ROOT': d.build_dir, 'MESON_INSTALL_PREFIX': d.prefix, 'MESON_INSTALL_DESTDIR_PREFIX': d.fullprefix, - } + 'MESONINTROSPECT': d.mesonintrospect} child_env = os.environ.copy() child_env.update(env) @@ -193,7 +202,7 @@ def run_install_script(d): def is_elf_platform(): platname = platform.system().lower() - if platname == 'darwin' or platname == 'windows': + if platname == 'darwin' or platname == 'windows' or platname == 'cygwin': return False return True diff --git a/mesontest.py b/mesontest.py index a1708e3..c4d1178 100755 --- a/mesontest.py +++ b/mesontest.py @@ -36,6 +36,10 @@ def is_windows(): platname = platform.system().lower() return platname == 'windows' or 'mingw' in platname +def is_cygwin(): + platname = platform.system().lower() + return 'cygwin' in platname + def determine_worker_count(): varname = 'MESON_TESTTHREADS' if varname in os.environ: @@ -150,7 +154,7 @@ def write_json_log(jsonlogfile, test_name, result): jsonlogfile.write(json.dumps(jresult) + '\n') def run_with_mono(fname): - if fname.endswith('.exe') and not is_windows(): + if fname.endswith('.exe') and not (is_windows() or is_cygwin()): return True return False @@ -202,7 +206,7 @@ class TestHarness: child_env.update(test.env) if len(test.extra_paths) > 0: - child_env['PATH'] += ';'.join([''] + test.extra_paths) + child_env['PATH'] += os.pathsep.join([''] + test.extra_paths) # If MALLOC_PERTURB_ is not set, or if it is set to an empty value, # (i.e., the test or the environment don't explicitly set it), set diff --git a/run_project_tests.py b/run_project_tests.py index 28de638..dc05524 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -31,6 +31,7 @@ import xml.etree.ElementTree as ET import time import multiprocessing import concurrent.futures as conc +import re from mesonbuild.coredata import backendlist @@ -208,12 +209,18 @@ def get_relative_files_list_from_dir(fromdir): 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' +def platform_fix_name(fname): + if '?lib' in fname: + if mesonlib.is_cygwin(): + fname = re.sub(r'\?lib(.*)\.dll$', r'cyg\1.dll', fname) + else: + fname = re.sub(r'\?lib', 'lib', fname) + + if fname.endswith('?exe'): + fname = fname[:-4] + if mesonlib.is_windows() or mesonlib.is_cygwin(): + return fname + '.exe' + return fname def validate_install(srcdir, installdir): @@ -230,13 +237,16 @@ def validate_install(srcdir, installdir): elif os.path.exists(info_file): with open(info_file) as f: for line in f: - expected[platform_fix_exe_name(line.strip())] = False + expected[platform_fix_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: + # Ignore missing PDB files if we aren't using cl + if fname.endswith('.pdb') and compiler != 'cl': + continue ret_msg += 'Expected file {0} missing.\n'.format(fname) # Check if there are any unexpected files found = get_relative_files_list_from_dir(installdir) @@ -437,9 +447,9 @@ def detect_tests_to_run(): 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)) + all_tests.append(('platform-windows', gather_tests('test cases/windows'), False if mesonlib.is_windows() or mesonlib.is_cygwin() else True)) all_tests.append(('platform-linux', gather_tests('test cases/linuxlike'), False if not (mesonlib.is_osx() or mesonlib.is_windows()) else True)) - all_tests.append(('framework', gather_tests('test cases/frameworks'), False if not mesonlib.is_osx() and not mesonlib.is_windows() else True)) + all_tests.append(('framework', gather_tests('test cases/frameworks'), False if not mesonlib.is_osx() and not mesonlib.is_windows() and not mesonlib.is_cygwin() else True)) all_tests.append(('java', gather_tests('test cases/java'), False if using_backend('ninja') and not mesonlib.is_osx() and have_java() else True)) all_tests.append(('C#', gather_tests('test cases/csharp'), False if using_backend('ninja') and shutil.which('mcs') else True)) all_tests.append(('vala', gather_tests('test cases/vala'), False if using_backend('ninja') and shutil.which('valac') else True)) diff --git a/run_unittests.py b/run_unittests.py index 0656f88..1b24d08 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -24,11 +24,11 @@ from pathlib import PurePath import mesonbuild.compilers import mesonbuild.environment import mesonbuild.mesonlib -from mesonbuild.mesonlib import is_windows, is_osx +from mesonbuild.mesonlib import is_windows, is_osx, is_cygwin from mesonbuild.environment import detect_ninja, Environment from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram -if is_windows(): +if is_windows() or is_cygwin(): exe_suffix = '.exe' else: exe_suffix = '' @@ -833,6 +833,8 @@ class AllPlatformTests(BasePlatformTests): self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_OSX) elif is_windows(): self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_MINGW) + elif is_cygwin(): + self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_CYGWIN) else: self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_STANDARD) if isinstance(cc, clang): @@ -947,6 +949,21 @@ class AllPlatformTests(BasePlatformTests): m = re.search('build c-asm.*: c_LINKER', contents) self.assertIsNotNone(m, msg=contents) + def test_preprocessor_checks_CPPFLAGS(self): + ''' + Test that preprocessor compiler checks read CPPFLAGS but not CFLAGS + ''' + testdir = os.path.join(self.common_test_dir, '140 get define') + define = 'MESON_TEST_DEFINE_VALUE' + # NOTE: this list can't have \n, ' or " + # \n is never substituted by the GNU pre-processor via a -D define + # ' and " confuse shlex.split() even when they are escaped + # % and # confuse the MSVC preprocessor + value = 'spaces and fun!@$^&*()-=_+{}[]:;<>?,./~`' + os.environ['CPPFLAGS'] = '-D{}="{}"'.format(define, value) + os.environ['CFLAGS'] = '-DMESON_FAIL_VALUE=cflags-read'.format(define) + self.init(testdir, ['-D{}={}'.format(define, value)]) + class WindowsTests(BasePlatformTests): ''' diff --git a/test cases/common/123 subproject project arguments/exe.c b/test cases/common/123 subproject project arguments/exe.c index b04344a..d6440f0 100644 --- a/test cases/common/123 subproject project arguments/exe.c +++ b/test cases/common/123 subproject project arguments/exe.c @@ -18,6 +18,10 @@ #error #endif +#ifndef PROJECT_OPTION_C_CPP +#error +#endif + int main(int argc, char **argv) { return 0; } diff --git a/test cases/common/123 subproject project arguments/exe.cpp b/test cases/common/123 subproject project arguments/exe.cpp index 7ffe098..8471c6f 100644 --- a/test cases/common/123 subproject project arguments/exe.cpp +++ b/test cases/common/123 subproject project arguments/exe.cpp @@ -18,6 +18,10 @@ #error #endif +#ifndef PROJECT_OPTION_C_CPP +#error +#endif + int main(int argc, char **argv) { return 0; } diff --git a/test cases/common/123 subproject project arguments/meson.build b/test cases/common/123 subproject project arguments/meson.build index aee803c..90d4c05 100644 --- a/test cases/common/123 subproject project arguments/meson.build +++ b/test cases/common/123 subproject project arguments/meson.build @@ -4,10 +4,13 @@ project('project options tester', 'c', 'cpp', add_global_arguments('-DGLOBAL_ARGUMENT', language: 'c') add_project_arguments('-DPROJECT_OPTION', language: 'c') -add_project_arguments('-DPROJECT_OPTION_1', language: 'c') add_project_arguments('-DPROJECT_OPTION_CPP', language: 'cpp') +add_project_arguments('-DPROJECT_OPTION_C_CPP', language: ['c', 'cpp']) sub = subproject('subexe', version : '1.0.0') + +add_project_arguments('-DPROJECT_OPTION_1', language: 'c') + e = executable('exe', 'exe.c') e = executable('execpp', 'exe.cpp') test('exetest', e) diff --git a/test cases/common/123 subproject project arguments/subprojects/subexe/subexe.c b/test cases/common/123 subproject project arguments/subprojects/subexe/subexe.c index 6ebd752..f748afc 100644 --- a/test cases/common/123 subproject project arguments/subprojects/subexe/subexe.c +++ b/test cases/common/123 subproject project arguments/subprojects/subexe/subexe.c @@ -6,6 +6,10 @@ #error #endif +#ifdef PROJECT_OPTION_C_CPP +#error +#endif + #ifndef GLOBAL_ARGUMENT #error #endif diff --git a/test cases/common/125 shared module/meson.build b/test cases/common/125 shared module/meson.build index 7c15bcc..d96d8fc 100644 --- a/test cases/common/125 shared module/meson.build +++ b/test cases/common/125 shared module/meson.build @@ -5,7 +5,8 @@ l = shared_library('runtime', 'runtime.c') # Do NOT link the module with the runtime library. This # is a common approach for plugins that are only used # with dlopen. Any symbols are resolved dynamically -# at runtime +# at runtime. This requires extra help on Windows, so +# should be avoided unless really neccessary. m = shared_module('mymodule', 'module.c') e = executable('prog', 'prog.c', link_with : l, dependencies : dl) test('import test', e, args : m) diff --git a/test cases/common/125 shared module/module.c b/test cases/common/125 shared module/module.c index 56078c5..181b760 100644 --- a/test cases/common/125 shared module/module.c +++ b/test cases/common/125 shared module/module.c @@ -9,14 +9,24 @@ #endif #endif -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) #include <stdio.h> -#include <windows.h> -#include <tlhelp32.h> typedef int (*fptr) (void); +#ifdef __CYGWIN__ + +#include <dlfcn.h> + +fptr find_any_f (const char *name) { + return (fptr) dlsym(RTLD_DEFAULT, name); +} +#else /* _WIN32 */ + +#include <windows.h> +#include <tlhelp32.h> + /* Unlike Linux and OS X, when a library is loaded, all the symbols aren't * loaded into a single namespace. You must fetch the symbol by iterating over * all loaded modules. Code for finding the function from any of the loaded @@ -45,6 +55,7 @@ fptr find_any_f (const char *name) { CloseHandle (snapshot); return f; } +#endif int DLL_PUBLIC func() { fptr f; diff --git a/test cases/common/126 llvm ir and assembly/square-x86_64.S b/test cases/common/126 llvm ir and assembly/square-x86_64.S index 4adc31e..1452f47 100644 --- a/test cases/common/126 llvm ir and assembly/square-x86_64.S +++ b/test cases/common/126 llvm ir and assembly/square-x86_64.S @@ -19,12 +19,12 @@ END .text .globl SYMBOL_NAME(square_unsigned) -# ifdef _WIN32 /* MinGW */ +# if defined(_WIN32) || defined(__CYGWIN__) /* msabi */ SYMBOL_NAME(square_unsigned): imull %ecx, %ecx movl %ecx, %eax retq -# else /* Linux and OS X */ +# else /* sysvabi */ SYMBOL_NAME(square_unsigned): imull %edi, %edi movl %edi, %eax diff --git a/test cases/common/135 generated assembly/main.c b/test cases/common/135 generated assembly/main.c index 97fe723..b669cba 100644 --- a/test cases/common/135 generated assembly/main.c +++ b/test cases/common/135 generated assembly/main.c @@ -1,5 +1,8 @@ #include <stdio.h> +#if defined(_WIN32) || defined(__CYGWIN__) + __declspec(dllimport) +#endif unsigned square_unsigned (unsigned a); int diff --git a/test cases/common/135 generated assembly/square-x86_64.S.in b/test cases/common/135 generated assembly/square-x86_64.S.in index b6d7fb0..0834f16 100644 --- a/test cases/common/135 generated assembly/square-x86_64.S.in +++ b/test cases/common/135 generated assembly/square-x86_64.S.in @@ -23,12 +23,12 @@ END .type square_unsigned,@function # endif -# ifdef _WIN32 /* MinGW */ +# if defined(_WIN32) || defined(__CYGWIN__) /* msabi */ SYMBOL_NAME(square_unsigned): imull %ecx, %ecx movl %ecx, %eax retq -# else /* Linux and OS X */ +# else /* sysvabi */ SYMBOL_NAME(square_unsigned): imull %edi, %edi movl %edi, %eax diff --git a/test cases/common/140 get define/meson.build b/test cases/common/140 get define/meson.build new file mode 100644 index 0000000..5ce4b36 --- /dev/null +++ b/test cases/common/140 get define/meson.build @@ -0,0 +1,31 @@ +project('get define', 'c', 'cpp') + +host_system = host_machine.system() + +foreach lang : ['c', 'cpp'] + cc = meson.get_compiler(lang) + if host_system == 'linux' + d = cc.get_define('__linux__') + assert(d == '1', '__linux__ value is @0@ instead of 1'.format(d)) + elif host_system == 'darwin' + d = cc.get_define('__APPLE__') + assert(d == '1', '__APPLE__ value is @0@ instead of 1'.format(d)) + elif host_system == 'windows' + d = cc.get_define('_WIN32') + assert(d == '1', '_WIN32 value is @0@ instead of 1'.format(d)) + elif host_system == 'cygwin' + d = cc.get_define('__CYGWIN__') + assert(d == '1', '__CYGWIN__ value is @0@ instead of 1'.format(d)) + else + error('Please report a bug and help us improve support for this platform') + endif + + # Check that an undefined value is empty. + have = cc.get_define('MESON_FAIL_VALUE') + assert(have == '', 'MESON_FAIL_VALUE value is "@0@" instead of ""'.format(have)) + + # This is used in the test_preprocessor_checks_CPPFLAGS() unit test. + have = cc.get_define('MESON_TEST_DEFINE_VALUE') + expect = get_option('MESON_TEST_DEFINE_VALUE') + assert(have == expect, 'MESON_TEST_DEFINE_VALUE value is "@0@" instead of "@1@"'.format(have, expect)) +endforeach diff --git a/test cases/common/140 get define/meson_options.txt b/test cases/common/140 get define/meson_options.txt new file mode 100644 index 0000000..a88cecd --- /dev/null +++ b/test cases/common/140 get define/meson_options.txt @@ -0,0 +1 @@ +option('MESON_TEST_DEFINE_VALUE', type : 'string', default : '') diff --git a/test cases/common/141 mesonintrospect from scripts/check_env.py b/test cases/common/141 mesonintrospect from scripts/check_env.py new file mode 100644 index 0000000..dc8ad63 --- /dev/null +++ b/test cases/common/141 mesonintrospect from scripts/check_env.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import os +import sys + +do_print = False + +if len(sys.argv) > 1: + do_print = bool(sys.argv[1]) + +if 'MESONINTROSPECT' not in os.environ: + raise RuntimeError('MESONINTROSPECT not found') + +mesonintrospect = os.environ['MESONINTROSPECT'] + +if not os.path.isfile(mesonintrospect): + raise RuntimeError('{!r} does not exist'.format(mesonintrospect)) + +if do_print: + print(mesonintrospect, end='') diff --git a/test cases/common/141 mesonintrospect from scripts/meson.build b/test cases/common/141 mesonintrospect from scripts/meson.build new file mode 100644 index 0000000..f78710b --- /dev/null +++ b/test cases/common/141 mesonintrospect from scripts/meson.build @@ -0,0 +1,14 @@ +project('mesonintrospect from scripts', 'c') + +python = import('python3').find_python() + +ret = run_command(python, ['check_env.py', '1']) +if ret.returncode() == 0 + find_program(ret.stdout()) +else + message(ret.stdout()) + message(ret.stderr()) +endif + +meson.add_postconf_script('check_env.py') +meson.add_install_script('check_env.py') diff --git a/test cases/common/139 compute int/config.h.in b/test cases/common/142 compute int/config.h.in index ad8d077..ad8d077 100644 --- a/test cases/common/139 compute int/config.h.in +++ b/test cases/common/142 compute int/config.h.in diff --git a/test cases/common/139 compute int/foobar.h b/test cases/common/142 compute int/foobar.h index fd3cb5e..fd3cb5e 100644 --- a/test cases/common/139 compute int/foobar.h +++ b/test cases/common/142 compute int/foobar.h diff --git a/test cases/common/139 compute int/meson.build b/test cases/common/142 compute int/meson.build index 43553fe..43553fe 100644 --- a/test cases/common/139 compute int/meson.build +++ b/test cases/common/142 compute int/meson.build diff --git a/test cases/common/139 compute int/prog.c.in b/test cases/common/142 compute int/prog.c.in index 3ff1463..3ff1463 100644 --- a/test cases/common/139 compute int/prog.c.in +++ b/test cases/common/142 compute int/prog.c.in diff --git a/test cases/common/139 custom target object output/meson.build b/test cases/common/143 custom target object output/meson.build index ede165b..ede165b 100644 --- a/test cases/common/139 custom target object output/meson.build +++ b/test cases/common/143 custom target object output/meson.build diff --git a/test cases/common/139 custom target object output/obj_generator.py b/test cases/common/143 custom target object output/obj_generator.py index a33872a..a33872a 100644 --- a/test cases/common/139 custom target object output/obj_generator.py +++ b/test cases/common/143 custom target object output/obj_generator.py diff --git a/test cases/common/139 custom target object output/objdir/meson.build b/test cases/common/143 custom target object output/objdir/meson.build index 0d7f6c2..0d7f6c2 100644 --- a/test cases/common/139 custom target object output/objdir/meson.build +++ b/test cases/common/143 custom target object output/objdir/meson.build diff --git a/test cases/common/139 custom target object output/objdir/source.c b/test cases/common/143 custom target object output/objdir/source.c index 7779b33..7779b33 100644 --- a/test cases/common/139 custom target object output/objdir/source.c +++ b/test cases/common/143 custom target object output/objdir/source.c diff --git a/test cases/common/139 custom target object output/progdir/meson.build b/test cases/common/143 custom target object output/progdir/meson.build index 4216c24..4216c24 100644 --- a/test cases/common/139 custom target object output/progdir/meson.build +++ b/test cases/common/143 custom target object output/progdir/meson.build diff --git a/test cases/common/139 custom target object output/progdir/prog.c b/test cases/common/143 custom target object output/progdir/prog.c index c1ece33..c1ece33 100644 --- a/test cases/common/139 custom target object output/progdir/prog.c +++ b/test cases/common/143 custom target object output/progdir/prog.c diff --git a/test cases/common/144 empty build file/meson.build b/test cases/common/144 empty build file/meson.build new file mode 100644 index 0000000..73d0397 --- /dev/null +++ b/test cases/common/144 empty build file/meson.build @@ -0,0 +1,2 @@ +project('subdir with empty meson.build test', 'c') +subdir('subdir') diff --git a/test cases/common/144 empty build file/subdir/meson.build b/test cases/common/144 empty build file/subdir/meson.build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test cases/common/144 empty build file/subdir/meson.build diff --git a/test cases/common/16 configure file/meson.build b/test cases/common/16 configure file/meson.build index 8271ca3..8ffc28c 100644 --- a/test cases/common/16 configure file/meson.build +++ b/test cases/common/16 configure file/meson.build @@ -22,6 +22,11 @@ e = executable('inctest', 'prog.c', cfile) test('inctest', e) +# Test if we can also pass files() as input +configure_file(input : files('config.h.in'), + output : 'config2.h', + configuration : conf) + # Now generate a header file with an external script. genprog = import('python3').find_python() scriptfile = '@0@/generator.py'.format(meson.current_source_dir()) diff --git a/test cases/common/23 global arg/meson.build b/test cases/common/23 global arg/meson.build index aec5c2d..d7fd428 100644 --- a/test cases/common/23 global arg/meson.build +++ b/test cases/common/23 global arg/meson.build @@ -3,6 +3,8 @@ project('global arg test', 'cpp', 'c') add_global_arguments('-DMYTHING', language : 'c') add_global_arguments('-DMYCPPTHING', language : 'cpp') +add_global_arguments('-DMYCANDCPPTHING', language: ['c', 'cpp']) + exe1 = executable('prog', 'prog.c') exe2 = executable('prog2', 'prog.cc') diff --git a/test cases/common/23 global arg/prog.c b/test cases/common/23 global arg/prog.c index df91777..ace5a0a 100644 --- a/test cases/common/23 global arg/prog.c +++ b/test cases/common/23 global arg/prog.c @@ -6,6 +6,10 @@ #error "Wrong global argument set" #endif +#ifndef MYCANDCPPTHING +#error "Global argument not set" +#endif + int main(int argc, char **argv) { return 0; } diff --git a/test cases/common/23 global arg/prog.cc b/test cases/common/23 global arg/prog.cc index 342fdd0..0ffd85e 100644 --- a/test cases/common/23 global arg/prog.cc +++ b/test cases/common/23 global arg/prog.cc @@ -6,6 +6,10 @@ #error "Global argument not set" #endif +#ifndef MYCANDCPPTHING +#error "Global argument not set" +#endif + int main(int argc, char **argv) { return 0; } diff --git a/test cases/common/37 has header/meson.build b/test cases/common/37 has header/meson.build index 4299ce5..b53849c 100644 --- a/test cases/common/37 has header/meson.build +++ b/test cases/common/37 has header/meson.build @@ -11,19 +11,19 @@ configure_file(input : non_existant_header, # Test that the fallback to __has_include also works on all compilers if host_system != 'darwin' - args = [[], ['-U__has_include']] + fallbacks = ['', '\n#undef __has_include'] else # On Darwin's clang you can't redefine builtin macros so the above doesn't work - args = [[]] + fallbacks = [''] endif -foreach arg : args +foreach fallback : fallbacks foreach comp : [meson.get_compiler('c'), meson.get_compiler('cpp')] - assert(comp.has_header('stdio.h', args : arg), 'Stdio missing.') + assert(comp.has_header('stdio.h', prefix : fallback), 'Stdio missing.') # stdio.h doesn't actually need stdlib.h, but just test that setting the # prefix does not result in an error. - assert(comp.has_header('stdio.h', prefix : '#include <stdlib.h>', args : arg), + assert(comp.has_header('stdio.h', prefix : '#include <stdlib.h>' + fallback), 'Stdio missing.') # XInput.h should not require type definitions from windows.h, but it does @@ -32,9 +32,9 @@ foreach arg : args # We only do this check on MSVC because MinGW often defines its own wrappers # that pre-include windows.h if comp.get_id() == 'msvc' - assert(comp.has_header('XInput.h', prefix : '#include <windows.h>', args : arg), + assert(comp.has_header('XInput.h', prefix : '#include <windows.h>' + fallback), 'XInput.h should not be missing on Windows') - assert(comp.has_header('XInput.h', prefix : '#define _X86_', args : arg), + assert(comp.has_header('XInput.h', prefix : '#define _X86_' + fallback), 'XInput.h should not need windows.h') endif @@ -42,13 +42,13 @@ foreach arg : args # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80005 # https://github.com/mesonbuild/meson/issues/1458 if host_system == 'linux' - assert(comp.has_header('linux/if.h', args : arg), + assert(comp.has_header('linux/if.h', prefix : fallback), 'Could not find <linux/if.h>') endif # This header exists in the source and the builddir, but we still must not # find it since we are looking in the system directories. - assert(not comp.has_header(non_existant_header, args : arg), + assert(not comp.has_header(non_existant_header, prefix : fallback), 'Found non-existant header.') endforeach endforeach diff --git a/test cases/failing/14 invalid option name/meson_options.txt b/test cases/failing/14 invalid option name/meson_options.txt index c656402..aab6ae8 100644 --- a/test cases/failing/14 invalid option name/meson_options.txt +++ b/test cases/failing/14 invalid option name/meson_options.txt @@ -1 +1 @@ -option('invalid/name', type : 'boolean', value : false)
\ No newline at end of file +option('invalid:name', type : 'boolean', value : false) diff --git a/test cases/failing/19 target clash/meson.build b/test cases/failing/19 target clash/meson.build index 070631b..fbc757c 100644 --- a/test cases/failing/19 target clash/meson.build +++ b/test cases/failing/19 target clash/meson.build @@ -7,7 +7,7 @@ project('clash', 'c') # This test might fail to work on different backends or when # output location is redirected. -if host_machine.system() == 'windows' +if host_machine.system() == 'windows' or host_machine.system() == 'cygwin' error('This is expected.') endif diff --git a/test cases/failing/43 project name colon/meson.build b/test cases/failing/43 project name colon/meson.build new file mode 100644 index 0000000..53e947e --- /dev/null +++ b/test cases/failing/43 project name colon/meson.build @@ -0,0 +1 @@ +project('name with :') diff --git a/test cases/linuxlike/10 large file support/meson.build b/test cases/linuxlike/10 large file support/meson.build index aa4eccf..6683345 100644 --- a/test cases/linuxlike/10 large file support/meson.build +++ b/test cases/linuxlike/10 large file support/meson.build @@ -1,5 +1,9 @@ project('trivial test', 'c') +if host_machine.system() == 'cygwin' + error('MESON_SKIP_TEST _FILE_OFFSET_BITS not yet supported on Cygwin.') +endif + cc = meson.get_compiler('c') size = cc.sizeof('off_t') diff --git a/test cases/linuxlike/11 runpath rpath ldlibrarypath/lib.c b/test cases/linuxlike/11 runpath rpath ldlibrarypath/lib.c new file mode 100644 index 0000000..2784e01 --- /dev/null +++ b/test cases/linuxlike/11 runpath rpath ldlibrarypath/lib.c @@ -0,0 +1,3 @@ +int some_symbol (void) { + return RET_VALUE; +} diff --git a/test cases/linuxlike/11 runpath rpath ldlibrarypath/lib1/meson.build b/test cases/linuxlike/11 runpath rpath ldlibrarypath/lib1/meson.build new file mode 100644 index 0000000..cbc75bd --- /dev/null +++ b/test cases/linuxlike/11 runpath rpath ldlibrarypath/lib1/meson.build @@ -0,0 +1,2 @@ +lib1 = shared_library('testeh', libsrc, + c_args : '-DRET_VALUE=1') diff --git a/test cases/linuxlike/11 runpath rpath ldlibrarypath/lib2/meson.build b/test cases/linuxlike/11 runpath rpath ldlibrarypath/lib2/meson.build new file mode 100644 index 0000000..f2c6dcc --- /dev/null +++ b/test cases/linuxlike/11 runpath rpath ldlibrarypath/lib2/meson.build @@ -0,0 +1,3 @@ +lib2 = shared_library('esteh', libsrc, + name_prefix : 'libt', + c_args : '-DRET_VALUE=2') diff --git a/test cases/linuxlike/11 runpath rpath ldlibrarypath/main.c b/test cases/linuxlike/11 runpath rpath ldlibrarypath/main.c new file mode 100644 index 0000000..c9eff99 --- /dev/null +++ b/test cases/linuxlike/11 runpath rpath ldlibrarypath/main.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +int some_symbol (void); + +int main (int argc, char *argv[]) { + int ret = some_symbol (); + if (ret == 1) + return 0; + fprintf (stderr, "ret was %i instead of 1\n", ret); + return -1; +} diff --git a/test cases/linuxlike/11 runpath rpath ldlibrarypath/meson.build b/test cases/linuxlike/11 runpath rpath ldlibrarypath/meson.build new file mode 100644 index 0000000..b49da66 --- /dev/null +++ b/test cases/linuxlike/11 runpath rpath ldlibrarypath/meson.build @@ -0,0 +1,14 @@ +project('runpath rpath ldlibrarypath', 'c') + +libsrc = files('lib.c') + +subdir('lib1') +subdir('lib2') + +lib2dir = meson.current_build_dir() + '/lib2' + +e = executable('testexe', 'main.c', + link_with : lib1) + +test('ld-library-path-test', e, + env : ['LD_LIBRARY_PATH=' + lib2dir]) diff --git a/test cases/linuxlike/7 library versions/meson.build b/test cases/linuxlike/7 library versions/meson.build index f162210..d156eb0 100644 --- a/test cases/linuxlike/7 library versions/meson.build +++ b/test cases/linuxlike/7 library versions/meson.build @@ -1,5 +1,9 @@ project('library versions', 'c') +if host_machine.system() == 'cygwin' + error('MESON_SKIP_TEST linuxlike soversions not supported on Cygwin.') +endif + some = shared_library('some', 'lib.c', version : '1.2.3', soversion : '0', diff --git a/test cases/linuxlike/8 subproject library install/meson.build b/test cases/linuxlike/8 subproject library install/meson.build index 63e57cf..ff55799 100644 --- a/test cases/linuxlike/8 subproject library install/meson.build +++ b/test cases/linuxlike/8 subproject library install/meson.build @@ -2,5 +2,9 @@ project('subproj lib install', 'c', version : '2.3.4', license : 'mylicense') +if host_machine.system() == 'cygwin' + error('MESON_SKIP_TEST linuxlike soversions not supported on Cygwin.') +endif + # Test that the subproject library gets installed subproject('sublib', version : '1.0.0') diff --git a/test cases/objc/2 nsstring/meson.build b/test cases/objc/2 nsstring/meson.build index ec496a2..a877d74 100644 --- a/test cases/objc/2 nsstring/meson.build +++ b/test cases/objc/2 nsstring/meson.build @@ -2,6 +2,8 @@ project('nsstring', 'objc') if host_machine.system() == 'darwin' dep = dependency('appleframeworks', modules : 'foundation') +elif host_machine.system() == 'cygwin' + error('MESON_SKIP_TEST GNUstep is not packaged for Cygwin.') else dep = dependency('gnustep') if host_machine.system() == 'linux' and meson.get_compiler('objc').get_id() == 'clang' diff --git a/test cases/windows/5 resources/meson.build b/test cases/windows/5 resources/meson.build index e92a43c..ddb7d6e 100644 --- a/test cases/windows/5 resources/meson.build +++ b/test cases/windows/5 resources/meson.build @@ -3,7 +3,7 @@ project('winmain', 'c') # MinGW windres has a bug due to which it doesn't parse args with space properly: # https://github.com/mesonbuild/meson/pull/1346 # https://sourceware.org/bugzilla/show_bug.cgi?id=4933 -if meson.get_compiler('c').get_id() == 'gcc' +if meson.get_compiler('c').get_id() == 'gcc' and host_machine.system() == 'windows' # Construct build_to_src and skip this test if it has spaces # because then the -I flag to windres will also have spaces # and we know the test will fail diff --git a/test cases/windows/7 mingw dll versioning/installed_files.txt b/test cases/windows/7 mingw dll versioning/installed_files.txt index 56187a6..9acd7db 100644 --- a/test cases/windows/7 mingw dll versioning/installed_files.txt +++ b/test cases/windows/7 mingw dll versioning/installed_files.txt @@ -1,10 +1,10 @@ -usr/bin/libsome-0.dll +usr/bin/?libsome-0.dll usr/lib/libsome.dll.a -usr/bin/libnoversion.dll +usr/bin/?libnoversion.dll usr/lib/libnoversion.dll.a -usr/bin/libonlyversion-1.dll +usr/bin/?libonlyversion-1.dll usr/lib/libonlyversion.dll.a -usr/bin/libonlysoversion-5.dll +usr/bin/?libonlysoversion-5.dll usr/lib/libonlysoversion.dll.a usr/libexec/libcustomdir.dll usr/libexec/libcustomdir.dll.a |