diff options
41 files changed, 653 insertions, 372 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 38ebe56..adc13b8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,23 +2,56 @@ version: 1.0.{build} os: Visual Studio 2015 +environment: + matrix: + - arch: x86 + compiler: msvc2010 + backend: ninja + + - arch: x86 + compiler: msvc2010 + backend: vs2010 + + - arch: x86 + compiler: msvc2015 + backend: ninja + + - arch: x86 + compiler: msvc2015 + backend: vs2015 + + - arch: x64 + compiler: msvc2015 + backend: ninja + + - arch: x64 + compiler: msvc2015 + backend: vs2015 + platform: - - x86 + - x64 branches: only: - master install: - - ps: (new-object net.webclient).DownloadFile('https://dl.dropboxusercontent.com/u/37517477/ninja.exe', 'c:\python34\ninja.exe') - - cmd: copy c:\python34\python.exe c:\python34\python3.exe - - '"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x86' + # Use the x86 python only when building for x86 for the cpython tests. + # For all other archs (including, say, arm), use the x64 python. + - ps: (new-object net.webclient).DownloadFile('https://dl.dropboxusercontent.com/u/37517477/ninja.exe', 'C:\projects\meson\ninja.exe') + - cmd: if %arch%==x86 (set MESON_PYTHON_PATH=C:\python34) else (set MESON_PYTHON_PATH=C:\python34-x64) + - cmd: echo Using Python at %MESON_PYTHON_PATH% + - cmd: copy %MESON_PYTHON_PATH%\python.exe %MESON_PYTHON_PATH%\python3.exe + - cmd: if %compiler%==msvc2010 ( call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %arch% ) + - cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% ) build_script: - cmd: echo No build step. + - cmd: if %backend%==ninja ( ninja.exe --version ) else ( MSBuild /version & echo. ) test_script: - - cmd: PATH c:\python34;%PATH%; && python3 run_tests.py --backend=ninja + - cmd: echo Running tests for %arch% and %compiler% with the %backend% backend + - cmd: PATH=%cd%;%MESON_PYTHON_PATH%;%PATH%; && python3 run_tests.py --backend=%backend% on_finish: - appveyor PushArtifact meson-test-run.txt -DeploymentName "Text test logs" diff --git a/.travis.yml b/.travis.yml index bc52ffa..8648572 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,12 @@ language: services: - docker +matrix: + exclude: + # On OS X gcc is just a wrapper around clang, so don't waste time testing that + - os: osx + compiler: gcc + before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ninja python3; fi @@ -30,5 +36,5 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo FROM jpakkane/mesonci:yakkety > Dockerfile; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then echo ADD . /root >> Dockerfile; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker build -t withgit .; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true ./run_tests.py -- $MESON_ARGS"; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run withgit /bin/sh -c "cd /root && TRAVIS=true CC=$CC CXX=$CXX ./run_tests.py -- $MESON_ARGS"; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index a4f2b51..2861bb6 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -81,8 +81,8 @@ class Backend(): def get_target_filename(self, t): if isinstance(t, build.CustomTarget): if len(t.get_outputs()) != 1: - mlog.log(mlog.red('WARNING'), 'custom_target {!r} has more ' \ - 'than one output! Using the first one.'.format(t.name)) + mlog.warning('custom_target {!r} has more than one output! ' \ + 'Using the first one.'.format(t.name)) filename = t.get_outputs()[0] else: assert(isinstance(t, build.BuildTarget)) @@ -572,32 +572,46 @@ class Backend(): i = i.replace('@INPUT%d@' % j, src) for (j, res) in enumerate(ofilenames): i = i.replace('@OUTPUT%d@' % j, res) - if i == '@INPUT@': - cmd += srcs - elif i == '@OUTPUT@': - cmd += ofilenames - else: - if '@OUTDIR@' in i: - i = i.replace('@OUTDIR@', outdir) - elif '@DEPFILE@' in i: - if target.depfile is None: - raise MesonException('Custom target %s has @DEPFILE@ but no depfile keyword argument.' % target.name) - if absolute_paths: - dfilename = os.path.join(self.get_target_private_dir_abs(target), target.depfile) - else: - dfilename = os.path.join(self.get_target_private_dir(target), target.depfile) - i = i.replace('@DEPFILE@', dfilename) - elif '@PRIVATE_OUTDIR_' in i: - match = re.search('@PRIVATE_OUTDIR_(ABS_)?([-a-zA-Z0-9.@:]*)@', i) - source = match.group(0) - if match.group(1) is None and not absolute_paths: - lead_dir = '' - else: - lead_dir = self.environment.get_build_dir() - i = i.replace(source, - os.path.join(lead_dir, - outdir)) - cmd.append(i) + if '@INPUT@' in i: + msg = 'Custom target {} has @INPUT@ in the command, but'.format(target.name) + if len(srcs) == 0: + raise MesonException(msg + ' no input files') + if i == '@INPUT@': + cmd += srcs + continue + else: + if len(srcs) > 1: + raise MesonException(msg + ' more than one input file') + i = i.replace('@INPUT@', srcs[0]) + elif '@OUTPUT@' in i: + msg = 'Custom target {} has @OUTPUT@ in the command, but'.format(target.name) + if len(ofilenames) == 0: + raise MesonException(msg + ' no output files') + if i == '@OUTPUT@': + cmd += ofilenames + continue + else: + if len(ofilenames) > 1: + raise MesonException(msg + ' more than one output file') + i = i.replace('@OUTPUT@', ofilenames[0]) + elif '@OUTDIR@' in i: + i = i.replace('@OUTDIR@', outdir) + elif '@DEPFILE@' in i: + if target.depfile is None: + raise MesonException('Custom target %s has @DEPFILE@ but no depfile keyword argument.' % target.name) + dfilename = os.path.join(outdir, target.depfile) + i = i.replace('@DEPFILE@', dfilename) + elif '@PRIVATE_OUTDIR_' in i: + match = re.search('@PRIVATE_OUTDIR_(ABS_)?([-a-zA-Z0-9.@:]*)@', i) + source = match.group(0) + if match.group(1) is None and not absolute_paths: + lead_dir = '' + else: + lead_dir = self.environment.get_build_dir() + i = i.replace(source, + os.path.join(lead_dir, + outdir)) + cmd.append(i) # This should not be necessary but removing it breaks # building GStreamer on Windows. The underlying issue # is problems with quoting backslashes on Windows diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 5fa7d79..76f47ab 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -215,7 +215,7 @@ int dummy; with open(os.path.join(builddir, 'compile_commands.json'), 'wb') as f: f.write(jsondb) except Exception: - mlog.log(mlog.red('Warning:', 'Could not create compilation database.')) + mlog.warning('Could not create compilation database.') # Get all generated headers. Any source file might need them so # we need to add an order dependency to them. @@ -494,8 +494,8 @@ int dummy; cmd_type = 'custom' if target.depfile is not None: - rel_dfile = os.path.join(self.get_target_private_dir(target), target.depfile) - abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_private_dir(target)) + rel_dfile = os.path.join(self.get_target_dir(target), target.depfile) + abs_pdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) os.makedirs(abs_pdir, exist_ok=True) elem.add_item('DEPFILE', rel_dfile) elem.add_item('COMMAND', cmd) @@ -581,7 +581,7 @@ int dummy; elem.add_item('DESC', 'Generating HTML coverage report.') elem.write(outfile) if not added_rule: - mlog.log(mlog.red('Warning:'), 'coverage requested but neither gcovr nor lcov/genhtml found.') + mlog.warning('coverage requested but neither gcovr nor lcov/genhtml found.') def generate_install(self, outfile): install_data_file = os.path.join(self.environment.get_scratch_dir(), 'install.dat') @@ -1694,9 +1694,9 @@ rule FORTRAN_DEP_HACK if target.has_pch(): tfilename = self.get_target_filename_abs(target) - return compiler.get_compile_debugfile_args(tfilename) + return compiler.get_compile_debugfile_args(tfilename, pch=True) else: - return compiler.get_compile_debugfile_args(objfile) + return compiler.get_compile_debugfile_args(objfile, pch=False) def get_link_debugfile_args(self, linker, target, outname): return linker.get_link_debugfile_args(outname) @@ -1720,10 +1720,11 @@ rule FORTRAN_DEP_HACK # Add the root source and build directories as include dirs curdir = target.get_subdir() tmppath = os.path.normpath(os.path.join(self.build_to_src, curdir)) - commands += compiler.get_include_args(tmppath, False) + src_inc = compiler.get_include_args(tmppath, False) if curdir == '': curdir = '.' - commands += compiler.get_include_args(curdir, False) + build_inc = compiler.get_include_args(curdir, False) + commands += build_inc + src_inc # -I args work differently than other ones. In them the first found # directory is used whereas for other flags (such as -ffoo -fno-foo) the # latest one is used. Therefore put the internal include directories diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index f1d949a..c66233e 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -284,20 +284,13 @@ class Vs2010Backend(backends.Backend): def generate_projects(self): projlist = [] - comp = None - for l, c in self.environment.coredata.compilers.items(): - if l == 'c' or l == 'cpp': - comp = c - break - if comp is None: - raise RuntimeError('C and C++ compilers missing.') for name, target in self.build.targets.items(): outdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) fname = name + '.vcxproj' relname = os.path.join(target.subdir, fname) projfile = os.path.join(outdir, fname) uuid = self.environment.coredata.target_guids[name] - self.gen_vcxproj(target, projfile, uuid, comp) + self.gen_vcxproj(target, projfile, uuid) projlist.append((name, relname, uuid)) return projlist @@ -430,12 +423,26 @@ class Vs2010Backend(backends.Backend): pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % lang - def add_additional_options(self, source_file, parent_node, extra_args, has_additional_options_set): - if has_additional_options_set: + def add_additional_options(self, lang, parent_node, file_args): + if len(file_args[lang]) == 0: # We only need per file options if they were not set per project. return - lang = Vs2010Backend.lang_from_source_file(source_file) - ET.SubElement(parent_node, "AdditionalOptions").text = ' '.join(extra_args[lang]) + ' %(AdditionalOptions)' + args = file_args[lang] + ['%(AdditionalOptions)'] + ET.SubElement(parent_node, "AdditionalOptions").text = ' '.join(args) + + def add_preprocessor_defines(self, lang, parent_node, file_defines): + if len(file_defines[lang]) == 0: + # We only need per file options if they were not set per project. + return + defines = file_defines[lang] + ['%(PreprocessorDefinitions)'] + ET.SubElement(parent_node, "PreprocessorDefinitions").text = ';'.join(defines) + + def add_include_dirs(self, lang, parent_node, file_inc_dirs): + if len(file_inc_dirs[lang]) == 0: + # We only need per file options if they were not set per project. + return + dirs = file_inc_dirs[lang] + ['%(AdditionalIncludeDirectories)'] + ET.SubElement(parent_node, "AdditionalIncludeDirectories").text = ';'.join(dirs) @staticmethod def has_objects(objects, additional_objects, generated_objects): @@ -505,7 +512,19 @@ class Vs2010Backend(backends.Backend): other.append(arg) return (lpaths, libs, other) - def gen_vcxproj(self, target, ofname, guid, compiler): + def _get_cl_compiler(self, target): + for lang, c in target.compilers.items(): + if lang in ('c', 'cpp'): + return c + # No source files, only objects, but we still need a compiler, so + # return a found compiler + if len(target.objects) > 0: + for lang, c in self.environment.coredata.compilers.items(): + if lang in ('c', 'cpp'): + return c + raise MesonException('Could not find a C or C++ compiler. MSVC can only build C/C++ projects.') + + def gen_vcxproj(self, target, ofname, guid): mlog.debug('Generating vcxproj %s.' % target.name) entrypoint = 'WinMainCRTStartup' subsystem = 'Windows' @@ -532,6 +551,7 @@ class Vs2010Backend(backends.Backend): # 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) + compiler = self._get_cl_compiler(target) buildtype_args = compiler.get_buildtype_args(self.buildtype) buildtype_link_args = compiler.get_buildtype_linker_args(self.buildtype) project_name = target.name @@ -643,83 +663,86 @@ class Vs2010Backend(backends.Backend): # Build information compiles = ET.SubElement(root, 'ItemDefinitionGroup') clconf = ET.SubElement(compiles, 'ClCompile') - inc_dirs = ['.', self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)), - proj_to_src_dir] + generated_files_include_dirs - - extra_args = {'c': [], 'cpp': []} + # Arguments, include dirs, defines for all files in the current target + target_args = [] + target_defines = [] + target_inc_dirs = ['.', self.relpath(self.get_target_private_dir(target), + self.get_target_dir(target)), + proj_to_src_dir] + generated_files_include_dirs + # Arguments, include dirs, defines passed to individual files in + # a target; perhaps because the args are language-specific + file_args = dict((lang, []) for lang in target.compilers) + file_defines = dict((lang, []) for lang in target.compilers) + file_inc_dirs = dict((lang, []) for lang in target.compilers) for l, args in self.environment.coredata.external_args.items(): - if l in extra_args: - extra_args[l] += args + if l in file_args: + file_args[l] += args for l, args in self.build.global_args.items(): - if l in extra_args: - extra_args[l] += args + if l in file_args: + file_args[l] += args for l, args in target.extra_args.items(): - if l in extra_args: - extra_args[l] += compiler.unix_compile_flags_to_native(args) - # 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) + if l in file_args: + file_args[l] += compiler.unix_compile_flags_to_native(args) + for l, comp in target.compilers.items(): + if l in file_args: + file_args[l] += comp.get_option_compile_args(self.environment.coredata.compiler_options) for d in target.get_external_deps(): # 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'): + if arg.startswith(('-D', '/D')): + define = arg[2:] + # De-dup + if define not in target_defines: + target_defines.append(define) + elif arg.startswith(('-I', '/I')): inc_dir = arg[2:] # De-dup - if inc_dir not in inc_dirs: - inc_dirs.append(inc_dir) + if inc_dir not in target_inc_dirs: + target_inc_dirs.append(inc_dir) else: - general_args.append(arg) + # De-dup + if arg not in target_args: + target_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] = [] + for l, args in file_args.items(): + file_args[l] = [] for arg in args: - if arg.startswith('-D') or arg.startswith('/D'): + if arg.startswith(('-D', '/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'): + if define not in file_defines[l]: + file_defines[l].append(define) + elif arg.startswith(('-I', '/I')): inc_dir = arg[2:] # De-dup - if inc_dir not in inc_dirs: - inc_dirs.append(inc_dir) + if inc_dir not in file_inc_dirs[l]: + file_inc_dirs[l].append(inc_dir) else: - extra_args[l].append(self.escape_additional_option(arg)) + file_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()) - additional_options_set = False - if not has_language_specific_args or len(languages) == 1: - if len(languages) == 0: - extra_args = [] - else: - extra_args = extra_args[languages[0]] - extra_args = general_args + extra_args - if len(extra_args) > 0: - extra_args.append('%(AdditionalOptions)') - ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(extra_args) - additional_options_set = True + if len(target_args) > 0: + target_args.append('%(AdditionalOptions)') + ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(target_args) + additional_options_set = True for d in target.include_dirs: for i in d.incdirs: curdir = os.path.join(d.curdir, i) - inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir - inc_dirs.append(os.path.join(proj_to_src_root, curdir)) # src dir + target_inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir + target_inc_dirs.append(os.path.join(proj_to_src_root, curdir)) # src dir for i in d.get_extra_build_dirs(): curdir = os.path.join(d.curdir, i) - inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir + target_inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir - inc_dirs.append('%(AdditionalIncludeDirectories)') - ET.SubElement(clconf, 'AdditionalIncludeDirectories').text = ';'.join(inc_dirs) - ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(defines) + target_inc_dirs.append('%(AdditionalIncludeDirectories)') + ET.SubElement(clconf, 'AdditionalIncludeDirectories').text = ';'.join(target_inc_dirs) + target_defines.append('%(PreprocessorDefinitions)') + ET.SubElement(clconf, 'PreprocessorDefinitions').text = ';'.join(target_defines) rebuild = ET.SubElement(clconf, 'MinimalRebuild') rebuild.text = 'true' funclink = ET.SubElement(clconf, 'FunctionLevelLinking') @@ -834,19 +857,26 @@ class Vs2010Backend(backends.Backend): for s in sources: relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src)) inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) + lang = Vs2010Backend.lang_from_source_file(s) self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s) - self.add_additional_options(s, inc_cl, extra_args, additional_options_set) + self.add_additional_options(lang, inc_cl, file_args) + self.add_preprocessor_defines(lang, inc_cl, file_defines) + self.add_include_dirs(lang, inc_cl, file_inc_dirs) basename = os.path.basename(s.fname) if basename in self.sources_conflicts[target.get_id()]: ET.SubElement(inc_cl, 'ObjectFileName').text = "$(IntDir)" + self.object_filename_from_source(target, s) for s in gen_src: inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=s) + lang = Vs2010Backend.lang_from_source_file(s) self.add_pch(inc_cl, proj_to_src_dir, pch_sources, s) - self.add_additional_options(s, inc_cl, extra_args, additional_options_set) + self.add_additional_options(lang, inc_cl, file_args) + self.add_preprocessor_defines(lang, inc_cl, file_defines) + self.add_include_dirs(lang, inc_cl, file_inc_dirs) for lang in pch_sources: header, impl, suffix = pch_sources[lang] relpath = os.path.join(proj_to_src_dir, impl) inc_cl = ET.SubElement(inc_src, 'CLCompile', Include=relpath) + lang = Vs2010Backend.lang_from_source_file(s) pch = ET.SubElement(inc_cl, 'PrecompiledHeader') pch.text = 'Create' pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') @@ -855,7 +885,9 @@ class Vs2010Backend(backends.Backend): # MSBuild searches for the header relative from the implementation, so we have to use # just the file name instead of the relative path to the file. pch_file.text = os.path.split(header)[1] - self.add_additional_options(impl, inc_cl, extra_args, additional_options_set) + self.add_additional_options(lang, inc_cl, file_args) + self.add_preprocessor_defines(lang, inc_cl, file_defines) + self.add_include_dirs(lang, inc_cl, file_inc_dirs) if self.has_objects(objects, additional_objects, gen_objs): inc_objs = ET.SubElement(root, 'ItemGroup') diff --git a/mesonbuild/build.py b/mesonbuild/build.py index c3867e0..d87d9a0 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -309,8 +309,8 @@ class BuildTarget(): if not k in known_kwargs: unknowns.append(k) if len(unknowns) > 0: - mlog.log(mlog.bold('Warning:'), 'Unknown keyword argument(s) in target %s: %s.' % - (self.name, ', '.join(unknowns))) + mlog.warning('Unknown keyword argument(s) in target %s: %s.' % + (self.name, ', '.join(unknowns))) def process_objectlist(self, objects): assert(isinstance(objects, list)) @@ -583,7 +583,7 @@ class BuildTarget(): if for_darwin(self.is_cross, self.environment) or for_windows(self.is_cross, self.environment): self.pic = True elif '-fPIC' in clist + cpplist: - mlog.log(mlog.red('WARNING:'), "Use the 'pic' kwarg instead of passing -fPIC manually to static library {!r}".format(self.name)) + mlog.warning("Use the 'pic' kwarg instead of passing -fPIC manually to static library {!r}".format(self.name)) self.pic = True else: self.pic = kwargs.get('pic', False) @@ -1139,8 +1139,8 @@ class CustomTarget: if k not in CustomTarget.known_kwargs: unknowns.append(k) if len(unknowns) > 0: - mlog.log(mlog.bold('Warning:'), 'Unknown keyword arguments in target %s: %s' % - (self.name, ', '.join(unknowns))) + mlog.warning('Unknown keyword arguments in target %s: %s' % + (self.name, ', '.join(unknowns))) def __repr__(self): repr_str = "<{0} {1}: {2}>" diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index 94e8a54..bbe6a72 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import shutil import contextlib import subprocess, os.path import tempfile @@ -434,7 +435,7 @@ class Compiler(): # Some compilers (msvc) write debug info to a separate file. # These args specify where it should be written. - def get_compile_debugfile_args(self, rel_obj): + def get_compile_debugfile_args(self, rel_obj, **kwargs): return [] def get_link_debugfile_args(self, rel_obj): @@ -512,6 +513,13 @@ class CCompiler(Compiler): def get_no_optimization_args(self): return ['-O0'] + def get_compiler_check_args(self): + ''' + Get arguments useful for compiler checks such as being permissive in + the code quality and not doing any optimization. + ''' + return self.get_no_optimization_args() + def get_output_args(self, target): return ['-o', target] @@ -643,9 +651,14 @@ int someSymbolHereJustForFun; extra_args = [] templ = '''{2} #include <{0}> -int main () {{ {1}; }}''' - # Pass -O0 to ensure that the symbol isn't optimized away - args = extra_args + self.get_no_optimization_args() +int main () {{ + /* If it's not defined as a macro, try to use as a symbol */ + #ifndef {1} + {1}; + #endif + return 0; +}}''' + args = extra_args + self.get_compiler_check_args() return self.compiles(templ.format(hname, symbol, prefix), env, args, dependencies) @contextlib.contextmanager @@ -784,7 +797,7 @@ int main(int argc, char **argv) {{ %s int temparray[%d-sizeof(%s)]; ''' - args = extra_args + self.get_no_optimization_args() + args = extra_args + self.get_compiler_check_args() if not self.compiles(element_exists_templ.format(prefix, element), env, args, dependencies): return -1 for i in range(1, 1024): @@ -833,7 +846,7 @@ struct tmp { int testarray[%d-offsetof(struct tmp, target)]; ''' - args = extra_args + self.get_no_optimization_args() + args = extra_args + self.get_compiler_check_args() if not self.compiles(type_exists_templ.format(typename), env, args, dependencies): return -1 for i in range(1, 1024): @@ -918,7 +931,7 @@ int main(int argc, char **argv) { head = '#include <limits.h>\n{0}\n' # We don't know what the function takes or returns, so try to use it as # a function pointer - main = '\nint main() {{ int a = (int) &{1}; }}' + main = '\nint main() {{ void *a = (void*) &{1}; }}' return head, main def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None): @@ -967,9 +980,8 @@ int main(int argc, char **argv) { head, main = self._no_prototype_templ() templ = head + stubs_fail + main - # Add -O0 to ensure that the symbol isn't optimized away by the compiler - args = extra_args + self.get_no_optimization_args() - if self.links(templ.format(prefix, funcname), env, extra_args, dependencies): + args = extra_args + self.get_compiler_check_args() + if self.links(templ.format(prefix, funcname), env, args, dependencies): return True # Some functions like alloca() are defined as compiler built-ins which # are inlined by the compiler, so test for that instead. Built-ins are @@ -1048,6 +1060,20 @@ class CPPCompiler(CCompiler): code = 'class breakCCompiler;int main(int argc, char **argv) { return 0; }\n' return self.sanity_check_impl(work_dir, environment, 'sanitycheckcpp.cc', code) + def has_header_symbol(self, hname, symbol, prefix, env, extra_args=None, dependencies=None): + # Check if it's a C-like symbol + if super().has_header_symbol(hname, symbol, prefix, env, extra_args, dependencies): + return True + # Check if it's a class or a template + if extra_args is None: + extra_args = [] + templ = '''{2} +#include <{0}> +using {1}; +int main () {{ return 0; }}''' + args = extra_args + self.get_compiler_check_args() + return self.compiles(templ.format(hname, symbol, prefix), env, args, dependencies) + class ObjCCompiler(CCompiler): def __init__(self, exelist, version, is_cross, exe_wrap): self.language = 'objc' @@ -1274,11 +1300,20 @@ class JavaCompiler(Compiler): pc.wait() if pc.returncode != 0: raise EnvironmentException('Java compiler %s can not compile programs.' % self.name_string()) - cmdlist = [self.javarunner, obj] - pe = subprocess.Popen(cmdlist, cwd=work_dir) - pe.wait() - if pe.returncode != 0: - raise EnvironmentException('Executables created by Java compiler %s are not runnable.' % self.name_string()) + runner = shutil.which(self.javarunner) + if runner: + cmdlist = [runner, obj] + pe = subprocess.Popen(cmdlist, cwd=work_dir) + pe.wait() + if pe.returncode != 0: + raise EnvironmentException('Executables created by Java compiler %s are not runnable.' % self.name_string()) + else: + m = "Java Virtual Machine wasn't found, but it's needed by Meson. " \ + "Please install a JRE.\nIf you have specific needs where this " \ + "requirement doesn't make sense, please open a bug at " \ + "https://github.com/mesonbuild/meson/issues/new and tell us " \ + "all about it." + raise EnvironmentException(m) def needs_static_linker(self): return False @@ -1848,19 +1883,29 @@ class VisualStudioCCompiler(CCompiler): raise MesonException('Compiling test app failed.') return not(warning_text in stde or warning_text in stdo) - def get_compile_debugfile_args(self, rel_obj): + def get_compile_debugfile_args(self, rel_obj, pch=False): pdbarr = rel_obj.split('.')[:-1] pdbarr += ['pdb'] - return ['/Fd' + '.'.join(pdbarr)] + args = ['/Fd' + '.'.join(pdbarr)] + # When generating a PDB file with PCH, all compile commands write + # to the same PDB file. Hence, we need to serialize the PDB + # writes using /FS since we do parallel builds. This slows down the + # build obviously, which is why we only do this when PCH is on. + # This was added in Visual Studio 2013 (MSVC 18.0). Before that it was + # always on: https://msdn.microsoft.com/en-us/library/dn502518.aspx + if pch and mesonlib.version_compare(self.version, '>=18.0'): + args = ['/FS'] + args + return args def get_link_debugfile_args(self, targetfile): pdbarr = targetfile.split('.')[:-1] pdbarr += ['pdb'] return ['/DEBUG', '/PDB:' + '.'.join(pdbarr)] -class VisualStudioCPPCompiler(VisualStudioCCompiler): +class VisualStudioCPPCompiler(VisualStudioCCompiler, CPPCompiler): def __init__(self, exelist, version, is_cross, exe_wrap): self.language = 'cpp' + CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) VisualStudioCCompiler.__init__(self, exelist, version, is_cross, exe_wrap) self.base_options = ['b_pch'] # FIXME add lto, pgo and the like @@ -2035,6 +2080,12 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): return options['cpp_winlibs'].value return [] + def get_compiler_check_args(self): + # -fpermissive allows non-conforming code to compile which is necessary + # for many C++ checks. Particularly, the has_header_symbol check is + # too strict without this and always fails. + return self.get_no_optimization_args() + ['-fpermissive'] + class GnuObjCCompiler(GnuCompiler,ObjCCompiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None, defines=None): @@ -2057,6 +2108,12 @@ class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler): '2': ['-Wall', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor'], '3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor']} + def get_compiler_check_args(self): + # -fpermissive allows non-conforming code to compile which is necessary + # for many ObjC++ checks. Particularly, the has_header_symbol check is + # too strict without this and always fails. + return self.get_no_optimization_args() + ['-fpermissive'] + class ClangCompiler(): def __init__(self, clang_type): self.id = 'clang' diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 943c087..88826f8 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -89,6 +89,10 @@ class MesonApp(): def validate_core_dirs(self, dir1, dir2): ndir1 = os.path.abspath(dir1) ndir2 = os.path.abspath(dir2) + if not os.path.exists(ndir1): + os.makedirs(ndir1) + if not os.path.exists(ndir2): + os.makedirs(ndir2) if not stat.S_ISDIR(os.stat(ndir1).st_mode): raise RuntimeError('%s is not a directory' % dir1) if not stat.S_ISDIR(os.stat(ndir2).st_mode): @@ -121,8 +125,8 @@ itself as required.''' 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)) + mlog.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): diff --git a/mesonbuild/mlog.py b/mesonbuild/mlog.py index dab51bd..cded2b0 100644 --- a/mesonbuild/mlog.py +++ b/mesonbuild/mlog.py @@ -53,6 +53,9 @@ def red(text): def green(text): return AnsiDecorator(text, "\033[1;32m") +def yellow(text): + return AnsiDecorator(text, "\033[1;33m") + def cyan(text): return AnsiDecorator(text, "\033[1;36m") @@ -81,3 +84,6 @@ def log(*args, **kwargs): if colorize_console: arr = process_markup(args, True) print(*arr, **kwargs) + +def warning(*args, **kwargs): + log(yellow('WARNING:'), *args, **kwargs) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 27200ae..f3f22bc 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -18,6 +18,7 @@ functionality such as gobject-introspection and gresources.''' from .. import build import os import sys +import copy import subprocess from ..mesonlib import MesonException from .. import dependencies @@ -43,11 +44,11 @@ class GnomeModule: def __print_gresources_warning(self, state): global gresource_warning_printed if not gresource_warning_printed: - if mesonlib.version_compare(self._get_native_glib_version(state), '< 2.50.0'): - mlog.log('Warning, GLib compiled dependencies do not work fully ' - 'with versions of GLib older than 2.50.0.\n' - 'See the following upstream issue:', - mlog.bold('https://bugzilla.gnome.org/show_bug.cgi?id=745754')) + if mesonlib.version_compare(self._get_native_glib_version(state), '< 2.50.2'): + mlog.warning('GLib compiled dependencies do not work fully ' + 'with versions of GLib older than 2.50.2.\n' + 'See the following upstream issue:', + mlog.bold('https://bugzilla.gnome.org/show_bug.cgi?id=745754')) gresource_warning_printed = True return [] @@ -60,9 +61,6 @@ class GnomeModule: if not isinstance(source_dirs, list): source_dirs = [source_dirs] - # Always include current directory, but after paths set by user - source_dirs.append(os.path.join(state.environment.get_source_dir(), state.subdir)) - if len(args) < 2: raise MesonException('Not enough arguments; The name of the resource and the path to the XML file are required') @@ -70,8 +68,8 @@ class GnomeModule: if not isinstance(dependencies, list): dependencies = [dependencies] - if mesonlib.version_compare(self._get_native_glib_version(state), - '< 2.48.2'): + glib_version = self._get_native_glib_version(state) + if mesonlib.version_compare(glib_version, '< 2.48.2'): if len(dependencies) > 0: raise MesonException( 'The "dependencies" argument of gnome.compile_resources() ' @@ -87,18 +85,18 @@ class GnomeModule: else: raise RuntimeError('Unreachable code.') - kwargs['depend_files'] = self._get_gresource_dependencies( + depend_files, depends, subdirs = self._get_gresource_dependencies( state, ifile, source_dirs, dependencies) - for source_dir in source_dirs: - sourcedir = os.path.join(state.build_to_src, state.subdir, source_dir) - cmd += ['--sourcedir', sourcedir] + # Make source dirs relative to build dir now + source_dirs = [os.path.join(state.build_to_src, state.subdir, d) for d in source_dirs] + # Always include current directory, but after paths set by user + source_dirs.append(os.path.join(state.build_to_src, state.subdir)) + # Ensure build directories of generated deps are included + source_dirs += subdirs - if len(dependencies) > 0: - # Add the build variant of each sourcedir if we have any - # generated dependencies. - sourcedir = os.path.join(state.subdir, source_dir) - cmd += ['--sourcedir', sourcedir] + for source_dir in set(source_dirs): + cmd += ['--sourcedir', source_dir] if 'c_name' in kwargs: cmd += ['--c-name', kwargs.pop('c_name')] @@ -106,17 +104,30 @@ class GnomeModule: cmd += mesonlib.stringlistify(kwargs.pop('extra_args', [])) - kwargs['command'] = cmd kwargs['input'] = args[1] kwargs['output'] = args[0] + '.c' + kwargs['depends'] = depends + if mesonlib.version_compare(glib_version, '< 2.50.2'): + # This will eventually go out of sync if dependencies are added + kwargs['depend_files'] = depend_files + kwargs['command'] = cmd + else: + depfile = kwargs['output'] + '.d' + kwargs['depfile'] = depfile + kwargs['command'] = copy.copy(cmd) + ['--dependency-file', '@DEPFILE@'] target_c = build.CustomTarget(args[0] + '_c', state.subdir, kwargs) - kwargs['output'] = args[0] + '.h' - target_h = build.CustomTarget(args[0] + '_h', state.subdir, kwargs) + + h_kwargs = { + 'command': cmd, + 'input': args[1], + 'output': args[0] + '.h', + # The header doesn't actually care about the files yet it errors if missing + 'depends': depends + } + target_h = build.CustomTarget(args[0] + '_h', state.subdir, h_kwargs) return [target_c, target_h] def _get_gresource_dependencies(self, state, input_file, source_dirs, dependencies): - self.__print_gresources_warning(state) - for dep in dependencies: if not isinstance(dep, interpreter.CustomTargetHolder) and not \ isinstance(dep, mesonlib.File): @@ -131,12 +142,13 @@ class GnomeModule: for source_dir in source_dirs: cmd += ['--sourcedir', os.path.join(state.subdir, source_dir)] + cmd += ['--sourcedir', state.subdir] # Current dir pc = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True, cwd=state.environment.get_source_dir()) (stdout, _) = pc.communicate() if pc.returncode != 0: - mlog.log(mlog.bold('Warning:'), 'glib-compile-resources has failed to get the dependencies for {}'.format(cmd[1])) + mlog.warning('glib-compile-resources has failed to get the dependencies for {}'.format(cmd[1])) raise subprocess.CalledProcessError(pc.returncode, cmd) dep_files = stdout.split('\n')[:-1] @@ -154,6 +166,8 @@ class GnomeModule: return os.path.exists(os.path.join(state.environment.get_source_dir(), f)) missing_dep_files = [f for f in dep_files if not exists_in_srcdir(f)] + depends = [] + subdirs = [] for missing in missing_dep_files: found = False missing_basename = os.path.basename(missing) @@ -164,6 +178,7 @@ class GnomeModule: found = True dep_files.remove(missing) dep_files.append(dep) + subdirs.append(dep.subdir) break elif isinstance(dep, interpreter.CustomTargetHolder): if dep.held_object.get_basename() == missing_basename: @@ -174,6 +189,8 @@ class GnomeModule: is_built=True, subdir=dep.held_object.get_subdir(), fname=dep.held_object.get_basename())) + depends.append(dep.held_object) + subdirs.append(dep.held_object.get_subdir()) break if not found: @@ -183,7 +200,7 @@ class GnomeModule: 'gnome.compile_resources() using the "dependencies" ' 'keyword argument.' % (missing, input_file)) - return dep_files + return dep_files, depends, subdirs @staticmethod def _get_link_args(state, lib, depends=None): @@ -297,7 +314,7 @@ class GnomeModule: except Exception: global girwarning_printed if not girwarning_printed: - mlog.log(mlog.bold('Warning:'), 'gobject-introspection dependency was not found, disabling gir generation.') + mlog.warning('gobject-introspection dependency was not found, disabling gir generation.') girwarning_printed = True return [] pkgargs = pkgstr.decode().strip().split() diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 7556375..3ecb40d 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -34,7 +34,7 @@ class PkgConfigModule: return l.name # In other cases, we can't guarantee that the compiler will be able to # find the library via '-lfoo', so tell the user that. - mlog.log(mlog.red('WARNING:'), msg.format(l.name, 'name_prefix', l.name, pcfile)) + mlog.warning(msg.format(l.name, 'name_prefix', l.name, pcfile)) return l.name def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, @@ -79,7 +79,7 @@ class PkgConfigModule: # If using a custom suffix, the compiler may not be able to # find the library if l.name_suffix_set: - mlog.log(mlog.red('WARNING:'), msg.format(l.name, 'name_suffix', lname, pcfile)) + mlog.warning(msg.format(l.name, 'name_suffix', lname, pcfile)) yield '-l%s' % lname if len(libraries) > 0: ofile.write('Libs: {}\n'.format(' '.join(generate_libs_flags(libraries)))) diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py index 81a70fc..b1d951b 100644 --- a/mesonbuild/modules/qt4.py +++ b/mesonbuild/modules/qt4.py @@ -90,7 +90,7 @@ class Qt4Module(): result = [] for child in root[0]: if child.tag != 'file': - mlog.log("Warning, malformed rcc file: ", os.path.join(state.subdir, fname)) + mlog.warning("malformed rcc file: ", os.path.join(state.subdir, fname)) break else: result.append(os.path.join(state.subdir, relative_part, child.text)) @@ -150,6 +150,6 @@ class Qt4Module(): return sources def initialize(): - mlog.log('Warning, rcc dependencies will not work properly until this upstream issue is fixed:', - mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460')) + mlog.warning('rcc dependencies will not work properly until this upstream issue is fixed:', + mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460')) return Qt4Module() diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py index 4f19b78..9fffcff 100644 --- a/mesonbuild/modules/qt5.py +++ b/mesonbuild/modules/qt5.py @@ -97,7 +97,7 @@ class Qt5Module(): result = [] for child in root[0]: if child.tag != 'file': - mlog.log("Warning, malformed rcc file: ", os.path.join(state.subdir, fname)) + mlog.warning("malformed rcc file: ", os.path.join(state.subdir, fname)) break else: result.append(os.path.join(state.subdir, relative_part, child.text)) @@ -160,6 +160,6 @@ class Qt5Module(): return sources def initialize(): - mlog.log('Warning, rcc dependencies will not work reliably until this upstream issue is fixed:', - mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460')) + mlog.warning('rcc dependencies will not work reliably until this upstream issue is fixed:', + mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460')) return Qt5Module() diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py index 13aa20b..2c9ed57 100644 --- a/mesonbuild/modules/rpm.py +++ b/mesonbuild/modules/rpm.py @@ -63,8 +63,8 @@ class RPMModule: so_installed = True elif isinstance(target, build.StaticLibrary) and target.need_install: to_delete.add('%%{buildroot}%%{_libdir}/%s' % target.get_filename()) - mlog.log('Warning, removing', mlog.bold(target.get_filename()), - 'from package because packaging static libs not recommended') + mlog.warning('removing', mlog.bold(target.get_filename()), + 'from package because packaging static libs not recommended') elif isinstance(target, gnome.GirTarget) and target.should_install(): files_devel.add('%%{_datadir}/gir-1.0/%s' % target.get_filename()[0]) elif isinstance(target, gnome.TypelibTarget) and target.should_install(): @@ -94,14 +94,13 @@ class RPMModule: for compiler in compiler_deps: fn.write('BuildRequires: %s\n' % compiler) for dep in state.environment.coredata.deps: - fn.write('BuildRequires: pkgconfig(%s)\n' % dep) + fn.write('BuildRequires: pkgconfig(%s)\n' % dep[0]) for lib in state.environment.coredata.ext_libs.values(): fn.write('BuildRequires: %s # FIXME\n' % lib.fullpath) - mlog.log('Warning, replace', mlog.bold(lib.fullpath), - 'with real package.', - 'You can use following command to find package which ' - 'contains this lib:', - mlog.bold('dnf provides %s' % lib.fullpath)) + mlog.warning('replace', mlog.bold(lib.fullpath), 'with real package.', + 'You can use following command to find package which ' + 'contains this lib:', + mlog.bold('dnf provides %s' % lib.fullpath)) for prog in state.environment.coredata.ext_progs.values(): if not prog.found(): fn.write('BuildRequires: %{_bindir}/%s # FIXME\n' % diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py index ddf4943..e8e1077 100755 --- a/mesonbuild/scripts/regen_checker.py +++ b/mesonbuild/scripts/regen_checker.py @@ -52,7 +52,7 @@ def run(args): regeninfo = pickle.load(f) with open(coredata, 'rb') as f: coredata = pickle.load(f) - mesonscript = coredata.meson_script_file + mesonscript = coredata.meson_script_launcher backend = coredata.get_builtin_option('backend') regen_timestamp = os.stat(dumpfile).st_mtime if need_regen(regeninfo, regen_timestamp): diff --git a/mesonbuild/scripts/scanbuild.py b/mesonbuild/scripts/scanbuild.py index f13a1a4..dd74ce8 100644 --- a/mesonbuild/scripts/scanbuild.py +++ b/mesonbuild/scripts/scanbuild.py @@ -16,10 +16,10 @@ import subprocess import shutil import tempfile -def scanbuild(srcdir, blddir, privdir, logdir, args): +def scanbuild(exename, srcdir, blddir, privdir, logdir, args): with tempfile.TemporaryDirectory(dir=privdir) as scandir: - meson_cmd = ['scan-build'] + args - build_cmd = ['scan-build', '-o', logdir, 'ninja'] + meson_cmd = [exename] + args + build_cmd = [exename, '-o', logdir, 'ninja'] rc = subprocess.call(meson_cmd + [srcdir, scandir]) if rc != 0: return rc @@ -32,7 +32,8 @@ def run(args): privdir = os.path.join(blddir, 'meson-private') logdir = os.path.join(blddir, 'meson-logs/scanbuild') shutil.rmtree(logdir, ignore_errors=True) - if not shutil.which('scan-build'): - print('Scan-build not installed') + exename = os.environ.get('SCANBUILD', 'scan-build') + if not shutil.which(exename): + print('Scan-build not installed.') return 1 - return scanbuild(srcdir, blddir, privdir, logdir, meson_cmd) + return scanbuild(exename, srcdir, blddir, privdir, logdir, meson_cmd) diff --git a/mesonbuild/scripts/yelphelper.py b/mesonbuild/scripts/yelphelper.py index 00d713a..f33454d 100644 --- a/mesonbuild/scripts/yelphelper.py +++ b/mesonbuild/scripts/yelphelper.py @@ -75,7 +75,7 @@ def install_help(srcdir, blddir, sources, media, langs, install_dir, destdir, pr outfile = os.path.join(indir, m) if not os.path.exists(infile): if lang == 'C': - mlog.log(mlog.bold('Warning:'), 'Media file "%s" did not exist in C directory' %m) + mlog.warning('Media file "%s" did not exist in C directory' %m) elif symlinks: srcfile = os.path.join(c_install_dir, m) mlog.log('Symlinking %s to %s.' %(outfile, srcfile)) diff --git a/run_project_tests.py b/run_project_tests.py index 22e92b8..15d656b 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -326,6 +326,28 @@ def have_d_compiler(): return True return False +def have_java(): + if shutil.which('javac') and shutil.which('java'): + return True + return False + +def using_backend(backends): + if isinstance(backends, str): + backends = (backends,) + for backend in backends: + if backend == 'ninja': + if not backend_flags: + return True + elif backend == 'xcode': + if backend_flags == '--backend=xcode': + return True + elif backend == 'vs': + if backend_flags.startswith('--backend=vs'): + return True + else: + raise AssertionError('Unknown backend type: ' + backend) + return False + def detect_tests_to_run(): all_tests = [] all_tests.append(('common', gather_tests('test cases/common'), False)) @@ -338,15 +360,15 @@ def detect_tests_to_run(): all_tests.append(('platform-windows', gather_tests('test cases/windows'), False if mesonlib.is_windows() 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(('java', gather_tests('test cases/java'), False if not mesonlib.is_osx() and shutil.which('javac') else True)) - all_tests.append(('C#', gather_tests('test cases/csharp'), False if shutil.which('mcs') else True)) - all_tests.append(('vala', gather_tests('test cases/vala'), False if shutil.which('valac') else True)) - all_tests.append(('rust', gather_tests('test cases/rust'), False if shutil.which('rustc') else True)) - all_tests.append(('d', gather_tests('test cases/d'), False if have_d_compiler() else True)) - all_tests.append(('objective c', gather_tests('test cases/objc'), False if not mesonlib.is_windows() else True)) - all_tests.append(('fortran', gather_tests('test cases/fortran'), False if shutil.which('gfortran') else True)) - all_tests.append(('swift', gather_tests('test cases/swift'), False if shutil.which('swiftc') else True)) - all_tests.append(('python3', gather_tests('test cases/python3'), False if shutil.which('python3') 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)) + all_tests.append(('rust', gather_tests('test cases/rust'), False if using_backend('ninja') and shutil.which('rustc') else True)) + all_tests.append(('d', gather_tests('test cases/d'), False if using_backend('ninja') and have_d_compiler() else True)) + all_tests.append(('objective c', gather_tests('test cases/objc'), False if using_backend(('ninja', 'xcode')) and not mesonlib.is_windows() else True)) + all_tests.append(('fortran', gather_tests('test cases/fortran'), False if using_backend('ninja') and shutil.which('gfortran') else True)) + all_tests.append(('swift', gather_tests('test cases/swift'), False if using_backend(('ninja', 'xcode')) and shutil.which('swiftc') else True)) + all_tests.append(('python3', gather_tests('test cases/python3'), False if using_backend('ninja') and shutil.which('python3') else True)) return all_tests def run_tests(extra_args): @@ -379,7 +401,7 @@ def run_tests(extra_args): futures.append((testname, t, result)) for (testname, t, result) in futures: result = result.result() - if result is None: + if result is None or 'MESON_SKIP_TEST' in result.stdo: print('Skipping:', t) current_test = ET.SubElement(current_suite, 'testcase', {'name' : testname, 'classname' : name}) @@ -490,6 +512,21 @@ if __name__ == '__main__': options = parser.parse_args() setup_commands(options.backend) + # Appveyor sets the `platform` environment variable which completely messes + # up building with the vs2010 and vs2015 backends. + # + # Specifically, MSBuild reads the `platform` environment variable to set + # the configured value for the platform (Win32/x64/arm), which breaks x86 + # builds. + # + # Appveyor setting this also breaks our 'native build arch' detection for + # Windows in environment.py:detect_windows_arch() by overwriting the value + # of `platform` set by vcvarsall.bat. + # + # While building for x86, `platform` should be unset. + if 'APPVEYOR' in os.environ and os.environ['arch'] == 'x86': + os.environ.pop('platform') + script_dir = os.path.split(__file__)[0] if script_dir != '': os.chdir(script_dir) diff --git a/test cases/common/103 manygen/subdir/manygen.py b/test cases/common/103 manygen/subdir/manygen.py index 4fd2f25..8449dc3 100755 --- a/test cases/common/103 manygen/subdir/manygen.py +++ b/test cases/common/103 manygen/subdir/manygen.py @@ -9,6 +9,7 @@ import shutil, subprocess with open(sys.argv[1]) as f: funcname = f.readline().strip() outdir = sys.argv[2] +buildtype_args = sys.argv[3] if not os.path.isdir(outdir): print('Outdir does not exist.') @@ -67,7 +68,7 @@ with open(tmpc, 'w') as f: ''' % funcname) if is_vs: - subprocess.check_call([compiler, '/nologo', '/c', '/Fo' + outo, tmpc]) + subprocess.check_call([compiler, '/nologo', '/c', buildtype_args, '/Fo' + outo, tmpc]) else: subprocess.check_call([compiler, '-c', '-o', outo, tmpc]) diff --git a/test cases/common/103 manygen/subdir/meson.build b/test cases/common/103 manygen/subdir/meson.build index 5c5d763..3036899 100644 --- a/test cases/common/103 manygen/subdir/meson.build +++ b/test cases/common/103 manygen/subdir/meson.build @@ -1,6 +1,17 @@ gen = find_program('manygen.py') +buildtype = get_option('buildtype') +buildtype_args = '-Dfooxxx' # a useless compiler argument if meson.get_compiler('c').get_id() == 'msvc' + # We need our manually generated code to use the same CRT as the executable. + # Taken from compilers.py since build files do not have access to this. + if buildtype == 'debug' + buildtype_args = '/MDd' + elif buildtype == 'debugoptimized' + buildtype_args = '/MDd' + elif buildtype == 'release' + buildtype_args = '/MD' + endif outfiles = ['gen_func.lib', 'gen_func.c', 'gen_func.h', 'gen_func.o'] else outfiles = ['gen_func.a', 'gen_func.c', 'gen_func.h', 'gen_func.o'] @@ -9,5 +20,5 @@ endif generated = custom_target('manygen', output : outfiles, input : ['funcinfo.def'], - command : [gen, '@INPUT@', '@OUTDIR@'], + command : [gen, '@INPUT@', '@OUTDIR@', buildtype_args], ) diff --git a/test cases/common/111 has header symbol/meson.build b/test cases/common/111 has header symbol/meson.build index e0afb42..b5c865f 100644 --- a/test cases/common/111 has header symbol/meson.build +++ b/test cases/common/111 has header symbol/meson.build @@ -1,18 +1,32 @@ -project('has header symbol', 'c') +project('has header symbol', 'c', 'cpp') cc = meson.get_compiler('c') +cpp = meson.get_compiler('cpp') -assert (cc.has_header_symbol('stdio.h', 'int'), 'base types should always be available') -assert (cc.has_header_symbol('stdio.h', 'printf'), 'printf function not found') -assert (cc.has_header_symbol('stdio.h', 'FILE'), 'FILE structure not found') -assert (cc.has_header_symbol('limits.h', 'INT_MAX'), 'INT_MAX define not found') -assert (not cc.has_header_symbol('limits.h', 'guint64'), 'guint64 is not defined in limits.h') -assert (not cc.has_header_symbol('stdlib.h', 'FILE'), 'FILE structure is defined in stdio.h, not stdlib.h') -assert (not cc.has_header_symbol('stdlol.h', 'printf'), 'stdlol.h shouldn\'t exist') -assert (not cc.has_header_symbol('stdlol.h', 'int'), 'shouldn\'t be able to find "int" with invalid header') +foreach comp : [cc, cpp] + assert (comp.has_header_symbol('stdio.h', 'int'), 'base types should always be available') + assert (comp.has_header_symbol('stdio.h', 'printf'), 'printf function not found') + assert (comp.has_header_symbol('stdio.h', 'FILE'), 'FILE structure not found') + assert (comp.has_header_symbol('limits.h', 'INT_MAX'), 'INT_MAX define not found') + assert (not comp.has_header_symbol('limits.h', 'guint64'), 'guint64 is not defined in limits.h') + assert (not comp.has_header_symbol('stdlib.h', 'FILE'), 'FILE structure is defined in stdio.h, not stdlib.h') + assert (not comp.has_header_symbol('stdlol.h', 'printf'), 'stdlol.h shouldn\'t exist') + assert (not comp.has_header_symbol('stdlol.h', 'int'), 'shouldn\'t be able to find "int" with invalid header') +endforeach # This is likely only available on Glibc, so just test for it if cc.has_function('ppoll') assert (not cc.has_header_symbol('poll.h', 'ppoll'), 'ppoll should not be accessible without _GNU_SOURCE') assert (cc.has_header_symbol('poll.h', 'ppoll', prefix : '#define _GNU_SOURCE'), 'ppoll should be accessible with _GNU_SOURCE') endif + +assert (cpp.has_header_symbol('iostream', 'std::iostream'), 'iostream not found in iostream.h') +assert (cpp.has_header_symbol('vector', 'std::vector'), 'vector not found in vector.h') +assert (not cpp.has_header_symbol('limits.h', 'std::iostream'), 'iostream should not be defined in limits.h') + +boost = dependency('boost', required : false) +if boost.found() + assert (cpp.has_header_symbol('boost/math/quaternion.hpp', 'boost::math::quaternion', dependencies : boost), 'quaternion not found') +else + assert (not cpp.has_header_symbol('boost/math/quaternion.hpp', 'boost::math::quaternion', dependencies : boost), 'quaternion found?!') +endif diff --git a/test cases/common/113 generatorcustom/meson.build b/test cases/common/113 generatorcustom/meson.build index 1f4cc88..472d565 100644 --- a/test cases/common/113 generatorcustom/meson.build +++ b/test cases/common/113 generatorcustom/meson.build @@ -1,17 +1,21 @@ project('generatorcustom', 'c') -creator = find_program('gen.py') -catter = find_program('catter.py') +if meson.get_compiler('c').get_id() != 'msvc' + creator = find_program('gen.py') + catter = find_program('catter.py') -gen = generator(creator, - output: '@BASENAME@.h', - arguments : ['@INPUT@', '@OUTPUT@']) + gen = generator(creator, + output: '@BASENAME@.h', + arguments : ['@INPUT@', '@OUTPUT@']) -hs = gen.process('res1.txt', 'res2.txt') + hs = gen.process('res1.txt', 'res2.txt') -allinone = custom_target('alltogether', - input : hs, - output : 'alltogether.h', - command : [catter, '@INPUT@', '@OUTPUT@']) + allinone = custom_target('alltogether', + input : hs, + output : 'alltogether.h', + command : [catter, '@INPUT@', '@OUTPUT@']) -executable('proggie', 'main.c', allinone) + executable('proggie', 'main.c', allinone) +else + error('MESON_SKIP_TEST: Skipping test on VS backend; see: https://github.com/mesonbuild/meson/issues/1004') +endif diff --git a/test cases/common/121 skip/meson.build b/test cases/common/121 skip/meson.build new file mode 100644 index 0000000..1adedb6 --- /dev/null +++ b/test cases/common/121 skip/meson.build @@ -0,0 +1,4 @@ +project('skip', 'c') + +error('MESON_SKIP_TEST this test is always skipped.') + diff --git a/test cases/common/16 configure file/config.h b/test cases/common/16 configure file/config.h new file mode 100644 index 0000000..e85b634 --- /dev/null +++ b/test cases/common/16 configure file/config.h @@ -0,0 +1 @@ +#error "This file should not be included. Build dir must become before source dir in search order" diff --git a/test cases/common/16 configure file/prog.c b/test cases/common/16 configure file/prog.c index 718a402..89a718e 100644 --- a/test cases/common/16 configure file/prog.c +++ b/test cases/common/16 configure file/prog.c @@ -1,5 +1,8 @@ #include <string.h> -#include "config.h" +/* config.h must not be in quotes: + * https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html + */ +#include <config.h> #ifdef SHOULD_BE_UNDEF #error "FAIL!" diff --git a/test cases/common/16 configure file/prog2.c b/test cases/common/16 configure file/prog2.c index be85033..a88c70f 100644 --- a/test cases/common/16 configure file/prog2.c +++ b/test cases/common/16 configure file/prog2.c @@ -1,4 +1,4 @@ -#include"config2.h" +#include<config2.h> int main(int argc, char **argv) { return ZERO_RESULT; diff --git a/test cases/common/33 try compile/meson.build b/test cases/common/33 try compile/meson.build index bca82ce..09ca395 100644 --- a/test cases/common/33 try compile/meson.build +++ b/test cases/common/33 try compile/meson.build @@ -1,4 +1,4 @@ -project('try compile', 'c') +project('try compile', 'c', 'cpp') code = '''#include<stdio.h> void func() { printf("Something.\n"); } @@ -8,19 +8,20 @@ breakcode = '''#include<nonexisting.h> void func() { printf("This won't work.\n"); } ''' -compiler = meson.get_compiler('c') -if compiler.compiles(code, name : 'should succeed') == false - error('Compiler is fail.') -endif +foreach compiler : [meson.get_compiler('c'), meson.get_compiler('cpp')] + if compiler.compiles(code, name : 'should succeed') == false + error('Compiler ' + compiler.get_id() + ' is fail.') + endif -if compiler.compiles(files('valid.c'), name : 'should succeed') == false - error('Compiler is fail.') -endif + if compiler.compiles(files('valid.c'), name : 'should succeed') == false + error('Compiler ' + compiler.get_id() + ' is fail.') + endif -if compiler.compiles(breakcode, name : 'should fail') - error('Compiler returned true on broken code.') -endif + if compiler.compiles(breakcode, name : 'should fail') + error('Compiler ' + compiler.get_id() + ' returned true on broken code.') + endif -if compiler.compiles(files('invalid.c'), name : 'should fail') - error('Compiler returned true on broken code.') -endif + if compiler.compiles(files('invalid.c'), name : 'should fail') + error('Compiler ' + compiler.get_id() + ' returned true on broken code.') + endif +endforeach diff --git a/test cases/common/35 sizeof/meson.build b/test cases/common/35 sizeof/meson.build index 4a0398b..9de5b78 100644 --- a/test cases/common/35 sizeof/meson.build +++ b/test cases/common/35 sizeof/meson.build @@ -1,13 +1,33 @@ -project('sizeof', 'c') +project('sizeof', 'c', 'cpp') +# Test with C cc = meson.get_compiler('c') + intsize = cc.sizeof('int') wcharsize = cc.sizeof('wchar_t', prefix : '#include<wchar.h>') cd = configuration_data() cd.set('INTSIZE', intsize) cd.set('WCHARSIZE', wcharsize) +cd.set('CONFIG', 'config.h') configure_file(input : 'config.h.in', output : 'config.h', configuration : cd) +s = configure_file(input : 'prog.c.in', output : 'prog.c', configuration : cd) -e = executable('prog', 'prog.c') +e = executable('prog', s) test('sizeof test', e) + +# Test with C++ +cpp = meson.get_compiler('cpp') + +intsize = cpp.sizeof('int') +wcharsize = cpp.sizeof('wchar_t', prefix : '#include<wchar.h>') + +cdpp = configuration_data() +cdpp.set('INTSIZE', intsize) +cdpp.set('WCHARSIZE', wcharsize) +cdpp.set('CONFIG', 'config.hpp') +configure_file(input : 'config.h.in', output : 'config.hpp', configuration : cdpp) +spp = configure_file(input : 'prog.c.in', output : 'prog.cc', configuration : cdpp) + +epp = executable('progpp', spp) +test('sizeof test c++', epp) diff --git a/test cases/common/35 sizeof/prog.c b/test cases/common/35 sizeof/prog.c.in index 9164c18..85b1229 100644 --- a/test cases/common/35 sizeof/prog.c +++ b/test cases/common/35 sizeof/prog.c.in @@ -1,6 +1,6 @@ -#include"config.h" -#include<stdio.h> -#include<wchar.h> +#include "@CONFIG@" +#include <stdio.h> +#include <wchar.h> int main(int argc, char **argv) { if(INTSIZE != sizeof(int)) { diff --git a/test cases/common/37 has header/meson.build b/test cases/common/37 has header/meson.build index bbfce6d..ce6e71a 100644 --- a/test cases/common/37 has header/meson.build +++ b/test cases/common/37 has header/meson.build @@ -1,11 +1,11 @@ -project('has header', 'c') +project('has header', 'c', 'cpp') -cc = meson.get_compiler('c') +foreach comp : [meson.get_compiler('c'), meson.get_compiler('cpp')] + if comp.has_header('stdio.h') == false + error('Stdio missing.') + endif -if cc.has_header('stdio.h') == false - error('Stdio missing.') -endif - -if cc.has_header('ouagadougou.h') - error('Found non-existant header.') -endif + if comp.has_header('ouagadougou.h') + error('Found non-existant header.') + endif +endforeach diff --git a/test cases/common/39 tryrun/meson.build b/test cases/common/39 tryrun/meson.build index f5d07ab..c64446f 100644 --- a/test cases/common/39 tryrun/meson.build +++ b/test cases/common/39 tryrun/meson.build @@ -1,14 +1,14 @@ -project('tryrun', 'c') +project('tryrun', 'c', 'cpp') # Complex to exercise all code paths. if meson.is_cross_build() if meson.has_exe_wrapper() - cc = meson.get_compiler('c', native : false) + compilers = [meson.get_compiler('c', native : false), meson.get_compiler('cpp', native : false)] else - cc = meson.get_compiler('c', native : true) + compilers = [meson.get_compiler('c', native : true), meson.get_compiler('cpp', native : true)] endif else - cc = meson.get_compiler('c') + compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] endif ok_code = '''#include<stdio.h> @@ -32,45 +32,47 @@ INPUTS = [ ['File', files('ok.c'), files('error.c'), files('no_compile.c')], ] -foreach input : INPUTS - type = input[0] - ok = cc.run(input[1], name : type + ' should succeed') - err = cc.run(input[2], name : type + ' should fail') - noc = cc.run(input[3], name : type + ' does not compile') +foreach cc : compilers + foreach input : INPUTS + type = input[0] + ok = cc.run(input[1], name : type + ' should succeed') + err = cc.run(input[2], name : type + ' should fail') + noc = cc.run(input[3], name : type + ' does not compile') - if noc.compiled() - error(type + ' compilation fail test failed.') - else - message(type + ' fail detected properly.') - endif + if noc.compiled() + error(type + ' compilation fail test failed.') + else + message(type + ' fail detected properly.') + endif - if ok.compiled() - message(type + ' compilation worked.') - else - error(type + ' compilation did not work.') - endif + if ok.compiled() + message(type + ' compilation worked.') + else + error(type + ' compilation did not work.') + endif - if ok.returncode() == 0 - message(type + ' return code ok.') - else - error(type + ' return code fail') - endif + if ok.returncode() == 0 + message(type + ' return code ok.') + else + error(type + ' return code fail') + endif - if err.returncode() == 1 - message(type + ' bad return code ok.') - else - error(type + ' bad return code fail.') - endif + if err.returncode() == 1 + message(type + ' bad return code ok.') + else + error(type + ' bad return code fail.') + endif - if ok.stdout().strip() == 'stdout' - message(type + ' stdout ok.') - else - message(type + ' bad stdout.') - endif + if ok.stdout().strip() == 'stdout' + message(type + ' stdout ok.') + else + message(type + ' bad stdout.') + endif - if ok.stderr().strip() == 'stderr' - message(type + ' stderr ok.') - else - message(type + ' bad stderr.') - endif + if ok.stderr().strip() == 'stderr' + message(type + ' stderr ok.') + else + message(type + ' bad stderr.') + endif + endforeach endforeach diff --git a/test cases/common/43 has function/meson.build b/test cases/common/43 has function/meson.build index 00ca640..61f96e1 100644 --- a/test cases/common/43 has function/meson.build +++ b/test cases/common/43 has function/meson.build @@ -1,41 +1,43 @@ -project('has function', 'c') +project('has function', 'c', 'cpp') -cc = meson.get_compiler('c') +compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] -if not cc.has_function('printf', prefix : '#include<stdio.h>') - error('"printf" function not found (should always exist).') -endif +foreach cc : compilers + if not cc.has_function('printf', prefix : '#include<stdio.h>') + error('"printf" function not found (should always exist).') + endif -# Should also be able to detect it without specifying the header -# We check for a different function here to make sure the result is -# not taken from a cache (ie. the check above) -# On MSVC fprintf is defined as an inline function in the header, so it cannot -# be found without the include. -if cc.get_id() != 'msvc' - assert(cc.has_function('fprintf'), '"fprintf" function not found without include (on !msvc).') -else - assert(cc.has_function('fprintf', prefix : '#include <stdio.h>'), '"fprintf" function not found with include (on msvc).') -endif + # Should also be able to detect it without specifying the header + # We check for a different function here to make sure the result is + # not taken from a cache (ie. the check above) + # On MSVC fprintf is defined as an inline function in the header, so it cannot + # be found without the include. + if cc.get_id() != 'msvc' + assert(cc.has_function('fprintf'), '"fprintf" function not found without include (on !msvc).') + else + assert(cc.has_function('fprintf', prefix : '#include <stdio.h>'), '"fprintf" function not found with include (on msvc).') + endif -if cc.has_function('hfkerhisadf', prefix : '#include<stdio.h>') - error('Found non-existent function "hfkerhisadf".') -endif + if cc.has_function('hfkerhisadf', prefix : '#include<stdio.h>') + error('Found non-existent function "hfkerhisadf".') + endif -# With glibc on Linux lchmod is a stub that will always return an error, -# we want to detect that and declare that the function is not available. -# We can't check for the C library used here of course, but if it's not -# implemented in glibc it's probably not implemented in any other 'slimmer' -# C library variants either, so the check should be safe either way hopefully. -if host_machine.system() == 'linux' and cc.get_id() == 'gcc' - assert (cc.has_function('poll', prefix : '#include <poll.h>'), 'couldn\'t detect "poll" when defined by a header') - assert (not cc.has_function('lchmod', prefix : '''#include <sys/stat.h> - #include <unistd.h>'''), '"lchmod" check should have failed') -endif + # With glibc on Linux lchmod is a stub that will always return an error, + # we want to detect that and declare that the function is not available. + # We can't check for the C library used here of course, but if it's not + # implemented in glibc it's probably not implemented in any other 'slimmer' + # C library variants either, so the check should be safe either way hopefully. + if host_machine.system() == 'linux' and cc.get_id() == 'gcc' + assert (cc.has_function('poll', prefix : '#include <poll.h>'), 'couldn\'t detect "poll" when defined by a header') + assert (not cc.has_function('lchmod', prefix : '''#include <sys/stat.h> + #include <unistd.h>'''), '"lchmod" check should have failed') + endif -# For some functions one needs to define _GNU_SOURCE before including the -# right headers to get them picked up. Make sure we can detect these functions -# as well without any prefix -if cc.has_header_symbol('sys/socket.h', 'recvmmsg', prefix : '#define _GNU_SOURCE') - # We assume that if recvmmsg exists sendmmsg does too - assert (cc.has_function('sendmmsg'), 'Failed to detect function "sendmmsg" (should always exist).') -endif + # For some functions one needs to define _GNU_SOURCE before including the + # right headers to get them picked up. Make sure we can detect these functions + # as well without any prefix + if cc.has_header_symbol('sys/socket.h', 'recvmmsg', prefix : '#define _GNU_SOURCE') + # We assume that if recvmmsg exists sendmmsg does too + assert (cc.has_function('sendmmsg'), 'Failed to detect function "sendmmsg" (should always exist).') + endif +endforeach diff --git a/test cases/common/44 has member/meson.build b/test cases/common/44 has member/meson.build index e60aeb3..4e61956 100644 --- a/test cases/common/44 has member/meson.build +++ b/test cases/common/44 has member/meson.build @@ -1,19 +1,21 @@ -project('has member', 'c') +project('has member', 'c', 'cpp') -cc = meson.get_compiler('c') +compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] -if not cc.has_member('struct tm', 'tm_sec', prefix : '#include<time.h>') - error('Did not detect member of "struct tm" that exists: "tm_sec"') -endif +foreach cc : compilers + if not cc.has_member('struct tm', 'tm_sec', prefix : '#include<time.h>') + error('Did not detect member of "struct tm" that exists: "tm_sec"') + endif -if cc.has_member('struct tm', 'tm_nonexistent', prefix : '#include<time.h>') - error('Not existing member "tm_nonexistent" found.') -endif + if cc.has_member('struct tm', 'tm_nonexistent', prefix : '#include<time.h>') + error('Not existing member "tm_nonexistent" found.') + endif -if not cc.has_members('struct tm', 'tm_sec', 'tm_min', prefix : '#include<time.h>') - error('Did not detect members of "struct tm" that exist: "tm_sec" "tm_min"') -endif + if not cc.has_members('struct tm', 'tm_sec', 'tm_min', prefix : '#include<time.h>') + error('Did not detect members of "struct tm" that exist: "tm_sec" "tm_min"') + endif -if cc.has_members('struct tm', 'tm_sec', 'tm_nonexistent2', prefix : '#include<time.h>') - error('Not existing member "tm_nonexistent2" found.') -endif + if cc.has_members('struct tm', 'tm_sec', 'tm_nonexistent2', prefix : '#include<time.h>') + error('Not existing member "tm_nonexistent2" found.') + endif +endforeach diff --git a/test cases/common/45 alignment/meson.build b/test cases/common/45 alignment/meson.build index 2ec3f89..a9bd65b 100644 --- a/test cases/common/45 alignment/meson.build +++ b/test cases/common/45 alignment/meson.build @@ -1,29 +1,31 @@ -project('alignment', 'c') +project('alignment', 'c', 'cpp') -cc = meson.get_compiler('c') +compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] -# These tests should return the same value on all -# platforms. If (and when) they don't, fix 'em up. -if cc.alignment('char') != 1 - error('Alignment of char misdetected.') -endif +foreach cc : compilers + # These tests should return the same value on all + # platforms. If (and when) they don't, fix 'em up. + if cc.alignment('char') != 1 + error('Alignment of char misdetected.') + endif -ptr_size = cc.sizeof('void*') -dbl_alignment = cc.alignment('double') + ptr_size = cc.sizeof('void*') + dbl_alignment = cc.alignment('double') -# These tests are not thorough. Doing this properly -# would take a lot of work because it is strongly -# platform and compiler dependent. So just check -# that they produce something fairly sane. + # These tests are not thorough. Doing this properly + # would take a lot of work because it is strongly + # platform and compiler dependent. So just check + # that they produce something fairly sane. -if ptr_size == 8 or ptr_size == 4 - message('Size of ptr ok.') -else - error('Size of ptr misdetected.') -endif + if ptr_size == 8 or ptr_size == 4 + message('Size of ptr ok.') + else + error('Size of ptr misdetected.') + endif -if dbl_alignment == 8 or dbl_alignment == 4 - message('Alignment of double ok.') -else - error('Alignment of double misdetected.') -endif + if dbl_alignment == 8 or dbl_alignment == 4 + message('Alignment of double ok.') + else + error('Alignment of double misdetected.') + endif +endforeach diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build index fa9439c..0933238 100644 --- a/test cases/common/51 pkgconfig-gen/meson.build +++ b/test cases/common/51 pkgconfig-gen/meson.build @@ -19,7 +19,7 @@ pkgg.generate( ) pkgconfig = find_program('pkg-config', required: false) -if pkgconfig.found() +if pkgconfig.found() and build_machine.system() != 'windows' test('pkgconfig-validation', pkgconfig, args: ['--validate', 'simple'], env: ['PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' ], diff --git a/test cases/common/56 custom target/meson.build b/test cases/common/56 custom target/meson.build index e216bae..feaa762 100644 --- a/test cases/common/56 custom target/meson.build +++ b/test cases/common/56 custom target/meson.build @@ -9,7 +9,7 @@ comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py') mytarget = custom_target('bindat', output : 'data.dat', input : 'data_source.txt', -command : [python, comp, '@INPUT@', '@OUTPUT@'], +command : [python, comp, '--input=@INPUT@', '--output=@OUTPUT@'], install : true, install_dir : 'subdir' ) diff --git a/test cases/common/56 custom target/my_compiler.py b/test cases/common/56 custom target/my_compiler.py index d99029b..4ba2da6 100755 --- a/test cases/common/56 custom target/my_compiler.py +++ b/test cases/common/56 custom target/my_compiler.py @@ -3,13 +3,14 @@ import sys if __name__ == '__main__': - if len(sys.argv) != 3: - print(sys.argv[0], 'input_file output_file') + if len(sys.argv) != 3 or not sys.argv[1].startswith('--input') or \ + not sys.argv[2].startswith('--output'): + print(sys.argv[0], '--input=input_file --output=output_file') sys.exit(1) - with open(sys.argv[1]) as f: + with open(sys.argv[1].split('=')[1]) as f: ifile = f.read() if ifile != 'This is a text only input file.\n': print('Malformed input') sys.exit(1) - with open(sys.argv[2], 'w') as ofile: + with open(sys.argv[2].split('=')[1], 'w') as ofile: ofile.write('This is a binary output file.\n') diff --git a/test cases/common/62 exe static shared/stat.c b/test cases/common/62 exe static shared/stat.c index 4eceb30..680ed92 100644 --- a/test cases/common/62 exe static shared/stat.c +++ b/test cases/common/62 exe static shared/stat.c @@ -1,5 +1,7 @@ +#include "subdir/exports.h" + int shlibfunc(); -int statlibfunc() { +int DLL_PUBLIC statlibfunc() { return shlibfunc(); } diff --git a/test cases/common/83 has type/meson.build b/test cases/common/83 has type/meson.build index 002f150..de8dbc8 100644 --- a/test cases/common/83 has type/meson.build +++ b/test cases/common/83 has type/meson.build @@ -1,11 +1,13 @@ -project('has type', 'c') +project('has type', 'c', 'cpp') -cc = meson.get_compiler('c') +compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] -if not cc.has_type('time_t', prefix : '#include<time.h>') - error('Did not detect type that exists.') -endif +foreach cc : compilers + if not cc.has_type('time_t', prefix : '#include<time.h>') + error('Did not detect type that exists.') + endif -if cc.has_type('no_time_t', prefix : '#include<time.h>') - error('Not existing type found.') -endif + if cc.has_type('no_time_t', prefix : '#include<time.h>') + error('Not existing type found.') + endif +endforeach diff --git a/test cases/frameworks/10 gtk-doc/meson.build b/test cases/frameworks/10 gtk-doc/meson.build index c6881ab..95eeefa 100644 --- a/test cases/frameworks/10 gtk-doc/meson.build +++ b/test cases/frameworks/10 gtk-doc/meson.build @@ -8,4 +8,6 @@ inc = include_directories('include') # We have to disable this test until this bug fix has landed to # distros https://bugzilla.gnome.org/show_bug.cgi?id=753145 -# subdir('doc') +error('MESON_SKIP_TEST can not enable gtk-doc test until upstream fixes have landed.') + +subdir('doc') diff --git a/test cases/python3/3 cython/meson.build b/test cases/python3/3 cython/meson.build index cd245c7..8729640 100644 --- a/test cases/python3/3 cython/meson.build +++ b/test cases/python3/3 cython/meson.build @@ -13,5 +13,5 @@ if cython.found() env : ['PYTHONPATH=' + pydir] ) else - message('Cython not found, skipping test.') + error('MESON_SKIP_TEST: Cython not found, skipping test.') endif |