meson-0.40.1/0000755000175000017500000000000013100703045014300 5ustar jpakkanejpakkane00000000000000meson-0.40.1/syntax-highlighting/0000755000175000017500000000000013100703042020266 5ustar jpakkanejpakkane00000000000000meson-0.40.1/syntax-highlighting/vim/0000755000175000017500000000000013100703042021061 5ustar jpakkanejpakkane00000000000000meson-0.40.1/syntax-highlighting/vim/ftdetect/0000755000175000017500000000000013100703042022663 5ustar jpakkanejpakkane00000000000000meson-0.40.1/syntax-highlighting/vim/ftdetect/meson.vim0000644000175000017500000000016013016624375024537 0ustar jpakkanejpakkane00000000000000au BufNewFile,BufRead meson.build set filetype=meson au BufNewFile,BufRead meson_options.txt set filetype=meson meson-0.40.1/syntax-highlighting/vim/indent/0000755000175000017500000000000013100703042022342 5ustar jpakkanejpakkane00000000000000meson-0.40.1/syntax-highlighting/vim/indent/meson.vim0000644000175000017500000001230413031276647024223 0ustar jpakkanejpakkane00000000000000" Vim indent file " Language: Meson " Maintainer: Nirbheek Chauhan " Original Authors: David Bustos " Bram Moolenaar " Last Change: 2015 Feb 23 " Only load this indent file when no other was loaded. if exists("b:did_indent") finish endif let b:did_indent = 1 " Some preliminary settings setlocal nolisp " Make sure lisp indenting doesn't supersede us setlocal autoindent " indentexpr isn't much help otherwise setlocal indentexpr=GetMesonIndent(v:lnum) setlocal indentkeys+==elif,=else,=endforeach,=endif,0) " Only define the function once. if exists("*GetMesonIndent") finish endif let s:keepcpo= &cpo setlocal cpo&vim " Come here when loading the script the first time. let s:maxoff = 50 " maximum number of lines to look backwards for () " Force sw=2 sts=2 because that's required by convention setlocal shiftwidth=2 setlocal softtabstop=2 function GetMesonIndent(lnum) echom getline(line(".")) " If this line is explicitly joined: If the previous line was also joined, " line it up with that one, otherwise add two 'shiftwidth' if getline(a:lnum - 1) =~ '\\$' if a:lnum > 1 && getline(a:lnum - 2) =~ '\\$' return indent(a:lnum - 1) endif return indent(a:lnum - 1) + (exists("g:mesonindent_continue") ? eval(g:mesonindent_continue) : (shiftwidth() * 2)) endif " If the start of the line is in a string don't change the indent. if has('syntax_items') \ && synIDattr(synID(a:lnum, 1, 1), "name") =~ "String$" return -1 endif " Search backwards for the previous non-empty line. let plnum = prevnonblank(v:lnum - 1) if plnum == 0 " This is the first non-empty line, use zero indent. return 0 endif " If the previous line is inside parenthesis, use the indent of the starting " line. " Trick: use the non-existing "dummy" variable to break out of the loop when " going too far back. call cursor(plnum, 1) let parlnum = searchpair('(\|{\|\[', '', ')\|}\|\]', 'nbW', \ "line('.') < " . (plnum - s:maxoff) . " ? dummy :" \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" \ . " =~ '\\(Comment\\|Todo\\|String\\)$'") if parlnum > 0 let plindent = indent(parlnum) let plnumstart = parlnum else let plindent = indent(plnum) let plnumstart = plnum endif " When inside parenthesis: If at the first line below the parenthesis add " two 'shiftwidth', otherwise same as previous line. " i = (a " + b " + c) call cursor(a:lnum, 1) let p = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" \ . " =~ '\\(Comment\\|Todo\\|String\\)$'") if p > 0 if p == plnum " When the start is inside parenthesis, only indent one 'shiftwidth'. let pp = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" \ . " =~ '\\(Comment\\|Todo\\|String\\)$'") if pp > 0 return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth()) endif return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (shiftwidth() * 2)) endif if plnumstart == p return indent(plnum) endif return plindent endif " Get the line and remove a trailing comment. " Use syntax highlighting attributes when possible. let pline = getline(plnum) let pline_len = strlen(pline) if has('syntax_items') " If the last character in the line is a comment, do a binary search for " the start of the comment. synID() is slow, a linear search would take " too long on a long line. if synIDattr(synID(plnum, pline_len, 1), "name") =~ "\\(Comment\\|Todo\\)$" let min = 1 let max = pline_len while min < max let col = (min + max) / 2 if synIDattr(synID(plnum, col, 1), "name") =~ "\\(Comment\\|Todo\\)$" let max = col else let min = col + 1 endif endwhile let pline = strpart(pline, 0, min - 1) endif else let col = 0 while col < pline_len if pline[col] == '#' let pline = strpart(pline, 0, col) break endif let col = col + 1 endwhile endif " If the previous line ended the conditional/loop if getline(plnum) =~ '^\s*\(endif\|endforeach\)\>\s*' " Maintain indent return -1 endif " If the previous line ended with a builtin, indent this line if pline =~ '^\s*\(foreach\|if\|else\|elif\)\>\s*' return plindent + shiftwidth() endif " If the current line begins with a header keyword, deindent if getline(a:lnum) =~ '^\s*\(else\|elif\|endif\|endforeach\)' " Unless the previous line was a one-liner if getline(plnumstart) =~ '^\s*\(foreach\|if\)\>\s*' return plindent endif " Or the user has already dedented if indent(a:lnum) <= plindent - shiftwidth() return -1 endif return plindent - shiftwidth() endif " When after a () construct we probably want to go back to the start line. " a = (b " + c) " here if parlnum > 0 return plindent endif return -1 endfunction let &cpo = s:keepcpo unlet s:keepcpo " vim:sw=2 meson-0.40.1/syntax-highlighting/vim/syntax/0000755000175000017500000000000013100703042022407 5ustar jpakkanejpakkane00000000000000meson-0.40.1/syntax-highlighting/vim/syntax/meson.vim0000644000175000017500000000764613055371450024277 0ustar jpakkanejpakkane00000000000000" Vim syntax file " Language: Meson " Maintainer: Nirbheek Chauhan " Last Change: 2016 Dec 7 " Credits: Zvezdan Petkovic " Neil Schemenauer " Dmitry Vasiliev " " This version is copied and edited from python.vim " It's very basic, and doesn't do many things I'd like it to " For instance, it should show errors for syntax that is valid in " Python but not in Meson. " " Optional highlighting can be controlled using these variables. " " let meson_space_error_highlight = 1 " " For version 5.x: Clear all syntax items. " For version 6.x: Quit when a syntax file was already loaded. if version < 600 syntax clear elseif exists("b:current_syntax") finish endif " We need nocompatible mode in order to continue lines with backslashes. " Original setting will be restored. let s:cpo_save = &cpo setlocal cpo&vim " https://github.com/mesonbuild/meson/wiki/Syntax syn keyword mesonConditional elif else if endif syn keyword mesonRepeat foreach endforeach syn keyword mesonOperator and not or syn match mesonComment "#.*$" contains=mesonTodo,@Spell syn keyword mesonTodo FIXME NOTE NOTES TODO XXX contained " Strings can either be single quoted or triple counted across multiple lines, " but always with a ' syn region mesonString \ start="\z('\)" end="\z1" skip="\\\\\|\\\z1" \ contains=mesonEscape,@Spell syn region mesonString \ start="\z('''\)" end="\z1" keepend \ contains=mesonEscape,mesonSpaceError,@Spell syn match mesonEscape "\\[abfnrtv'\\]" contained syn match mesonEscape "\\\o\{1,3}" contained syn match mesonEscape "\\x\x\{2}" contained syn match mesonEscape "\%(\\u\x\{4}\|\\U\x\{8}\)" contained " Meson allows case-insensitive Unicode IDs: http://www.unicode.org/charts/ syn match mesonEscape "\\N{\a\+\%(\s\a\+\)*}" contained syn match mesonEscape "\\$" " Meson only supports integer numbers " https://github.com/mesonbuild/meson/wiki/Syntax#numbers syn match mesonNumber "\<\d\+\>" " booleans syn keyword mesonConstant false true " Built-in functions syn keyword mesonBuiltin \ add_global_arguments \ add_global_link_arguments \ add_languages \ add_project_arguments \ add_project_link_arguments \ add_test_setup \ benchmark \ build_machine \ build_target \ configuration_data \ configure_file \ custom_target \ declare_dependency \ dependency \ environment \ error \ executable \ files \ find_library \ find_program \ generator \ get_option \ get_variable \ gettext \ host_machine \ import \ include_directories \ install_data \ install_headers \ install_man \ install_subdir \ is_variable \ jar \ join_paths \ library \ meson \ message \ project \ run_command \ run_target \ set_variable \ shared_library \ shared_module \ static_library \ subdir \ subproject \ target_machine \ test \ vcs_tag if exists("meson_space_error_highlight") " trailing whitespace syn match mesonSpaceError display excludenl "\s\+$" " mixed tabs and spaces syn match mesonSpaceError display " \+\t" syn match mesonSpaceError display "\t\+ " endif if version >= 508 || !exists("did_meson_syn_inits") if version <= 508 let did_meson_syn_inits = 1 command -nargs=+ HiLink hi link else command -nargs=+ HiLink hi def link endif " The default highlight links. Can be overridden later. HiLink mesonStatement Statement HiLink mesonConditional Conditional HiLink mesonRepeat Repeat HiLink mesonOperator Operator HiLink mesonComment Comment HiLink mesonTodo Todo HiLink mesonString String HiLink mesonEscape Special HiLink mesonNumber Number HiLink mesonBuiltin Function HiLink mesonConstant Number if exists("meson_space_error_highlight") HiLink mesonSpaceError Error endif delcommand HiLink endif let b:current_syntax = "meson" let &cpo = s:cpo_save unlet s:cpo_save " vim:set sw=2 sts=2 ts=8 noet: meson-0.40.1/syntax-highlighting/vim/README0000644000175000017500000000013713016624375021763 0ustar jpakkanejpakkane00000000000000ftdetect sets the filetype syntax does Meson syntax highlighting plugin does Meson indentation meson-0.40.1/PKG-INFO0000644000175000017500000000206013100703045015373 0ustar jpakkanejpakkane00000000000000Metadata-Version: 1.1 Name: meson Version: 0.40.1 Summary: A high performance build system Home-page: http://mesonbuild.com Author: Jussi Pakkanen Author-email: jpakkane@gmail.com License: Apache License, Version 2.0 Description: Meson is a cross-platform build system designed to be both as fast and as user friendly as possible. It supports many languages and compilers, including GCC, Clang and Visual Studio. Its build definitions are written in a simple non-turing complete DSL. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Apache Software License Classifier: Natural Language :: English Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX :: BSD Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python :: 3 :: Only Classifier: Topic :: Software Development :: Build Tools meson-0.40.1/run_cross_test.py0000755000175000017500000000340213026303756017744 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Copyright 2013-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. '''Runs the basic test suite through a cross compiler. Not part of the main test suite because of two reasons: 1) setup of the cross build is platform specific 2) it can be slow (e.g. when invoking test apps via wine) Eventually migrate to something fancier.''' import sys, os from run_project_tests import gather_tests, run_tests, StopException, setup_commands from run_project_tests import failing_logs def runtests(cross_file): commontests = [('common', gather_tests('test cases/common'), False)] try: (passing_tests, failing_tests, skipped_tests) = run_tests(commontests, 'meson-cross-test-run', ['--cross', cross_file]) except StopException: pass print('\nTotal passed cross tests:', passing_tests) print('Total failed cross tests:', failing_tests) print('Total skipped cross tests:', skipped_tests) if failing_tests > 0 and ('TRAVIS' in os.environ or 'APPVEYOR' in os.environ): print('\nMesonlogs of failing tests\n') for l in failing_logs: print(l, '\n') sys.exit(failing_tests) if __name__ == '__main__': setup_commands('ninja') cross_file = sys.argv[1] runtests(cross_file) meson-0.40.1/run_project_tests.py0000755000175000017500000006521613074426732020462 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Copyright 2012-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from glob import glob import os, subprocess, shutil, sys, signal from io import StringIO from ast import literal_eval from enum import Enum import tempfile import mesontest from mesonbuild import environment from mesonbuild import mesonlib from mesonbuild import mlog from mesonbuild import mesonmain from mesonbuild.mesonlib import stringlistify, Popen_safe from mesonbuild.coredata import backendlist import argparse import xml.etree.ElementTree as ET import time import multiprocessing import concurrent.futures as conc import re from run_tests import get_backend_commands, get_backend_args_for_dir, Backend class BuildStep(Enum): configure = 1 build = 2 test = 3 install = 4 clean = 5 validate = 6 class TestResult: def __init__(self, msg, step, stdo, stde, mlog, conftime=0, buildtime=0, testtime=0): self.msg = msg self.step = step self.stdo = stdo self.stde = stde self.mlog = mlog self.conftime = conftime self.buildtime = buildtime self.testtime = testtime class DummyFuture(conc.Future): ''' Dummy Future implementation that executes the provided function when you ask for the result. Used on platforms where sem_open() is not available: MSYS2, OpenBSD, etc: https://bugs.python.org/issue3770 ''' def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def set_function(self, fn, *args, **kwargs): self.fn = fn self.fn_args = args self.fn_kwargs = kwargs def result(self, **kwargs): try: result = self.fn(*self.fn_args, **self.fn_kwargs) except BaseException as e: self.set_exception(e) else: self.set_result(result) return super().result(**kwargs) class DummyExecutor(conc.Executor): ''' Dummy single-thread 'concurrent' executor for use on platforms where sem_open is not available: https://bugs.python.org/issue3770 ''' def __init__(self): from threading import Lock self._shutdown = False self._shutdownLock = Lock() def submit(self, fn, *args, **kwargs): with self._shutdownLock: if self._shutdown: raise RuntimeError('Cannot schedule new futures after shutdown') f = DummyFuture() f.set_function(fn, *args, **kwargs) return f def shutdown(self, wait=True): with self._shutdownLock: self._shutdown = True class AutoDeletedDir: def __init__(self, d): self.dir = d def __enter__(self): os.makedirs(self.dir, exist_ok=True) return self.dir def __exit__(self, _type, value, traceback): # On Windows, shutil.rmtree fails sometimes, because 'the directory is not empty'. # Retrying fixes this. # That's why we don't use tempfile.TemporaryDirectory, but wrap the deletion in the AutoDeletedDir class. retries = 5 for i in range(0, retries): try: shutil.rmtree(self.dir) return # Sometimes we get: ValueError: I/O operation on closed file. except ValueError: return # Deleting can raise OSError or PermissionError on Windows # (most likely because of anti-virus locking the file) except (OSError, PermissionError): if i == retries - 1: mlog.warning('Could not delete temporary directory.') return time.sleep(0.1 * (2**i)) failing_logs = [] print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ do_debug = not {'MESON_PRINT_TEST_OUTPUT', 'TRAVIS', 'APPVEYOR'}.isdisjoint(os.environ) no_meson_log_msg = 'No meson-log.txt found.' meson_command = os.path.join(os.getcwd(), 'meson') if not os.path.exists(meson_command): meson_command += '.py' if not os.path.exists(meson_command): raise RuntimeError('Could not find main Meson script to run.') class StopException(Exception): def __init__(self): super().__init__('Stopped by user') stop = False def stop_handler(signal, frame): global stop stop = True signal.signal(signal.SIGINT, stop_handler) signal.signal(signal.SIGTERM, stop_handler) # Needed when running cross tests because we don't generate prebuilt files compiler = None def setup_commands(optbackend): global do_debug, backend, backend_flags global compile_commands, clean_commands, test_commands, install_commands, uninstall_commands backend = optbackend msbuild_exe = shutil.which('msbuild') # Auto-detect backend if unspecified if backend is None: if msbuild_exe is not None: backend = 'vs' # Meson will auto-detect VS version to use elif mesonlib.is_osx(): backend = 'xcode' else: backend = 'ninja' # Set backend arguments for Meson if backend.startswith('vs'): backend_flags = ['--backend=' + backend] backend = Backend.vs elif backend == 'xcode': backend_flags = ['--backend=xcode'] backend = Backend.xcode elif backend == 'ninja': backend_flags = ['--backend=ninja'] backend = Backend.ninja else: raise RuntimeError('Unknown backend: {!r}'.format(backend)) compile_commands, clean_commands, test_commands, install_commands, \ uninstall_commands = get_backend_commands(backend, do_debug) def get_relative_files_list_from_dir(fromdir): paths = [] for (root, _, files) in os.walk(fromdir): reldir = os.path.relpath(root, start=fromdir) for f in files: path = os.path.join(reldir, f).replace('\\', '/') if path.startswith('./'): path = path[2:] paths.append(path) return paths def platform_fix_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, compiler): # List of installed files info_file = os.path.join(srcdir, 'installed_files.txt') # If this exists, the test does not install any other files noinst_file = 'usr/no-installed-files' expected = {} found = {} ret_msg = '' # Generate list of expected files if os.path.exists(os.path.join(installdir, noinst_file)): expected[noinst_file] = False elif os.path.exists(info_file): with open(info_file) as f: for line in f: 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) for fname in found: # Windows-specific tests check for the existence of installed PDB # files, but common tests do not, for obvious reasons. Ignore any # extra PDB files found. if fname not in expected and not fname.endswith('.pdb') and compiler == 'cl': ret_msg += 'Extra file {0} found.\n'.format(fname) return ret_msg def log_text_file(logfile, testdir, stdo, stde): global stop, executor, futures logfile.write('%s\nstdout\n\n---\n' % testdir) logfile.write(stdo) logfile.write('\n\n---\n\nstderr\n\n---\n') logfile.write(stde) logfile.write('\n\n---\n\n') if print_debug: print(stdo) print(stde, file=sys.stderr) if stop: print("Aborting..") for f in futures: f[2].cancel() executor.shutdown() raise StopException() def run_configure_inprocess(commandlist): old_stdout = sys.stdout sys.stdout = mystdout = StringIO() old_stderr = sys.stderr sys.stderr = mystderr = StringIO() try: returncode = mesonmain.run(commandlist[0], commandlist[1:]) finally: sys.stdout = old_stdout sys.stderr = old_stderr return returncode, mystdout.getvalue(), mystderr.getvalue() def run_test_inprocess(testdir): old_stdout = sys.stdout sys.stdout = mystdout = StringIO() old_stderr = sys.stderr sys.stderr = mystderr = StringIO() old_cwd = os.getcwd() os.chdir(testdir) try: returncode_test = mesontest.run(['--no-rebuild']) returncode_benchmark = mesontest.run(['--no-rebuild', '--benchmark', '--logbase', 'benchmarklog']) finally: sys.stdout = old_stdout sys.stderr = old_stderr os.chdir(old_cwd) return max(returncode_test, returncode_benchmark), mystdout.getvalue(), mystderr.getvalue() def parse_test_args(testdir): args = [] try: with open(os.path.join(testdir, 'test_args.txt'), 'r') as f: content = f.read() try: args = literal_eval(content) except Exception: raise Exception('Malformed test_args file.') args = stringlistify(args) except FileNotFoundError: pass return args def run_test(skipped, testdir, extra_args, compiler, backend, flags, commands, should_fail): if skipped: return None with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: with AutoDeletedDir(tempfile.mkdtemp(prefix='i ', dir=os.getcwd())) as install_dir: try: return _run_test(testdir, build_dir, install_dir, extra_args, compiler, backend, flags, commands, should_fail) finally: mlog.shutdown() # Close the log file because otherwise Windows wets itself. def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backend, flags, commands, should_fail): compile_commands, clean_commands, install_commands, uninstall_commands = commands test_args = parse_test_args(testdir) gen_start = time.time() # Configure in-process gen_command = [meson_command, '--prefix', '/usr', '--libdir', 'lib', testdir, test_build_dir]\ + flags + test_args + extra_args (returncode, stdo, stde) = run_configure_inprocess(gen_command) try: logfile = os.path.join(test_build_dir, 'meson-logs/meson-log.txt') with open(logfile, errors='ignore') as f: mesonlog = f.read() except Exception: mesonlog = no_meson_log_msg gen_time = time.time() - gen_start if should_fail == 'meson': if returncode != 0: return TestResult('', BuildStep.configure, stdo, stde, mesonlog, gen_time) return TestResult('Test that should have failed succeeded', BuildStep.configure, stdo, stde, mesonlog, gen_time) if returncode != 0: return TestResult('Generating the build system failed.', BuildStep.configure, stdo, stde, mesonlog, gen_time) # Build with subprocess dir_args = get_backend_args_for_dir(backend, test_build_dir) build_start = time.time() pc, o, e = Popen_safe(compile_commands + dir_args, cwd=test_build_dir) build_time = time.time() - build_start stdo += o stde += e if should_fail == 'build': if pc.returncode != 0: return TestResult('', BuildStep.build, stdo, stde, mesonlog, gen_time) return TestResult('Test that should have failed to build succeeded', BuildStep.build, stdo, stde, mesonlog, gen_time) if pc.returncode != 0: return TestResult('Compiling source code failed.', BuildStep.build, stdo, stde, mesonlog, gen_time, build_time) # Touch the meson.build file to force a regenerate so we can test that # regeneration works. We need to sleep for 0.2s because Ninja tracks mtimes # at a low resolution: https://github.com/ninja-build/ninja/issues/371 time.sleep(0.2) os.utime(os.path.join(testdir, 'meson.build')) test_start = time.time() # Test in-process (returncode, tstdo, tstde) = run_test_inprocess(test_build_dir) test_time = time.time() - test_start stdo += tstdo stde += tstde if should_fail == 'test': if returncode != 0: return TestResult('', BuildStep.test, stdo, stde, mesonlog, gen_time) return TestResult('Test that should have failed to run unit tests succeeded', BuildStep.test, stdo, stde, mesonlog, gen_time) if returncode != 0: return TestResult('Running unit tests failed.', BuildStep.test, stdo, stde, mesonlog, gen_time, build_time, test_time) # Do installation, if the backend supports it if len(install_commands) != 0: env = os.environ.copy() env['DESTDIR'] = install_dir # Install with subprocess pi, o, e = Popen_safe(install_commands, cwd=test_build_dir, env=env) stdo += o stde += e if pi.returncode != 0: return TestResult('Running install failed.', BuildStep.install, stdo, stde, mesonlog, gen_time, build_time, test_time) # Clean with subprocess env = os.environ.copy() pi, o, e = Popen_safe(clean_commands + dir_args, cwd=test_build_dir, env=env) stdo += o stde += e if pi.returncode != 0: return TestResult('Running clean failed.', BuildStep.clean, stdo, stde, mesonlog, gen_time, build_time, test_time) if len(install_commands) == 0: return TestResult('', BuildStep.install, '', '', mesonlog, gen_time, build_time, test_time) return TestResult(validate_install(testdir, install_dir, compiler), BuildStep.validate, stdo, stde, mesonlog, gen_time, build_time, test_time) def gather_tests(testdir): tests = [t.replace('\\', '/').split('/', 2)[2] for t in glob(os.path.join(testdir, '*'))] testlist = [(int(t.split()[0]), t) for t in tests] testlist.sort() tests = [os.path.join(testdir, t[1]) for t in testlist] return tests def have_d_compiler(): if shutil.which("ldc2"): return True elif shutil.which("ldc"): return True elif shutil.which("gdc"): return True elif shutil.which("dmd"): return True return False def have_java(): if shutil.which('javac') and shutil.which('java'): return True return False def detect_tests_to_run(): all_tests = [] all_tests.append(('common', gather_tests('test cases/common'), False)) all_tests.append(('failing-meson', gather_tests('test cases/failing'), False)) all_tests.append(('failing-build', gather_tests('test cases/failing build'), False)) all_tests.append(('failing-tests', gather_tests('test cases/failing tests'), False)) all_tests.append(('prebuilt', gather_tests('test cases/prebuilt'), False)) all_tests.append(('platform-osx', gather_tests('test cases/osx'), False if mesonlib.is_osx() else True)) all_tests.append(('platform-windows', gather_tests('test cases/windows'), False if mesonlib.is_windows() 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() and not mesonlib.is_cygwin() else True)) all_tests.append(('java', gather_tests('test cases/java'), False if backend is Backend.ninja and not mesonlib.is_osx() and have_java() else True)) all_tests.append(('C#', gather_tests('test cases/csharp'), False if backend is Backend.ninja and shutil.which('mcs') else True)) all_tests.append(('vala', gather_tests('test cases/vala'), False if backend is Backend.ninja and shutil.which('valac') else True)) all_tests.append(('rust', gather_tests('test cases/rust'), False if backend is Backend.ninja and shutil.which('rustc') else True)) all_tests.append(('d', gather_tests('test cases/d'), False if backend is Backend.ninja and have_d_compiler() else True)) all_tests.append(('objective c', gather_tests('test cases/objc'), False if backend in (Backend.ninja, Backend.xcode) and not mesonlib.is_windows() else True)) all_tests.append(('fortran', gather_tests('test cases/fortran'), False if backend is Backend.ninja and shutil.which('gfortran') else True)) all_tests.append(('swift', gather_tests('test cases/swift'), False if backend in (Backend.ninja, Backend.xcode) and shutil.which('swiftc') else True)) all_tests.append(('python3', gather_tests('test cases/python3'), False if backend is Backend.ninja and shutil.which('python3') else True)) return all_tests def run_tests(all_tests, log_name_base, extra_args): global stop, executor, futures txtname = log_name_base + '.txt' xmlname = log_name_base + '.xml' logfile = open(txtname, 'w', encoding="utf_8") junit_root = ET.Element('testsuites') conf_time = 0 build_time = 0 test_time = 0 passing_tests = 0 failing_tests = 0 skipped_tests = 0 commands = (compile_commands, clean_commands, install_commands, uninstall_commands) try: # This fails in some CI environments for unknown reasons. num_workers = multiprocessing.cpu_count() except Exception as e: print('Could not determine number of CPUs due to the following reason:' + str(e)) print('Defaulting to using only one process') num_workers = 1 try: executor = conc.ProcessPoolExecutor(max_workers=num_workers) except ImportError: print('Platform doesn\'t ProcessPoolExecutor, falling back to single-threaded testing\n') executor = DummyExecutor() for name, test_cases, skipped in all_tests: current_suite = ET.SubElement(junit_root, 'testsuite', {'name': name, 'tests': str(len(test_cases))}) if skipped: print('\nNot running %s tests.\n' % name) else: print('\nRunning %s tests.\n' % name) futures = [] for t in test_cases: # Jenkins screws us over by automatically sorting test cases by name # and getting it wrong by not doing logical number sorting. (testnum, testbase) = os.path.split(t)[-1].split(' ', 1) testname = '%.3d %s' % (int(testnum), testbase) should_fail = False if name.startswith('failing'): should_fail = name.split('failing-')[1] result = executor.submit(run_test, skipped, t, extra_args, compiler, backend, backend_flags, commands, should_fail) futures.append((testname, t, result)) for (testname, t, result) in futures: sys.stdout.flush() result = result.result() 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}) ET.SubElement(current_test, 'skipped', {}) skipped_tests += 1 else: without_install = "" if len(install_commands) > 0 else " (without install)" if result.msg != '': print('Failed test{} during {}: {!r}'.format(without_install, result.step.name, t)) print('Reason:', result.msg) failing_tests += 1 if result.step == BuildStep.configure and result.mlog != no_meson_log_msg: # For configure failures, instead of printing stdout, # print the meson log if available since it's a superset # of stdout and often has very useful information. failing_logs.append(result.mlog) else: failing_logs.append(result.stdo) failing_logs.append(result.stde) else: print('Succeeded test%s: %s' % (without_install, t)) passing_tests += 1 conf_time += result.conftime build_time += result.buildtime test_time += result.testtime total_time = conf_time + build_time + test_time log_text_file(logfile, t, result.stdo, result.stde) current_test = ET.SubElement(current_suite, 'testcase', {'name': testname, 'classname': name, 'time': '%.3f' % total_time}) if result.msg != '': ET.SubElement(current_test, 'failure', {'message': result.msg}) stdoel = ET.SubElement(current_test, 'system-out') stdoel.text = result.stdo stdeel = ET.SubElement(current_test, 'system-err') stdeel.text = result.stde print("\nTotal configuration time: %.2fs" % conf_time) print("Total build time: %.2fs" % build_time) print("Total test time: %.2fs" % test_time) ET.ElementTree(element=junit_root).write(xmlname, xml_declaration=True, encoding='UTF-8') return passing_tests, failing_tests, skipped_tests def check_file(fname): linenum = 1 with open(fname, 'rb') as f: lines = f.readlines() for line in lines: if b'\t' in line: print("File %s contains a literal tab on line %d. Only spaces are permitted." % (fname, linenum)) sys.exit(1) if b'\r' in line: print("File %s contains DOS line ending on line %d. Only unix-style line endings are permitted." % (fname, linenum)) sys.exit(1) linenum += 1 def check_format(): for (root, _, files) in os.walk('.'): for file in files: if file.endswith('.py') or file.endswith('.build') or file == 'meson_options.txt': fullname = os.path.join(root, file) check_file(fullname) def pbcompile(compiler, source, objectfile): if compiler == 'cl': cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source] else: cmd = [compiler, '-c', source, '-o', objectfile] subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def generate_pb_object(compiler, object_suffix): source = 'test cases/prebuilt/1 object/source.c' objectfile = 'test cases/prebuilt/1 object/prebuilt.' + object_suffix pbcompile(compiler, source, objectfile) return objectfile def generate_pb_static(compiler, object_suffix, static_suffix): source = 'test cases/prebuilt/2 static/libdir/best.c' objectfile = 'test cases/prebuilt/2 static/libdir/best.' + object_suffix stlibfile = 'test cases/prebuilt/2 static/libdir/libbest.' + static_suffix pbcompile(compiler, source, objectfile) if compiler == 'cl': linker = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile] else: linker = ['ar', 'csr', stlibfile, objectfile] subprocess.check_call(linker) os.unlink(objectfile) return stlibfile def generate_prebuilt(): global compiler static_suffix = 'a' if shutil.which('cl'): compiler = 'cl' static_suffix = 'lib' elif shutil.which('cc'): compiler = 'cc' elif shutil.which('gcc'): compiler = 'gcc' else: raise RuntimeError("Could not find C compiler.") if mesonlib.is_windows(): object_suffix = 'obj' else: object_suffix = 'o' objectfile = generate_pb_object(compiler, object_suffix) stlibfile = generate_pb_static(compiler, object_suffix, static_suffix) return objectfile, stlibfile def check_meson_commands_work(): global backend, meson_command, compile_commands, test_commands, install_commands testdir = 'test cases/common/1 trivial' with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: print('Checking that configuring works...') gen_cmd = [sys.executable, meson_command, testdir, build_dir] + backend_flags pc, o, e = Popen_safe(gen_cmd) if pc.returncode != 0: raise RuntimeError('Failed to configure {!r}:\n{}\n{}'.format(testdir, e, o)) print('Checking that building works...') dir_args = get_backend_args_for_dir(backend, build_dir) pc, o, e = Popen_safe(compile_commands + dir_args, cwd=build_dir) if pc.returncode != 0: raise RuntimeError('Failed to build {!r}:\n{}\n{}'.format(testdir, e, o)) print('Checking that testing works...') pc, o, e = Popen_safe(test_commands, cwd=build_dir) if pc.returncode != 0: raise RuntimeError('Failed to test {!r}:\n{}\n{}'.format(testdir, e, o)) if install_commands: print('Checking that installing works...') pc, o, e = Popen_safe(install_commands, cwd=build_dir) if pc.returncode != 0: raise RuntimeError('Failed to install {!r}:\n{}\n{}'.format(testdir, e, o)) if __name__ == '__main__': parser = argparse.ArgumentParser(description="Run the test suite of Meson.") parser.add_argument('extra_args', nargs='*', help='arguments that are passed directly to Meson (remember to have -- before these).') parser.add_argument('--backend', default=None, dest='backend', choices=backendlist) options = parser.parse_args() setup_commands(options.backend) script_dir = os.path.split(__file__)[0] if script_dir != '': os.chdir(script_dir) check_format() check_meson_commands_work() pbfiles = generate_prebuilt() try: all_tests = detect_tests_to_run() (passing_tests, failing_tests, skipped_tests) = run_tests(all_tests, 'meson-test-run', options.extra_args) except StopException: pass for f in pbfiles: os.unlink(f) print('\nTotal passed tests:', passing_tests) print('Total failed tests:', failing_tests) print('Total skipped tests:', skipped_tests) if failing_tests > 0: print('\nMesonlogs of failing tests\n') for l in failing_logs: print(l, '\n') sys.exit(failing_tests) meson-0.40.1/contributing.txt0000644000175000017500000000406313012152443017555 0ustar jpakkanejpakkane00000000000000Contributing to the Meson build system There are two simple ways to submit your patches. The preferred way is to send a github pull request. Small changes can also be sent as patches as emails to the Meson mailing list. Remember to add your name to the list of contributors in authors.txt. Python Coding style Meson follows the basic Python coding style. Additional rules are the following: - indent 4 spaces, no tabs ever - indent meson.build files with two spaces - try to keep the code as simple as possible - contact the mailing list before embarking on large scale projects to avoid wasted effort - all new features must come with a test (or several if it is a big feature) C/C++ coding style Meson has a bunch of test code in several languages. The rules for those are simple. - indent 4 spaces, no tabs ever - brace always on the same line as if/for/else/function definition External dependencies The goal of Meson is to be as easily usable as possible. The user experience should be "get Python3 and Ninja, run", even on Windows. Unfortunately this means that we can't have dependencies on projects outside of Python's standard library. This applies only to core functionality, though. For additional helper programs etc the use of external dependencies may be ok. If you feel that you are dealing with this kind of case, please raise the issue on the mailing list first. What not to contribute? There are a few things that people seem to want to add to Meson but which are not there by design and will not be added either. The first one is defining your own functions or a generalised for loop. These are bad because they would make Meson's DSL Turing complete. The second feature is a Make backend. The FAQ has specific information why these two features will not be added to Meson: https://github.com/mesonbuild/meson/wiki/FAQ Merge requests adding either of these two features will be automatically rejected. Please save everyone's time (especially your own) and don't start working on these features. Do I need to sign a CLA? No. All contributions are welcome. meson-0.40.1/ghwt.py0000755000175000017500000000735412763077471015664 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import urllib.request, json, sys, os, shutil, subprocess import configparser, hashlib private_repos = {'meson', 'wrapweb', 'meson-ci'} def gh_get(url): r = urllib.request.urlopen(url) jd = json.loads(r.read().decode('utf-8')) return jd def list_projects(): jd = gh_get('https://api.github.com/orgs/mesonbuild/repos') entries = [entry['name'] for entry in jd] entries = [e for e in entries if e not in private_repos] entries.sort() for i in entries: print(i) return 0 def unpack(sproj, branch, outdir): subprocess.check_call(['git', 'clone', '-b', branch, 'https://github.com/mesonbuild/%s.git' % sproj, outdir]) usfile = os.path.join(outdir, 'upstream.wrap') assert(os.path.isfile(usfile)) config = configparser.ConfigParser() config.read(usfile) us_url = config['wrap-file']['source_url'] us = urllib.request.urlopen(us_url).read() h = hashlib.sha256() h.update(us) dig = h.hexdigest() should = config['wrap-file']['source_hash'] if dig != should: print('Incorrect hash on download.') print(' expected:', dig) print(' obtained:', should) return 1 spdir = os.path.split(outdir)[0] ofilename = os.path.join(spdir, config['wrap-file']['source_filename']) with open(ofilename, 'wb') as ofile: ofile.write(us) if 'lead_directory_missing' in config['wrap-file']: os.mkdir(outdir) shutil.unpack_archive(ofilename, outdir) else: shutil.unpack_archive(ofilename, spdir) extdir = os.path.join(spdir, config['wrap-file']['directory']) assert(os.path.isdir(extdir)) shutil.move(os.path.join(outdir, '.git'), extdir) subprocess.check_call(['git', 'reset', '--hard'], cwd=extdir) shutil.rmtree(outdir) shutil.move(extdir, outdir) shutil.rmtree(os.path.join(outdir, '.git')) os.unlink(ofilename) def install(sproj): sproj_dir = os.path.join('subprojects', sproj) if not os.path.isdir('subprojects'): print('Run this in your source root and make sure there is a subprojects directory in it.') return 1 if os.path.isdir(sproj_dir): print('Subproject is already there. To update, nuke the dir and reinstall.') return 1 blist = gh_get('https://api.github.com/repos/mesonbuild/%s/branches' % sproj) blist = [b['name'] for b in blist] blist = [b for b in blist if b != 'master'] blist.sort() branch = blist[-1] print('Using branch', branch) return unpack(sproj, branch, sproj_dir) def run(args): if len(args) == 0 or args[0] == '-h' or args[0] == '--help': print(sys.argv[0], 'list/install', 'package_name') return 1 command = args[0] args = args[1:] if command == 'list': list_projects() return 0 elif command == 'install': if len(args) != 1: print('Install requires exactly one argument.') return 1 return install(args[0]) else: print('Unknown command') return 1 if __name__ == '__main__': print('This is an emergency wrap downloader. Use only when wrapdb is down.') sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/0000755000175000017500000000000013100703042016436 5ustar jpakkanejpakkane00000000000000meson-0.40.1/mesonbuild/modules/0000755000175000017500000000000013100703042020106 5ustar jpakkanejpakkane00000000000000meson-0.40.1/mesonbuild/modules/qt5.py0000644000175000017500000001674113074426732021224 0ustar jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from .. import mlog from .. import build from ..mesonlib import MesonException, Popen_safe from ..dependencies import Qt5Dependency from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue class Qt5Module(ExtensionModule): tools_detected = False def _detect_tools(self, env, method): if self.tools_detected: return mlog.log('Detecting Qt5 tools') # FIXME: We currently require Qt5 to exist while importing the module. # We should make it gracefully degrade and not create any targets if # the import is marked as 'optional' (not implemented yet) kwargs = {'required': 'true', 'modules': 'Core', 'silent': 'true', 'method': method} qt5 = Qt5Dependency(env, kwargs) # Get all tools and then make sure that they are the right version self.moc, self.uic, self.rcc = qt5.compilers_detect() # Moc, uic and rcc write their version strings to stderr. # Moc and rcc return a non-zero result when doing so. # What kind of an idiot thought that was a good idea? if self.moc.found(): stdout, stderr = Popen_safe(self.moc.get_command() + ['-v'])[1:3] stdout = stdout.strip() stderr = stderr.strip() if 'Qt 5' in stderr: moc_ver = stderr elif '5.' in stdout: moc_ver = stdout else: raise MesonException('Moc preprocessor is not for Qt 5. Output:\n%s\n%s' % (stdout, stderr)) mlog.log(' moc:', mlog.green('YES'), '(%s, %s)' % (self.moc.get_path(), moc_ver.split()[-1])) else: mlog.log(' moc:', mlog.red('NO')) if self.uic.found(): stdout, stderr = Popen_safe(self.uic.get_command() + ['-v'])[1:3] stdout = stdout.strip() stderr = stderr.strip() if 'version 5.' in stderr: uic_ver = stderr elif '5.' in stdout: uic_ver = stdout else: raise MesonException('Uic compiler is not for Qt 5. Output:\n%s\n%s' % (stdout, stderr)) mlog.log(' uic:', mlog.green('YES'), '(%s, %s)' % (self.uic.get_path(), uic_ver.split()[-1])) else: mlog.log(' uic:', mlog.red('NO')) if self.rcc.found(): stdout, stderr = Popen_safe(self.rcc.get_command() + ['-v'])[1:3] stdout = stdout.strip() stderr = stderr.strip() if 'version 5.' in stderr: rcc_ver = stderr elif '5.' in stdout: rcc_ver = stdout else: raise MesonException('Rcc compiler is not for Qt 5. Output:\n%s\n%s' % (stdout, stderr)) mlog.log(' rcc:', mlog.green('YES'), '(%s, %s)' % (self.rcc.get_path(), rcc_ver.split()[-1])) else: mlog.log(' rcc:', mlog.red('NO')) self.tools_detected = True def parse_qrc(self, state, fname): abspath = os.path.join(state.environment.source_dir, state.subdir, fname) relative_part = os.path.split(fname)[0] try: tree = ET.parse(abspath) root = tree.getroot() result = [] for child in root[0]: if child.tag != 'file': mlog.warning("malformed rcc file: ", os.path.join(state.subdir, fname)) break else: result.append(os.path.join(state.subdir, relative_part, child.text)) return result except Exception: return [] def preprocess(self, state, args, kwargs): rcc_files = kwargs.pop('qresources', []) if not isinstance(rcc_files, list): rcc_files = [rcc_files] ui_files = kwargs.pop('ui_files', []) if not isinstance(ui_files, list): ui_files = [ui_files] moc_headers = kwargs.pop('moc_headers', []) if not isinstance(moc_headers, list): moc_headers = [moc_headers] moc_sources = kwargs.pop('moc_sources', []) if not isinstance(moc_sources, list): moc_sources = [moc_sources] sources = kwargs.pop('sources', []) if not isinstance(sources, list): sources = [sources] sources += args[1:] method = kwargs.get('method', 'auto') self._detect_tools(state.environment, method) err_msg = "{0} sources specified and couldn't find {1}, " \ "please check your qt5 installation" if len(moc_headers) + len(moc_sources) > 0 and not self.moc.found(): raise MesonException(err_msg.format('MOC', 'moc-qt5')) if len(rcc_files) > 0: if not self.rcc.found(): raise MesonException(err_msg.format('RCC', 'rcc-qt5')) qrc_deps = [] for i in rcc_files: qrc_deps += self.parse_qrc(state, i) if len(args) > 0: name = args[0] else: basename = os.path.split(rcc_files[0])[1] name = 'qt5-' + basename.replace('.', '_') rcc_kwargs = {'input': rcc_files, 'output': name + '.cpp', 'command': [self.rcc, '-o', '@OUTPUT@', '@INPUT@'], 'depend_files': qrc_deps} res_target = build.CustomTarget(name, state.subdir, rcc_kwargs) sources.append(res_target) if len(ui_files) > 0: if not self.uic.found(): raise MesonException(err_msg.format('UIC', 'uic-qt5')) ui_kwargs = {'output': 'ui_@BASENAME@.h', 'arguments': ['-o', '@OUTPUT@', '@INPUT@']} ui_gen = build.Generator([self.uic], ui_kwargs) ui_output = ui_gen.process_files('Qt5 ui', ui_files, state) sources.append(ui_output) if len(moc_headers) > 0: moc_kwargs = {'output': 'moc_@BASENAME@.cpp', 'arguments': ['@INPUT@', '-o', '@OUTPUT@']} moc_gen = build.Generator([self.moc], moc_kwargs) moc_output = moc_gen.process_files('Qt5 moc header', moc_headers, state) sources.append(moc_output) if len(moc_sources) > 0: moc_kwargs = {'output': '@BASENAME@.moc', 'arguments': ['@INPUT@', '-o', '@OUTPUT@']} moc_gen = build.Generator([self.moc], moc_kwargs) moc_output = moc_gen.process_files('Qt5 moc source', moc_sources, state) sources.append(moc_output) return ModuleReturnValue(sources, sources) def initialize(): 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() meson-0.40.1/mesonbuild/modules/rpm.py0000644000175000017500000001636013055371477021312 0ustar jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. '''This module provides helper functions for RPM related functionality such as generating template RPM spec file.''' from .. import build from .. import compilers import datetime from .. import mlog from . import GirTarget, TypelibTarget from . import ModuleReturnValue from . import ExtensionModule import os class RPMModule(ExtensionModule): def generate_spec_template(self, state, args, kwargs): compiler_deps = set() for compiler in state.compilers.values(): if isinstance(compiler, compilers.GnuCCompiler): compiler_deps.add('gcc') elif isinstance(compiler, compilers.GnuCPPCompiler): compiler_deps.add('gcc-c++') elif isinstance(compiler, compilers.ValaCompiler): compiler_deps.add('vala') elif isinstance(compiler, compilers.GnuFortranCompiler): compiler_deps.add('gcc-gfortran') elif isinstance(compiler, compilers.GnuObjCCompiler): compiler_deps.add('gcc-objc') elif compiler == compilers.GnuObjCPPCompiler: compiler_deps.add('gcc-objc++') else: mlog.log('RPM spec file will not created, generating not allowed for:', mlog.bold(compiler.get_id())) return proj = state.project_name.replace(' ', '_').replace('\t', '_') so_installed = False devel_subpkg = False files = set() files_devel = set() to_delete = set() for target in state.targets.values(): if isinstance(target, build.Executable) and target.need_install: files.add('%%{_bindir}/%s' % target.get_filename()) elif isinstance(target, build.SharedLibrary) and target.need_install: files.add('%%{_libdir}/%s' % target.get_filename()) for alias in target.get_aliases(): if alias.endswith('.so'): files_devel.add('%%{_libdir}/%s' % alias) else: files.add('%%{_libdir}/%s' % alias) so_installed = True elif isinstance(target, build.StaticLibrary) and target.need_install: to_delete.add('%%{buildroot}%%{_libdir}/%s' % target.get_filename()) mlog.warning('removing', mlog.bold(target.get_filename()), 'from package because packaging static libs not recommended') elif isinstance(target, GirTarget) and target.should_install(): files_devel.add('%%{_datadir}/gir-1.0/%s' % target.get_filename()[0]) elif isinstance(target, TypelibTarget) and target.should_install(): files.add('%%{_libdir}/girepository-1.0/%s' % target.get_filename()[0]) for header in state.headers: if len(header.get_install_subdir()) > 0: files_devel.add('%%{_includedir}/%s/' % header.get_install_subdir()) else: for hdr_src in header.get_sources(): files_devel.add('%%{_includedir}/%s' % hdr_src) for man in state.man: for man_file in man.get_sources(): files.add('%%{_mandir}/man%u/%s.*' % (int(man_file.split('.')[-1]), man_file)) if len(files_devel) > 0: devel_subpkg = True filename = os.path.join(state.environment.get_build_dir(), '%s.spec' % proj) with open(filename, 'w+') as fn: fn.write('Name: %s\n' % proj) fn.write('Version: # FIXME\n') fn.write('Release: 1%{?dist}\n') fn.write('Summary: # FIXME\n') fn.write('License: # FIXME\n') fn.write('\n') fn.write('Source0: %{name}-%{version}.tar.xz # FIXME\n') fn.write('\n') 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[0]) for lib in state.environment.coredata.ext_libs.values(): name = lib.get_name() fn.write('BuildRequires: {} # FIXME\n'.format(name)) mlog.warning('replace', mlog.bold(name), 'with the real package.', 'You can use following command to find package which ' 'contains this lib:', mlog.bold("dnf provides '*/lib{}.so'".format(name))) for prog in state.environment.coredata.ext_progs.values(): if not prog.found(): fn.write('BuildRequires: %%{_bindir}/%s # FIXME\n' % prog.get_name()) else: fn.write('BuildRequires: {}\n'.format(prog.get_path())) fn.write('BuildRequires: meson\n') fn.write('\n') fn.write('%description\n') fn.write('\n') if devel_subpkg: fn.write('%package devel\n') fn.write('Summary: Development files for %{name}\n') fn.write('Requires: %{name}%{?_isa} = %{?epoch:%{epoch}:}{version}-%{release}\n') fn.write('\n') fn.write('%description devel\n') fn.write('Development files for %{name}.\n') fn.write('\n') fn.write('%prep\n') fn.write('%autosetup\n') fn.write('\n') fn.write('%build\n') fn.write('%meson\n') fn.write('%meson_build\n') fn.write('\n') fn.write('%install\n') fn.write('%meson_install\n') if len(to_delete) > 0: fn.write('rm -vf %s\n' % ' '.join(to_delete)) fn.write('\n') fn.write('%check\n') fn.write('%meson_test\n') fn.write('\n') fn.write('%files\n') for f in files: fn.write('%s\n' % f) fn.write('\n') if devel_subpkg: fn.write('%files devel\n') for f in files_devel: fn.write('%s\n' % f) fn.write('\n') if so_installed: fn.write('%post -p /sbin/ldconfig\n') fn.write('%postun -p /sbin/ldconfig\n') fn.write('\n') fn.write('%changelog\n') fn.write('* %s meson - \n' % datetime.date.today().strftime('%a %b %d %Y')) fn.write('- \n') fn.write('\n') mlog.log('RPM spec template written to %s.spec.\n' % proj) return ModuleReturnValue(None, []) def initialize(): return RPMModule() meson-0.40.1/mesonbuild/modules/qt4.py0000644000175000017500000001643513074426732021223 0ustar jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from .. import mlog from .. import build from ..mesonlib import MesonException, Popen_safe from ..dependencies import Qt4Dependency from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue class Qt4Module(ExtensionModule): tools_detected = False def _detect_tools(self, env, method): if self.tools_detected: return mlog.log('Detecting Qt4 tools') # FIXME: We currently require Qt4 to exist while importing the module. # We should make it gracefully degrade and not create any targets if # the import is marked as 'optional' (not implemented yet) kwargs = {'required': 'true', 'modules': 'Core', 'silent': 'true', 'method': method} qt4 = Qt4Dependency(env, kwargs) # Get all tools and then make sure that they are the right version self.moc, self.uic, self.rcc = qt4.compilers_detect() # Moc, uic and rcc write their version strings to stderr. # Moc and rcc return a non-zero result when doing so. # What kind of an idiot thought that was a good idea? if self.moc.found(): stdout, stderr = Popen_safe(self.moc.get_command() + ['-v'])[1:3] stdout = stdout.strip() stderr = stderr.strip() if 'Qt Meta' in stderr: moc_ver = stderr else: raise MesonException('Moc preprocessor is not for Qt 4. Output:\n%s\n%s' % (stdout, stderr)) mlog.log(' moc:', mlog.green('YES'), '(%s, %s)' % (self.moc.get_path(), moc_ver.split()[-1])) else: mlog.log(' moc:', mlog.red('NO')) if self.uic.found(): stdout, stderr = Popen_safe(self.uic.get_command() + ['-v'])[1:3] stdout = stdout.strip() stderr = stderr.strip() if 'version 4.' in stderr: uic_ver = stderr else: raise MesonException('Uic compiler is not for Qt4. Output:\n%s\n%s' % (stdout, stderr)) mlog.log(' uic:', mlog.green('YES'), '(%s, %s)' % (self.uic.get_path(), uic_ver.split()[-1])) else: mlog.log(' uic:', mlog.red('NO')) if self.rcc.found(): stdout, stderr = Popen_safe(self.rcc.get_command() + ['-v'])[1:3] stdout = stdout.strip() stderr = stderr.strip() if 'version 4.' in stderr: rcc_ver = stderr else: raise MesonException('Rcc compiler is not for Qt 4. Output:\n%s\n%s' % (stdout, stderr)) mlog.log(' rcc:', mlog.green('YES'), '(%s, %s)' % (self.rcc.get_path(), rcc_ver.split()[-1])) else: mlog.log(' rcc:', mlog.red('NO')) self.tools_detected = True def parse_qrc(self, state, fname): abspath = os.path.join(state.environment.source_dir, state.subdir, fname) relative_part = os.path.split(fname)[0] try: tree = ET.parse(abspath) root = tree.getroot() result = [] for child in root[0]: if child.tag != 'file': mlog.warning("malformed rcc file: ", os.path.join(state.subdir, fname)) break else: result.append(os.path.join(state.subdir, relative_part, child.text)) return result except Exception: return [] def preprocess(self, state, args, kwargs): rcc_files = kwargs.pop('qresources', []) if not isinstance(rcc_files, list): rcc_files = [rcc_files] ui_files = kwargs.pop('ui_files', []) if not isinstance(ui_files, list): ui_files = [ui_files] moc_headers = kwargs.pop('moc_headers', []) if not isinstance(moc_headers, list): moc_headers = [moc_headers] moc_sources = kwargs.pop('moc_sources', []) if not isinstance(moc_sources, list): moc_sources = [moc_sources] sources = kwargs.pop('sources', []) if not isinstance(sources, list): sources = [sources] sources += args[1:] method = kwargs.get('method', 'auto') self._detect_tools(state.environment, method) err_msg = "{0} sources specified and couldn't find {1}, " \ "please check your qt4 installation" if len(moc_headers) + len(moc_sources) > 0 and not self.moc.found(): raise MesonException(err_msg.format('MOC', 'moc-qt4')) if len(rcc_files) > 0: if not self.rcc.found(): raise MesonException(err_msg.format('RCC', 'rcc-qt4')) qrc_deps = [] for i in rcc_files: qrc_deps += self.parse_qrc(state, i) if len(args) > 0: name = args[0] else: basename = os.path.split(rcc_files[0])[1] name = 'qt4-' + basename.replace('.', '_') rcc_kwargs = {'input': rcc_files, 'output': name + '.cpp', 'command': [self.rcc, '-o', '@OUTPUT@', '@INPUT@'], 'depend_files': qrc_deps} res_target = build.CustomTarget(name, state.subdir, rcc_kwargs) sources.append(res_target) if len(ui_files) > 0: if not self.uic.found(): raise MesonException(err_msg.format('UIC', 'uic-qt4')) ui_kwargs = {'output': 'ui_@BASENAME@.h', 'arguments': ['-o', '@OUTPUT@', '@INPUT@']} ui_gen = build.Generator([self.uic], ui_kwargs) ui_output = ui_gen.process_files('Qt4 ui', ui_files, state) sources.append(ui_output) if len(moc_headers) > 0: moc_kwargs = {'output': 'moc_@BASENAME@.cpp', 'arguments': ['@INPUT@', '-o', '@OUTPUT@']} moc_gen = build.Generator([self.moc], moc_kwargs) moc_output = moc_gen.process_files('Qt4 moc header', moc_headers, state) sources.append(moc_output) if len(moc_sources) > 0: moc_kwargs = {'output': '@BASENAME@.moc', 'arguments': ['@INPUT@', '-o', '@OUTPUT@']} moc_gen = build.Generator([self.moc], moc_kwargs) moc_output = moc_gen.process_files('Qt4 moc source', moc_sources, state) sources.append(moc_output) return ModuleReturnValue(sources, sources) def initialize(): 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() meson-0.40.1/mesonbuild/modules/windows.py0000644000175000017500000000657513074426732022211 0ustar jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from .. import mlog from .. import mesonlib, dependencies, build from ..mesonlib import MesonException from . import get_include_args from . import ModuleReturnValue from . import ExtensionModule class WindowsModule(ExtensionModule): def detect_compiler(self, compilers): for l in ('c', 'cpp'): if l in compilers: return compilers[l] raise MesonException('Resource compilation requires a C or C++ compiler.') def compile_resources(self, state, args, kwargs): comp = self.detect_compiler(state.compilers) extra_args = mesonlib.stringlistify(kwargs.get('args', [])) inc_dirs = kwargs.pop('include_directories', []) if not isinstance(inc_dirs, list): inc_dirs = [inc_dirs] for incd in inc_dirs: if not isinstance(incd.held_object, (str, build.IncludeDirs)): raise MesonException('Resource include dirs should be include_directories().') extra_args += get_include_args(inc_dirs) if comp.id == 'msvc': rescomp = dependencies.ExternalProgram('rc', silent=True) res_args = extra_args + ['/nologo', '/fo@OUTPUT@', '@INPUT@'] suffix = 'res' else: m = 'Argument {!r} has a space which may not work with windres due to ' \ 'a MinGW bug: https://sourceware.org/bugzilla/show_bug.cgi?id=4933' for arg in extra_args: if ' ' in arg: mlog.warning(m.format(arg)) 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' if not rescomp.found(): raise MesonException('Could not find Windows resource compiler %s.' % ' '.join(rescomp.get_command())) res_kwargs = {'output': '@BASENAME@.' + suffix, 'arguments': res_args} res_gen = build.Generator([rescomp], res_kwargs) res_output = res_gen.process_files('Windows resource', args, state) return ModuleReturnValue(res_output, [res_output]) def initialize(): return WindowsModule() meson-0.40.1/mesonbuild/modules/i18n.py0000644000175000017500000001171413035766234021266 0ustar jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import shutil from os import path from .. import coredata, mesonlib, build from ..mesonlib import MesonException from . import ModuleReturnValue from . import ExtensionModule PRESET_ARGS = { 'glib': [ '--from-code=UTF-8', '--add-comments', # https://developer.gnome.org/glib/stable/glib-I18N.html '--keyword=_', '--keyword=N_', '--keyword=C_:1c,2', '--keyword=NC_:1c,2', '--keyword=g_dcgettext:2', '--keyword=g_dngettext:2,3', '--keyword=g_dpgettext2:2c,3', '--flag=N_:1:pass-c-format', '--flag=C_:2:pass-c-format', '--flag=NC_:2:pass-c-format', '--flag=g_dngettext:2:pass-c-format', '--flag=g_strdup_printf:1:c-format', '--flag=g_string_printf:2:c-format', '--flag=g_string_append_printf:2:c-format', '--flag=g_error_new:3:c-format', '--flag=g_set_error:4:c-format', ] } class I18nModule(ExtensionModule): def merge_file(self, state, args, kwargs): podir = kwargs.pop('po_dir', None) if not podir: raise MesonException('i18n: po_dir is a required kwarg') podir = path.join(state.build_to_src, state.subdir, podir) file_type = kwargs.pop('type', 'xml') VALID_TYPES = ('xml', 'desktop') if file_type not in VALID_TYPES: raise MesonException('i18n: "{}" is not a valid type {}'.format(file_type, VALID_TYPES)) kwargs['command'] = ['msgfmt', '--' + file_type, '--template', '@INPUT@', '-d', podir, '-o', '@OUTPUT@'] ct = build.CustomTarget(kwargs['output'] + '_merge', state.subdir, kwargs) return ModuleReturnValue(ct, [ct]) def gettext(self, state, args, kwargs): if len(args) != 1: raise coredata.MesonException('Gettext requires one positional argument (package name).') if not shutil.which('xgettext'): raise coredata.MesonException('Can not do gettext because xgettext is not installed.') packagename = args[0] languages = mesonlib.stringlistify(kwargs.get('languages', [])) datadirs = mesonlib.stringlistify(kwargs.get('data_dirs', [])) extra_args = mesonlib.stringlistify(kwargs.get('args', [])) preset = kwargs.pop('preset', None) if preset: preset_args = PRESET_ARGS.get(preset) if not preset_args: raise coredata.MesonException('i18n: Preset "{}" is not one of the valid options: {}'.format( preset, list(PRESET_ARGS.keys()))) extra_args = set(preset_args + extra_args) pkg_arg = '--pkgname=' + packagename lang_arg = '--langs=' + '@@'.join(languages) if languages else None datadirs = '--datadirs=' + ':'.join(datadirs) if datadirs else None extra_args = '--extra-args=' + '@@'.join(extra_args) if extra_args else None potargs = [state.environment.get_build_command(), '--internal', 'gettext', 'pot', pkg_arg] if datadirs: potargs.append(datadirs) if extra_args: potargs.append(extra_args) pottarget = build.RunTarget(packagename + '-pot', sys.executable, potargs, [], state.subdir) gmoargs = [state.environment.get_build_command(), '--internal', 'gettext', 'gen_gmo'] if lang_arg: gmoargs.append(lang_arg) gmotarget = build.RunTarget(packagename + '-gmo', sys.executable, gmoargs, [], state.subdir) updatepoargs = [state.environment.get_build_command(), '--internal', 'gettext', 'update_po', pkg_arg] if lang_arg: updatepoargs.append(lang_arg) if datadirs: updatepoargs.append(datadirs) if extra_args: updatepoargs.append(extra_args) updatepotarget = build.RunTarget(packagename + '-update-po', sys.executable, updatepoargs, [], state.subdir) script = [sys.executable, state.environment.get_build_command()] args = ['--internal', 'gettext', 'install', '--subdir=' + state.subdir, '--localedir=' + state.environment.coredata.get_builtin_option('localedir'), pkg_arg] if lang_arg: args.append(lang_arg) iscript = build.RunScript(script, args) return ModuleReturnValue(None, [pottarget, gmotarget, iscript, updatepotarget]) def initialize(): return I18nModule() meson-0.40.1/mesonbuild/modules/gnome.py0000644000175000017500000014404013076631051021604 0ustar jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. '''This module provides helper functions for Gnome/GLib related functionality such as gobject-introspection and gresources.''' from .. import build import os import sys import copy import subprocess from . import ModuleReturnValue from ..mesonlib import MesonException, OrderedSet, Popen_safe from ..dependencies import Dependency, PkgConfigDependency, InternalDependency from .. import mlog from .. import mesonlib from .. import compilers from .. import interpreter from . import GResourceTarget, GResourceHeaderTarget, GirTarget, TypelibTarget, VapiTarget from . import find_program, get_include_args from . import ExtensionModule # gresource compilation is broken due to the way # the resource compiler and Ninja clash about it # # https://github.com/ninja-build/ninja/issues/1184 # https://bugzilla.gnome.org/show_bug.cgi?id=774368 gresource_dep_needed_version = '>= 2.51.1' native_glib_version = None girwarning_printed = False gdbuswarning_printed = False gresource_warning_printed = False _gir_has_extra_lib_arg = None def gir_has_extra_lib_arg(): global _gir_has_extra_lib_arg if _gir_has_extra_lib_arg is not None: return _gir_has_extra_lib_arg _gir_has_extra_lib_arg = False try: g_ir_scanner = find_program('g-ir-scanner', '').get_command() opts = Popen_safe(g_ir_scanner + ['--help'], stderr=subprocess.STDOUT)[1] _gir_has_extra_lib_arg = '--extra-library' in opts except (MesonException, FileNotFoundError, subprocess.CalledProcessError): pass return _gir_has_extra_lib_arg class GnomeModule(ExtensionModule): gir_dep = None @staticmethod def _get_native_glib_version(state): global native_glib_version if native_glib_version is None: glib_dep = PkgConfigDependency('glib-2.0', state.environment, {'native': True}) native_glib_version = glib_dep.get_modversion() return native_glib_version def __print_gresources_warning(self, state): global gresource_warning_printed if not gresource_warning_printed: if not mesonlib.version_compare(self._get_native_glib_version(state), gresource_dep_needed_version): mlog.warning('GLib compiled dependencies do not work reliably with \n' 'the current version of GLib. See the following upstream issue:', mlog.bold('https://bugzilla.gnome.org/show_bug.cgi?id=774368')) gresource_warning_printed = True return [] @staticmethod def _print_gdbus_warning(): global gdbuswarning_printed if not gdbuswarning_printed: mlog.warning('Code generated with gdbus_codegen() requires the root directory be added to\n' ' include_directories of targets with GLib < 2.51.3:', mlog.bold('https://github.com/mesonbuild/meson/issues/1387')) gdbuswarning_printed = True def compile_resources(self, state, args, kwargs): self.__print_gresources_warning(state) glib_version = self._get_native_glib_version(state) cmd = ['glib-compile-resources', '@INPUT@'] source_dirs = kwargs.pop('source_dir', []) if not isinstance(source_dirs, list): source_dirs = [source_dirs] if len(args) < 2: raise MesonException('Not enough arguments; the name of the resource ' 'and the path to the XML file are required') dependencies = kwargs.pop('dependencies', []) if not isinstance(dependencies, list): dependencies = [dependencies] # Validate dependencies for (ii, dep) in enumerate(dependencies): if hasattr(dep, 'held_object'): dependencies[ii] = dep = dep.held_object if not isinstance(dep, (mesonlib.File, build.CustomTarget)): m = 'Unexpected dependency type {!r} for gnome.compile_resources() ' \ '"dependencies" argument.\nPlease pass the return value of ' \ 'custom_target() or configure_file()' raise MesonException(m.format(dep)) if isinstance(dep, build.CustomTarget): if not mesonlib.version_compare(glib_version, gresource_dep_needed_version): m = 'The "dependencies" argument of gnome.compile_resources() can not\n' \ 'be used with the current version of glib-compile-resources due to\n' \ '' raise MesonException(m) ifile = args[1] if isinstance(ifile, mesonlib.File): # glib-compile-resources will be run inside the source dir, # so we need either 'src_to_build' or the absolute path. # Absolute path is the easiest choice. if ifile.is_built: ifile = os.path.join(state.environment.get_build_dir(), ifile.subdir, ifile.fname) else: ifile = os.path.join(ifile.subdir, ifile.fname) elif isinstance(ifile, str): ifile = os.path.join(state.subdir, ifile) elif isinstance(ifile, (interpreter.CustomTargetHolder, interpreter.GeneratedObjectsHolder)): m = 'Resource xml files generated at build-time cannot be used ' \ 'with gnome.compile_resources() because we need to scan ' \ 'the xml for dependencies. Use configure_file() instead ' \ 'to generate it at configure-time.' raise MesonException(m) else: raise MesonException('Invalid file argument: {!r}'.format(ifile)) depend_files, depends, subdirs = self._get_gresource_dependencies( state, ifile, source_dirs, dependencies) # 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 for source_dir in OrderedSet(source_dirs): cmd += ['--sourcedir', source_dir] if 'c_name' in kwargs: cmd += ['--c-name', kwargs.pop('c_name')] export = kwargs.pop('export', False) if not export: cmd += ['--internal'] cmd += ['--generate', '--target', '@OUTPUT@'] cmd += mesonlib.stringlistify(kwargs.pop('extra_args', [])) gresource = kwargs.pop('gresource_bundle', False) if gresource: output = args[0] + '.gresource' name = args[0] + '_gresource' else: output = args[0] + '.c' name = args[0] + '_c' if kwargs.get('install', False) and not gresource: raise MesonException('The install kwarg only applies to gresource bundles, see install_header') install_header = kwargs.pop('install_header', False) if install_header and gresource: raise MesonException('The install_header kwarg does not apply to gresource bundles') if install_header and not export: raise MesonException('GResource header is installed yet export is not enabled') kwargs['input'] = args[1] kwargs['output'] = output kwargs['depends'] = depends if not mesonlib.version_compare(glib_version, gresource_dep_needed_version): # 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 = GResourceTarget(name, state.subdir, kwargs) if gresource: # Only one target for .gresource files return ModuleReturnValue(target_c, [target_c]) 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 } if install_header: h_kwargs['install'] = install_header h_kwargs['install_dir'] = kwargs.get('install_dir', state.environment.coredata.get_builtin_option('includedir')) target_h = GResourceHeaderTarget(args[0] + '_h', state.subdir, h_kwargs) rv = [target_c, target_h] return ModuleReturnValue(rv, rv) def _get_gresource_dependencies(self, state, input_file, source_dirs, dependencies): cmd = ['glib-compile-resources', input_file, '--generate-dependencies'] for source_dir in source_dirs: cmd += ['--sourcedir', os.path.join(state.subdir, source_dir)] cmd += ['--sourcedir', state.subdir] # Current dir pc, stdout, stderr = Popen_safe(cmd, cwd=state.environment.get_source_dir()) if pc.returncode != 0: m = 'glib-compile-resources failed to get dependencies for {}:\n{}' mlog.warning(m.format(cmd[1], stderr)) raise subprocess.CalledProcessError(pc.returncode, cmd) dep_files = stdout.split('\n')[:-1] # In generate-dependencies mode, glib-compile-resources doesn't raise # an error for missing resources but instead prints whatever filename # was listed in the input file. That's good because it means we can # handle resource files that get generated as part of the build, as # follows. # # If there are multiple generated resource files with the same basename # then this code will get confused. def exists_in_srcdir(f): 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) for dep in dependencies: if hasattr(dep, 'held_object'): dep = dep.held_object if isinstance(dep, mesonlib.File): if dep.fname == missing_basename: found = True dep_files.remove(missing) dep_files.append(dep) subdirs.append(dep.subdir) break elif isinstance(dep, build.CustomTarget): if dep.get_basename() == missing_basename: found = True dep_files.remove(missing) dep_files.append( mesonlib.File( is_built=True, subdir=dep.get_subdir(), fname=dep.get_basename())) depends.append(dep) subdirs.append(dep.get_subdir()) break else: raise RuntimeError('Unreachable code.') if not found: raise MesonException( 'Resource "%s" listed in "%s" was not found. If this is a ' 'generated file, pass the target that generates it to ' 'gnome.compile_resources() using the "dependencies" ' 'keyword argument.' % (missing, input_file)) return dep_files, depends, subdirs def _get_link_args(self, state, lib, depends=None, include_rpath=False, use_gir_args=False): if gir_has_extra_lib_arg() and use_gir_args: link_command = ['--extra-library=%s' % lib.name] else: link_command = ['-l%s' % lib.name] if isinstance(lib, build.SharedLibrary): libdir = os.path.join(state.environment.get_build_dir(), lib.subdir) link_command += ['-L%s' % libdir] if include_rpath: link_command += ['-Wl,-rpath %s' % libdir] if depends: depends.append(lib) return link_command def _get_dependencies_flags(self, deps, state, depends=None, include_rpath=False, use_gir_args=False): cflags = OrderedSet() ldflags = OrderedSet() gi_includes = OrderedSet() if not isinstance(deps, list): deps = [deps] for dep in deps: if hasattr(dep, 'held_object'): dep = dep.held_object if isinstance(dep, InternalDependency): cflags.update(get_include_args(dep.include_directories)) for lib in dep.libraries: ldflags.update(self._get_link_args(state, lib.held_object, depends, include_rpath)) libdepflags = self._get_dependencies_flags(lib.held_object.get_external_deps(), state, depends, include_rpath, use_gir_args) cflags.update(libdepflags[0]) ldflags.update(libdepflags[1]) gi_includes.update(libdepflags[2]) extdepflags = self._get_dependencies_flags(dep.ext_deps, state, depends, include_rpath, use_gir_args) cflags.update(extdepflags[0]) ldflags.update(extdepflags[1]) gi_includes.update(extdepflags[2]) for source in dep.sources: if hasattr(source, 'held_object') and isinstance(source.held_object, GirTarget): gi_includes.update([os.path.join(state.environment.get_build_dir(), source.held_object.get_subdir())]) # This should be any dependency other than an internal one. elif isinstance(dep, Dependency): cflags.update(dep.get_compile_args()) for lib in dep.get_link_args(): if (os.path.isabs(lib) and # For PkgConfigDependency only: getattr(dep, 'is_libtool', False)): lib_dir = os.path.dirname(lib) ldflags.update(["-L%s" % lib_dir]) if include_rpath: ldflags.update(['-Wl,-rpath {}'.format(lib_dir)]) libname = os.path.basename(lib) if libname.startswith("lib"): libname = libname[3:] libname = libname.split(".so")[0] lib = "-l%s" % libname # Hack to avoid passing some compiler options in if lib.startswith("-W"): continue if gir_has_extra_lib_arg() and use_gir_args: lib = lib.replace('-l', '--extra-library=') ldflags.update([lib]) if isinstance(dep, PkgConfigDependency): girdir = dep.get_pkgconfig_variable("girdir") if girdir: gi_includes.update([girdir]) elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): for incd in dep.get_include_dirs(): cflags.update(incd.get_incdirs()) else: mlog.log('dependency %s not handled to build gir files' % dep) continue return cflags, ldflags, gi_includes def generate_gir(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gir takes one argument') if kwargs.get('install_dir'): raise MesonException('install_dir is not supported with generate_gir(), see "install_dir_gir" and "install_dir_typelib"') giscanner = find_program('g-ir-scanner', 'Gir') gicompiler = find_program('g-ir-compiler', 'Gir') girtarget = args[0] while hasattr(girtarget, 'held_object'): girtarget = girtarget.held_object if not isinstance(girtarget, (build.Executable, build.SharedLibrary)): raise MesonException('Gir target must be an executable or shared library') try: if not self.gir_dep: self.gir_dep = PkgConfigDependency('gobject-introspection-1.0', state.environment, {'native': True}) pkgargs = self.gir_dep.get_compile_args() except Exception: raise MesonException('gobject-introspection dependency was not found, gir cannot be generated.') ns = kwargs.pop('namespace') nsversion = kwargs.pop('nsversion') libsources = kwargs.pop('sources') girfile = '%s-%s.gir' % (ns, nsversion) depends = [girtarget] gir_inc_dirs = [] scan_command = [giscanner, '@INPUT@'] scan_command += pkgargs scan_command += ['--no-libtool', '--namespace=' + ns, '--nsversion=' + nsversion, '--warn-all', '--output', '@OUTPUT@'] extra_args = mesonlib.stringlistify(kwargs.pop('extra_args', [])) scan_command += extra_args scan_command += ['-I' + os.path.join(state.environment.get_source_dir(), state.subdir), '-I' + os.path.join(state.environment.get_build_dir(), state.subdir)] scan_command += get_include_args(girtarget.get_include_dirs()) if 'link_with' in kwargs: link_with = kwargs.pop('link_with') if not isinstance(link_with, list): link_with = [link_with] for link in link_with: scan_command += self._get_link_args(state, link.held_object, depends, use_gir_args=True) if 'includes' in kwargs: includes = kwargs.pop('includes') if not isinstance(includes, list): includes = [includes] for inc in includes: if hasattr(inc, 'held_object'): inc = inc.held_object if isinstance(inc, str): scan_command += ['--include=%s' % (inc, )] elif isinstance(inc, GirTarget): gir_inc_dirs += [ os.path.join(state.environment.get_build_dir(), inc.get_subdir()), ] scan_command += [ "--include=%s" % (inc.get_basename()[:-4], ), ] depends += [inc] else: raise MesonException( 'Gir includes must be str, GirTarget, or list of them') cflags = [] if state.global_args.get('c'): cflags += state.global_args['c'] if state.project_args.get('c'): cflags += state.project_args['c'] if 'c' in state.compilers: compiler = state.compilers['c'] sanitize = compiler.get_options().get('b_sanitize') if sanitize: cflags += compilers.sanitizer_compile_args(sanitize) if cflags: scan_command += ['--cflags-begin'] scan_command += cflags scan_command += ['--cflags-end'] if kwargs.get('symbol_prefix'): sym_prefix = kwargs.pop('symbol_prefix') if not isinstance(sym_prefix, str): raise MesonException('Gir symbol prefix must be str') scan_command += ['--symbol-prefix=%s' % sym_prefix] if kwargs.get('identifier_prefix'): identifier_prefix = kwargs.pop('identifier_prefix') if not isinstance(identifier_prefix, str): raise MesonException('Gir identifier prefix must be str') scan_command += ['--identifier-prefix=%s' % identifier_prefix] if kwargs.get('export_packages'): pkgs = kwargs.pop('export_packages') if isinstance(pkgs, str): scan_command += ['--pkg-export=%s' % pkgs] elif isinstance(pkgs, list): scan_command += ['--pkg-export=%s' % pkg for pkg in pkgs] else: raise MesonException('Gir export packages must be str or list') deps = kwargs.pop('dependencies', []) if not isinstance(deps, list): deps = [deps] deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() + deps) # Need to recursively add deps on GirTarget sources from our # dependencies and also find the include directories needed for the # typelib generation custom target below. typelib_includes = [] for dep in deps: if hasattr(dep, 'held_object'): dep = dep.held_object # Add a dependency on each GirTarget listed in dependencies and add # the directory where it will be generated to the typelib includes if isinstance(dep, InternalDependency): for source in dep.sources: if hasattr(source, 'held_object'): source = source.held_object if isinstance(source, GirTarget) and source not in depends: depends.append(source) subdir = os.path.join(state.environment.get_build_dir(), source.get_subdir()) if subdir not in typelib_includes: typelib_includes.append(subdir) # Do the same, but for dependencies of dependencies. These are # stored in the list of generated sources for each link dep (from # girtarget.get_all_link_deps() above). # FIXME: Store this in the original form from declare_dependency() # so it can be used here directly. elif isinstance(dep, build.SharedLibrary): for source in dep.generated: if isinstance(source, GirTarget): subdir = os.path.join(state.environment.get_build_dir(), source.get_subdir()) if subdir not in typelib_includes: typelib_includes.append(subdir) elif isinstance(dep, PkgConfigDependency): girdir = dep.get_pkgconfig_variable("girdir") if girdir and girdir not in typelib_includes: typelib_includes.append(girdir) # ldflags will be misinterpreted by gir scanner (showing # spurious dependencies) but building GStreamer fails if they # are not used here. cflags, ldflags, gi_includes = self._get_dependencies_flags(deps, state, depends, use_gir_args=True) scan_command += list(cflags) # need to put our output directory first as we need to use the # generated libraries instead of any possibly installed system/prefix # ones. if isinstance(girtarget, build.SharedLibrary): scan_command += ["-L@PRIVATE_OUTDIR_ABS_%s@" % girtarget.get_id()] scan_command += list(ldflags) for i in gi_includes: scan_command += ['--add-include-path=%s' % i] inc_dirs = kwargs.pop('include_directories', []) if not isinstance(inc_dirs, list): inc_dirs = [inc_dirs] for incd in inc_dirs: if not isinstance(incd.held_object, (str, build.IncludeDirs)): raise MesonException( 'Gir include dirs should be include_directories().') scan_command += get_include_args(inc_dirs) scan_command += get_include_args(gir_inc_dirs + inc_dirs, prefix='--add-include-path=') if isinstance(girtarget, build.Executable): scan_command += ['--program', girtarget] elif isinstance(girtarget, build.SharedLibrary): libname = girtarget.get_basename() scan_command += ['--library', libname] scankwargs = {'output': girfile, 'input': libsources, 'command': scan_command, 'depends': depends} if kwargs.get('install'): scankwargs['install'] = kwargs['install'] scankwargs['install_dir'] = kwargs.get('install_dir_gir', os.path.join(state.environment.get_datadir(), 'gir-1.0')) scan_target = GirTarget(girfile, state.subdir, scankwargs) typelib_output = '%s-%s.typelib' % (ns, nsversion) typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@'] typelib_cmd += get_include_args(gir_inc_dirs, prefix='--includedir=') for incdir in typelib_includes: typelib_cmd += ["--includedir=" + incdir] typelib_kwargs = { 'output': typelib_output, 'command': typelib_cmd, } if kwargs.get('install'): typelib_kwargs['install'] = kwargs['install'] typelib_kwargs['install_dir'] = kwargs.get('install_dir_typelib', os.path.join(state.environment.get_libdir(), 'girepository-1.0')) typelib_target = TypelibTarget(typelib_output, state.subdir, typelib_kwargs) rv = [scan_target, typelib_target] return ModuleReturnValue(rv, rv) def compile_schemas(self, state, args, kwargs): if len(args) != 0: raise MesonException('Compile_schemas does not take positional arguments.') srcdir = os.path.join(state.build_to_src, state.subdir) outdir = state.subdir cmd = [find_program('glib-compile-schemas', 'gsettings-compile')] cmd += ['--targetdir', outdir, srcdir] kwargs['command'] = cmd kwargs['input'] = [] kwargs['output'] = 'gschemas.compiled' if state.subdir == '': targetname = 'gsettings-compile' else: targetname = 'gsettings-compile-' + state.subdir target_g = build.CustomTarget(targetname, state.subdir, kwargs) return ModuleReturnValue(target_g, [target_g]) def yelp(self, state, args, kwargs): if len(args) < 1: raise MesonException('Yelp requires a project id') project_id = args[0] sources = mesonlib.stringlistify(kwargs.pop('sources', [])) if not sources: if len(args) > 1: sources = mesonlib.stringlistify(args[1:]) if not sources: raise MesonException('Yelp requires a list of sources') source_str = '@@'.join(sources) langs = mesonlib.stringlistify(kwargs.pop('languages', [])) media = mesonlib.stringlistify(kwargs.pop('media', [])) symlinks = kwargs.pop('symlink_media', False) if not isinstance(symlinks, bool): raise MesonException('symlink_media must be a boolean') if kwargs: raise MesonException('Unknown arguments passed: {}'.format(', '.join(kwargs.keys()))) script = [sys.executable, state.environment.get_build_command()] args = ['--internal', 'yelphelper', 'install', '--subdir=' + state.subdir, '--id=' + project_id, '--installdir=' + os.path.join(state.environment.get_datadir(), 'help'), '--sources=' + source_str] if symlinks: args.append('--symlinks=true') if media: args.append('--media=' + '@@'.join(media)) if langs: args.append('--langs=' + '@@'.join(langs)) inscript = build.RunScript(script, args) potargs = [state.environment.get_build_command(), '--internal', 'yelphelper', 'pot', '--subdir=' + state.subdir, '--id=' + project_id, '--sources=' + source_str] pottarget = build.RunTarget('help-' + project_id + '-pot', sys.executable, potargs, [], state.subdir) poargs = [state.environment.get_build_command(), '--internal', 'yelphelper', 'update-po', '--subdir=' + state.subdir, '--id=' + project_id, '--sources=' + source_str, '--langs=' + '@@'.join(langs)] potarget = build.RunTarget('help-' + project_id + '-update-po', sys.executable, poargs, [], state.subdir) rv = [inscript, pottarget, potarget] return ModuleReturnValue(None, rv) def gtkdoc(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gtkdoc must have one positional argument.') modulename = args[0] if not isinstance(modulename, str): raise MesonException('Gtkdoc arg must be string.') if 'src_dir' not in kwargs: raise MesonException('Keyword argument src_dir missing.') main_file = kwargs.get('main_sgml', '') if not isinstance(main_file, str): raise MesonException('Main sgml keyword argument must be a string.') main_xml = kwargs.get('main_xml', '') if not isinstance(main_xml, str): raise MesonException('Main xml keyword argument must be a string.') if main_xml != '': if main_file != '': raise MesonException('You can only specify main_xml or main_sgml, not both.') main_file = main_xml targetname = modulename + '-doc' command = [sys.executable, state.environment.get_build_command()] namespace = kwargs.get('namespace', '') mode = kwargs.get('mode', 'auto') VALID_MODES = ('xml', 'sgml', 'none', 'auto') if mode not in VALID_MODES: raise MesonException('gtkdoc: Mode {} is not a valid mode: {}'.format(mode, VALID_MODES)) src_dirs = kwargs['src_dir'] if not isinstance(src_dirs, list): src_dirs = [src_dirs] header_dirs = [] for src_dir in src_dirs: if hasattr(src_dir, 'held_object'): src_dir = src_dir.held_object if not isinstance(src_dir, build.IncludeDirs): raise MesonException('Invalid keyword argument for src_dir.') for inc_dir in src_dir.get_incdirs(): header_dirs.append(os.path.join(state.environment.get_source_dir(), src_dir.get_curdir(), inc_dir)) else: header_dirs.append(src_dir) args = ['--internal', 'gtkdoc', '--sourcedir=' + state.environment.get_source_dir(), '--builddir=' + state.environment.get_build_dir(), '--subdir=' + state.subdir, '--headerdirs=' + '@@'.join(header_dirs), '--mainfile=' + main_file, '--modulename=' + modulename, '--mode=' + mode] if namespace: args.append('--namespace=' + namespace) args += self._unpack_args('--htmlargs=', 'html_args', kwargs) args += self._unpack_args('--scanargs=', 'scan_args', kwargs) args += self._unpack_args('--scanobjsargs=', 'scanobjs_args', kwargs) args += self._unpack_args('--gobjects-types-file=', 'gobject_typesfile', kwargs, state) args += self._unpack_args('--fixxrefargs=', 'fixxref_args', kwargs) args += self._unpack_args('--html-assets=', 'html_assets', kwargs, state) args += self._unpack_args('--content-files=', 'content_files', kwargs, state) args += self._unpack_args('--expand-content-files=', 'expand_content_files', kwargs, state) args += self._unpack_args('--ignore-headers=', 'ignore_headers', kwargs) args += self._unpack_args('--installdir=', 'install_dir', kwargs, state) args += self._get_build_args(kwargs, state) res = [build.RunTarget(targetname, command[0], command[1:] + args, [], state.subdir)] if kwargs.get('install', True): res.append(build.RunScript(command, args)) return ModuleReturnValue(None, res) def _get_build_args(self, kwargs, state): args = [] cflags, ldflags, gi_includes = self._get_dependencies_flags(kwargs.get('dependencies', []), state, include_rpath=True) inc_dirs = kwargs.get('include_directories', []) if not isinstance(inc_dirs, list): inc_dirs = [inc_dirs] for incd in inc_dirs: if not isinstance(incd.held_object, (str, build.IncludeDirs)): raise MesonException( 'Gir include dirs should be include_directories().') cflags.update(get_include_args(inc_dirs)) if cflags: args += ['--cflags=%s' % ' '.join(cflags)] if ldflags: args += ['--ldflags=%s' % ' '.join(ldflags)] compiler = state.environment.coredata.compilers.get('c') if compiler: args += ['--cc=%s' % ' '.join(compiler.get_exelist())] args += ['--ld=%s' % ' '.join(compiler.get_linker_exelist())] return args def gtkdoc_html_dir(self, state, args, kwarga): if len(args) != 1: raise MesonException('Must have exactly one argument.') modulename = args[0] if not isinstance(modulename, str): raise MesonException('Argument must be a string') return ModuleReturnValue(os.path.join('share/gtkdoc/html', modulename), []) @staticmethod def _unpack_args(arg, kwarg_name, kwargs, expend_file_state=None): if kwarg_name not in kwargs: return [] new_args = kwargs[kwarg_name] if not isinstance(new_args, list): new_args = [new_args] args = [] for i in new_args: if expend_file_state and isinstance(i, mesonlib.File): i = os.path.join(expend_file_state.environment.get_build_dir(), i.subdir, i.fname) elif not isinstance(i, str): raise MesonException(kwarg_name + ' values must be strings.') args.append(i) if args: return [arg + '@@'.join(args)] return [] def gdbus_codegen(self, state, args, kwargs): if len(args) != 2: raise MesonException('Gdbus_codegen takes two arguments, name and xml file.') namebase = args[0] xml_file = args[1] target_name = namebase + '-gdbus' cmd = [find_program('gdbus-codegen', target_name)] if 'interface_prefix' in kwargs: 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'): cmd += ['--output-directory', '@OUTDIR@', '--generate-c-code', namebase, '@INPUT@'] else: self._print_gdbus_warning() cmd += ['--generate-c-code', '@OUTDIR@/' + namebase, '@INPUT@'] outputs = [namebase + '.c', namebase + '.h'] custom_kwargs = {'input': xml_file, 'output': outputs, 'command': cmd } ct = build.CustomTarget(target_name, state.subdir, custom_kwargs) return ModuleReturnValue(ct, [ct]) def mkenums(self, state, args, kwargs): if len(args) != 1: raise MesonException('Mkenums requires one positional argument.') basename = args[0] if 'sources' not in kwargs: raise MesonException('Missing keyword argument "sources".') sources = kwargs.pop('sources') if isinstance(sources, str): sources = [sources] elif not isinstance(sources, list): raise MesonException( 'Sources keyword argument must be a string or array.') cmd = [] known_kwargs = ['comments', 'eprod', 'fhead', 'fprod', 'ftail', 'identifier_prefix', 'symbol_prefix', 'template', 'vhead', 'vprod', 'vtail'] known_custom_target_kwargs = ['install_dir', 'build_always', 'depends', 'depend_files'] c_template = h_template = None install_header = False for arg, value in kwargs.items(): if arg == 'sources': raise AssertionError("sources should've already been handled") elif arg == 'c_template': c_template = value if 'template' in kwargs: raise MesonException('Mkenums does not accept both ' 'c_template and template keyword ' 'arguments at the same time.') elif arg == 'h_template': h_template = value if 'template' in kwargs: raise MesonException('Mkenums does not accept both ' 'h_template and template keyword ' 'arguments at the same time.') elif arg == 'install_header': install_header = value elif arg in known_kwargs: cmd += ['--' + arg.replace('_', '-'), value] elif arg not in known_custom_target_kwargs: raise MesonException( 'Mkenums does not take a %s keyword argument.' % (arg, )) cmd = [find_program('glib-mkenums', 'mkenums')] + cmd custom_kwargs = {} for arg in known_custom_target_kwargs: if arg in kwargs: custom_kwargs[arg] = kwargs[arg] targets = [] if h_template is not None: h_output = os.path.splitext(h_template)[0] # We always set template as the first element in the source array # so --template consumes it. h_cmd = cmd + ['--template', '@INPUT@'] h_sources = [h_template] + sources custom_kwargs['install'] = install_header if 'install_dir' not in custom_kwargs: custom_kwargs['install_dir'] = \ state.environment.coredata.get_builtin_option('includedir') h_target = self._make_mkenum_custom_target(state, h_sources, h_output, h_cmd, custom_kwargs) targets.append(h_target) if c_template is not None: c_output = os.path.splitext(c_template)[0] # We always set template as the first element in the source array # so --template consumes it. c_cmd = cmd + ['--template', '@INPUT@'] c_sources = [c_template] + sources # Never install the C file. Complain on bug tracker if you need it. custom_kwargs['install'] = False if h_template is not None: if 'depends' in custom_kwargs: custom_kwargs['depends'] += [h_target] else: custom_kwargs['depends'] = h_target c_target = self._make_mkenum_custom_target(state, c_sources, c_output, c_cmd, custom_kwargs) targets.insert(0, c_target) if c_template is None and h_template is None: generic_cmd = cmd + ['@INPUT@'] custom_kwargs['install'] = install_header if 'install_dir' not in custom_kwargs: custom_kwargs['install_dir'] = \ state.environment.coredata.get_builtin_option('includedir') target = self._make_mkenum_custom_target(state, sources, basename, generic_cmd, custom_kwargs) return ModuleReturnValue(target, [target]) elif len(targets) == 1: return ModuleReturnValue(targets[0], [targets[0]]) else: return ModuleReturnValue(targets, targets) @staticmethod def _make_mkenum_custom_target(state, sources, output, cmd, kwargs): custom_kwargs = { 'input': sources, 'output': output, 'capture': True, 'command': cmd } custom_kwargs.update(kwargs) return build.CustomTarget(output, state.subdir, custom_kwargs, # https://github.com/mesonbuild/meson/issues/973 absolute_paths=True) def genmarshal(self, state, args, kwargs): if len(args) != 1: raise MesonException( 'Genmarshal requires one positional argument.') output = args[0] if 'sources' not in kwargs: raise MesonException('Missing keyword argument "sources".') sources = kwargs.pop('sources') if isinstance(sources, str): sources = [sources] elif not isinstance(sources, list): raise MesonException( 'Sources keyword argument must be a string or array.') cmd = [find_program('glib-genmarshal', output + '_genmarshal')] known_kwargs = ['internal', 'nostdinc', 'skip_source', 'stdinc', 'valist_marshallers'] known_custom_target_kwargs = ['build_always', 'depends', 'depend_files', 'install_dir', 'install_header'] for arg, value in kwargs.items(): if arg == 'prefix': cmd += ['--prefix', value] elif arg in known_kwargs and value: cmd += ['--' + arg.replace('_', '-')] elif arg not in known_custom_target_kwargs: raise MesonException( 'Genmarshal does not take a %s keyword argument.' % ( arg, )) install_header = kwargs.pop('install_header', False) install_dir = kwargs.pop('install_dir', None) custom_kwargs = { 'input': sources, } # https://github.com/GNOME/glib/commit/0fbc98097fac4d3e647684f344e508abae109fdf if mesonlib.version_compare(self._get_native_glib_version(state), '>= 2.51.0'): cmd += ['--output', '@OUTPUT@'] else: custom_kwargs['capture'] = True for arg in known_custom_target_kwargs: if arg in kwargs: custom_kwargs[arg] = kwargs[arg] custom_kwargs['command'] = cmd + ['--body', '@INPUT@'] custom_kwargs['output'] = output + '.c' body = build.CustomTarget(output + '_c', state.subdir, custom_kwargs) custom_kwargs['install'] = install_header if install_dir is not None: custom_kwargs['install_dir'] = install_dir custom_kwargs['command'] = cmd + ['--header', '@INPUT@'] custom_kwargs['output'] = output + '.h' header = build.CustomTarget(output + '_h', state.subdir, custom_kwargs) rv = [body, header] return ModuleReturnValue(rv, rv) @staticmethod def _vapi_args_to_command(prefix, variable, kwargs, accept_vapi=False): arg_list = kwargs.get(variable) if not arg_list: return [] ret = [] if not isinstance(arg_list, list): arg_list = [arg_list] for arg in arg_list: if not isinstance(arg, str): types = 'strings' + ' or InternalDependencys' if accept_vapi else '' raise MesonException('All {} must be {}'.format(variable, types)) ret.append(prefix + arg) return ret def _extract_vapi_packages(self, state, kwargs): ''' Packages are special because we need to: - Get a list of packages for the .deps file - Get a list of depends for any VapiTargets - Get package name from VapiTargets - Add include dirs for any VapiTargets ''' arg_list = kwargs.get('packages') if not arg_list: return [], [], [], [] if not isinstance(arg_list, list): arg_list = [arg_list] vapi_depends = [] vapi_packages = [] vapi_includes = [] ret = [] remaining_args = [] for arg in arg_list: if hasattr(arg, 'held_object'): arg = arg.held_object if isinstance(arg, InternalDependency): targets = [t for t in arg.sources if isinstance(t, VapiTarget)] for target in targets: srcdir = os.path.join(state.environment.get_source_dir(), target.get_subdir()) outdir = os.path.join(state.environment.get_build_dir(), target.get_subdir()) outfile = target.get_outputs()[0][:-5] # Strip .vapi ret.append('--vapidir=' + outdir) ret.append('--girdir=' + outdir) ret.append('--pkg=' + outfile) vapi_depends.append(target) vapi_packages.append(outfile) vapi_includes.append(srcdir) else: vapi_packages.append(arg) remaining_args.append(arg) kwargs['packages'] = remaining_args vapi_args = ret + self._vapi_args_to_command('--pkg=', 'packages', kwargs, accept_vapi=True) return vapi_args, vapi_depends, vapi_packages, vapi_includes def _generate_deps(self, state, library, packages, install_dir): outdir = state.environment.scratch_dir fname = os.path.join(outdir, library + '.deps') with open(fname, 'w') as ofile: for package in packages: ofile.write(package + '\n') return build.Data(mesonlib.File(True, outdir, fname), install_dir) def _get_vapi_link_with(self, target): link_with = [] for dep in target.get_target_dependencies(): if isinstance(dep, build.SharedLibrary): link_with.append(dep) elif isinstance(dep, GirTarget): link_with += self._get_vapi_link_with(dep) return link_with def generate_vapi(self, state, args, kwargs): if len(args) != 1: raise MesonException('The library name is required') if not isinstance(args[0], str): raise MesonException('The first argument must be the name of the library') created_values = [] library = args[0] build_dir = os.path.join(state.environment.get_build_dir(), state.subdir) source_dir = os.path.join(state.environment.get_source_dir(), state.subdir) pkg_cmd, vapi_depends, vapi_packages, vapi_includes = self._extract_vapi_packages(state, kwargs) cmd = [find_program('vapigen', 'Vaapi')] cmd += ['--quiet', '--library=' + library, '--directory=' + build_dir] cmd += self._vapi_args_to_command('--vapidir=', 'vapi_dirs', kwargs) cmd += self._vapi_args_to_command('--metadatadir=', 'metadata_dirs', kwargs) cmd += self._vapi_args_to_command('--girdir=', 'gir_dirs', kwargs) cmd += pkg_cmd cmd += ['--metadatadir=' + source_dir] inputs = kwargs.get('sources') if not inputs: raise MesonException('sources are required to generate the vapi file') if not isinstance(inputs, list): inputs = [inputs] link_with = [] for i in inputs: if isinstance(i, str): cmd.append(os.path.join(source_dir, i)) elif hasattr(i, 'held_object') and isinstance(i.held_object, GirTarget): link_with += self._get_vapi_link_with(i.held_object) subdir = os.path.join(state.environment.get_build_dir(), i.held_object.get_subdir()) gir_file = os.path.join(subdir, i.held_object.get_outputs()[0]) cmd.append(gir_file) else: raise MesonException('Input must be a str or GirTarget') vapi_output = library + '.vapi' custom_kwargs = { 'command': cmd, 'input': inputs, 'output': vapi_output, 'depends': vapi_depends, } install_dir = kwargs.get('install_dir', os.path.join(state.environment.coredata.get_builtin_option('datadir'), 'vala', 'vapi')) if kwargs.get('install'): custom_kwargs['install'] = kwargs['install'] custom_kwargs['install_dir'] = install_dir # We shouldn't need this locally but we install it deps_target = self._generate_deps(state, library, vapi_packages, install_dir) created_values.append(deps_target) vapi_target = VapiTarget(vapi_output, state.subdir, custom_kwargs) # So to try our best to get this to just work we need: # - link with with the correct library # - include the vapi and dependent vapi files in sources # - add relevant directories to include dirs incs = [build.IncludeDirs(state.subdir, ['.'] + vapi_includes, False)] sources = [vapi_target] + vapi_depends rv = InternalDependency(None, incs, [], [], link_with, sources, []) created_values.append(rv) return ModuleReturnValue(rv, created_values) def initialize(): return GnomeModule() meson-0.40.1/mesonbuild/modules/python3.py0000644000175000017500000000553613070746245022117 0ustar jpakkanejpakkane00000000000000# Copyright 2016-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import sysconfig from .. import mesonlib, dependencies from . import ExtensionModule from mesonbuild.modules import ModuleReturnValue class Python3Module(ExtensionModule): def __init__(self): super().__init__() self.snippets.add('extension_module') def extension_module(self, interpreter, state, args, kwargs): if 'name_prefix' in kwargs: raise mesonlib.MesonException('Name_prefix is set automatically, specifying it is forbidden.') if 'name_suffix' in kwargs: raise mesonlib.MesonException('Name_suffix is set automatically, specifying it is forbidden.') host_system = state.host_machine.system if host_system == 'darwin': # Default suffix is 'dylib' but Python does not use it for extensions. suffix = 'so' elif host_system == 'windows': # On Windows the extension is pyd for some unexplainable reason. suffix = 'pyd' else: suffix = [] kwargs['name_prefix'] = '' kwargs['name_suffix'] = suffix return interpreter.func_shared_module(None, args, kwargs) def find_python(self, state, args, kwargs): py3 = dependencies.ExternalProgram('python3', sys.executable, silent=True) return ModuleReturnValue(py3, [py3]) def language_version(self, state, args, kwargs): if args or kwargs: raise mesonlib.MesonException('language_version() takes no arguments.') return ModuleReturnValue(sysconfig.get_python_version(), []) def sysconfig_path(self, state, args, kwargs): if len(args) != 1: raise mesonlib.MesonException('sysconfig_path() requires passing the name of path to get.') if kwargs: raise mesonlib.MesonException('sysconfig_path() does not accept keywords.') path_name = args[0] valid_names = sysconfig.get_path_names() if path_name not in valid_names: raise mesonlib.MesonException('{} is not a valid path name {}.'.format(path_name, valid_names)) # Get a relative path without a prefix, e.g. lib/python3.6/site-packages path = sysconfig.get_path(path_name, vars={'base': ''})[1:] return ModuleReturnValue(path, []) def initialize(): return Python3Module() meson-0.40.1/mesonbuild/modules/modtest.py0000644000175000017500000000156013035766234022164 0ustar jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from . import ModuleReturnValue from . import ExtensionModule class TestModule(ExtensionModule): def print_hello(self, state, args, kwargs): print('Hello from a Meson module') rv = ModuleReturnValue(None, []) return rv def initialize(): return TestModule() meson-0.40.1/mesonbuild/modules/__init__.py0000644000175000017500000000516513070746245022250 0ustar jpakkanejpakkane00000000000000import os from .. import build from .. import dependencies from ..mesonlib import MesonException _found_programs = {} class ExtensionModule: def __init__(self): self.snippets = set() # List of methods that operate only on the interpreter. def is_snippet(self, funcname): return funcname in self.snippets def find_program(program_name, target_name): if program_name in _found_programs: return _found_programs[program_name] program = dependencies.ExternalProgram(program_name) if not program.found(): m = "Target {!r} can't be generated as {!r} could not be found" raise MesonException(m.format(target_name, program_name)) _found_programs[program_name] = program return program def get_include_args(include_dirs, prefix='-I'): ''' Expand include arguments to refer to the source and build dirs by using @SOURCE_ROOT@ and @BUILD_ROOT@ for later substitution ''' if not include_dirs: return [] dirs_str = [] for incdirs in include_dirs: if hasattr(incdirs, "held_object"): dirs = incdirs.held_object else: dirs = incdirs if isinstance(dirs, str): dirs_str += ['%s%s' % (prefix, dirs)] continue # Should be build.IncludeDirs object. basedir = dirs.get_curdir() for d in dirs.get_incdirs(): expdir = os.path.join(basedir, d) srctreedir = os.path.join('@SOURCE_ROOT@', expdir) buildtreedir = os.path.join('@BUILD_ROOT@', expdir) dirs_str += ['%s%s' % (prefix, buildtreedir), '%s%s' % (prefix, srctreedir)] for d in dirs.get_extra_build_dirs(): dirs_str += ['%s%s' % (prefix, d)] return dirs_str class ModuleReturnValue: def __init__(self, return_value, new_objects): self.return_value = return_value assert(isinstance(new_objects, list)) self.new_objects = new_objects class GResourceTarget(build.CustomTarget): def __init__(self, name, subdir, kwargs): super().__init__(name, subdir, kwargs) class GResourceHeaderTarget(build.CustomTarget): def __init__(self, name, subdir, kwargs): super().__init__(name, subdir, kwargs) class GirTarget(build.CustomTarget): def __init__(self, name, subdir, kwargs): super().__init__(name, subdir, kwargs) class TypelibTarget(build.CustomTarget): def __init__(self, name, subdir, kwargs): super().__init__(name, subdir, kwargs) class VapiTarget(build.CustomTarget): def __init__(self, name, subdir, kwargs): super().__init__(name, subdir, kwargs) meson-0.40.1/mesonbuild/modules/pkgconfig.py0000644000175000017500000001605713074426732022462 0ustar jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from .. import build from .. import mesonlib from .. import mlog from . import ModuleReturnValue from . import ExtensionModule class PkgConfigModule(ExtensionModule): def _get_lname(self, l, msg, pcfile): # Nothing special if not l.name_prefix_set: return l.name # Sometimes people want the library to start with 'lib' everywhere, # which is achieved by setting name_prefix to '' and the target name to # 'libfoo'. In that case, try to get the pkg-config '-lfoo' arg correct. if l.prefix == '' and l.name.startswith('lib'): return l.name[3:] # If the library is imported via an import library which is always # named after the target name, '-lfoo' is correct. if l.import_filename: 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.warning(msg.format(l.name, 'name_prefix', l.name, pcfile)) return l.name def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, url, version, pcfile, pub_reqs, priv_reqs, conflicts, priv_libs): coredata = state.environment.get_coredata() outdir = state.environment.scratch_dir fname = os.path.join(outdir, pcfile) with open(fname, 'w') as ofile: ofile.write('prefix=%s\n' % coredata.get_builtin_option('prefix')) # '${prefix}' is ignored if the second path is absolute (see # 'os.path.join' for details) ofile.write('libdir=%s\n' % os.path.join('${prefix}', coredata.get_builtin_option('libdir'))) ofile.write('includedir=%s\n' % os.path.join('${prefix}', coredata.get_builtin_option('includedir'))) ofile.write('\n') ofile.write('Name: %s\n' % name) if len(description) > 0: ofile.write('Description: %s\n' % description) if len(url) > 0: ofile.write('URL: %s\n' % url) ofile.write('Version: %s\n' % version) if len(pub_reqs) > 0: ofile.write('Requires: {}\n'.format(' '.join(pub_reqs))) if len(priv_reqs) > 0: ofile.write( 'Requires.private: {}\n'.format(' '.join(priv_reqs))) if len(conflicts) > 0: ofile.write('Conflicts: {}\n'.format(' '.join(conflicts))) def generate_libs_flags(libs): msg = 'Library target {0!r} has {1!r} set. Compilers ' \ 'may not find it from its \'-l{2}\' linker flag in the ' \ '{3!r} pkg-config file.' for l in libs: if isinstance(l, str): yield l else: install_dir = l.get_custom_install_dir()[0] if install_dir: yield '-L${prefix}/%s ' % install_dir else: yield '-L${libdir}' lname = self._get_lname(l, msg, pcfile) # If using a custom suffix, the compiler may not be able to # find the library if l.name_suffix_set: 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)))) if len(priv_libs) > 0: ofile.write('Libs.private: {}\n'.format(' '.join(generate_libs_flags(priv_libs)))) ofile.write('Cflags:') for h in subdirs: if h == '.': h = '' ofile.write(' ') ofile.write(os.path.join('-I${includedir}', h)) ofile.write('\n') def process_libs(self, libs): if not isinstance(libs, list): libs = [libs] processed_libs = [] for l in libs: if hasattr(l, 'held_object'): l = l.held_object if not isinstance(l, (build.SharedLibrary, build.StaticLibrary, str)): raise mesonlib.MesonException('Library argument not a library object nor a string.') processed_libs.append(l) return processed_libs def generate(self, state, args, kwargs): if len(args) > 0: raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.') libs = self.process_libs(kwargs.get('libraries', [])) priv_libs = self.process_libs(kwargs.get('libraries_private', [])) subdirs = mesonlib.stringlistify(kwargs.get('subdirs', ['.'])) version = kwargs.get('version', None) if not isinstance(version, str): raise mesonlib.MesonException('Version must be specified.') name = kwargs.get('name', None) if not isinstance(name, str): raise mesonlib.MesonException('Name not specified.') filebase = kwargs.get('filebase', name) if not isinstance(filebase, str): raise mesonlib.MesonException('Filebase must be a string.') description = kwargs.get('description', None) if not isinstance(description, str): raise mesonlib.MesonException('Description is not a string.') url = kwargs.get('url', '') if not isinstance(url, str): raise mesonlib.MesonException('URL is not a string.') pub_reqs = mesonlib.stringlistify(kwargs.get('requires', [])) priv_reqs = mesonlib.stringlistify(kwargs.get('requires_private', [])) conflicts = mesonlib.stringlistify(kwargs.get('conflicts', [])) pcfile = filebase + '.pc' pkgroot = kwargs.get('install_dir', None) if pkgroot is None: pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'pkgconfig') if not isinstance(pkgroot, str): raise mesonlib.MesonException('Install_dir must be a string.') self.generate_pkgconfig_file(state, libs, subdirs, name, description, url, version, pcfile, pub_reqs, priv_reqs, conflicts, priv_libs) res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot) return ModuleReturnValue(res, [res]) def initialize(): return PkgConfigModule() meson-0.40.1/mesonbuild/mparser.py0000644000175000017500000005557613076631051020517 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import re from .mesonlib import MesonException from . import mlog class ParseException(MesonException): def __init__(self, text, line, lineno, colno): # Format as error message, followed by the line with the error, followed by a caret to show the error column. super().__init__("%s\n%s\n%s" % (text, line, '%s^' % (' ' * colno))) self.lineno = lineno self.colno = colno class BlockParseException(MesonException): def __init__(self, text, line, lineno, colno, start_line, start_lineno, start_colno): # This can be formatted in two ways - one if the block start and end are on the same line, and a different way if they are on different lines. if lineno == start_lineno: # If block start and end are on the same line, it is formatted as: # Error message # Followed by the line with the error # Followed by a caret to show the block start # Followed by underscores # Followed by a caret to show the block end. super().__init__("%s\n%s\n%s" % (text, line, '%s^%s^' % (' ' * start_colno, '_' * (colno - start_colno - 1)))) else: # If block start and end are on different lines, it is formatted as: # Error message # Followed by the line with the error # Followed by a caret to show the error column. # Followed by a message saying where the block started. # Followed by the line of the block start. # Followed by a caret for the block start. super().__init__("%s\n%s\n%s\nFor a block that started at %d,%d\n%s\n%s" % (text, line, '%s^' % (' ' * colno), start_lineno, start_colno, start_line, "%s^" % (' ' * start_colno))) self.lineno = lineno self.colno = colno class Token: def __init__(self, tid, subdir, line_start, lineno, colno, bytespan, value): self.tid = tid self.subdir = subdir self.line_start = line_start self.lineno = lineno self.colno = colno self.bytespan = bytespan self.value = value def __eq__(self, other): if isinstance(other, str): return self.tid == other return self.tid == other.tid class Lexer: def __init__(self, code): self.code = code self.keywords = {'true', 'false', 'if', 'else', 'elif', 'endif', 'and', 'or', 'not', 'foreach', 'endforeach'} self.token_specification = [ # Need to be sorted longest to shortest. ('ignore', re.compile(r'[ \t]')), ('id', re.compile('[_a-zA-Z][_0-9a-zA-Z]*')), ('number', re.compile(r'\d+')), ('eol_cont', re.compile(r'\\\n')), ('eol', re.compile(r'\n')), ('multiline_string', re.compile(r"'''(.|\n)*?'''", re.M)), ('comment', re.compile(r'#.*')), ('lparen', re.compile(r'\(')), ('rparen', re.compile(r'\)')), ('lbracket', re.compile(r'\[')), ('rbracket', re.compile(r'\]')), ('dblquote', re.compile(r'"')), ('string', re.compile(r"'([^'\\]|(\\.))*'")), ('comma', re.compile(r',')), ('plusassign', re.compile(r'\+=')), ('dot', re.compile(r'\.')), ('plus', re.compile(r'\+')), ('dash', re.compile(r'-')), ('star', re.compile(r'\*')), ('percent', re.compile(r'%')), ('fslash', re.compile(r'/')), ('colon', re.compile(r':')), ('equal', re.compile(r'==')), ('nequal', re.compile(r'!=')), ('assign', re.compile(r'=')), ('le', re.compile(r'<=')), ('lt', re.compile(r'<')), ('ge', re.compile(r'>=')), ('gt', re.compile(r'>')), ('questionmark', re.compile(r'\?')), ] def getline(self, line_start): return self.code[line_start:self.code.find('\n', line_start)] def lex(self, subdir): line_start = 0 lineno = 1 loc = 0 par_count = 0 bracket_count = 0 col = 0 while loc < len(self.code): matched = False value = None for (tid, reg) in self.token_specification: mo = reg.match(self.code, loc) if mo: curline = lineno curline_start = line_start col = mo.start() - line_start matched = True span_start = loc loc = mo.end() span_end = loc bytespan = (span_start, span_end) match_text = mo.group() if tid == 'ignore' or tid == 'comment': break elif tid == 'lparen': par_count += 1 elif tid == 'rparen': par_count -= 1 elif tid == 'lbracket': bracket_count += 1 elif tid == 'rbracket': bracket_count -= 1 elif tid == 'dblquote': raise ParseException('Double quotes are not supported. Use single quotes.', self.getline(line_start), lineno, col) elif tid == 'string': value = match_text[1:-1]\ .replace(r"\'", "'")\ .replace(r" \\ ".strip(), r" \ ".strip())\ .replace("\\n", "\n") elif tid == 'multiline_string': tid = 'string' value = match_text[3:-3] lines = match_text.split('\n') if len(lines) > 1: lineno += len(lines) - 1 line_start = mo.end() - len(lines[-1]) elif tid == 'number': value = int(match_text) elif tid == 'eol' or tid == 'eol_cont': lineno += 1 line_start = loc if par_count > 0 or bracket_count > 0: break elif tid == 'id': if match_text in self.keywords: tid = match_text else: value = match_text yield Token(tid, subdir, curline_start, curline, col, bytespan, value) break if not matched: raise ParseException('lexer', self.getline(line_start), lineno, col) class ElementaryNode: def __init__(self, token): self.lineno = token.lineno self.subdir = token.subdir self.colno = token.colno self.value = token.value self.bytespan = token.bytespan class BooleanNode(ElementaryNode): def __init__(self, token, value): super().__init__(token) self.value = value assert(isinstance(self.value, bool)) class IdNode(ElementaryNode): def __init__(self, token): super().__init__(token) assert(isinstance(self.value, str)) def __str__(self): return "Id node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno) class NumberNode(ElementaryNode): def __init__(self, token): super().__init__(token) assert(isinstance(self.value, int)) class StringNode(ElementaryNode): def __init__(self, token): super().__init__(token) assert(isinstance(self.value, str)) def __str__(self): return "String node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno) class ArrayNode: def __init__(self, args): self.subdir = args.subdir self.lineno = args.lineno self.colno = args.colno self.args = args class EmptyNode: def __init__(self, lineno, colno): self.subdir = '' self.lineno = lineno self.colno = colno self.value = None class OrNode: def __init__(self, left, right): self.subdir = left.subdir self.lineno = left.lineno self.colno = left.colno self.left = left self.right = right class AndNode: def __init__(self, left, right): self.subdir = left.subdir self.lineno = left.lineno self.colno = left.colno self.left = left self.right = right class ComparisonNode: def __init__(self, ctype, left, right): self.lineno = left.lineno self.colno = left.colno self.subdir = left.subdir self.left = left self.right = right self.ctype = ctype class ArithmeticNode: def __init__(self, operation, left, right): self.subdir = left.subdir self.lineno = left.lineno self.colno = left.colno self.left = left self.right = right self.operation = operation class NotNode: def __init__(self, location_node, value): self.subdir = location_node.subdir self.lineno = location_node.lineno self.colno = location_node.colno self.value = value class CodeBlockNode: def __init__(self, location_node): self.subdir = location_node.subdir self.lineno = location_node.lineno self.colno = location_node.colno self.lines = [] class IndexNode: def __init__(self, iobject, index): self.iobject = iobject self.index = index self.subdir = iobject.subdir self.lineno = iobject.lineno self.colno = iobject.colno class MethodNode: def __init__(self, subdir, lineno, colno, source_object, name, args): self.subdir = subdir self.lineno = lineno self.colno = colno self.source_object = source_object self.name = name assert(isinstance(self.name, str)) self.args = args class FunctionNode: def __init__(self, subdir, lineno, colno, func_name, args): self.subdir = subdir self.lineno = lineno self.colno = colno self.func_name = func_name assert(isinstance(func_name, str)) self.args = args class AssignmentNode: def __init__(self, lineno, colno, var_name, value): self.lineno = lineno self.colno = colno self.var_name = var_name assert(isinstance(var_name, str)) self.value = value class PlusAssignmentNode: def __init__(self, lineno, colno, var_name, value): self.lineno = lineno self.colno = colno self.var_name = var_name assert(isinstance(var_name, str)) self.value = value class ForeachClauseNode: def __init__(self, lineno, colno, varname, items, block): self.lineno = lineno self.colno = colno self.varname = varname self.items = items self.block = block class IfClauseNode: def __init__(self, lineno, colno): self.lineno = lineno self.colno = colno self.ifs = [] self.elseblock = EmptyNode(lineno, colno) class UMinusNode: def __init__(self, current_location, value): self.subdir = current_location.subdir self.lineno = current_location.lineno self.colno = current_location.colno self.value = value class IfNode: def __init__(self, lineno, colno, condition, block): self.lineno = lineno self.colno = colno self.condition = condition self.block = block class TernaryNode: def __init__(self, lineno, colno, condition, trueblock, falseblock): self.lineno = lineno self.colno = colno self.condition = condition self.trueblock = trueblock self.falseblock = falseblock class ArgumentNode: def __init__(self, token): self.lineno = token.lineno self.colno = token.colno self.subdir = token.subdir self.arguments = [] self.commas = [] self.kwargs = {} self.order_error = False def prepend(self, statement): if self.num_kwargs() > 0: self.order_error = True if not isinstance(statement, EmptyNode): self.arguments = [statement] + self.arguments def append(self, statement): if self.num_kwargs() > 0: self.order_error = True if not isinstance(statement, EmptyNode): self.arguments += [statement] def set_kwarg(self, name, value): if name in self.kwargs: mlog.warning('Keyword argument "%s" defined multiple times. This will be a an error in future Meson releases.' % name) self.kwargs[name] = value def num_args(self): return len(self.arguments) def num_kwargs(self): return len(self.kwargs) def incorrect_order(self): return self.order_error def __len__(self): return self.num_args() # Fixme comparison_map = {'equal': '==', 'nequal': '!=', 'lt': '<', 'le': '<=', 'gt': '>', 'ge': '>=' } # Recursive descent parser for Meson's definition language. # Very basic apart from the fact that we have many precedence # levels so there are not enough words to describe them all. # Enter numbering: # # 1 assignment # 2 or # 3 and # 4 comparison # 5 arithmetic # 6 negation # 7 funcall, method call # 8 parentheses # 9 plain token 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 def getsym(self): try: self.current = next(self.stream) except StopIteration: self.current = Token('eof', '', self.current.line_start, self.current.lineno, self.current.colno + self.current.bytespan[1] - self.current.bytespan[0], (0, 0), None) def getline(self): return self.lexer.getline(self.current.line_start) def accept(self, s): if self.current.tid == s: self.getsym() return True return False def expect(self, s): if self.accept(s): return True raise ParseException('Expecting %s got %s.' % (s, self.current.tid), self.getline(), self.current.lineno, self.current.colno) def block_expect(self, s, block_start): if self.accept(s): return True raise BlockParseException('Expecting %s got %s.' % (s, self.current.tid), self.getline(), self.current.lineno, self.current.colno, self.lexer.getline(block_start.line_start), block_start.lineno, block_start.colno) def parse(self): block = self.codeblock() self.expect('eof') return block def statement(self): return self.e1() def e1(self): left = self.e2() if self.accept('plusassign'): value = self.e1() if not isinstance(left, IdNode): raise ParseException('Plusassignment target must be an id.', self.getline(), left.lineno, left.colno) return PlusAssignmentNode(left.lineno, left.colno, left.value, value) elif self.accept('assign'): value = self.e1() if not isinstance(left, IdNode): raise ParseException('Assignment target must be an id.', self.getline(), left.lineno, left.colno) return AssignmentNode(left.lineno, left.colno, left.value, value) elif self.accept('questionmark'): if self.in_ternary: raise ParseException('Nested ternary operators are not allowed.', self.getline(), left.lineno, left.colno) self.in_ternary = True trueblock = self.e1() self.expect('colon') falseblock = self.e1() self.in_ternary = False return TernaryNode(left.lineno, left.colno, left, trueblock, falseblock) return left def e2(self): left = self.e3() while self.accept('or'): left = OrNode(left, self.e3()) return left def e3(self): left = self.e4() while self.accept('and'): left = AndNode(left, self.e4()) return left def e4(self): left = self.e5() for nodename, operator_type in comparison_map.items(): if self.accept(nodename): return ComparisonNode(operator_type, left, self.e5()) return left def e5(self): return self.e5add() def e5add(self): left = self.e5sub() if self.accept('plus'): return ArithmeticNode('add', left, self.e5add()) return left def e5sub(self): left = self.e5mod() if self.accept('dash'): return ArithmeticNode('sub', left, self.e5sub()) return left def e5mod(self): left = self.e5mul() if self.accept('percent'): return ArithmeticNode('mod', left, self.e5mod()) return left def e5mul(self): left = self.e5div() if self.accept('star'): return ArithmeticNode('mul', left, self.e5mul()) return left def e5div(self): left = self.e6() if self.accept('fslash'): return ArithmeticNode('div', left, self.e5div()) return left def e6(self): if self.accept('not'): return NotNode(self.current, self.e7()) if self.accept('dash'): return UMinusNode(self.current, self.e7()) return self.e7() def e7(self): left = self.e8() block_start = self.current if self.accept('lparen'): args = self.args() self.block_expect('rparen', block_start) if not isinstance(left, IdNode): raise ParseException('Function call must be applied to plain id', self.getline(), left.lineno, left.colno) left = FunctionNode(left.subdir, left.lineno, left.colno, left.value, args) go_again = True while go_again: go_again = False if self.accept('dot'): go_again = True left = self.method_call(left) if self.accept('lbracket'): go_again = True left = self.index_call(left) return left def e8(self): block_start = self.current if self.accept('lparen'): e = self.statement() self.block_expect('rparen', block_start) return e elif self.accept('lbracket'): args = self.args() self.block_expect('rbracket', block_start) return ArrayNode(args) else: return self.e9() def e9(self): t = self.current if self.accept('true'): return BooleanNode(t, True) if self.accept('false'): return BooleanNode(t, False) if self.accept('id'): return IdNode(t) if self.accept('number'): return NumberNode(t) if self.accept('string'): return StringNode(t) return EmptyNode(self.current.lineno, self.current.colno) def args(self): s = self.statement() a = ArgumentNode(s) while not isinstance(s, EmptyNode): potential = self.current if self.accept('comma'): a.commas.append(potential) a.append(s) elif self.accept('colon'): if not isinstance(s, IdNode): raise ParseException('Keyword argument must be a plain identifier.', self.getline(), s.lineno, s.colno) a.set_kwarg(s.value, self.statement()) potential = self.current if not self.accept('comma'): return a a.commas.append(potential) else: a.append(s) return a s = self.statement() return a def method_call(self, source_object): methodname = self.e9() if not(isinstance(methodname, IdNode)): raise ParseException('Method name must be plain id', self.getline(), self.current.lineno, self.current.colno) self.expect('lparen') args = self.args() self.expect('rparen') method = MethodNode(methodname.subdir, methodname.lineno, methodname.colno, source_object, methodname.value, args) if self.accept('dot'): return self.method_call(method) return method def index_call(self, source_object): index_statement = self.statement() self.expect('rbracket') return IndexNode(source_object, index_statement) def foreachblock(self): t = self.current self.expect('id') varname = t self.expect('colon') items = self.statement() block = self.codeblock() return ForeachClauseNode(varname.lineno, varname.colno, varname, items, block) def ifblock(self): condition = self.statement() clause = IfClauseNode(condition.lineno, condition.colno) block = self.codeblock() clause.ifs.append(IfNode(clause.lineno, clause.colno, condition, block)) self.elseifblock(clause) clause.elseblock = self.elseblock() return clause def elseifblock(self, clause): while self.accept('elif'): s = self.statement() self.expect('eol') b = self.codeblock() clause.ifs.append(IfNode(s.lineno, s.colno, s, b)) def elseblock(self): if self.accept('else'): self.expect('eol') return self.codeblock() def line(self): block_start = self.current if self.current == 'eol': return EmptyNode(self.current.lineno, self.current.colno) if self.accept('if'): block = self.ifblock() self.block_expect('endif', block_start) return block if self.accept('foreach'): block = self.foreachblock() self.block_expect('endforeach', block_start) return block return self.statement() def codeblock(self): block = CodeBlockNode(self.current) cond = True while cond: curline = self.line() if not isinstance(curline, EmptyNode): block.lines.append(curline) cond = self.accept('eol') return block meson-0.40.1/mesonbuild/interpreter.py0000644000175000017500000035120313076637146021406 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from . import mparser from . import environment from . import coredata from . import dependencies from . import mlog from . import build from . import optinterpreter from . import compilers from .wrap import wrap, WrapMode from . import mesonlib 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 from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode from .interpreterbase import InterpreterObject, MutableInterpreterObject from .modules import ModuleReturnValue import os, sys, shutil, uuid import re from collections import namedtuple import importlib run_depr_printed = False def stringifyUserArguments(args): if isinstance(args, list): return '[%s]' % ', '.join([stringifyUserArguments(x) for x in args]) elif isinstance(args, int): return str(args) elif isinstance(args, str): return "'%s'" % args raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.') class TryRunResultHolder(InterpreterObject): def __init__(self, res): super().__init__() self.res = res self.methods.update({'returncode': self.returncode_method, 'compiled': self.compiled_method, 'stdout': self.stdout_method, 'stderr': self.stderr_method, }) def returncode_method(self, args, kwargs): return self.res.returncode def compiled_method(self, args, kwargs): return self.res.compiled def stdout_method(self, args, kwargs): return self.res.stdout def stderr_method(self, args, kwargs): return self.res.stderr class RunProcess(InterpreterObject): 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, 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, mesonintrospect, in_builddir): cmd_name = command_array[0] env = {'MESON_SOURCE_ROOT': source_dir, 'MESON_BUILD_ROOT': build_dir, 'MESON_SUBDIR': subdir, 'MESONINTROSPECT': mesonintrospect} if in_builddir: cwd = os.path.join(build_dir, subdir) else: cwd = os.path.join(source_dir, subdir) child_env = os.environ.copy() child_env.update(env) mlog.debug('Running command:', ' '.join(command_array)) try: return Popen_safe(command_array, env=child_env, cwd=cwd) except FileNotFoundError: pass # Was not a command, is a program in path? exe = shutil.which(cmd_name) if exe is not None: command_array = [exe] + command_array[1:] return Popen_safe(command_array, env=child_env, cwd=cwd) # No? Maybe it is a script in the source tree. fullpath = os.path.join(source_dir, subdir, cmd_name) command_array = [fullpath] + command_array[1:] try: return Popen_safe(command_array, env=child_env, cwd=cwd) except FileNotFoundError: raise InterpreterException('Could not execute command "%s".' % cmd_name) def returncode_method(self, args, kwargs): return self.returncode def stdout_method(self, args, kwargs): return self.stdout def stderr_method(self, args, kwargs): return self.stderr class ConfigureFileHolder(InterpreterObject): def __init__(self, subdir, sourcename, targetname, configuration_data): InterpreterObject.__init__(self) self.held_object = build.ConfigureFile(subdir, sourcename, targetname, configuration_data) class EnvironmentVariablesHolder(MutableInterpreterObject): def __init__(self): super().__init__() self.held_object = build.EnvironmentVariables() self.methods.update({'set': self.set_method, 'append': self.append_method, 'prepend': self.prepend_method, }) def __repr__(self): repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.held_object.envvars) @stringArgs def add_var(self, method, args, kwargs): if not isinstance(kwargs.get("separator", ""), str): raise InterpreterException("EnvironmentVariablesHolder methods 'separator'" " argument needs to be a string.") if len(args) < 2: raise InterpreterException("EnvironmentVariablesHolder methods require at least" "2 arguments, first is the name of the variable and" " following one are values") self.held_object.envvars.append((method, args[0], args[1:], kwargs)) def set_method(self, args, kwargs): self.add_var(self.held_object.set, args, kwargs) def append_method(self, args, kwargs): self.add_var(self.held_object.append, args, kwargs) def prepend_method(self, args, kwargs): self.add_var(self.held_object.prepend, args, kwargs) class ConfigurationDataHolder(MutableInterpreterObject): def __init__(self): super().__init__() self.used = False # These objects become immutable after use in configure_file. self.held_object = build.ConfigurationData() self.methods.update({'set': self.set_method, 'set10': self.set10_method, 'set_quoted': self.set_quoted_method, 'has': self.has_method, 'get': self.get_method, }) def is_used(self): return self.used def mark_used(self): self.used = True def validate_args(self, args, kwargs): if len(args) != 2: raise InterpreterException("Configuration set requires 2 arguments.") if self.used: raise InterpreterException("Can not set values on configuration object that has been used.") name = args[0] val = args[1] desc = kwargs.get('description', None) if not isinstance(name, str): raise InterpreterException("First argument to set must be a string.") if desc is not None and not isinstance(desc, str): raise InterpreterException('Description must be a string.') return name, val, desc def set_method(self, args, kwargs): (name, val, desc) = self.validate_args(args, kwargs) self.held_object.values[name] = (val, desc) def set_quoted_method(self, args, kwargs): (name, val, desc) = self.validate_args(args, kwargs) if not isinstance(val, str): raise InterpreterException("Second argument to set_quoted must be a string.") escaped_val = '\\"'.join(val.split('"')) self.held_object.values[name] = ('"' + escaped_val + '"', desc) def set10_method(self, args, kwargs): (name, val, desc) = self.validate_args(args, kwargs) if val: self.held_object.values[name] = (1, desc) else: self.held_object.values[name] = (0, desc) def has_method(self, args, kwargs): return args[0] in self.held_object.values def get_method(self, args, kwargs): if len(args) < 1 or len(args) > 2: raise InterpreterException('Get method takes one or two arguments.') name = args[0] if name in self.held_object: return self.held_object.get(name)[0] if len(args) > 1: return args[1] raise InterpreterException('Entry %s not in configuration data.' % name) def get(self, name): return self.held_object.values[name] # (val, desc) def keys(self): return self.held_object.values.keys() # Interpreter objects can not be pickled so we must have # these wrappers. class DependencyHolder(InterpreterObject): def __init__(self, dep): InterpreterObject.__init__(self) self.held_object = dep self.methods.update({'found': self.found_method, 'type_name': self.type_name_method, 'version': self.version_method, 'get_pkgconfig_variable': self.pkgconfig_method, }) def type_name_method(self, args, kwargs): return self.held_object.type_name def found_method(self, args, kwargs): if self.held_object.type_name == 'internal': return True return self.held_object.found() def version_method(self, args, kwargs): return self.held_object.get_version() def pkgconfig_method(self, args, kwargs): if not isinstance(args, list): args = [args] if len(args) != 1: raise InterpreterException('get_pkgconfig_variable takes exactly one argument.') varname = args[0] if not isinstance(varname, str): raise InterpreterException('Variable name must be a string.') return self.held_object.get_pkgconfig_variable(varname) class InternalDependencyHolder(InterpreterObject): def __init__(self, dep): InterpreterObject.__init__(self) self.held_object = dep self.methods.update({'found': self.found_method, 'version': self.version_method, }) def found_method(self, args, kwargs): return True def version_method(self, args, kwargs): return self.held_object.get_version() class ExternalProgramHolder(InterpreterObject): def __init__(self, ep): InterpreterObject.__init__(self) self.held_object = ep self.methods.update({'found': self.found_method, 'path': self.path_method}) def found_method(self, args, kwargs): return self.found() def path_method(self, args, kwargs): return self.held_object.get_path() def found(self): return self.held_object.found() def get_command(self): return self.held_object.get_command() def get_name(self): return self.held_object.get_name() class ExternalLibraryHolder(InterpreterObject): def __init__(self, el): InterpreterObject.__init__(self) self.held_object = el self.methods.update({'found': self.found_method}) def found(self): return self.held_object.found() def found_method(self, args, kwargs): return self.found() def get_name(self): return self.held_object.name def get_compile_args(self): return self.held_object.get_compile_args() def get_link_args(self): return self.held_object.get_link_args() def get_exe_args(self): return self.held_object.get_exe_args() class GeneratorHolder(InterpreterObject): def __init__(self, interpreter, args, kwargs): super().__init__() self.interpreter = interpreter self.held_object = build.Generator(args, kwargs) self.methods.update({'process': self.process_method}) def process_method(self, args, kwargs): extras = mesonlib.stringlistify(kwargs.get('extra_args', [])) gl = self.held_object.process_files('Generator', args, self.interpreter, extra_args=extras) return GeneratedListHolder(gl) class GeneratedListHolder(InterpreterObject): def __init__(self, arg1, extra_args=[]): super().__init__() if isinstance(arg1, GeneratorHolder): self.held_object = build.GeneratedList(arg1.held_object, extra_args) else: self.held_object = arg1 def __repr__(self): r = '<{}: {!r}>' return r.format(self.__class__.__name__, self.held_object.get_outputs()) def add_file(self, a): self.held_object.add_file(a) class BuildMachine(InterpreterObject): def __init__(self, compilers): self.compilers = compilers InterpreterObject.__init__(self) self.held_object = environment.MachineInfo(environment.detect_system(), environment.detect_cpu_family(self.compilers), environment.detect_cpu(self.compilers), sys.byteorder) self.methods.update({'system': self.system_method, 'cpu_family': self.cpu_family_method, 'cpu': self.cpu_method, 'endian': self.endian_method, }) def cpu_family_method(self, args, kwargs): return self.held_object.cpu_family def cpu_method(self, args, kwargs): return self.held_object.cpu def system_method(self, args, kwargs): return self.held_object.system def endian_method(self, args, kwargs): return self.held_object.endian # This class will provide both host_machine and # target_machine class CrossMachineInfo(InterpreterObject): def __init__(self, cross_info): InterpreterObject.__init__(self) minimum_cross_info = {'cpu', 'cpu_family', 'endian', 'system'} if set(cross_info) < minimum_cross_info: raise InterpreterException( 'Machine info is currently {}\n'.format(cross_info) + 'but is missing {}.'.format(minimum_cross_info - set(cross_info))) self.info = cross_info self.held_object = environment.MachineInfo(cross_info['system'], cross_info['cpu_family'], cross_info['cpu'], cross_info['endian']) self.methods.update({'system': self.system_method, 'cpu': self.cpu_method, 'cpu_family': self.cpu_family_method, 'endian': self.endian_method, }) def cpu_family_method(self, args, kwargs): return self.held_object.cpu_family def cpu_method(self, args, kwargs): return self.held_object.cpu def system_method(self, args, kwargs): return self.held_object.system def endian_method(self, args, kwargs): return self.held_object.endian class IncludeDirsHolder(InterpreterObject): def __init__(self, idobj): super().__init__() self.held_object = idobj class Headers(InterpreterObject): def __init__(self, sources, kwargs): InterpreterObject.__init__(self) self.sources = sources self.install_subdir = kwargs.get('subdir', '') self.custom_install_dir = kwargs.get('install_dir', None) if self.custom_install_dir is not None: if not isinstance(self.custom_install_dir, str): raise InterpreterException('Custom_install_dir must be a string.') def set_install_subdir(self, subdir): self.install_subdir = subdir def get_install_subdir(self): return self.install_subdir def get_sources(self): return self.sources def get_custom_install_dir(self): return self.custom_install_dir class DataHolder(InterpreterObject): def __init__(self, data): super().__init__() self.held_object = data def get_source_subdir(self): return self.held_object.source_subdir def get_sources(self): return self.held_object.sources def get_install_dir(self): return self.held_object.install_dir class InstallDir(InterpreterObject): def __init__(self, src_subdir, inst_subdir, install_dir, install_mode): InterpreterObject.__init__(self) self.source_subdir = src_subdir self.installable_subdir = inst_subdir self.install_dir = install_dir self.install_mode = install_mode class Man(InterpreterObject): def __init__(self, source_subdir, sources, kwargs): InterpreterObject.__init__(self) self.source_subdir = source_subdir self.sources = sources self.validate_sources() if len(kwargs) > 1: raise InvalidArguments('Man function takes at most one keyword arguments.') self.custom_install_dir = kwargs.get('install_dir', None) if self.custom_install_dir is not None and not isinstance(self.custom_install_dir, str): raise InterpreterException('Custom_install_dir must be a string.') def validate_sources(self): for s in self.sources: try: num = int(s.split('.')[-1]) except (IndexError, ValueError): num = 0 if num < 1 or num > 8: raise InvalidArguments('Man file must have a file extension of a number between 1 and 8') def get_custom_install_dir(self): return self.custom_install_dir def get_sources(self): return self.sources def get_source_subdir(self): return self.source_subdir class GeneratedObjectsHolder(InterpreterObject): def __init__(self, held_object): super().__init__() self.held_object = held_object class TargetHolder(InterpreterObject): def __init__(self): super().__init__() class BuildTargetHolder(TargetHolder): def __init__(self, target, interp): super().__init__() self.held_object = target self.interpreter = interp self.methods.update({'extract_objects': self.extract_objects_method, 'extract_all_objects': self.extract_all_objects_method, 'get_id': self.get_id_method, 'outdir': self.outdir_method, 'full_path': self.full_path_method, 'private_dir_include': self.private_dir_include_method, }) def __repr__(self): r = '<{} {}: {}>' h = self.held_object return r.format(self.__class__.__name__, h.get_id(), h.filename) def is_cross(self): return self.held_object.is_cross() def private_dir_include_method(self, args, kwargs): return IncludeDirsHolder(build.IncludeDirs('', [], False, [self.interpreter.backend.get_target_private_dir(self.held_object)])) def full_path_method(self, args, kwargs): return self.interpreter.backend.get_target_filename_abs(self.held_object) def outdir_method(self, args, kwargs): return self.interpreter.backend.get_target_dir(self.held_object) def extract_objects_method(self, args, kwargs): gobjs = self.held_object.extract_objects(args) return GeneratedObjectsHolder(gobjs) def extract_all_objects_method(self, args, kwargs): gobjs = self.held_object.extract_all_objects() return GeneratedObjectsHolder(gobjs) def get_id_method(self, args, kwargs): return self.held_object.get_id() class ExecutableHolder(BuildTargetHolder): def __init__(self, target, interp): super().__init__(target, interp) class StaticLibraryHolder(BuildTargetHolder): def __init__(self, target, interp): super().__init__(target, interp) class SharedLibraryHolder(BuildTargetHolder): def __init__(self, target, interp): super().__init__(target, interp) class SharedModuleHolder(BuildTargetHolder): def __init__(self, target, interp): super().__init__(target, interp) class JarHolder(BuildTargetHolder): def __init__(self, target, interp): super().__init__(target, interp) class CustomTargetHolder(TargetHolder): def __init__(self, object_to_hold, interp): super().__init__() self.held_object = object_to_hold self.interpreter = interp self.methods.update({'full_path': self.full_path_method, }) def __repr__(self): r = '<{} {}: {}>' h = self.held_object return r.format(self.__class__.__name__, h.get_id(), h.command) def full_path_method(self, args, kwargs): return self.interpreter.backend.get_target_filename_abs(self.held_object) class RunTargetHolder(InterpreterObject): def __init__(self, name, command, args, dependencies, subdir): self.held_object = build.RunTarget(name, command, args, dependencies, subdir) def __repr__(self): r = '<{} {}: {}>' h = self.held_object return r.format(self.__class__.__name__, h.get_id(), h.command) class Test(InterpreterObject): def __init__(self, name, suite, exe, is_parallel, cmd_args, env, should_fail, timeout, workdir): InterpreterObject.__init__(self) self.name = name self.suite = suite self.exe = exe self.is_parallel = is_parallel self.cmd_args = cmd_args self.env = env self.should_fail = should_fail self.timeout = timeout self.workdir = workdir def get_exe(self): return self.exe def get_name(self): return self.name class SubprojectHolder(InterpreterObject): def __init__(self, subinterpreter): super().__init__() self.held_object = subinterpreter self.methods.update({'get_variable': self.get_variable_method, }) def get_variable_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Get_variable takes one argument.') varname = args[0] if not isinstance(varname, str): raise InterpreterException('Get_variable takes a string argument.') return self.held_object.variables[varname] class CompilerHolder(InterpreterObject): def __init__(self, compiler, env): InterpreterObject.__init__(self) self.compiler = compiler self.environment = env self.methods.update({'compiles': self.compiles_method, 'links': self.links_method, '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, 'has_function': self.has_function_method, 'has_member': self.has_member_method, 'has_members': self.has_members_method, 'has_type': self.has_type_method, 'alignment': self.alignment_method, 'version': self.version_method, 'cmd_array': self.cmd_array_method, 'find_library': self.find_library_method, 'has_argument': self.has_argument_method, 'has_multi_arguments': self.has_multi_arguments_method, 'first_supported_argument': self.first_supported_argument_method, 'unittest_args': self.unittest_args_method, 'symbols_have_underscore_prefix': self.symbols_have_underscore_prefix_method, }) def version_method(self, args, kwargs): return self.compiler.version def cmd_array_method(self, args, kwargs): return self.compiler.exelist def determine_args(self, kwargs): nobuiltins = kwargs.get('no_builtin_args', False) if not isinstance(nobuiltins, bool): raise InterpreterException('Type of no_builtin_args not a boolean.') args = [] incdirs = kwargs.get('include_directories', []) if not isinstance(incdirs, list): incdirs = [incdirs] for i in incdirs: if not isinstance(i, IncludeDirsHolder): raise InterpreterException('Include directories argument must be an include_directories object.') for idir in i.held_object.get_incdirs(): idir = os.path.join(self.environment.get_source_dir(), idir) args += self.compiler.get_include_args(idir, False) if not nobuiltins: opts = self.environment.coredata.compiler_options args += self.compiler.get_option_compile_args(opts) args += self.compiler.get_option_link_args(opts) args += mesonlib.stringlistify(kwargs.get('args', [])) return args def determine_dependencies(self, kwargs): deps = kwargs.get('dependencies', None) if deps is not None: if not isinstance(deps, list): deps = [deps] final_deps = [] for d in deps: try: d = d.held_object except Exception: pass if isinstance(d, InternalDependency) or not isinstance(d, Dependency): raise InterpreterException('Dependencies must be external dependencies') final_deps.append(d) deps = final_deps return deps def alignment_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Alignment method takes exactly one positional argument.') check_stringlist(args) typename = args[0] prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of sizeof must be a string.') extra_args = mesonlib.stringlistify(kwargs.get('args', [])) deps = self.determine_dependencies(kwargs) result = self.compiler.alignment(typename, prefix, self.environment, extra_args, deps) mlog.log('Checking for alignment of "', mlog.bold(typename), '": ', result, sep='') return result def run_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Run method takes exactly one positional argument.') code = args[0] if isinstance(code, mesonlib.File): code = mesonlib.File.from_absolute_file( code.rel_to_builddir(self.environment.source_dir)) elif not isinstance(code, str): raise InvalidArguments('Argument must be string or file.') testname = kwargs.get('name', '') if not isinstance(testname, str): raise InterpreterException('Testname argument must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) result = self.compiler.run(code, self.environment, extra_args, deps) if len(testname) > 0: if not result.compiled: h = mlog.red('DID NOT COMPILE') elif result.returncode == 0: h = mlog.green('YES') else: h = mlog.red('NO (%d)' % result.returncode) mlog.log('Checking if "', mlog.bold(testname), '" runs: ', h, sep='') return TryRunResultHolder(result) def get_id_method(self, args, kwargs): return self.compiler.get_id() def symbols_have_underscore_prefix_method(self, args, kwargs): ''' Check if the compiler prefixes _ (underscore) to global C symbols See: https://en.wikipedia.org/wiki/Name_mangling#C ''' return self.compiler.symbols_have_underscore_prefix(self.environment) def unittest_args_method(self, args, kwargs): # At time, only D compilers have this feature. if not hasattr(self.compiler, 'get_unittest_args'): raise InterpreterException('This {} compiler has no unittest arguments.'.format(self.compiler.language)) return self.compiler.get_unittest_args() def has_member_method(self, args, kwargs): if len(args) != 2: raise InterpreterException('Has_member takes exactly two arguments.') check_stringlist(args) typename = args[0] membername = args[1] prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_member must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) had = self.compiler.has_members(typename, [membername], prefix, self.environment, extra_args, deps) if had: hadtxt = mlog.green('YES') else: hadtxt = mlog.red('NO') mlog.log('Checking whether type "', mlog.bold(typename), '" has member "', mlog.bold(membername), '": ', hadtxt, sep='') return had def has_members_method(self, args, kwargs): check_stringlist(args) typename = args[0] membernames = args[1:] prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_members must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) had = self.compiler.has_members(typename, membernames, prefix, self.environment, extra_args, deps) if had: hadtxt = mlog.green('YES') else: hadtxt = mlog.red('NO') members = mlog.bold(', '.join(['"{}"'.format(m) for m in membernames])) mlog.log('Checking whether type "', mlog.bold(typename), '" has members ', members, ': ', hadtxt, sep='') return had def has_function_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Has_function takes exactly one argument.') check_stringlist(args) funcname = args[0] prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_function must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) had = self.compiler.has_function(funcname, prefix, self.environment, extra_args, deps) if had: hadtxt = mlog.green('YES') else: hadtxt = mlog.red('NO') mlog.log('Checking for function "', mlog.bold(funcname), '": ', hadtxt, sep='') return had def has_type_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Has_type takes exactly one argument.') check_stringlist(args) typename = args[0] prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_type must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) had = self.compiler.has_type(typename, prefix, self.environment, extra_args, deps) if had: hadtxt = mlog.green('YES') else: hadtxt = mlog.red('NO') mlog.log('Checking for type "', mlog.bold(typename), '": ', hadtxt, sep='') return had def compute_int_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Compute_int takes exactly one argument.') check_stringlist(args) expression = args[0] prefix = kwargs.get('prefix', '') l = kwargs.get('low', -1024) h = kwargs.get('high', 1024) guess = kwargs.get('guess', None) if not isinstance(prefix, str): raise InterpreterException('Prefix argument of compute_int must be a string.') if not isinstance(l, int): raise InterpreterException('Low argument of compute_int must be an int.') if not isinstance(h, int): raise InterpreterException('High argument of compute_int must be an int.') if guess is not None and not isinstance(guess, int): raise InterpreterException('Guess argument of compute_int must be an int.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) res = self.compiler.compute_int(expression, l, h, guess, prefix, self.environment, extra_args, deps) mlog.log('Computing int of "%s": %d' % (expression, res)) return res def sizeof_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Sizeof takes exactly one argument.') check_stringlist(args) element = args[0] prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of sizeof must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) esize = self.compiler.sizeof(element, prefix, self.environment, extra_args, deps) 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.') code = args[0] if isinstance(code, mesonlib.File): code = mesonlib.File.from_absolute_file( code.rel_to_builddir(self.environment.source_dir)) elif not isinstance(code, str): raise InvalidArguments('Argument must be string or file.') testname = kwargs.get('name', '') if not isinstance(testname, str): raise InterpreterException('Testname argument must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) result = self.compiler.compiles(code, self.environment, extra_args, deps) if len(testname) > 0: if result: h = mlog.green('YES') else: h = mlog.red('NO') mlog.log('Checking if "', mlog.bold(testname), '" compiles: ', h, sep='') return result def links_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('links method takes exactly one argument.') code = args[0] if isinstance(code, mesonlib.File): code = mesonlib.File.from_absolute_file( code.rel_to_builddir(self.environment.source_dir)) elif not isinstance(code, str): raise InvalidArguments('Argument must be string or file.') testname = kwargs.get('name', '') if not isinstance(testname, str): raise InterpreterException('Testname argument must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) result = self.compiler.links(code, self.environment, extra_args, deps) if len(testname) > 0: if result: h = mlog.green('YES') else: h = mlog.red('NO') mlog.log('Checking if "', mlog.bold(testname), '" links: ', h, sep='') return result def has_header_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('has_header method takes exactly one argument.') check_stringlist(args) hname = args[0] prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_header must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) haz = self.compiler.has_header(hname, prefix, self.environment, extra_args, deps) if haz: h = mlog.green('YES') else: h = mlog.red('NO') mlog.log('Has header "%s":' % hname, h) return haz def has_header_symbol_method(self, args, kwargs): if len(args) != 2: raise InterpreterException('has_header_symbol method takes exactly two arguments.') check_stringlist(args) hname = args[0] symbol = args[1] prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_header_symbol must be a string.') extra_args = self.determine_args(kwargs) deps = self.determine_dependencies(kwargs) haz = self.compiler.has_header_symbol(hname, symbol, prefix, self.environment, extra_args, deps) if haz: h = mlog.green('YES') else: h = mlog.red('NO') mlog.log('Header <{0}> has symbol "{1}":'.format(hname, symbol), h) return haz def find_library_method(self, args, kwargs): # TODO add dependencies support? if len(args) != 1: raise InterpreterException('find_library method takes one argument.') libname = args[0] if not isinstance(libname, str): raise InterpreterException('Library name not a string.') required = kwargs.get('required', True) if not isinstance(required, bool): raise InterpreterException('required must be boolean.') search_dirs = mesonlib.stringlistify(kwargs.get('dirs', [])) for i in search_dirs: if not os.path.isabs(i): raise InvalidCode('Search directory %s is not an absolute path.' % i) linkargs = self.compiler.find_library(libname, self.environment, search_dirs) if required and not linkargs: l = self.compiler.language.capitalize() raise InterpreterException('{} library {!r} not found'.format(l, libname)) lib = dependencies.ExternalLibrary(libname, linkargs, self.compiler.language) return ExternalLibraryHolder(lib) def has_argument_method(self, args, kwargs): args = mesonlib.stringlistify(args) if len(args) != 1: raise InterpreterException('Has_arg takes exactly one argument.') result = self.compiler.has_argument(args[0], self.environment) if result: h = mlog.green('YES') else: h = mlog.red('NO') mlog.log('Compiler for {} supports argument {}:'.format(self.compiler.language, args[0]), h) return result def has_multi_arguments_method(self, args, kwargs): args = mesonlib.stringlistify(args) result = self.compiler.has_multi_arguments(args, self.environment) if result: h = mlog.green('YES') else: h = mlog.red('NO') mlog.log( 'Compiler for {} supports arguments {}:'.format( self.compiler.language, ' '.join(args)), h) return result def first_supported_argument_method(self, args, kwargs): for i in mesonlib.stringlistify(args): if self.compiler.has_argument(i, self.environment): mlog.log('First supported argument:', mlog.bold(i)) return [i] mlog.log('First supported argument:', mlog.red('None')) return [] ModuleState = namedtuple('ModuleState', [ 'build_to_src', 'subdir', 'environment', 'project_name', 'project_version', 'compilers', 'targets', 'data', 'headers', 'man', 'global_args', 'project_args', 'build_machine', 'host_machine', 'target_machine']) class ModuleHolder(InterpreterObject): def __init__(self, modname, module, interpreter): InterpreterObject.__init__(self) self.modname = modname self.held_object = module self.interpreter = interpreter def method_call(self, method_name, args, kwargs): try: fn = getattr(self.held_object, method_name) except AttributeError: raise InvalidArguments('Module %s does not have method %s.' % (self.modname, method_name)) if method_name.startswith('_'): raise InvalidArguments('Function {!r} in module {!r} is private.'.format(method_name, self.modname)) # This is not 100% reliable but we can't use hash() # because the Build object contains dicts and lists. num_targets = len(self.interpreter.build.targets) state = ModuleState( build_to_src=os.path.relpath(self.interpreter.environment.get_source_dir(), self.interpreter.environment.get_build_dir()), subdir=self.interpreter.subdir, environment=self.interpreter.environment, project_name=self.interpreter.build.project_name, project_version=self.interpreter.build.dep_manifest[self.interpreter.active_projectname], compilers=self.interpreter.build.compilers, targets=self.interpreter.build.targets, data=self.interpreter.build.data, headers=self.interpreter.build.get_headers(), man=self.interpreter.build.get_man(), global_args=self.interpreter.build.global_args, project_args=self.interpreter.build.projects_args.get(self.interpreter.subproject, {}), build_machine=self.interpreter.builtin['build_machine'].held_object, host_machine=self.interpreter.builtin['host_machine'].held_object, target_machine=self.interpreter.builtin['target_machine'].held_object, ) if self.held_object.is_snippet(method_name): value = fn(self.interpreter, state, args, kwargs) return self.interpreter.holderify(value) else: value = fn(state, args, kwargs) if num_targets != len(self.interpreter.build.targets): raise InterpreterException('Extension module altered internal state illegally.') return self.interpreter.module_method_callback(value) class MesonMain(InterpreterObject): def __init__(self, build, interpreter): InterpreterObject.__init__(self) self.build = build self.interpreter = interpreter self._found_source_scripts = {} self.methods.update({'get_compiler': self.get_compiler_method, 'is_cross_build': self.is_cross_build_method, 'has_exe_wrapper': self.has_exe_wrapper_method, 'is_unity': self.is_unity_method, 'is_subproject': self.is_subproject_method, 'current_source_dir': self.current_source_dir_method, 'current_build_dir': self.current_build_dir_method, 'source_root': self.source_root_method, 'build_root': self.build_root_method, 'add_install_script': self.add_install_script_method, 'add_postconf_script': self.add_postconf_script_method, 'install_dependency_manifest': self.install_dependency_manifest_method, 'project_version': self.project_version_method, 'version': self.version_method, 'project_name': self.project_name_method, 'get_cross_property': self.get_cross_property_method, 'backend': self.backend_method, }) def _find_source_script(self, name, args): # Prefer scripts in the current source directory search_dir = os.path.join(self.interpreter.environment.source_dir, self.interpreter.subdir) key = (name, search_dir) if key in self._found_source_scripts: found = self._found_source_scripts[key] else: found = dependencies.ExternalProgram(name, search_dir=search_dir) if found.found(): self._found_source_scripts[key] = found else: raise InterpreterException('Script {!r} not found'.format(name)) return build.RunScript(found.get_command(), args) def add_install_script_method(self, args, kwargs): if len(args) < 1: raise InterpreterException('add_install_script takes one or more arguments') check_stringlist(args, 'add_install_script args must be strings') script = self._find_source_script(args[0], args[1:]) self.build.install_scripts.append(script) def add_postconf_script_method(self, args, kwargs): if len(args) < 1: raise InterpreterException('add_postconf_script takes one or more arguments') check_stringlist(args, 'add_postconf_script arguments must be strings') script = self._find_source_script(args[0], args[1:]) self.build.postconf_scripts.append(script) def current_source_dir_method(self, args, kwargs): src = self.interpreter.environment.source_dir sub = self.interpreter.subdir if sub == '': return src return os.path.join(src, sub) def current_build_dir_method(self, args, kwargs): src = self.interpreter.environment.build_dir sub = self.interpreter.subdir if sub == '': return src return os.path.join(src, sub) def backend_method(self, args, kwargs): return self.interpreter.backend.name def source_root_method(self, args, kwargs): return self.interpreter.environment.source_dir def build_root_method(self, args, kwargs): return self.interpreter.environment.build_dir def has_exe_wrapper_method(self, args, kwargs): if self.is_cross_build_method(None, None) and \ 'binaries' in self.build.environment.cross_info.config and \ self.build.environment.cross_info.need_exe_wrapper(): exe_wrap = self.build.environment.cross_info.config['binaries'].get('exe_wrapper', None) if exe_wrap is None: return False # We return True when exe_wrap is defined, when it's not needed, and # when we're compiling natively. The last two are semantically confusing. # Need to revisit this. return True def is_cross_build_method(self, args, kwargs): return self.build.environment.is_cross_build() def get_compiler_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('get_compiler_method must have one and only one argument.') cname = args[0] native = kwargs.get('native', None) if native is None: if self.build.environment.is_cross_build(): native = False else: native = True if not isinstance(native, bool): raise InterpreterException('Type of "native" must be a boolean.') if native: clist = self.build.compilers else: clist = self.build.cross_compilers if cname in clist: return CompilerHolder(clist[cname], self.build.environment) raise InterpreterException('Tried to access compiler for unspecified language "%s".' % cname) def is_unity_method(self, args, kwargs): optval = self.interpreter.environment.coredata.get_builtin_option('unity') if optval == 'on' or (optval == 'subprojects' and self.interpreter.subproject != ''): return True return False def is_subproject_method(self, args, kwargs): return self.interpreter.is_subproject() def install_dependency_manifest_method(self, args, kwargs): if len(args) != 1: raise InterpreterException('Must specify manifest install file name') if not isinstance(args[0], str): raise InterpreterException('Argument must be a string.') self.build.dep_manifest_name = args[0] def project_version_method(self, args, kwargs): return self.build.dep_manifest[self.interpreter.active_projectname]['version'] def version_method(self, args, kwargs): return coredata.version def project_name_method(self, args, kwargs): return self.interpreter.active_projectname def get_cross_property_method(self, args, kwargs): if len(args) < 1 or len(args) > 2: raise InterpreterException('Must have one or two arguments.') propname = args[0] if not isinstance(propname, str): raise InterpreterException('Property name must be string.') try: props = self.interpreter.environment.cross_info.get_properties() return props[propname] except Exception: if len(args) == 2: return args[1] raise InterpreterException('Unknown cross property: %s.' % propname) class Interpreter(InterpreterBase): def __init__(self, build, backend, subproject='', subdir='', subproject_dir='subprojects', default_project_options=[]): super().__init__(build.environment.get_source_dir(), subdir) self.build = build self.environment = build.environment self.coredata = self.environment.get_coredata() self.backend = backend self.subproject = subproject self.subproject_dir = subproject_dir self.option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt') self.load_root_meson_file() self.sanity_check_ast() self.builtin.update({'meson': MesonMain(build, self)}) self.generators = [] self.visited_subdirs = {} 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. self.build_func_dict() self.parse_project() self.builtin['build_machine'] = BuildMachine(self.coredata.compilers) if not self.build.environment.is_cross_build(): self.builtin['host_machine'] = self.builtin['build_machine'] self.builtin['target_machine'] = self.builtin['build_machine'] else: cross_info = self.build.environment.cross_info if cross_info.has_host(): self.builtin['host_machine'] = CrossMachineInfo(cross_info.config['host_machine']) else: self.builtin['host_machine'] = self.builtin['build_machine'] if cross_info.has_target(): self.builtin['target_machine'] = CrossMachineInfo(cross_info.config['target_machine']) else: self.builtin['target_machine'] = self.builtin['host_machine'] self.build_def_files = [os.path.join(self.subdir, environment.build_filename)] def build_func_dict(self): self.funcs.update({'project': self.func_project, 'message': self.func_message, 'error': self.func_error, 'executable': self.func_executable, 'dependency': self.func_dependency, 'static_library': self.func_static_lib, 'shared_library': self.func_shared_lib, 'shared_module': self.func_shared_module, 'library': self.func_library, 'jar': self.func_jar, 'build_target': self.func_build_target, 'custom_target': self.func_custom_target, 'run_target': self.func_run_target, 'generator': self.func_generator, 'test': self.func_test, 'benchmark': self.func_benchmark, 'install_headers': self.func_install_headers, 'install_man': self.func_install_man, 'subdir': self.func_subdir, 'install_data': self.func_install_data, 'install_subdir': self.func_install_subdir, 'configure_file': self.func_configure_file, 'include_directories': self.func_include_directories, 'add_global_arguments': self.func_add_global_arguments, 'add_project_arguments': self.func_add_project_arguments, 'add_global_link_arguments': self.func_add_global_link_arguments, 'add_project_link_arguments': self.func_add_project_link_arguments, 'add_test_setup': self.func_add_test_setup, 'add_languages': self.func_add_languages, 'find_program': self.func_find_program, 'find_library': self.func_find_library, 'configuration_data': self.func_configuration_data, 'run_command': self.func_run_command, 'gettext': self.func_gettext, 'option': self.func_option, 'get_option': self.func_get_option, 'subproject': self.func_subproject, 'vcs_tag': self.func_vcs_tag, 'set_variable': self.func_set_variable, 'is_variable': self.func_is_variable, 'get_variable': self.func_get_variable, 'import': self.func_import, 'files': self.func_files, 'declare_dependency': self.func_declare_dependency, 'assert': self.func_assert, 'environment': self.func_environment, 'join_paths': self.func_join_paths, }) def holderify(self, item): if isinstance(item, list): return [self.holderify(x) for x in item] if isinstance(item, build.CustomTarget): return CustomTargetHolder(item, self) elif isinstance(item, (int, str)) or item is None: return item elif isinstance(item, build.Executable): return ExecutableHolder(item, self) elif isinstance(item, build.GeneratedList): return GeneratedListHolder(item) elif isinstance(item, build.RunTarget): raise RuntimeError('This is not a pipe.') elif isinstance(item, build.RunScript): raise RuntimeError('Do not do this.') elif isinstance(item, build.Data): return DataHolder(item) elif isinstance(item, dependencies.InternalDependency): return InternalDependencyHolder(item) elif isinstance(item, dependencies.ExternalProgram): return ExternalProgramHolder(item) elif hasattr(item, 'held_object'): return item else: raise InterpreterException('Module returned a value of unknown type.') def process_new_values(self, invalues): if not isinstance(invalues, list): invalues = [invalues] for v in invalues: if isinstance(v, (build.BuildTarget, build.CustomTarget, build.RunTarget)): self.add_target(v.name, v) elif isinstance(v, list): self.module_method_callback(v) elif isinstance(v, build.GeneratedList): pass elif isinstance(v, build.RunScript): self.build.install_scripts.append(v) elif isinstance(v, build.Data): self.build.data.append(v) elif isinstance(v, dependencies.ExternalProgram): return ExternalProgramHolder(v) elif isinstance(v, dependencies.InternalDependency): # FIXME: This is special cased and not ideal: # The first source is our new VapiTarget, the rest are deps self.process_new_values(v.sources[0]) elif hasattr(v, 'held_object'): pass else: raise InterpreterException('Module returned a value of unknown type.') def module_method_callback(self, return_object): if not isinstance(return_object, ModuleReturnValue): assert False raise InterpreterException('Bug in module, it returned an invalid object') invalues = return_object.new_objects self.process_new_values(invalues) return self.holderify(return_object.return_value) def get_build_def_files(self): return self.build_def_files def get_variables(self): return self.variables def check_cross_stdlibs(self): if self.build.environment.is_cross_build(): cross_info = self.build.environment.cross_info for l, c in self.build.cross_compilers.items(): try: di = mesonlib.stringlistify(cross_info.get_stdlib(l)) if len(di) != 2: raise InterpreterException('Stdlib definition for %s should have exactly two elements.' % l) projname, depname = di subproj = self.do_subproject(projname, {}) self.build.cross_stdlibs[l] = subproj.get_variable_method([depname], {}) except KeyError: pass @stringArgs @noKwargs def func_import(self, node, args, kwargs): if len(args) != 1: raise InvalidCode('Import takes one argument.') modname = args[0] if modname not in self.environment.coredata.modules: try: module = importlib.import_module('mesonbuild.modules.' + modname) except ImportError: raise InvalidArguments('Module "%s" does not exist' % (modname, )) self.environment.coredata.modules[modname] = module.initialize() return ModuleHolder(modname, self.environment.coredata.modules[modname], self) @stringArgs @noKwargs def func_files(self, node, args, kwargs): return [mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, fname) for fname in args] @noPosargs def func_declare_dependency(self, node, args, kwargs): version = kwargs.get('version', self.project_version) if not isinstance(version, str): raise InterpreterException('Version must be a string.') incs = kwargs.get('include_directories', []) if not isinstance(incs, list): incs = [incs] libs = kwargs.get('link_with', []) if not isinstance(libs, list): libs = [libs] sources = kwargs.get('sources', []) if not isinstance(sources, list): sources = [sources] sources = self.source_strings_to_files(self.flatten(sources)) deps = self.flatten(kwargs.get('dependencies', [])) if not isinstance(deps, list): deps = [deps] compile_args = mesonlib.stringlistify(kwargs.get('compile_args', [])) link_args = mesonlib.stringlistify(kwargs.get('link_args', [])) final_deps = [] for d in deps: try: d = d.held_object except Exception: pass if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary, dependencies.InternalDependency)): raise InterpreterException('Dependencies must be external deps') final_deps.append(d) dep = dependencies.InternalDependency(version, incs, compile_args, link_args, libs, sources, final_deps) return DependencyHolder(dep) @noKwargs def func_assert(self, node, args, kwargs): if len(args) != 2: raise InterpreterException('Assert takes exactly two arguments') value, message = args if not isinstance(value, bool): raise InterpreterException('Assert value not bool.') if not isinstance(message, str): raise InterpreterException('Assert message not a string.') if not value: raise InterpreterException('Assert failed: ' + message) def validate_arguments(self, args, argcount, arg_types): if argcount is not None: if argcount != len(args): raise InvalidArguments('Expected %d arguments, got %d.' % (argcount, len(args))) for i in range(min(len(args), len(arg_types))): wanted = arg_types[i] actual = args[i] if wanted is not None: if not isinstance(actual, wanted): raise InvalidArguments('Incorrect argument type.') def func_run_command(self, node, args, kwargs): if len(args) < 1: raise InterpreterException('Not enough arguments') cmd = args[0] cargs = args[1:] if isinstance(cmd, ExternalProgramHolder): cmd = cmd.get_command() elif isinstance(cmd, str): cmd = [cmd] else: raise InterpreterException('First argument should be find_program() ' 'or string, not {!r}'.format(cmd)) expanded_args = [] for a in mesonlib.flatten(cargs): if isinstance(a, str): expanded_args.append(a) elif isinstance(a, mesonlib.File): if a.is_built: raise InterpreterException('Can not use generated files in run_command.') expanded_args.append(os.path.join(self.environment.get_source_dir(), str(a))) else: raise InterpreterException('Run_command arguments must be strings or the output of files().') args = cmd + expanded_args 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, get_meson_script(self.environment, 'mesonintrospect'), in_builddir) @stringArgs def func_gettext(self, nodes, args, kwargs): raise InterpreterException('Gettext() function has been moved to module i18n. Import it and use i18n.gettext() instead') def func_option(self, nodes, args, kwargs): raise InterpreterException('Tried to call option() in build description file. All options must be in the option file.') @stringArgs def func_subproject(self, nodes, args, kwargs): if len(args) != 1: raise InterpreterException('Subproject takes exactly one argument') dirname = args[0] return self.do_subproject(dirname, kwargs) def do_subproject(self, dirname, kwargs): if dirname in self.subproject_stack: fullstack = self.subproject_stack + [dirname] incpath = ' => '.join(fullstack) raise InvalidCode('Recursive include of subprojects: %s.' % incpath) if dirname in self.subprojects: return self.subprojects[dirname] subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir) r = wrap.Resolver(subproject_dir_abs, self.coredata.wrap_mode) try: resolved = r.resolve(dirname) except RuntimeError as e: msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}' 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.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', []))) subi.subprojects = self.subprojects subi.subproject_stack = self.subproject_stack + [dirname] current_active = self.active_projectname subi.run() if 'version' in kwargs: pv = subi.project_version wanted = kwargs['version'] if pv == 'undefined' or not mesonlib.version_compare(pv, wanted): raise InterpreterException('Subproject %s version is %s but %s required.' % (dirname, pv, wanted)) self.active_projectname = current_active mlog.log('\nSubproject', mlog.bold(dirname), 'finished.') self.build.subprojects[dirname] = subi.project_version self.subprojects.update(subi.subprojects) self.subprojects[dirname] = SubprojectHolder(subi) self.build_def_files += subi.build_def_files return self.subprojects[dirname] @stringArgs @noKwargs def func_get_option(self, nodes, args, kwargs): if len(args) != 1: raise InterpreterException('Argument required for get_option.') optname = args[0] try: return self.environment.get_coredata().get_builtin_option(optname) except RuntimeError: pass try: return self.environment.coredata.compiler_options[optname].value except KeyError: pass if not coredata.is_builtin_option(optname) and self.is_subproject(): optname = self.subproject + ':' + optname try: return self.environment.coredata.user_options[optname].value except KeyError: pass if optname.endswith('_link_args'): try: lang = optname[:-10] return self.coredata.external_link_args[lang] except KeyError: pass if optname.endswith('_args'): try: lang = optname[:-5] return self.coredata.external_args[lang] except KeyError: pass raise InterpreterException('Tried to access unknown option "%s".' % optname) @noKwargs def func_configuration_data(self, node, args, kwargs): if len(args) != 0: raise InterpreterException('configuration_data takes no arguments') return ConfigurationDataHolder() def parse_default_options(self, default_options): if not isinstance(default_options, list): default_options = [default_options] for option in default_options: if not isinstance(option, str): mlog.debug(option) raise InterpreterException('Default options must be strings') if '=' not in option: raise InterpreterException('All default options must be of type key=value.') key, value = option.split('=', 1) if coredata.is_builtin_option(key): if self.subproject != '': continue # Only the master project is allowed to set global options. if not self.environment.had_argument_for(key): self.coredata.set_builtin_option(key, value) # If this was set on the command line, do not override. else: # Option values set with subproject() default_options override those # set in project() default_options. pref = key + '=' for i in self.default_project_options: if i.startswith(pref): option = i break # If we are in a subproject, add the subproject prefix to option # name. if self.subproject != '': option = self.subproject + ':' + option newoptions = [option] + self.environment.cmd_line_options.projectoptions self.environment.cmd_line_options.projectoptions = newoptions # Add options that are only in default_options. for defopt in self.default_project_options: key, value = defopt.split('=') pref = key + '=' for i in default_options: if i.startswith(pref): break else: defopt = self.subproject + ':' + defopt newoptions = [defopt] + self.environment.cmd_line_options.projectoptions self.environment.cmd_line_options.projectoptions = newoptions @stringArgs 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 = 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 = 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[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: self.subproject_dir = kwargs['subproject_dir'] if 'meson_version' in kwargs: cv = coredata.version 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] = 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: raise InterpreterException('Compiling Vala requires C. Add C to your project languages and rerun Meson.') if not self.is_subproject(): self.check_cross_stdlibs() @stringArgs def func_add_languages(self, node, args, kwargs): return self.add_languages(args, kwargs.get('required', True)) @noKwargs def func_message(self, node, args, kwargs): # reduce arguments again to avoid flattening posargs (posargs, _) = self.reduce_arguments(node.args) if len(posargs) != 1: raise InvalidArguments('Expected 1 argument, got %d' % len(posargs)) arg = posargs[0] if isinstance(arg, list): argstr = stringifyUserArguments(arg) elif isinstance(arg, str): argstr = arg elif isinstance(arg, int): argstr = str(arg) else: raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.') mlog.log(mlog.bold('Message:'), argstr) @noKwargs def func_error(self, node, args, kwargs): self.validate_arguments(args, 1, [str]) raise InterpreterException('Error encountered: ' + args[0]) def detect_compilers(self, lang, need_cross_compiler): cross_comp = None if lang == 'c': comp = self.environment.detect_c_compiler(False) if need_cross_compiler: cross_comp = self.environment.detect_c_compiler(True) elif lang == 'cpp': comp = self.environment.detect_cpp_compiler(False) if need_cross_compiler: cross_comp = self.environment.detect_cpp_compiler(True) elif lang == 'objc': comp = self.environment.detect_objc_compiler(False) if need_cross_compiler: cross_comp = self.environment.detect_objc_compiler(True) elif lang == 'objcpp': comp = self.environment.detect_objcpp_compiler(False) if need_cross_compiler: cross_comp = self.environment.detect_objcpp_compiler(True) elif lang == 'java': comp = self.environment.detect_java_compiler() if need_cross_compiler: cross_comp = comp # Java is platform independent. elif lang == 'cs': comp = self.environment.detect_cs_compiler() if need_cross_compiler: cross_comp = comp # C# is platform independent. elif lang == 'vala': comp = self.environment.detect_vala_compiler() if need_cross_compiler: cross_comp = comp # Vala compiles to platform-independent C elif lang == 'd': comp = self.environment.detect_d_compiler(False) if need_cross_compiler: cross_comp = self.environment.detect_d_compiler(True) elif lang == 'rust': comp = self.environment.detect_rust_compiler() if need_cross_compiler: cross_comp = comp # FIXME, not correct. elif lang == 'fortran': comp = self.environment.detect_fortran_compiler(False) if need_cross_compiler: cross_comp = self.environment.detect_fortran_compiler(True) elif lang == 'swift': comp = self.environment.detect_swift_compiler() if need_cross_compiler: raise InterpreterException('Cross compilation with Swift is not working yet.') # cross_comp = self.environment.detect_fortran_compiler(True) else: raise InvalidCode('Tried to use unknown language "%s".' % lang) comp.sanity_check(self.environment.get_scratch_dir(), self.environment) self.coredata.compilers[lang] = comp # Native compiler always exist so always add its options. new_options = comp.get_options() if cross_comp is not None: cross_comp.sanity_check(self.environment.get_scratch_dir(), self.environment) self.coredata.cross_compilers[lang] = cross_comp new_options.update(cross_comp.get_options()) optprefix = lang + '_' for i in new_options: if not i.startswith(optprefix): raise InterpreterException('Internal error, %s has incorrect prefix.' % i) cmd_prefix = i + '=' for cmd_arg in self.environment.cmd_line_options.projectoptions: if cmd_arg.startswith(cmd_prefix): value = cmd_arg.split('=', 1)[1] new_options[i].set_value(value) new_options.update(self.coredata.compiler_options) self.coredata.compiler_options = new_options return comp, cross_comp def add_languages(self, args, required): success = True need_cross_compiler = self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler() for lang in sorted(args, key=compilers.sort_clike): lang = lang.lower() if lang in self.coredata.compilers: comp = self.coredata.compilers[lang] cross_comp = self.coredata.cross_compilers.get(lang, None) else: try: (comp, cross_comp) = self.detect_compilers(lang, need_cross_compiler) except Exception: if not required: mlog.log('Compiler for language', mlog.bold(lang), 'not found.') success = False continue else: 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: (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='') self.build.add_cross_compiler(cross_comp) if self.environment.is_cross_build() and not need_cross_compiler: self.build.add_cross_compiler(comp) self.add_base_options(comp) return success def add_base_options(self, compiler): proj_opt = self.environment.cmd_line_options.projectoptions for optname in compiler.base_options: if optname in self.coredata.base_options: continue oobj = compilers.base_options[optname] for po in proj_opt: if po.startswith(optname + '='): oobj.set_value(po.split('=', 1)[1]) break self.coredata.base_options[optname] = oobj def func_find_program(self, node, args, kwargs): if len(args) == 0: raise InterpreterException('No program name specified.') required = kwargs.get('required', True) if not isinstance(required, bool): raise InvalidArguments('"required" argument must be a boolean.') # Search for scripts relative to current subdir. # Do not cache found programs because find_program('foobar') # might give different results when run from different source dirs. source_dir = os.path.join(self.environment.get_source_dir(), self.subdir) for exename in args: if isinstance(exename, mesonlib.File): if exename.is_built: search_dir = os.path.join(self.environment.get_build_dir(), exename.subdir) else: search_dir = os.path.join(self.environment.get_source_dir(), exename.subdir) exename = exename.fname elif isinstance(exename, str): search_dir = source_dir else: raise InvalidArguments('find_program only accepts strings and ' 'files, not {!r}'.format(exename)) extprog = dependencies.ExternalProgram(exename, search_dir=search_dir) progobj = ExternalProgramHolder(extprog) if progobj.found(): return progobj if required and not progobj.found(): raise InvalidArguments('Program "%s" not found.' % exename) return progobj def func_find_library(self, node, args, kwargs): mlog.log(mlog.red('DEPRECATION:'), 'find_library() is removed, use the corresponding method in compiler object instead.') def func_dependency(self, node, args, kwargs): self.validate_arguments(args, 1, [str]) name = args[0] if '<' in name or '>' in name or '=' in name: raise InvalidArguments('Characters <, > and = are forbidden in dependency names. To specify' 'version\n requirements use the \'version\' keyword argument instead.') identifier = dependencies.get_dep_identifier(name, kwargs) # Check if we want this as a cross-dep or a native-dep # FIXME: Not all dependencies support such a distinction right now, # and we repeat this check inside dependencies that do. We need to # consolidate this somehow. is_cross = self.environment.is_cross_build() if 'native' in kwargs and is_cross: want_cross = not kwargs['native'] else: want_cross = is_cross # Check if we've already searched for and found this dep cached_dep = None if identifier in self.coredata.deps: cached_dep = self.coredata.deps[identifier] if 'version' in kwargs: wanted = kwargs['version'] found = cached_dep.get_version() if not cached_dep.found() or \ not mesonlib.version_compare_many(found, wanted)[0]: # Cached dep has the wrong version. Check if an external # dependency or a fallback dependency provides it. cached_dep = None # Don't re-use cached dep if it wasn't required but this one is, # so we properly go into fallback/error code paths if kwargs.get('required', True) and not getattr(cached_dep, 'required', False): cached_dep = None # Don't reuse cached dep if one is a cross-dep and the other is a native dep if not getattr(cached_dep, 'want_cross', is_cross) == want_cross: cached_dep = None if cached_dep: dep = cached_dep else: # We need to actually search for this dep exception = None dep = None # If the fallback has already been configured (possibly by a higher level project) # try to use it before using the native version if 'fallback' in kwargs: dirname, varname = self.get_subproject_infos(kwargs) if dirname in self.subprojects: try: dep = self.subprojects[dirname].get_variable_method([varname], {}) dep = dep.held_object except KeyError: pass if not dep: try: dep = dependencies.find_external_dependency(name, self.environment, kwargs) except dependencies.DependencyException as e: exception = e pass if not dep or not dep.found(): if 'fallback' in kwargs: fallback_dep = self.dependency_fallback(name, kwargs) if fallback_dep: return fallback_dep if not dep: raise exception self.coredata.deps[identifier] = dep return DependencyHolder(dep) def get_subproject_infos(self, kwargs): fbinfo = kwargs['fallback'] check_stringlist(fbinfo) if len(fbinfo) != 2: raise InterpreterException('Fallback info must have exactly two items.') return fbinfo def dependency_fallback(self, name, kwargs): if self.coredata.wrap_mode in (WrapMode.nofallback, WrapMode.nodownload): mlog.log('Not looking for a fallback subproject for the dependency', mlog.bold(name), 'because:\nAutomatic wrap-based fallback ' 'dependency downloading is disabled.') return None dirname, varname = self.get_subproject_infos(kwargs) # Try to execute the subproject try: sp_kwargs = {} try: sp_kwargs['default_options'] = kwargs['default_options'] except KeyError: pass self.do_subproject(dirname, sp_kwargs) # Invalid code is always an error except InvalidCode: raise # If the subproject execution failed in a non-fatal way, don't raise an # exception; let the caller handle things. except: mlog.log('Also couldn\'t find a fallback subproject in', mlog.bold(os.path.join(self.subproject_dir, dirname)), 'for the dependency', mlog.bold(name)) return None try: dep = self.subprojects[dirname].get_variable_method([varname], {}) except KeyError: if kwargs.get('required', True): m = 'Fallback variable {!r} in the subproject {!r} does not exist' raise DependencyException(m.format(varname, dirname)) # If the dependency is not required, don't raise an exception mlog.log('Also couldn\'t find the dependency', mlog.bold(name), 'in the fallback subproject', mlog.bold(os.path.join(self.subproject_dir, dirname))) return None if not isinstance(dep, DependencyHolder): raise InvalidCode('Fallback variable {!r} in the subproject {!r} is ' 'not a dependency object.'.format(varname, dirname)) # Check if the version of the declared dependency matches what we want if 'version' in kwargs: wanted = kwargs['version'] found = dep.version_method([], {}) if found == 'undefined' or not mesonlib.version_compare(found, wanted): mlog.log('Subproject', mlog.bold(dirname), 'dependency', mlog.bold(varname), 'version is', mlog.bold(found), 'but', mlog.bold(wanted), 'is required.') return None mlog.log('Found a', mlog.green('fallback'), 'subproject', mlog.bold(os.path.join(self.subproject_dir, dirname)), 'for', mlog.bold(name)) return dep def func_executable(self, node, args, kwargs): return self.build_target(node, args, kwargs, ExecutableHolder) def func_static_lib(self, node, args, kwargs): return self.build_target(node, args, kwargs, StaticLibraryHolder) def func_shared_lib(self, node, args, kwargs): return self.build_target(node, args, kwargs, SharedLibraryHolder) def func_shared_module(self, node, args, kwargs): return self.build_target(node, args, kwargs, SharedModuleHolder) def func_library(self, node, args, kwargs): if self.coredata.get_builtin_option('default_library') == 'shared': return self.func_shared_lib(node, args, kwargs) return self.func_static_lib(node, args, kwargs) def func_jar(self, node, args, kwargs): return self.build_target(node, args, kwargs, JarHolder) def func_build_target(self, node, args, kwargs): if 'target_type' not in kwargs: raise InterpreterException('Missing target_type keyword argument') target_type = kwargs.pop('target_type') if target_type == 'executable': return self.func_executable(node, args, kwargs) elif target_type == 'shared_library': return self.func_shared_lib(node, args, kwargs) elif target_type == 'static_library': return self.func_static_lib(node, args, kwargs) elif target_type == 'library': return self.func_library(node, args, kwargs) elif target_type == 'jar': return self.func_jar(node, args, kwargs) else: raise InterpreterException('Unknown target_type.') def func_vcs_tag(self, node, args, kwargs): fallback = kwargs.pop('fallback', None) if not isinstance(fallback, str): raise InterpreterException('Keyword argument fallback must exist and be a string.') replace_string = kwargs.pop('replace_string', '@VCS_TAG@') regex_selector = '(.*)' # default regex selector for custom command: use complete output vcs_cmd = kwargs.get('command', None) if vcs_cmd and not isinstance(vcs_cmd, list): vcs_cmd = [vcs_cmd] source_dir = os.path.normpath(os.path.join(self.environment.get_source_dir(), self.subdir)) if vcs_cmd: # Is the command an executable in path or maybe a script in the source tree? vcs_cmd[0] = shutil.which(vcs_cmd[0]) or os.path.join(source_dir, vcs_cmd[0]) else: vcs = mesonlib.detect_vcs(source_dir) if vcs: mlog.log('Found %s repository at %s' % (vcs['name'], vcs['wc_dir'])) vcs_cmd = vcs['get_rev'].split() regex_selector = vcs['rev_regex'] else: vcs_cmd = [' '] # executing this cmd will fail in vcstagger.py and force to use the fallback string # vcstagger.py parameters: infile, outfile, fallback, source_dir, replace_string, regex_selector, command... kwargs['command'] = [sys.executable, self.environment.get_build_command(), '--internal', 'vcstagger', '@INPUT0@', '@OUTPUT0@', fallback, source_dir, replace_string, regex_selector] + vcs_cmd kwargs.setdefault('build_always', True) return self.func_custom_target(node, [kwargs['output']], kwargs) @stringArgs def func_custom_target(self, node, args, kwargs): if len(args) != 1: raise InterpreterException('custom_target: Only one positional argument is allowed, and it must be a string name') name = args[0] tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, kwargs), self) self.add_target(name, tg.held_object) return tg def func_run_target(self, node, args, kwargs): global run_depr_printed if len(args) > 1: if not run_depr_printed: mlog.log(mlog.red('DEPRECATION'), 'positional version of run_target is deprecated, use the keyword version instead.') run_depr_printed = True if 'command' in kwargs: raise InterpreterException('Can not have command both in positional and keyword arguments.') all_args = args[1:] deps = [] elif len(args) == 1: if 'command' not in kwargs: raise InterpreterException('Missing "command" keyword argument') all_args = kwargs['command'] if not isinstance(all_args, list): all_args = [all_args] deps = kwargs.get('depends', []) if not isinstance(deps, list): deps = [deps] else: raise InterpreterException('Run_target needs at least one positional argument.') cleaned_args = [] for i in mesonlib.flatten(all_args): try: i = i.held_object except AttributeError: pass if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)): mlog.debug('Wrong type:', str(i)) raise InterpreterException('Invalid argument to run_target.') cleaned_args.append(i) name = args[0] if not isinstance(name, str): raise InterpreterException('First argument must be a string.') cleaned_deps = [] for d in deps: try: d = d.held_object except AttributeError: pass if not isinstance(d, (build.BuildTarget, build.CustomTarget)): raise InterpreterException('Depends items must be build targets.') cleaned_deps.append(d) command = cleaned_args[0] cmd_args = cleaned_args[1:] tg = RunTargetHolder(name, command, cmd_args, cleaned_deps, self.subdir) self.add_target(name, tg.held_object) return tg def func_generator(self, node, args, kwargs): gen = GeneratorHolder(self, args, kwargs) self.generators.append(gen) return gen def func_benchmark(self, node, args, kwargs): self.add_test(node, args, kwargs, False) def func_test(self, node, args, kwargs): self.add_test(node, args, kwargs, True) def unpack_env_kwarg(self, kwargs): envlist = kwargs.get('env', EnvironmentVariablesHolder()) if isinstance(envlist, EnvironmentVariablesHolder): env = envlist.held_object else: if not isinstance(envlist, list): envlist = [envlist] env = {} for e in envlist: if '=' not in e: raise InterpreterException('Env var definition must be of type key=val.') (k, val) = e.split('=', 1) k = k.strip() val = val.strip() if ' ' in k: raise InterpreterException('Env var key must not have spaces in it.') env[k] = val return env def add_test(self, node, args, kwargs, is_base_test): if len(args) != 2: raise InterpreterException('Incorrect number of arguments') if not isinstance(args[0], str): raise InterpreterException('First argument of test must be a string.') if not isinstance(args[1], (ExecutableHolder, JarHolder, ExternalProgramHolder)): raise InterpreterException('Second argument must be executable.') par = kwargs.get('is_parallel', True) if not isinstance(par, bool): raise InterpreterException('Keyword argument is_parallel must be a boolean.') cmd_args = kwargs.get('args', []) if not isinstance(cmd_args, list): cmd_args = [cmd_args] for i in cmd_args: if not isinstance(i, (str, mesonlib.File, TargetHolder)): raise InterpreterException('Command line arguments must be strings, files or targets.') env = self.unpack_env_kwarg(kwargs) should_fail = kwargs.get('should_fail', False) if not isinstance(should_fail, bool): raise InterpreterException('Keyword argument should_fail must be a boolean.') timeout = kwargs.get('timeout', 30) if 'workdir' in kwargs: workdir = kwargs['workdir'] if not isinstance(workdir, str): raise InterpreterException('Workdir keyword argument must be a string.') if not os.path.isabs(workdir): raise InterpreterException('Workdir keyword argument must be an absolute path.') else: workdir = None if not isinstance(timeout, int): raise InterpreterException('Timeout must be an integer.') suite = [] for s in mesonlib.stringlistify(kwargs.get('suite', '')): if len(s) > 0: s = ':' + s if self.is_subproject(): suite.append(self.subproject.replace(' ', '_').replace(':', '_') + s) else: suite.append(self.build.project_name.replace(' ', '_').replace(':', '_') + s) t = Test(args[0], suite, args[1].held_object, par, cmd_args, env, should_fail, timeout, workdir) if is_base_test: self.build.tests.append(t) mlog.debug('Adding test "', mlog.bold(args[0]), '".', sep='') else: self.build.benchmarks.append(t) mlog.debug('Adding benchmark "', mlog.bold(args[0]), '".', sep='') def func_install_headers(self, node, args, kwargs): source_files = self.source_strings_to_files(args) h = Headers(source_files, kwargs) self.build.headers.append(h) return h @stringArgs def func_install_man(self, node, args, kwargs): m = Man(self.subdir, args, kwargs) self.build.man.append(m) return m @noKwargs def func_subdir(self, node, args, kwargs): self.validate_arguments(args, 1, [str]) if '..' in args[0]: raise InvalidArguments('Subdir contains ..') if self.subdir == '' and args[0] == self.subproject_dir: raise InvalidArguments('Must not go into subprojects dir with subdir(), use subproject() instead.') prev_subdir = self.subdir subdir = os.path.join(prev_subdir, args[0]) if os.path.isabs(subdir): raise InvalidArguments('Subdir argument must be a relative path.') if subdir in self.visited_subdirs: raise InvalidArguments('Tried to enter directory "%s", which has already been visited.' % subdir) self.visited_subdirs[subdir] = True self.subdir = subdir os.makedirs(os.path.join(self.environment.build_dir, subdir), exist_ok=True) buildfilename = os.path.join(self.subdir, environment.build_filename) self.build_def_files.append(buildfilename) absname = os.path.join(self.environment.get_source_dir(), buildfilename) if not os.path.isfile(absname): self.subdir = prev_subdir raise InterpreterException('Nonexistent build def file %s.' % buildfilename) with open(absname, encoding='utf8') as f: code = f.read() assert(isinstance(code, str)) try: codeblock = mparser.Parser(code, self.subdir).parse() except mesonlib.MesonException as me: me.file = buildfilename raise me self.evaluate_codeblock(codeblock) self.subdir = prev_subdir def _get_kwarg_install_mode(self, kwargs): if 'install_mode' not in kwargs: return None install_mode = [] mode = mesonlib.typeslistify(kwargs.get('install_mode', []), (str, int)) for m in mode: # We skip any arguments that are set to `false` if m is False: m = None install_mode.append(m) if len(install_mode) > 3: raise InvalidArguments('Keyword argument install_mode takes at ' 'most 3 arguments.') if len(install_mode) > 0 and install_mode[0] is not None and \ not isinstance(install_mode[0], str): raise InvalidArguments('Keyword argument install_mode requires the ' 'permissions arg to be a string or false') return FileMode(*install_mode) def func_install_data(self, node, args, kwargs): kwsource = mesonlib.stringlistify(kwargs.get('sources', [])) raw_sources = args + kwsource sources = [] source_strings = [] for s in raw_sources: if isinstance(s, mesonlib.File): sources.append(s) else: source_strings.append(s) sources += self.source_strings_to_files(source_strings) install_dir = kwargs.get('install_dir', None) if not isinstance(install_dir, (str, type(None))): raise InvalidArguments('Keyword argument install_dir not a string.') install_mode = self._get_kwarg_install_mode(kwargs) data = DataHolder(build.Data(sources, install_dir, install_mode)) self.build.data.append(data.held_object) return data @stringArgs def func_install_subdir(self, node, args, kwargs): if len(args) != 1: raise InvalidArguments('Install_subdir requires exactly one argument.') if 'install_dir' not in kwargs: raise InvalidArguments('Missing keyword argument install_dir') install_dir = kwargs['install_dir'] if not isinstance(install_dir, str): raise InvalidArguments('Keyword argument install_dir not a string.') install_mode = self._get_kwarg_install_mode(kwargs) idir = InstallDir(self.subdir, args[0], install_dir, install_mode) self.build.install_dirs.append(idir) return idir def func_configure_file(self, node, args, kwargs): if len(args) > 0: raise InterpreterException("configure_file takes only keyword arguments.") if 'output' not in kwargs: raise InterpreterException('Required keyword argument "output" not defined.') if 'configuration' in kwargs and 'command' in kwargs: raise InterpreterException('Must not specify both "configuration" ' 'and "command" keyword arguments since ' 'they are mutually exclusive.') # Validate input inputfile = None ifile_abs = None if 'input' in kwargs: inputfile = kwargs['input'] if isinstance(inputfile, list): if len(inputfile) != 1: m = "Keyword argument 'input' requires exactly one file" raise InterpreterException(m) inputfile = inputfile[0] if not isinstance(inputfile, (str, mesonlib.File)): raise InterpreterException('Input must be a string or a file') if isinstance(inputfile, str): inputfile = os.path.join(self.subdir, inputfile) ifile_abs = os.path.join(self.environment.source_dir, inputfile) else: ifile_abs = inputfile.absolute_path(self.environment.source_dir, self.environment.build_dir) inputfile = inputfile.relative_name() elif 'command' in kwargs and '@INPUT@' in kwargs['command']: raise InterpreterException('@INPUT@ used as command argument, but no input file specified.') # Validate output output = kwargs['output'] if not isinstance(output, str): raise InterpreterException('Output file name must be a string') if os.path.split(output)[0] != '': raise InterpreterException('Output file name must not contain a subdirectory.') (ofile_path, ofile_fname) = os.path.split(os.path.join(self.subdir, output)) ofile_abs = os.path.join(self.environment.build_dir, ofile_path, ofile_fname) if 'configuration' in kwargs: conf = kwargs['configuration'] if not isinstance(conf, ConfigurationDataHolder): raise InterpreterException('Argument "configuration" is not of type configuration_data') mlog.log('Configuring', mlog.bold(output), 'using configuration') 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(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) mesonlib.do_conf_file(ifile_abs, ofile_abs, conf.held_object) else: mesonlib.dump_conf_header(ofile_abs, conf.held_object) conf.mark_used() elif 'command' in kwargs: # We use absolute paths for input and output here because the cwd # that the command is run from is 'unspecified', so it could change. # Currently it's builddir/subdir for in_builddir else srcdir/subdir. if ifile_abs: values = mesonlib.get_filenames_templates_dict([ifile_abs], [ofile_abs]) else: values = mesonlib.get_filenames_templates_dict(None, [ofile_abs]) # Substitute @INPUT@, @OUTPUT@, etc here. cmd = mesonlib.substitute_values(kwargs['command'], values) mlog.log('Configuring', mlog.bold(output), 'with command') res = self.func_run_command(node, cmd, {'in_builddir': True}) if res.returncode != 0: raise InterpreterException('Running configure command failed.\n%s\n%s' % (res.stdout, res.stderr)) else: raise InterpreterException('Configure_file must have either "configuration" or "command".') idir = kwargs.get('install_dir', None) if isinstance(idir, str): cfile = mesonlib.File.from_built_file(ofile_path, ofile_fname) self.build.data.append(build.Data([cfile], idir)) return mesonlib.File.from_built_file(self.subdir, output) @stringArgs def func_include_directories(self, node, args, kwargs): src_root = self.environment.get_source_dir() build_root = self.environment.get_build_dir() absbase_src = os.path.join(src_root, self.subdir) absbase_build = os.path.join(build_root, self.subdir) for a in args: if a.startswith(src_root): raise InvalidArguments('''Tried to form an absolute path to a source dir. You should not do that but use relative paths instead. To get include path to any directory relative to the current dir do incdir = include_directories(dirname) After this incdir will contain both the current source dir as well as the corresponding build dir. It can then be used in any subdirectory and Meson will take care of all the busywork to make paths work. Dirname can even be '.' to mark the current directory. Though you should remember that the current source and build directories are always put in the include directories by default so you only need to do include_directories('.') if you intend to use the result in a different subdirectory. ''') absdir_src = os.path.join(absbase_src, a) absdir_build = os.path.join(absbase_build, a) if not os.path.isdir(absdir_src) and not os.path.isdir(absdir_build): raise InvalidArguments('Include dir %s does not exist.' % a) is_system = kwargs.get('is_system', False) if not isinstance(is_system, bool): raise InvalidArguments('Is_system must be boolean.') i = IncludeDirsHolder(build.IncludeDirs(self.subdir, args, is_system)) return i @stringArgs def func_add_test_setup(self, node, args, kwargs): if len(args) != 1: raise InterpreterException('Add_test_setup needs one argument for the setup name.') setup_name = args[0] if re.fullmatch('[_a-zA-Z][_0-9a-zA-Z]*', setup_name) is None: raise InterpreterException('Setup name may only contain alphanumeric characters.') try: inp = kwargs.get('exe_wrapper', []) if not isinstance(inp, list): inp = [inp] exe_wrapper = [] for i in inp: if hasattr(i, 'held_object'): i = i.held_object if isinstance(i, str): exe_wrapper.append(i) elif isinstance(i, dependencies.ExternalProgram): if not i.found(): raise InterpreterException('Tried to use non-found external executable.') exe_wrapper += i.get_command() else: raise InterpreterException('Exe wrapper can only contain strings or external binaries.') except KeyError: exe_wrapper = None gdb = kwargs.get('gdb', False) if not isinstance(gdb, bool): raise InterpreterException('Gdb option must be a boolean') timeout_multiplier = kwargs.get('timeout_multiplier', 1) if not isinstance(timeout_multiplier, int): raise InterpreterException('Timeout multiplier must be a number.') env = self.unpack_env_kwarg(kwargs) setupobj = build.TestSetup(exe_wrapper=exe_wrapper, gdb=gdb, timeout_multiplier=timeout_multiplier, env=env) if self.subproject == '': # Dunno what we should do with subprojects really. Let's start simple # and just use the master project ones. self.build.test_setups[setup_name] = setupobj @stringArgs def func_add_global_arguments(self, node, args, kwargs): 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 = '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.'.format(node.func_name) raise InvalidCode(msg) 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 {}'.format(node.func_name)) 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() @stringArgs @noKwargs def func_join_paths(self, node, args, kwargs): return os.path.join(*args).replace('\\', '/') def run(self): super().run() mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets)))) def source_strings_to_files(self, sources): results = [] for s in sources: if isinstance(s, (mesonlib.File, GeneratedListHolder, CustomTargetHolder)): pass elif isinstance(s, str): s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s) else: raise InterpreterException("Source item is not string or File-type object.") results.append(s) return results def add_target(self, name, tobj): if name == '': raise InterpreterException('Target name must not be empty.') if name in coredata.forbidden_target_names: raise InvalidArguments('Target name "%s" is reserved for Meson\'s internal use. Please rename.' % name) # To permit an executable and a shared library to have the # same name, such as "foo.exe" and "libfoo.a". idname = tobj.get_id() if idname in self.build.targets: raise InvalidCode('Tried to create target "%s", but a target of that name already exists.' % name) self.build.targets[idname] = tobj if idname not in self.coredata.target_guids: self.coredata.target_guids[idname] = str(uuid.uuid4()).upper() def build_target(self, node, args, kwargs, targetholder): if len(args) == 0: raise InterpreterException('Target does not have a name.') name = args[0] sources = args[1:] if self.environment.is_cross_build(): if kwargs.get('native', False): is_cross = False else: is_cross = True else: is_cross = False try: kw_src = self.flatten(kwargs['sources']) if not isinstance(kw_src, list): kw_src = [kw_src] except KeyError: kw_src = [] sources += kw_src sources = self.source_strings_to_files(sources) objs = self.flatten(kwargs.get('objects', [])) kwargs['dependencies'] = self.flatten(kwargs.get('dependencies', [])) if not isinstance(objs, list): objs = [objs] self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources) if targetholder is ExecutableHolder: targetclass = build.Executable elif targetholder is SharedLibraryHolder: targetclass = build.SharedLibrary elif targetholder is SharedModuleHolder: targetclass = build.SharedModule elif targetholder is StaticLibraryHolder: targetclass = build.StaticLibrary elif targetholder is JarHolder: targetclass = build.Jar else: mlog.debug('Unknown target type:', str(targetholder)) raise RuntimeError('Unreachable code') target = targetclass(name, self.subdir, self.subproject, is_cross, sources, objs, self.environment, kwargs) if is_cross: self.add_cross_stdlib_info(target) l = targetholder(target, self) self.add_target(name, l.held_object) self.project_args_frozen = True return l def get_used_languages(self, target): result = {} for i in target.sources: for lang, c in self.build.compilers.items(): if c.can_compile(i): result[lang] = True break return result def add_cross_stdlib_info(self, target): for l in self.get_used_languages(target): if self.environment.cross_info.has_stdlib(l) \ and self.subproject != self.environment.cross_info.get_stdlib(l)[0]: target.add_deps(self.build.cross_stdlibs[l]) def check_sources_exist(self, subdir, sources): for s in sources: if not isinstance(s, str): continue # This means a generated source and they always exist. fname = os.path.join(subdir, s) if not os.path.isfile(fname): raise InterpreterException('Tried to add non-existing source file %s.' % s) def format_string(self, templ, args): templ = self.to_native(templ) if isinstance(args, mparser.ArgumentNode): args = args.arguments for (i, arg) in enumerate(args): arg = self.to_native(self.evaluate_statement(arg)) if isinstance(arg, bool): # Python boolean is upper case. arg = str(arg).lower() templ = templ.replace('@{}@'.format(i), str(arg)) return templ # Only permit object extraction from the same subproject def validate_extraction(self, buildtarget): if not self.subdir.startswith(self.subproject_dir): if buildtarget.subdir.startswith(self.subproject_dir): raise InterpreterException('Tried to extract objects from a subproject target.') else: if not buildtarget.subdir.startswith(self.subproject_dir): raise InterpreterException('Tried to extract objects from the main project from a subproject.') if self.subdir.split('/')[1] != buildtarget.subdir.split('/')[1]: raise InterpreterException('Tried to extract objects from a different subproject.') def check_contains(self, obj, args): if len(args) != 1: raise InterpreterException('Contains method takes exactly one argument.') item = args[0] for element in obj: if isinstance(element, list): found = self.check_contains(element, args) if found: return True try: if element == item: return True except Exception: pass return False def is_subproject(self): return self.subproject != '' meson-0.40.1/mesonbuild/mintro.py0000644000175000017500000002256013055371450020342 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """This is a helper script for IDE developers. It allows you to extract information such as list of targets, files, compiler flags, tests and so on. All output is in JSON for simple parsing. Currently only works for the Ninja backend. Others use generated project files and don't need this info.""" import json, pickle from . import coredata, build import argparse import sys, os import pathlib parser = argparse.ArgumentParser() parser.add_argument('--targets', action='store_true', dest='list_targets', default=False, help='List top level targets.') parser.add_argument('--installed', action='store_true', dest='list_installed', default=False, help='List all installed files and directories.') parser.add_argument('--target-files', action='store', dest='target_files', default=None, help='List source files for a given target.') parser.add_argument('--buildsystem-files', action='store_true', dest='buildsystem_files', default=False, help='List files that make up the build system.') parser.add_argument('--buildoptions', action='store_true', dest='buildoptions', default=False, help='List all build options.') parser.add_argument('--tests', action='store_true', dest='tests', default=False, help='List all unit tests.') parser.add_argument('--benchmarks', action='store_true', dest='benchmarks', default=False, help='List all benchmarks.') parser.add_argument('--dependencies', action='store_true', dest='dependencies', default=False, help='List external dependencies.') parser.add_argument('--projectinfo', action='store_true', dest='projectinfo', default=False, help='Information about projects.') parser.add_argument('builddir', nargs='?', help='The build directory') def determine_installed_path(target, installdata): install_target = None for i in installdata.targets: if os.path.split(i[0])[1] == target.get_filename(): # FIXME, might clash due to subprojects. install_target = i break if install_target is None: raise RuntimeError('Something weird happened. File a bug.') fname = i[0] outdir = i[1] outname = os.path.join(installdata.prefix, outdir, os.path.split(fname)[-1]) # Normalize the path by using os.path.sep consistently, etc. # Does not change the effective path. return str(pathlib.PurePath(outname)) def list_installed(installdata): res = {} if installdata is not None: for path, installpath, unused_prefix in installdata.data: res[path] = os.path.join(installdata.prefix, installpath) print(json.dumps(res)) def list_targets(coredata, builddata, installdata): tlist = [] for (idname, target) in builddata.get_targets().items(): t = {} t['name'] = target.get_basename() t['id'] = idname fname = target.get_filename() if isinstance(fname, list): fname = [os.path.join(target.subdir, x) for x in fname] else: fname = os.path.join(target.subdir, fname) t['filename'] = fname if isinstance(target, build.Executable): typename = 'executable' elif isinstance(target, build.SharedLibrary): typename = 'shared library' elif isinstance(target, build.StaticLibrary): typename = 'static library' elif isinstance(target, build.CustomTarget): typename = 'custom' elif isinstance(target, build.RunTarget): typename = 'run' else: typename = 'unknown' t['type'] = typename if installdata and target.should_install(): t['installed'] = True t['install_filename'] = determine_installed_path(target, installdata) else: t['installed'] = False tlist.append(t) print(json.dumps(tlist)) def list_target_files(target_name, coredata, builddata): try: t = builddata.targets[target_name] sources = t.sources + t.extra_files except KeyError: print("Unknown target %s." % target_name) sys.exit(1) sources = [os.path.join(i.subdir, i.fname) for i in sources] print(json.dumps(sources)) def list_buildoptions(coredata, builddata): optlist = [] add_keys(optlist, coredata.user_options) add_keys(optlist, coredata.compiler_options) add_keys(optlist, coredata.base_options) add_keys(optlist, coredata.builtins) print(json.dumps(optlist)) def add_keys(optlist, options): keys = list(options.keys()) keys.sort() for key in keys: opt = options[key] optdict = {} optdict['name'] = key optdict['value'] = opt.value if isinstance(opt, coredata.UserStringOption): typestr = 'string' elif isinstance(opt, coredata.UserBooleanOption): typestr = 'boolean' elif isinstance(opt, coredata.UserComboOption): optdict['choices'] = opt.choices typestr = 'combo' elif isinstance(opt, coredata.UserStringArrayOption): typestr = 'stringarray' else: raise RuntimeError("Unknown option type") optdict['type'] = typestr optdict['description'] = opt.description optlist.append(optdict) def list_buildsystem_files(coredata, builddata): src_dir = builddata.environment.get_source_dir() # I feel dirty about this. But only slightly. filelist = [] for root, _, files in os.walk(src_dir): for f in files: if f == 'meson.build' or f == 'meson_options.txt': filelist.append(os.path.relpath(os.path.join(root, f), src_dir)) print(json.dumps(filelist)) def list_deps(coredata): result = {} for d in coredata.deps.values(): if d.found(): args = {'compile_args': d.get_compile_args(), 'link_args': d.get_link_args()} result[d.name] = args print(json.dumps(result)) def list_tests(testdata): result = [] for t in testdata: to = {} if isinstance(t.fname, str): fname = [t.fname] else: fname = t.fname to['cmd'] = fname + t.cmd_args if isinstance(t.env, build.EnvironmentVariables): to['env'] = t.env.get_env(os.environ) else: to['env'] = t.env to['name'] = t.name to['workdir'] = t.workdir to['timeout'] = t.timeout to['suite'] = t.suite result.append(to) print(json.dumps(result)) def list_projinfo(builddata): result = {} result['name'] = builddata.project_name result['version'] = builddata.project_version subprojects = [] for k, v in builddata.subprojects.items(): c = {'name': k, 'version': v} subprojects.append(c) result['subprojects'] = subprojects print(json.dumps(result)) def run(args): datadir = 'meson-private' options = parser.parse_args(args) if options.builddir is not None: datadir = os.path.join(options.builddir, datadir) if not os.path.isdir(datadir): print('Current directory is not a build dir. Please specify it or ' 'change the working directory to it.') return 1 corefile = os.path.join(datadir, 'coredata.dat') buildfile = os.path.join(datadir, 'build.dat') installfile = os.path.join(datadir, 'install.dat') testfile = os.path.join(datadir, 'meson_test_setup.dat') benchmarkfile = os.path.join(datadir, 'meson_benchmark_setup.dat') # Load all data files with open(corefile, 'rb') as f: coredata = pickle.load(f) with open(buildfile, 'rb') as f: builddata = pickle.load(f) with open(testfile, 'rb') as f: testdata = pickle.load(f) with open(benchmarkfile, 'rb') as f: benchmarkdata = pickle.load(f) # Install data is only available with the Ninja backend if os.path.isfile(installfile): with open(installfile, 'rb') as f: installdata = pickle.load(f) else: installdata = None if options.list_targets: list_targets(coredata, builddata, installdata) elif options.list_installed: list_installed(installdata) elif options.target_files is not None: list_target_files(options.target_files, coredata, builddata) elif options.buildsystem_files: list_buildsystem_files(coredata, builddata) elif options.buildoptions: list_buildoptions(coredata, builddata) elif options.tests: list_tests(testdata) elif options.benchmarks: list_tests(benchmarkdata) elif options.dependencies: list_deps(coredata) elif options.projectinfo: list_projinfo(builddata) else: print('No command specified') return 1 return 0 if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/dependencies.py0000644000175000017500000020006013076637146021463 0ustar jpakkanejpakkane00000000000000# Copyright 2013-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This file contains the detection logic for external # dependencies. Mostly just uses pkg-config but also contains # custom logic for packages that don't provide them. # Currently one file, should probably be split into a # package before this gets too big. import re import sys import os, stat, glob, shutil import subprocess import sysconfig from enum import Enum from collections import OrderedDict from . mesonlib import MesonException, version_compare, version_compare_many, Popen_safe from . import mlog from . import mesonlib from .environment import detect_cpu_family, for_windows class DependencyException(MesonException): '''Exceptions raised while trying to find dependencies''' class DependencyMethods(Enum): # Auto means to use whatever dependency checking mechanisms in whatever order meson thinks is best. AUTO = 'auto' PKGCONFIG = 'pkg-config' QMAKE = 'qmake' # Just specify the standard link arguments, assuming the operating system provides the library. SYSTEM = 'system' # Detect using sdl2-config SDLCONFIG = 'sdlconfig' # This is only supported on OSX - search the frameworks directory by name. EXTRAFRAMEWORK = 'extraframework' # Detect using the sysconfig module. SYSCONFIG = 'sysconfig' class Dependency: def __init__(self, type_name, kwargs): self.name = "null" self.language = None self.is_found = False self.type_name = type_name method = DependencyMethods(kwargs.get('method', 'auto')) # Set the detection method. If the method is set to auto, use any available method. # If method is set to a specific string, allow only that detection method. if method == DependencyMethods.AUTO: self.methods = self.get_methods() elif method in self.get_methods(): self.methods = [method] else: raise MesonException('Unsupported detection method: {}, allowed methods are {}'.format(method.value, mlog.format_list(map(lambda x: x.value, [DependencyMethods.AUTO] + self.get_methods())))) def __repr__(self): s = '<{0} {1}: {2}>' return s.format(self.__class__.__name__, self.name, self.is_found) def get_compile_args(self): return [] def get_link_args(self): return [] def found(self): return self.is_found def get_sources(self): """Source files that need to be added to the target. As an example, gtest-all.cc when using GTest.""" return [] def get_methods(self): return [DependencyMethods.AUTO] def get_name(self): return self.name def get_exe_args(self, compiler): return [] def need_threads(self): return False def get_pkgconfig_variable(self, variable_name): raise MesonException('Tried to get a pkg-config variable from a non-pkgconfig dependency.') class InternalDependency(Dependency): def __init__(self, version, incdirs, compile_args, link_args, libraries, sources, ext_deps): super().__init__('internal', {}) self.version = version self.include_directories = incdirs self.compile_args = compile_args self.link_args = link_args self.libraries = libraries self.sources = sources self.ext_deps = ext_deps def get_compile_args(self): return self.compile_args def get_link_args(self): return self.link_args def get_version(self): return self.version class PkgConfigDependency(Dependency): # The class's copy of the pkg-config path. Avoids having to search for it # multiple times in the same Meson invocation. class_pkgbin = None def __init__(self, name, environment, kwargs): Dependency.__init__(self, 'pkgconfig', kwargs) self.is_libtool = False self.required = kwargs.get('required', True) self.static = kwargs.get('static', False) self.silent = kwargs.get('silent', False) if not isinstance(self.static, bool): raise DependencyException('Static keyword must be boolean') # Store a copy of the pkg-config path on the object itself so it is # stored in the pickled coredata and recovered. self.pkgbin = None self.cargs = [] self.libs = [] if 'native' in kwargs and environment.is_cross_build(): self.want_cross = not kwargs['native'] else: self.want_cross = environment.is_cross_build() self.name = name self.modversion = 'none' # When finding dependencies for cross-compiling, we don't care about # the 'native' pkg-config if self.want_cross: if 'pkgconfig' not in environment.cross_info.config['binaries']: if self.required: raise DependencyException('Pkg-config binary missing from cross file') else: pkgname = environment.cross_info.config['binaries']['pkgconfig'] potential_pkgbin = ExternalProgram(pkgname, silent=True) if potential_pkgbin.found(): # FIXME, we should store all pkg-configs in ExternalPrograms. # However that is too destabilizing a change to do just before release. self.pkgbin = potential_pkgbin.get_command()[0] PkgConfigDependency.class_pkgbin = self.pkgbin else: mlog.debug('Cross pkg-config %s not found.' % potential_pkgbin.name) # Only search for the native pkg-config the first time and # store the result in the class definition elif PkgConfigDependency.class_pkgbin is None: self.pkgbin = self.check_pkgconfig() PkgConfigDependency.class_pkgbin = self.pkgbin else: self.pkgbin = PkgConfigDependency.class_pkgbin self.is_found = False if not self.pkgbin: if self.required: raise DependencyException('Pkg-config not found.') return if self.want_cross: self.type_string = 'Cross' else: self.type_string = 'Native' mlog.debug('Determining dependency {!r} with pkg-config executable ' '{!r}'.format(name, self.pkgbin)) ret, self.modversion = self._call_pkgbin(['--modversion', name]) if ret != 0: if self.required: raise DependencyException('{} dependency {!r} not found' ''.format(self.type_string, name)) return found_msg = [self.type_string + ' dependency', mlog.bold(name), 'found:'] self.version_reqs = kwargs.get('version', None) if self.version_reqs is None: self.is_found = True else: if not isinstance(self.version_reqs, (str, list)): raise DependencyException('Version argument must be string or list.') if isinstance(self.version_reqs, str): self.version_reqs = [self.version_reqs] (self.is_found, not_found, found) = \ version_compare_many(self.modversion, self.version_reqs) if not self.is_found: found_msg += [mlog.red('NO'), 'found {!r} but need:'.format(self.modversion), ', '.join(["'{}'".format(e) for e in not_found])] if found: found_msg += ['; matched:', ', '.join(["'{}'".format(e) for e in found])] if not self.silent: mlog.log(*found_msg) if self.required: m = 'Invalid version of dependency, need {!r} {!r} found {!r}.' raise DependencyException(m.format(name, not_found, self.modversion)) return found_msg += [mlog.green('YES'), self.modversion] # Fetch cargs to be used while using this dependency self._set_cargs() # Fetch the libraries and library paths needed for using this self._set_libs() # Print the found message only at the very end because fetching cflags # and libs can also fail if other needed pkg-config files aren't found. if not self.silent: mlog.log(*found_msg) def __repr__(self): s = '<{0} {1}: {2} {3}>' return s.format(self.__class__.__name__, self.name, self.is_found, self.version_reqs) def _call_pkgbin(self, args): p, out = Popen_safe([self.pkgbin] + args, env=os.environ)[0:2] return p.returncode, out.strip() def _set_cargs(self): ret, out = self._call_pkgbin(['--cflags', self.name]) if ret != 0: raise DependencyException('Could not generate cargs for %s:\n\n%s' % (self.name, out)) self.cargs = out.split() def _set_libs(self): libcmd = [self.name, '--libs'] if self.static: libcmd.append('--static') ret, out = self._call_pkgbin(libcmd) if ret != 0: raise DependencyException('Could not generate libs for %s:\n\n%s' % (self.name, out)) self.libs = [] for lib in out.split(): if lib.endswith(".la"): shared_libname = self.extract_libtool_shlib(lib) shared_lib = os.path.join(os.path.dirname(lib), shared_libname) if not os.path.exists(shared_lib): shared_lib = os.path.join(os.path.dirname(lib), ".libs", shared_libname) if not os.path.exists(shared_lib): raise DependencyException('Got a libtools specific "%s" dependencies' 'but we could not compute the actual shared' 'library path' % lib) lib = shared_lib self.is_libtool = True self.libs.append(lib) def get_pkgconfig_variable(self, variable_name): ret, out = self._call_pkgbin(['--variable=' + variable_name, self.name]) variable = '' if ret != 0: if self.required: raise DependencyException('%s dependency %s not found.' % (self.type_string, self.name)) else: variable = out.strip() mlog.debug('Got pkgconfig variable %s : %s' % (variable_name, variable)) return variable def get_modversion(self): return self.modversion def get_version(self): return self.modversion def get_compile_args(self): return self.cargs def get_link_args(self): return self.libs def get_methods(self): return [DependencyMethods.PKGCONFIG] def check_pkgconfig(self): evar = 'PKG_CONFIG' if evar in os.environ: pkgbin = os.environ[evar].strip() else: pkgbin = 'pkg-config' try: p, out = Popen_safe([pkgbin, '--version'])[0:2] if p.returncode != 0: # Set to False instead of None to signify that we've already # searched for it and not found it pkgbin = False except (FileNotFoundError, PermissionError): pkgbin = False if pkgbin and not os.path.isabs(pkgbin) and shutil.which(pkgbin): # Sometimes shutil.which fails where Popen succeeds, so # only find the abs path if it can be found by shutil.which pkgbin = shutil.which(pkgbin) if not self.silent: if pkgbin: mlog.log('Found pkg-config:', mlog.bold(pkgbin), '(%s)' % out.strip()) else: mlog.log('Found Pkg-config:', mlog.red('NO')) return pkgbin def found(self): return self.is_found def extract_field(self, la_file, fieldname): with open(la_file) as f: for line in f: arr = line.strip().split('=') if arr[0] == fieldname: return arr[1][1:-1] return None def extract_dlname_field(self, la_file): return self.extract_field(la_file, 'dlname') def extract_libdir_field(self, la_file): return self.extract_field(la_file, 'libdir') def extract_libtool_shlib(self, la_file): ''' Returns the path to the shared library corresponding to this .la file ''' dlname = self.extract_dlname_field(la_file) if dlname is None: return None # Darwin uses absolute paths where possible; since the libtool files never # contain absolute paths, use the libdir field if mesonlib.is_osx(): dlbasename = os.path.basename(dlname) libdir = self.extract_libdir_field(la_file) if libdir is None: return dlbasename return os.path.join(libdir, dlbasename) # From the comments in extract_libtool(), older libtools had # a path rather than the raw dlname return os.path.basename(dlname) class WxDependency(Dependency): wx_found = None def __init__(self, environment, kwargs): Dependency.__init__(self, 'wx', kwargs) self.is_found = False self.modversion = 'none' if WxDependency.wx_found is None: self.check_wxconfig() if not WxDependency.wx_found: mlog.log("Neither wx-config-3.0 nor wx-config found; can't detect dependency") return p, out = Popen_safe([self.wxc, '--version'])[0:2] if p.returncode != 0: mlog.log('Dependency wxwidgets found:', mlog.red('NO')) self.cargs = [] self.libs = [] else: self.modversion = out.strip() version_req = kwargs.get('version', None) if version_req is not None: if not version_compare(self.modversion, version_req, strict=True): mlog.log('Wxwidgets version %s does not fullfill requirement %s' % (self.modversion, version_req)) return mlog.log('Dependency wxwidgets found:', mlog.green('YES')) self.is_found = True self.requested_modules = self.get_requested(kwargs) # wx-config seems to have a cflags as well but since it requires C++, # this should be good, at least for now. p, out = Popen_safe([self.wxc, '--cxxflags'])[0:2] if p.returncode != 0: raise DependencyException('Could not generate cargs for wxwidgets.') self.cargs = out.split() p, out = Popen_safe([self.wxc, '--libs'] + self.requested_modules)[0:2] if p.returncode != 0: raise DependencyException('Could not generate libs for wxwidgets.') self.libs = out.split() def get_requested(self, kwargs): modules = 'modules' if modules not in kwargs: return [] candidates = kwargs[modules] if isinstance(candidates, str): return [candidates] for c in candidates: if not isinstance(c, str): raise DependencyException('wxwidgets module argument is not a string.') return candidates def get_modversion(self): return self.modversion def get_version(self): return self.modversion def get_compile_args(self): return self.cargs def get_link_args(self): return self.libs def check_wxconfig(self): for wxc in ['wx-config-3.0', 'wx-config']: try: p, out = Popen_safe([wxc, '--version'])[0:2] if p.returncode == 0: mlog.log('Found wx-config:', mlog.bold(shutil.which(wxc)), '(%s)' % out.strip()) self.wxc = wxc WxDependency.wx_found = True return except (FileNotFoundError, PermissionError): pass WxDependency.wxconfig_found = False mlog.log('Found wx-config:', mlog.red('NO')) def found(self): return self.is_found class ExternalProgram: windows_exts = ('exe', 'msc', 'com', 'bat') def __init__(self, name, command=None, silent=False, search_dir=None): self.name = name if command is not None: if not isinstance(command, list): self.command = [command] else: self.command = command else: self.command = self._search(name, search_dir) if not silent: if self.found(): mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'), '(%s)' % ' '.join(self.command)) else: mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO')) def __repr__(self): r = '<{} {!r} -> {!r}>' return r.format(self.__class__.__name__, self.name, self.command) @staticmethod def _shebang_to_cmd(script): """ Windows does not understand shebangs, so we check if the file has a shebang and manually parse it to figure out the interpreter to use """ try: with open(script) as f: first_line = f.readline().strip() if first_line.startswith('#!'): commands = first_line[2:].split('#')[0].strip().split() if mesonlib.is_windows(): # Windows does not have UNIX paths so remove them, # but don't remove Windows paths if commands[0].startswith('/'): commands[0] = commands[0].split('/')[-1] if len(commands) > 0 and commands[0] == 'env': commands = commands[1:] # Windows does not ship python3.exe, but we know the path to it if len(commands) > 0 and commands[0] == 'python3': commands[0] = sys.executable return commands + [script] except Exception: pass return False def _is_executable(self, path): suffix = os.path.splitext(path)[-1].lower()[1:] if mesonlib.is_windows(): if suffix in self.windows_exts: return True elif os.access(path, os.X_OK): return not os.path.isdir(path) return False def _search_dir(self, name, search_dir): if search_dir is None: return False trial = os.path.join(search_dir, name) if os.path.exists(trial): if self._is_executable(trial): return [trial] else: for ext in self.windows_exts: trial_ext = '{}.{}'.format(trial, ext) if os.path.exists(trial_ext): return [trial_ext] return False # Now getting desperate. Maybe it is a script file that is a) not chmodded # executable or b) we are on windows so they can't be directly executed. return self._shebang_to_cmd(trial) def _search(self, name, search_dir): ''' Search in the specified dir for the specified executable by name and if not found search in PATH ''' commands = self._search_dir(name, search_dir) if commands: return commands # Do a standard search in PATH command = shutil.which(name) if not mesonlib.is_windows(): # On UNIX-like platforms, the standard PATH search is enough return [command] # HERE BEGINS THE TERROR OF WINDOWS if command: # On Windows, even if the PATH search returned a full path, we can't be # sure that it can be run directly if it's not a native executable. # For instance, interpreted scripts sometimes need to be run explicitly # with an interpreter if the file association is not done properly. name_ext = os.path.splitext(command)[1] if name_ext[1:].lower() in self.windows_exts: # Good, it can be directly executed return [command] # Try to extract the interpreter from the shebang commands = self._shebang_to_cmd(command) if commands: return commands else: # Maybe the name is an absolute path to a native Windows # executable, but without the extension. This is technically wrong, # but many people do it because it works in the MinGW shell. if os.path.isabs(name): for ext in self.windows_exts: command = '{}.{}'.format(name, ext) if os.path.exists(command): return [command] # On Windows, interpreted scripts must have an extension otherwise they # cannot be found by a standard PATH search. So we do a custom search # where we manually search for a script with a shebang in PATH. search_dirs = os.environ.get('PATH', '').split(';') for search_dir in search_dirs: commands = self._search_dir(name, search_dir) if commands: return commands return [None] def found(self): return self.command[0] is not None def get_command(self): return self.command[:] def get_path(self): # Assume that the last element is the full path to the script # If it's not a script, this will be an array of length 1 if self.found(): return self.command[-1] return None def get_name(self): return self.name class ExternalLibrary(Dependency): # TODO: Add `language` support to all Dependency objects so that languages # can be exposed for dependencies that support that (i.e., not pkg-config) def __init__(self, name, link_args, language, silent=False): super().__init__('external', {}) self.name = name self.language = language self.is_found = False self.link_args = [] self.lang_args = [] if link_args: self.is_found = True if not isinstance(link_args, list): link_args = [link_args] self.lang_args = {language: link_args} # We special-case Vala for now till the Dependency object gets # proper support for exposing the language it was written in. # Without this, vala-specific link args will end up in the C link # args list if you link to a Vala library. # This hack use to be in CompilerHolder.find_library(). if language != 'vala': self.link_args = link_args if not silent: if self.is_found: mlog.log('Library', mlog.bold(name), 'found:', mlog.green('YES')) else: mlog.log('Library', mlog.bold(name), 'found:', mlog.red('NO')) def found(self): return self.is_found def get_name(self): return self.name def get_link_args(self): return self.link_args def get_lang_args(self, lang): if lang in self.lang_args: return self.lang_args[lang] return [] class BoostDependency(Dependency): # Some boost libraries have different names for # their sources and libraries. This dict maps # between the two. name2lib = {'test': 'unit_test_framework'} def __init__(self, environment, kwargs): Dependency.__init__(self, 'boost', kwargs) self.name = 'boost' self.environment = environment self.libdir = '' if 'native' in kwargs and environment.is_cross_build(): self.want_cross = not kwargs['native'] else: self.want_cross = environment.is_cross_build() try: self.boost_root = os.environ['BOOST_ROOT'] if not os.path.isabs(self.boost_root): raise DependencyException('BOOST_ROOT must be an absolute path.') except KeyError: self.boost_root = None if self.boost_root is None: if self.want_cross: 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: 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') mlog.debug('Boost library root dir is', self.boost_root) self.src_modules = {} self.lib_modules = {} self.lib_modules_mt = {} self.detect_version() self.requested_modules = self.get_requested(kwargs) module_str = ', '.join(self.requested_modules) if self.version is not None: self.detect_src_modules() self.detect_lib_modules() self.validate_requested() if self.boost_root is not None: info = self.version + ', ' + self.boost_root else: info = self.version mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info) else: mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO')) if 'cpp' not in self.environment.coredata.compilers: raise DependencyException('Tried to use Boost but a C++ compiler is not defined.') self.cpp_compiler = self.environment.coredata.compilers['cpp'] def detect_win_root(self): globtext = 'c:\\local\\boost_*' files = glob.glob(globtext) if len(files) > 0: return files[0] return 'C:\\' def get_compile_args(self): args = [] include_dir = '' if self.boost_root is not None: if mesonlib.is_windows(): include_dir = self.boost_root else: include_dir = os.path.join(self.boost_root, 'include') else: include_dir = self.incdir # Use "-isystem" when including boost headers instead of "-I" # to avoid compiler warnings/failures when "-Werror" is used # Careful not to use "-isystem" on default include dirs as it # breaks some of the headers for certain gcc versions # For example, doing g++ -isystem /usr/include on a simple # "int main()" source results in the error: # "/usr/include/c++/6.3.1/cstdlib:75:25: fatal error: stdlib.h: No such file or directory" # See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129 # and http://stackoverflow.com/questions/37218953/isystem-on-a-system-include-directory-causes-errors # for more details # TODO: The correct solution would probably be to ask the # compiler for it's default include paths (ie: "gcc -xc++ -E # -v -") and avoid including those with -isystem # For now, use -isystem for all includes except for some # typical defaults (which don't need to be included at all # since they are in the default include paths) if include_dir != '/usr/include' and include_dir != '/usr/local/include': args.append("".join(self.cpp_compiler.get_include_args(include_dir, True))) return args def get_requested(self, kwargs): candidates = kwargs.get('modules', []) if isinstance(candidates, str): return [candidates] for c in candidates: if not isinstance(c, str): raise DependencyException('Boost module argument is not a string.') return candidates def validate_requested(self): for m in self.requested_modules: if m not in self.src_modules: raise DependencyException('Requested Boost module "%s" not found.' % m) def found(self): return self.version is not None def get_version(self): return self.version def detect_version(self): try: ifile = open(os.path.join(self.boost_inc_subdir, 'version.hpp')) except FileNotFoundError: self.version = None return with ifile: for line in ifile: if line.startswith("#define") and 'BOOST_LIB_VERSION' in line: ver = line.split()[-1] ver = ver[1:-1] self.version = ver.replace('_', '.') return self.version = None def detect_src_modules(self): for entry in os.listdir(self.boost_inc_subdir): entry = os.path.join(self.boost_inc_subdir, entry) if stat.S_ISDIR(os.stat(entry).st_mode): self.src_modules[os.path.split(entry)[-1]] = True def detect_lib_modules(self): if mesonlib.is_windows(): return self.detect_lib_modules_win() return self.detect_lib_modules_nix() def detect_lib_modules_win(self): arch = detect_cpu_family(self.environment.coredata.compilers) # Guess the libdir if arch == 'x86': gl = 'lib32*' elif arch == 'x86_64': gl = 'lib64*' else: # Does anyone do Boost cross-compiling to other archs on Windows? gl = None # See if the libdir is valid if gl: libdir = glob.glob(os.path.join(self.boost_root, gl)) else: libdir = [] # Can't find libdir, bail if len(libdir) == 0: return libdir = libdir[0] self.libdir = libdir globber = 'boost_*-gd-*.lib' # FIXME for entry in glob.glob(os.path.join(libdir, globber)): (_, fname) = os.path.split(entry) base = fname.split('_', 1)[1] modname = base.split('-', 1)[0] self.lib_modules_mt[modname] = fname def detect_lib_modules_nix(self): if mesonlib.is_osx(): libsuffix = 'dylib' else: libsuffix = 'so' globber = 'libboost_*.{}'.format(libsuffix) 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')] for libdir in libdirs: for entry in glob.glob(os.path.join(libdir, globber)): lib = os.path.basename(entry) name = lib.split('.')[0].split('_', 1)[-1] # I'm not 100% sure what to do here. Some distros # have modules such as thread only as -mt versions. if entry.endswith('-mt.so'): self.lib_modules_mt[name] = True else: self.lib_modules[name] = True def get_win_link_args(self): args = [] if self.boost_root: args.append('-L' + self.libdir) for module in self.requested_modules: module = BoostDependency.name2lib.get(module, module) if module in self.lib_modules_mt: args.append(self.lib_modules_mt[module]) return args def get_link_args(self): if mesonlib.is_windows(): return self.get_win_link_args() 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 # The compiler's library detector is the most reliable so use that first. default_detect = self.cpp_compiler.find_library(libname, self.environment, []) if default_detect is not None: if module == 'unit_testing_framework': emon_args = self.cpp_compiler.find_library('boost_test_exec_monitor') else: emon_args = None args += default_detect if emon_args is not None: args += emon_args elif module in self.lib_modules or module in self.lib_modules_mt: linkcmd = '-l' + libname args.append(linkcmd) # FIXME a hack, but Boost's testing framework has a lot of # different options and it's hard to determine what to do # without feedback from actual users. Update this # as we get more bug reports. if module == 'unit_testing_framework': args.append('-lboost_test_exec_monitor') elif module + '-mt' in self.lib_modules_mt: linkcmd = '-lboost_' + module + '-mt' args.append(linkcmd) if module == 'unit_testing_framework': args.append('-lboost_test_exec_monitor-mt') return args def get_sources(self): return [] def need_threads(self): return 'thread' in self.requested_modules class GTestDependency(Dependency): def __init__(self, environment, kwargs): Dependency.__init__(self, 'gtest', kwargs) self.main = kwargs.get('main', False) self.name = 'gtest' self.libname = 'libgtest.so' self.libmain_name = 'libgtest_main.so' self.include_dir = '/usr/include' self.src_dirs = ['/usr/src/gtest/src', '/usr/src/googletest/googletest/src'] self.detect() def found(self): return self.is_found def detect(self): trial_dirs = mesonlib.get_library_dirs() glib_found = False gmain_found = False for d in trial_dirs: if os.path.isfile(os.path.join(d, self.libname)): glib_found = True if os.path.isfile(os.path.join(d, self.libmain_name)): gmain_found = True if glib_found and gmain_found: self.is_found = True self.compile_args = [] self.link_args = ['-lgtest'] if self.main: self.link_args.append('-lgtest_main') self.sources = [] mlog.log('Dependency GTest found:', mlog.green('YES'), '(prebuilt)') elif self.detect_srcdir(): self.is_found = True self.compile_args = ['-I' + self.src_include_dir] self.link_args = [] if self.main: self.sources = [self.all_src, self.main_src] else: self.sources = [self.all_src] mlog.log('Dependency GTest found:', mlog.green('YES'), '(building self)') else: mlog.log('Dependency GTest found:', mlog.red('NO')) self.is_found = False return self.is_found def detect_srcdir(self): for s in self.src_dirs: if os.path.exists(s): self.src_dir = s self.all_src = mesonlib.File.from_absolute_file( os.path.join(self.src_dir, 'gtest-all.cc')) self.main_src = mesonlib.File.from_absolute_file( os.path.join(self.src_dir, 'gtest_main.cc')) self.src_include_dir = os.path.normpath(os.path.join(self.src_dir, '..')) return True return False def get_compile_args(self): arr = [] if self.include_dir != '/usr/include': arr.append('-I' + self.include_dir) if hasattr(self, 'src_include_dir'): arr.append('-I' + self.src_include_dir) return arr def get_link_args(self): return self.link_args def get_version(self): return '1.something_maybe' def get_sources(self): return self.sources def need_threads(self): return True class GMockDependency(Dependency): def __init__(self, environment, kwargs): Dependency.__init__(self, 'gmock', kwargs) # GMock may be a library or just source. # Work with both. self.name = 'gmock' self.libname = 'libgmock.so' trial_dirs = mesonlib.get_library_dirs() gmock_found = False for d in trial_dirs: if os.path.isfile(os.path.join(d, self.libname)): gmock_found = True if gmock_found: self.is_found = True self.compile_args = [] self.link_args = ['-lgmock'] self.sources = [] mlog.log('Dependency GMock found:', mlog.green('YES'), '(prebuilt)') return for d in ['/usr/src/googletest/googlemock/src', '/usr/src/gmock/src', '/usr/src/gmock']: if os.path.exists(d): self.is_found = True # Yes, we need both because there are multiple # versions of gmock that do different things. d2 = os.path.normpath(os.path.join(d, '..')) self.compile_args = ['-I' + d, '-I' + d2] self.link_args = [] all_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock-all.cc')) main_src = mesonlib.File.from_absolute_file(os.path.join(d, 'gmock_main.cc')) if kwargs.get('main', False): self.sources = [all_src, main_src] else: self.sources = [all_src] mlog.log('Dependency GMock found:', mlog.green('YES'), '(building self)') return mlog.log('Dependency GMock found:', mlog.red('NO')) self.is_found = False def get_version(self): return '1.something_maybe' def get_compile_args(self): return self.compile_args def get_sources(self): return self.sources def get_link_args(self): return self.link_args def found(self): return self.is_found class QtBaseDependency(Dependency): def __init__(self, name, env, kwargs): Dependency.__init__(self, name, kwargs) self.name = name self.qtname = name.capitalize() self.qtver = name[-1] if self.qtver == "4": self.qtpkgname = 'Qt' else: self.qtpkgname = self.qtname self.root = '/usr' self.bindir = None self.silent = kwargs.get('silent', False) # We store the value of required here instead of passing it on to # PkgConfigDependency etc because we want to try the qmake-based # fallback as well. self.required = kwargs.pop('required', True) kwargs['required'] = False mods = kwargs.get('modules', []) self.cargs = [] self.largs = [] self.is_found = False if isinstance(mods, str): mods = [mods] if len(mods) == 0: raise DependencyException('No ' + self.qtname + ' modules specified.') type_text = 'cross' if env.is_cross_build() else 'native' found_msg = '{} {} {{}} dependency (modules: {}) found:' \ ''.format(self.qtname, type_text, ', '.join(mods)) from_text = 'pkg-config' # Keep track of the detection methods used, for logging purposes. methods = [] # Prefer pkg-config, then fallback to `qmake -query` if DependencyMethods.PKGCONFIG in self.methods: self._pkgconfig_detect(mods, env, kwargs) methods.append('pkgconfig') if not self.is_found and DependencyMethods.QMAKE in self.methods: from_text = self._qmake_detect(mods, env, kwargs) methods.append('qmake-' + self.name) methods.append('qmake') if not self.is_found: # Reset compile args and link args self.cargs = [] self.largs = [] from_text = '(checked {})'.format(mlog.format_list(methods)) self.version = 'none' if self.required: err_msg = '{} {} dependency not found {}' \ ''.format(self.qtname, type_text, from_text) raise DependencyException(err_msg) if not self.silent: mlog.log(found_msg.format(from_text), mlog.red('NO')) return from_text = '`{}`'.format(from_text) if not self.silent: mlog.log(found_msg.format(from_text), mlog.green('YES')) def compilers_detect(self): "Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH" if self.bindir: moc = ExternalProgram(os.path.join(self.bindir, 'moc'), silent=True) uic = ExternalProgram(os.path.join(self.bindir, 'uic'), silent=True) rcc = ExternalProgram(os.path.join(self.bindir, 'rcc'), silent=True) else: # We don't accept unsuffixed 'moc', 'uic', and 'rcc' because they # are sometimes older, or newer versions. moc = ExternalProgram('moc-' + self.name, silent=True) uic = ExternalProgram('uic-' + self.name, silent=True) rcc = ExternalProgram('rcc-' + self.name, silent=True) return moc, uic, rcc def _pkgconfig_detect(self, mods, env, kwargs): modules = OrderedDict() for module in mods: modules[module] = PkgConfigDependency(self.qtpkgname + module, env, kwargs) self.is_found = True for m in modules.values(): if not m.found(): self.is_found = False return self.cargs += m.get_compile_args() self.largs += m.get_link_args() self.version = m.modversion # Try to detect moc, uic, rcc if 'Core' in modules: core = modules['Core'] else: corekwargs = {'required': 'false', 'silent': 'true'} core = PkgConfigDependency(self.qtpkgname + 'Core', env, corekwargs) # Used by self.compilers_detect() self.bindir = self.get_pkgconfig_host_bins(core) if not self.bindir: # If exec_prefix is not defined, the pkg-config file is broken prefix = core.get_pkgconfig_variable('exec_prefix') if prefix: self.bindir = os.path.join(prefix, 'bin') def _find_qmake(self, qmake, env): # Even when cross-compiling, if we don't get a cross-info qmake, we # fallback to using the qmake in PATH because that's what we used to do if env.is_cross_build(): qmake = env.cross_info.config['binaries'].get('qmake', qmake) return ExternalProgram(qmake, silent=True) def _qmake_detect(self, mods, env, kwargs): for qmake in ('qmake-' + self.name, 'qmake'): self.qmake = self._find_qmake(qmake, env) if not self.qmake.found(): continue # Check that the qmake is for qt5 pc, stdo = Popen_safe(self.qmake.get_command() + ['-v'])[0:2] if pc.returncode != 0: continue if not 'Qt version ' + self.qtver in stdo: mlog.log('QMake is not for ' + self.qtname) continue # Found qmake for Qt5! break else: # Didn't find qmake :( return self.version = re.search(self.qtver + '(\.\d+)+', stdo).group(0) # Query library path, header path, and binary path mlog.log("Found qmake:", mlog.bold(self.qmake.get_name()), '(%s)' % self.version) stdo = Popen_safe(self.qmake.get_command() + ['-query'])[1] qvars = {} for line in stdo.split('\n'): line = line.strip() if line == '': continue (k, v) = tuple(line.split(':', 1)) qvars[k] = v if mesonlib.is_osx(): return self._framework_detect(qvars, mods, kwargs) incdir = qvars['QT_INSTALL_HEADERS'] self.cargs.append('-I' + incdir) libdir = qvars['QT_INSTALL_LIBS'] # Used by self.compilers_detect() self.bindir = qvars['QT_INSTALL_BINS'] self.is_found = True for module in mods: mincdir = os.path.join(incdir, 'Qt' + module) self.cargs.append('-I' + mincdir) if for_windows(env.is_cross_build(), env): libfile = os.path.join(libdir, self.qtpkgname + module + '.lib') if not os.path.isfile(libfile): # MinGW can link directly to .dll libfile = os.path.join(self.bindir, self.qtpkgname + module + '.dll') if not os.path.isfile(libfile): self.is_found = False break else: libfile = os.path.join(libdir, 'lib{}{}.so'.format(self.qtpkgname, module)) if not os.path.isfile(libfile): self.is_found = False break self.largs.append(libfile) return qmake def _framework_detect(self, qvars, modules, kwargs): libdir = qvars['QT_INSTALL_LIBS'] for m in modules: fname = 'Qt' + m fwdep = ExtraFrameworkDependency(fname, kwargs.get('required', True), libdir, kwargs) self.cargs.append('-F' + libdir) if fwdep.found(): self.is_found = True self.cargs += fwdep.get_compile_args() self.largs += fwdep.get_link_args() # Used by self.compilers_detect() self.bindir = qvars['QT_INSTALL_BINS'] def get_version(self): return self.version def get_compile_args(self): return self.cargs def get_sources(self): return [] def get_link_args(self): return self.largs def get_methods(self): return [DependencyMethods.PKGCONFIG, DependencyMethods.QMAKE] def found(self): return self.is_found def get_exe_args(self, compiler): # Originally this was -fPIE but nowadays the default # for upstream and distros seems to be -reduce-relocations # which requires -fPIC. This may cause a performance # penalty when using self-built Qt or on platforms # where -fPIC is not required. If this is an issue # for you, patches are welcome. return compiler.get_pic_args() class Qt5Dependency(QtBaseDependency): def __init__(self, env, kwargs): QtBaseDependency.__init__(self, 'qt5', env, kwargs) def get_pkgconfig_host_bins(self, core): return core.get_pkgconfig_variable('host_bins') class Qt4Dependency(QtBaseDependency): def __init__(self, env, kwargs): QtBaseDependency.__init__(self, 'qt4', env, kwargs) def get_pkgconfig_host_bins(self, core): # Only return one bins dir, because the tools are generally all in one # directory for Qt4, in Qt5, they must all be in one directory. Return # the first one found among the bin variables, in case one tool is not # configured to be built. applications = ['moc', 'uic', 'rcc', 'lupdate', 'lrelease'] for application in applications: try: return os.path.dirname(core.get_pkgconfig_variable('%s_location' % application)) except MesonException: pass class GnuStepDependency(Dependency): def __init__(self, environment, kwargs): Dependency.__init__(self, 'gnustep', kwargs) self.required = kwargs.get('required', True) self.modules = kwargs.get('modules', []) self.detect() def detect(self): self.confprog = 'gnustep-config' try: gp = Popen_safe([self.confprog, '--help'])[0] except (FileNotFoundError, PermissionError): self.args = None mlog.log('Dependency GnuStep found:', mlog.red('NO'), '(no gnustep-config)') return if gp.returncode != 0: self.args = None mlog.log('Dependency GnuStep found:', mlog.red('NO')) return if 'gui' in self.modules: arg = '--gui-libs' else: arg = '--base-libs' fp, flagtxt, flagerr = Popen_safe([self.confprog, '--objc-flags']) if fp.returncode != 0: raise DependencyException('Error getting objc-args: %s %s' % (flagtxt, flagerr)) args = flagtxt.split() self.args = self.filter_arsg(args) fp, libtxt, liberr = Popen_safe([self.confprog, arg]) if fp.returncode != 0: raise DependencyException('Error getting objc-lib args: %s %s' % (libtxt, liberr)) self.libs = self.weird_filter(libtxt.split()) self.version = self.detect_version() mlog.log('Dependency', mlog.bold('GnuStep'), 'found:', mlog.green('YES'), self.version) def weird_filter(self, elems): """When building packages, the output of the enclosing Make is sometimes mixed among the subprocess output. I have no idea why. As a hack filter out everything that is not a flag.""" return [e for e in elems if e.startswith('-')] def filter_arsg(self, args): """gnustep-config returns a bunch of garbage args such as -O2 and so on. Drop everything that is not needed.""" result = [] for f in args: if f.startswith('-D') \ or f.startswith('-f') \ or f.startswith('-I') \ or f == '-pthread' \ or (f.startswith('-W') and not f == '-Wall'): result.append(f) return result def detect_version(self): gmake = self.get_variable('GNUMAKE') makefile_dir = self.get_variable('GNUSTEP_MAKEFILES') # This Makefile has the GNUStep version set base_make = os.path.join(makefile_dir, 'Additional', 'base.make') # Print the Makefile variable passed as the argument. For instance, if # you run the make target `print-SOME_VARIABLE`, this will print the # value of the variable `SOME_VARIABLE`. printver = "print-%:\n\t@echo '$($*)'" env = os.environ.copy() # See base.make to understand why this is set env['FOUNDATION_LIB'] = 'gnu' p, o, e = Popen_safe([gmake, '-f', '-', '-f', base_make, 'print-GNUSTEP_BASE_VERSION'], env=env, write=printver, stdin=subprocess.PIPE) version = o.strip() if not version: mlog.debug("Couldn't detect GNUStep version, falling back to '1'") # Fallback to setting some 1.x version version = '1' return version def get_variable(self, var): p, o, e = Popen_safe([self.confprog, '--variable=' + var]) if p.returncode != 0 and self.required: raise DependencyException('{!r} for variable {!r} failed to run' ''.format(self.confprog, var)) return o.strip() def found(self): return self.args is not None def get_version(self): return self.version def get_compile_args(self): if self.args is None: return [] return self.args def get_link_args(self): return self.libs class AppleFrameworks(Dependency): def __init__(self, environment, kwargs): Dependency.__init__(self, 'appleframeworks', kwargs) modules = kwargs.get('modules', []) if isinstance(modules, str): modules = [modules] if len(modules) == 0: raise DependencyException("AppleFrameworks dependency requires at least one module.") self.frameworks = modules def get_link_args(self): args = [] for f in self.frameworks: args.append('-framework') args.append(f) return args def found(self): return mesonlib.is_osx() def get_version(self): return 'unknown' class GLDependency(Dependency): def __init__(self, environment, kwargs): Dependency.__init__(self, 'gl', kwargs) self.is_found = False self.cargs = [] self.linkargs = [] if DependencyMethods.PKGCONFIG in self.methods: try: pcdep = PkgConfigDependency('gl', environment, kwargs) if pcdep.found(): self.type_name = 'pkgconfig' self.is_found = True self.cargs = pcdep.get_compile_args() self.linkargs = pcdep.get_link_args() self.version = pcdep.get_version() return except Exception: pass if DependencyMethods.SYSTEM in self.methods: if mesonlib.is_osx(): self.is_found = True self.linkargs = ['-framework', 'OpenGL'] self.version = '1' # FIXME return if mesonlib.is_windows(): self.is_found = True self.linkargs = ['-lopengl32'] self.version = '1' # FIXME: unfixable? return def get_link_args(self): return self.linkargs def get_version(self): return self.version def get_methods(self): if mesonlib.is_osx() or mesonlib.is_windows(): return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM] else: return [DependencyMethods.PKGCONFIG] # There are three different ways of depending on SDL2: # sdl2-config, pkg-config and OSX framework class SDL2Dependency(Dependency): def __init__(self, environment, kwargs): Dependency.__init__(self, 'sdl2', kwargs) self.is_found = False self.cargs = [] self.linkargs = [] if DependencyMethods.PKGCONFIG in self.methods: try: pcdep = PkgConfigDependency('sdl2', environment, kwargs) if pcdep.found(): self.type_name = 'pkgconfig' self.is_found = True self.cargs = pcdep.get_compile_args() self.linkargs = pcdep.get_link_args() self.version = pcdep.get_version() return except Exception as e: mlog.debug('SDL 2 not found via pkgconfig. Trying next, error was:', str(e)) pass if DependencyMethods.SDLCONFIG in self.methods: sdlconf = shutil.which('sdl2-config') if sdlconf: stdo = Popen_safe(['sdl2-config', '--cflags'])[1] self.cargs = stdo.strip().split() stdo = Popen_safe(['sdl2-config', '--libs'])[1] self.linkargs = stdo.strip().split() stdo = Popen_safe(['sdl2-config', '--version'])[1] self.version = stdo.strip() self.is_found = True mlog.log('Dependency', mlog.bold('sdl2'), 'found:', mlog.green('YES'), self.version, '(%s)' % sdlconf) return mlog.debug('Could not find sdl2-config binary, trying next.') if DependencyMethods.EXTRAFRAMEWORK in self.methods: if mesonlib.is_osx(): fwdep = ExtraFrameworkDependency('sdl2', kwargs.get('required', True), None, kwargs) if fwdep.found(): self.is_found = True self.cargs = fwdep.get_compile_args() self.linkargs = fwdep.get_link_args() self.version = '2' # FIXME return mlog.log('Dependency', mlog.bold('sdl2'), 'found:', mlog.red('NO')) def get_compile_args(self): return self.cargs def get_link_args(self): return self.linkargs def found(self): return self.is_found def get_version(self): return self.version def get_methods(self): if mesonlib.is_osx(): return [DependencyMethods.PKGCONFIG, DependencyMethods.SDLCONFIG, DependencyMethods.EXTRAFRAMEWORK] else: return [DependencyMethods.PKGCONFIG, DependencyMethods.SDLCONFIG] class ExtraFrameworkDependency(Dependency): def __init__(self, name, required, path, kwargs): Dependency.__init__(self, 'extraframeworks', kwargs) self.name = None self.detect(name, path) if self.found(): mlog.log('Dependency', mlog.bold(name), 'found:', mlog.green('YES'), os.path.join(self.path, self.name)) else: mlog.log('Dependency', name, 'found:', mlog.red('NO')) def detect(self, name, path): lname = name.lower() if path is None: paths = ['/Library/Frameworks'] else: paths = [path] for p in paths: for d in os.listdir(p): fullpath = os.path.join(p, d) if lname != d.split('.')[0].lower(): continue if not stat.S_ISDIR(os.stat(fullpath).st_mode): continue self.path = p self.name = d return def get_compile_args(self): if self.found(): return ['-I' + os.path.join(self.path, self.name, 'Headers')] return [] def get_link_args(self): if self.found(): return ['-F' + self.path, '-framework', self.name.split('.')[0]] return [] def found(self): return self.name is not None def get_version(self): return 'unknown' class ThreadDependency(Dependency): def __init__(self, environment, kwargs): super().__init__('threads', {}) self.name = 'threads' self.is_found = True mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES')) def need_threads(self): return True def get_version(self): return 'unknown' class Python3Dependency(Dependency): def __init__(self, environment, kwargs): super().__init__('python3', kwargs) self.name = 'python3' self.is_found = False # We can only be sure that it is Python 3 at this point self.version = '3' if DependencyMethods.PKGCONFIG in self.methods: try: pkgdep = PkgConfigDependency('python3', environment, kwargs) if pkgdep.found(): self.cargs = pkgdep.cargs self.libs = pkgdep.libs self.version = pkgdep.get_version() self.is_found = True return except Exception: pass if not self.is_found: if mesonlib.is_windows() and DependencyMethods.SYSCONFIG in self.methods: self._find_libpy3_windows(environment) elif mesonlib.is_osx() and DependencyMethods.EXTRAFRAMEWORK in self.methods: # In OSX the Python 3 framework does not have a version # number in its name. fw = ExtraFrameworkDependency('python', False, None, kwargs) if fw.found(): self.cargs = fw.get_compile_args() self.libs = fw.get_link_args() self.is_found = True if self.is_found: mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES')) else: mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO')) def _find_libpy3_windows(self, env): ''' Find python3 libraries on Windows and also verify that the arch matches what we are building for. ''' pyarch = sysconfig.get_platform() arch = detect_cpu_family(env.coredata.compilers) if arch == 'x86': arch = '32' elif arch == 'x86_64': arch = '64' else: # We can't cross-compile Python 3 dependencies on Windows yet mlog.log('Unknown architecture {!r} for'.format(arch), mlog.bold(self.name)) self.is_found = False return # Pyarch ends in '32' or '64' if arch != pyarch[-2:]: mlog.log('Need', mlog.bold(self.name), 'for {}-bit, but found {}-bit'.format(arch, pyarch[-2:])) self.is_found = False return inc = sysconfig.get_path('include') platinc = sysconfig.get_path('platinclude') self.cargs = ['-I' + inc] if inc != platinc: self.cargs.append('-I' + platinc) # Nothing exposes this directly that I coulf find basedir = sysconfig.get_config_var('base') vernum = sysconfig.get_config_var('py_version_nodot') self.libs = ['-L{}/libs'.format(basedir), '-lpython{}'.format(vernum)] self.version = sysconfig.get_config_var('py_version_short') self.is_found = True def get_compile_args(self): return self.cargs def get_link_args(self): return self.libs def get_methods(self): if mesonlib.is_windows(): return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSCONFIG] elif mesonlib.is_osx(): return [DependencyMethods.PKGCONFIG, DependencyMethods.EXTRAFRAMEWORK] else: return [DependencyMethods.PKGCONFIG] 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', []) if isinstance(modlist, str): modlist = [modlist] for module in modlist: elements.append(module) # We use a tuple because we need a non-mutable structure to use as the key # of a dictionary and a string has potential for name collisions identifier = tuple(elements) identifier += ('main', kwargs.get('main', False)) identifier += ('static', kwargs.get('static', False)) if 'fallback' in kwargs: f = kwargs.get('fallback') identifier += ('fallback', f[0], f[1]) return identifier def find_external_dependency(name, environment, kwargs): required = kwargs.get('required', True) if not isinstance(required, bool): raise DependencyException('Keyword "required" must be a boolean.') if not isinstance(kwargs.get('method', ''), str): raise DependencyException('Keyword "method" must be a string.') lname = name.lower() if lname in packages: dep = packages[lname](environment, kwargs) if required and not dep.found(): raise DependencyException('Dependency "%s" not found' % name) return dep pkg_exc = None pkgdep = None try: pkgdep = PkgConfigDependency(name, environment, kwargs) if pkgdep.found(): return pkgdep except Exception as e: pkg_exc = e if mesonlib.is_osx(): fwdep = ExtraFrameworkDependency(name, required, None, kwargs) if required and not fwdep.found(): m = 'Dependency {!r} not found, tried Extra Frameworks ' \ 'and Pkg-Config:\n\n' + str(pkg_exc) raise DependencyException(m.format(name)) return fwdep if pkg_exc is not None: raise pkg_exc mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) return pkgdep # This has to be at the end so the classes it references # are defined. packages = {'boost': BoostDependency, 'gtest': GTestDependency, 'gmock': GMockDependency, 'qt5': Qt5Dependency, 'qt4': Qt4Dependency, 'gnustep': GnuStepDependency, 'appleframeworks': AppleFrameworks, 'wxwidgets': WxDependency, 'sdl2': SDL2Dependency, 'gl': GLDependency, 'threads': ThreadDependency, 'python3': Python3Dependency, 'valgrind': ValgrindDependency, } meson-0.40.1/mesonbuild/scripts/0000755000175000017500000000000013100703042020125 5ustar jpakkanejpakkane00000000000000meson-0.40.1/mesonbuild/scripts/meson_install.py0000644000175000017500000003043213076164167023375 0ustar jpakkanejpakkane00000000000000# Copyright 2013-2014 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys, pickle, os, shutil, subprocess, gzip, platform, errno from glob import glob from . import depfixer from . import destdir_join from ..mesonlib import is_windows, Popen_safe install_log_file = None def set_mode(path, mode): if mode is None: # Keep mode unchanged return if (mode.perms_s or mode.owner or mode.group) is None: # Nothing to set return # No chown() on Windows, and must set one of owner/group if not is_windows() and (mode.owner or mode.group) is not None: try: shutil.chown(path, mode.owner, mode.group) 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 if mode.perms_s is not None: try: os.chmod(path, mode.perms) except PermissionError as e: msg = '{!r}: Unable to set permissions {!r}: {}, ignoring...' print(msg.format(path, mode.perms_s, e.strerror)) def append_to_log(line): install_log_file.write(line) if not line.endswith('\n'): install_log_file.write('\n') install_log_file.flush() def do_copyfile(from_file, to_file): if not os.path.isfile(from_file): raise RuntimeError('Tried to install something that isn\'t a file:' '{!r}'.format(from_file)) # copyfile fails if the target file already exists, so remove it to # allow overwriting a previous install. If the target is not a file, we # want to give a readable error. if os.path.exists(to_file): if not os.path.isfile(to_file): raise RuntimeError('Destination {!r} already exists and is not ' 'a file'.format(to_file)) os.unlink(to_file) shutil.copyfile(from_file, to_file) shutil.copystat(from_file, to_file) append_to_log(to_file) def do_copydir(src_prefix, src_dir, dst_dir): ''' Copies the directory @src_prefix (full path) into @dst_dir @src_dir is simply the parent directory of @src_prefix ''' for root, dirs, files in os.walk(src_prefix): for d in dirs: abs_src = os.path.join(src_dir, root, d) filepart = abs_src[len(src_dir) + 1:] abs_dst = os.path.join(dst_dir, filepart) if os.path.isdir(abs_dst): continue if os.path.exists(abs_dst): print('Tried to copy directory %s but a file of that name already exists.' % abs_dst) sys.exit(1) os.makedirs(abs_dst) shutil.copystat(abs_src, abs_dst) for f in files: abs_src = os.path.join(src_dir, root, f) filepart = abs_src[len(src_dir) + 1:] abs_dst = os.path.join(dst_dir, filepart) if os.path.isdir(abs_dst): print('Tried to copy file %s but a directory of that name already exists.' % abs_dst) if os.path.exists(abs_dst): os.unlink(abs_dst) parent_dir = os.path.split(abs_dst)[0] if not os.path.isdir(parent_dir): os.mkdir(parent_dir) shutil.copystat(os.path.split(abs_src)[0], parent_dir) shutil.copy2(abs_src, abs_dst, follow_symlinks=False) append_to_log(abs_dst) def get_destdir_path(d, path): if os.path.isabs(path): output = destdir_join(d.destdir, path) else: output = os.path.join(d.fullprefix, path) return output def do_install(datafilename): with open(datafilename, 'rb') as ifile: d = pickle.load(ifile) d.destdir = os.environ.get('DESTDIR', '') d.fullprefix = destdir_join(d.destdir, d.prefix) install_subdirs(d) # Must be first, because it needs to delete the old subtree. install_targets(d) install_headers(d) install_man(d) install_data(d) run_install_script(d) def install_subdirs(data): for (src_dir, inst_dir, dst_dir, mode) in data.install_subdirs: if src_dir.endswith('/') or src_dir.endswith('\\'): src_dir = src_dir[:-1] src_prefix = os.path.join(src_dir, inst_dir) print('Installing subdir %s to %s' % (src_prefix, dst_dir)) dst_dir = get_destdir_path(data, dst_dir) if not os.path.exists(dst_dir): os.makedirs(dst_dir) do_copydir(src_prefix, src_dir, dst_dir) dst_prefix = os.path.join(dst_dir, inst_dir) set_mode(dst_prefix, mode) def install_data(d): for i in d.data: fullfilename = i[0] outfilename = get_destdir_path(d, i[1]) mode = i[2] outdir = os.path.split(outfilename)[0] os.makedirs(outdir, exist_ok=True) print('Installing %s to %s' % (fullfilename, outdir)) do_copyfile(fullfilename, outfilename) set_mode(outfilename, mode) def install_man(d): for m in d.man: full_source_filename = m[0] outfilename = get_destdir_path(d, m[1]) outdir = os.path.split(outfilename)[0] os.makedirs(outdir, exist_ok=True) print('Installing %s to %s' % (full_source_filename, outdir)) if outfilename.endswith('.gz') and not full_source_filename.endswith('.gz'): with open(outfilename, 'wb') as of: with open(full_source_filename, 'rb') as sf: of.write(gzip.compress(sf.read())) shutil.copystat(full_source_filename, outfilename) append_to_log(outfilename) else: do_copyfile(full_source_filename, outfilename) def install_headers(d): for t in d.headers: fullfilename = t[0] fname = os.path.split(fullfilename)[1] outdir = get_destdir_path(d, t[1]) outfilename = os.path.join(outdir, fname) print('Installing %s to %s' % (fname, outdir)) os.makedirs(outdir, exist_ok=True) do_copyfile(fullfilename, outfilename) def run_install_script(d): env = {'MESON_SOURCE_ROOT': d.source_dir, '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) for i in d.install_scripts: script = i['exe'] args = i['args'] name = ' '.join(script + args) print('Running custom install script {!r}'.format(name)) try: rc = subprocess.call(script + args, env=child_env) if rc != 0: sys.exit(rc) except: print('Failed to run install script {!r}'.format(name)) sys.exit(1) def is_elf_platform(): platname = platform.system().lower() if platname == 'darwin' or platname == 'windows' or platname == 'cygwin': return False return True def check_for_stampfile(fname): '''Some languages e.g. Rust have output files whose names are not known at configure time. Check if this is the case and return the real file instead.''' if fname.endswith('.so') or fname.endswith('.dll'): if os.stat(fname).st_size == 0: (base, suffix) = os.path.splitext(fname) files = glob(base + '-*' + suffix) if len(files) > 1: print("Stale dynamic library files in build dir. Can't install.") sys.exit(1) if len(files) == 1: return files[0] elif fname.endswith('.a') or fname.endswith('.lib'): if os.stat(fname).st_size == 0: (base, suffix) = os.path.splitext(fname) files = glob(base + '-*' + '.rlib') if len(files) > 1: print("Stale static library files in build dir. Can't install.") sys.exit(1) if len(files) == 1: return files[0] return fname def install_targets(d): for t in d.targets: fname = check_for_stampfile(t[0]) outdir = get_destdir_path(d, t[1]) outname = os.path.join(outdir, os.path.split(fname)[-1]) aliases = t[2] should_strip = t[3] install_rpath = t[4] print('Installing %s to %s' % (fname, outname)) os.makedirs(outdir, exist_ok=True) if not os.path.exists(fname): raise RuntimeError('File {!r} could not be found'.format(fname)) elif os.path.isfile(fname): do_copyfile(fname, outname) if should_strip and d.strip_bin is not None: if fname.endswith('.jar'): print('Not stripping jar target:', os.path.split(fname)[1]) continue print('Stripping target {!r}'.format(fname)) ps, stdo, stde = Popen_safe(d.strip_bin + [outname]) if ps.returncode != 0: print('Could not strip file.\n') print('Stdout:\n%s\n' % stdo) print('Stderr:\n%s\n' % stde) sys.exit(1) pdb_filename = os.path.splitext(fname)[0] + '.pdb' if not should_strip and os.path.exists(pdb_filename): pdb_outname = os.path.splitext(outname)[0] + '.pdb' print('Installing pdb file %s to %s' % (pdb_filename, pdb_outname)) do_copyfile(pdb_filename, pdb_outname) elif os.path.isdir(fname): fname = os.path.join(d.build_dir, fname.rstrip('/')) do_copydir(fname, os.path.dirname(fname), outdir) else: raise RuntimeError('Unknown file type for {!r}'.format(fname)) printed_symlink_error = False for alias, to in aliases.items(): try: symlinkfilename = os.path.join(outdir, alias) try: os.unlink(symlinkfilename) except FileNotFoundError: pass os.symlink(to, symlinkfilename) append_to_log(symlinkfilename) except (NotImplementedError, OSError): if not printed_symlink_error: print("Symlink creation does not work on this platform. " "Skipping all symlinking.") printed_symlink_error = True if is_elf_platform() and os.path.isfile(outname): try: e = depfixer.Elf(outname, False) e.fix_rpath(install_rpath) except SystemExit as e: if isinstance(e.code, int) and e.code == 0: pass else: raise def run(args): global install_log_file if len(args) != 1: print('Installer script for Meson. Do not run on your own, mmm\'kay?') print('meson_install.py [install info file]') datafilename = args[0] private_dir = os.path.split(datafilename)[0] log_dir = os.path.join(private_dir, '../meson-logs') with open(os.path.join(log_dir, 'install-log.txt'), 'w') as lf: install_log_file = lf append_to_log('# List of files installed by Meson') append_to_log('# Does not contain files installed by custom scripts.') do_install(datafilename) install_log_file = None return 0 if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/scripts/gtkdochelper.py0000644000175000017500000002060213074426732023174 0ustar jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys, os import subprocess import shutil import argparse from ..mesonlib import MesonException, Popen_safe from . import destdir_join parser = argparse.ArgumentParser() parser.add_argument('--sourcedir', dest='sourcedir') parser.add_argument('--builddir', dest='builddir') parser.add_argument('--subdir', dest='subdir') parser.add_argument('--headerdirs', dest='headerdirs') parser.add_argument('--mainfile', dest='mainfile') parser.add_argument('--modulename', dest='modulename') parser.add_argument('--htmlargs', dest='htmlargs', default='') parser.add_argument('--scanargs', dest='scanargs', default='') parser.add_argument('--scanobjsargs', dest='scanobjsargs', default='') parser.add_argument('--gobjects-types-file', dest='gobject_typesfile', default='') parser.add_argument('--fixxrefargs', dest='fixxrefargs', default='') parser.add_argument('--ld', dest='ld', default='') parser.add_argument('--cc', dest='cc', default='') parser.add_argument('--ldflags', dest='ldflags', default='') parser.add_argument('--cflags', dest='cflags', default='') parser.add_argument('--content-files', dest='content_files', default='') parser.add_argument('--expand-content-files', dest='expand_content_files', default='') parser.add_argument('--html-assets', dest='html_assets', default='') parser.add_argument('--ignore-headers', dest='ignore_headers', default='') parser.add_argument('--namespace', dest='namespace', default='') parser.add_argument('--mode', dest='mode', default='') parser.add_argument('--installdir', dest='install_dir') def gtkdoc_run_check(cmd, cwd): # Put stderr into stdout since we want to print it out anyway. # This preserves the order of messages. p, out = Popen_safe(cmd, cwd=cwd, stderr=subprocess.STDOUT)[0:2] if p.returncode != 0: err_msg = ["{!r} failed with status {:d}".format(cmd[0], p.returncode)] if out: err_msg.append(out) raise MesonException('\n'.join(err_msg)) def build_gtkdoc(source_root, build_root, doc_subdir, src_subdirs, main_file, module, html_args, scan_args, fixxref_args, gobject_typesfile, scanobjs_args, ld, cc, ldflags, cflags, html_assets, content_files, ignore_headers, namespace, expand_content_files, mode): print("Building documentation for %s" % module) src_dir_args = [] for src_dir in src_subdirs: if not os.path.isabs(src_dir): dirs = [os.path.join(source_root, src_dir), os.path.join(build_root, src_dir)] else: dirs = [src_dir] src_dir_args += ['--source-dir=' + d for d in dirs] doc_src = os.path.join(source_root, doc_subdir) abs_out = os.path.join(build_root, doc_subdir) htmldir = os.path.join(abs_out, 'html') content_files += [main_file] sections = os.path.join(doc_src, module + "-sections.txt") if os.path.exists(sections): content_files.append(sections) overrides = os.path.join(doc_src, module + "-overrides.txt") if os.path.exists(overrides): content_files.append(overrides) # Copy files to build directory for f in content_files: f_abs = os.path.join(doc_src, f) shutil.copyfile(f_abs, os.path.join( abs_out, os.path.basename(f_abs))) shutil.rmtree(htmldir, ignore_errors=True) try: os.mkdir(htmldir) except Exception: pass for f in html_assets: f_abs = os.path.join(doc_src, f) shutil.copyfile(f_abs, os.path.join(htmldir, os.path.basename(f_abs))) scan_cmd = ['gtkdoc-scan', '--module=' + module] + src_dir_args if ignore_headers: scan_cmd.append('--ignore-headers=' + ' '.join(ignore_headers)) # Add user-specified arguments scan_cmd += scan_args gtkdoc_run_check(scan_cmd, abs_out) if gobject_typesfile: scanobjs_cmd = ['gtkdoc-scangobj'] + scanobjs_args + ['--types=' + gobject_typesfile, '--module=' + module, '--cflags=' + cflags, '--ldflags=' + ldflags] gtkdoc_run_check(scanobjs_cmd, abs_out) # Make docbook files if mode == 'auto': # Guessing is probably a poor idea but these keeps compat # with previous behavior if main_file.endswith('sgml'): modeflag = '--sgml-mode' else: modeflag = '--xml-mode' elif mode == 'xml': modeflag = '--xml-mode' elif mode == 'sgml': modeflag = '--sgml-mode' else: # none modeflag = None mkdb_cmd = ['gtkdoc-mkdb', '--module=' + module, '--output-format=xml', '--expand-content-files=' + ' '.join(expand_content_files), ] + src_dir_args if namespace: mkdb_cmd.append('--name-space=' + namespace) if modeflag: mkdb_cmd.append(modeflag) if len(main_file) > 0: # Yes, this is the flag even if the file is in xml. mkdb_cmd.append('--main-sgml-file=' + main_file) gtkdoc_run_check(mkdb_cmd, abs_out) # Make HTML documentation mkhtml_cmd = ['gtkdoc-mkhtml', '--path=' + ':'.join((doc_src, abs_out)), module, ] + html_args if len(main_file) > 0: mkhtml_cmd.append('../' + main_file) else: mkhtml_cmd.append('%s-docs.xml' % module) # html gen must be run in the HTML dir gtkdoc_run_check(mkhtml_cmd, os.path.join(abs_out, 'html')) # Fix cross-references in HTML files fixref_cmd = ['gtkdoc-fixxref', '--module=' + module, '--module-dir=html'] + fixxref_args gtkdoc_run_check(fixref_cmd, abs_out) def install_gtkdoc(build_root, doc_subdir, install_prefix, datadir, module): source = os.path.join(build_root, doc_subdir, 'html') final_destination = os.path.join(install_prefix, datadir, module) shutil.rmtree(final_destination, ignore_errors=True) shutil.copytree(source, final_destination) def run(args): options = parser.parse_args(args) if len(options.htmlargs) > 0: htmlargs = options.htmlargs.split('@@') else: htmlargs = [] if len(options.scanargs) > 0: scanargs = options.scanargs.split('@@') else: scanargs = [] if len(options.scanobjsargs) > 0: scanobjsargs = options.scanobjsargs.split('@@') else: scanobjsargs = [] if len(options.fixxrefargs) > 0: fixxrefargs = options.fixxrefargs.split('@@') else: fixxrefargs = [] build_gtkdoc( options.sourcedir, options.builddir, options.subdir, options.headerdirs.split('@@'), options.mainfile, options.modulename, htmlargs, scanargs, fixxrefargs, options.gobject_typesfile, scanobjsargs, options.ld, options.cc, options.ldflags, options.cflags, options.html_assets.split('@@') if options.html_assets else [], options.content_files.split('@@') if options.content_files else [], options.ignore_headers.split('@@') if options.ignore_headers else [], options.namespace, options.expand_content_files.split('@@') if options.expand_content_files else [], options.mode) if 'MESON_INSTALL_PREFIX' in os.environ: install_dir = options.install_dir if options.install_dir else options.modulename destdir = os.environ.get('DESTDIR', '') installdir = destdir_join(destdir, os.environ['MESON_INSTALL_PREFIX']) install_gtkdoc(options.builddir, options.subdir, installdir, 'share/gtk-doc/html', install_dir) return 0 if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/scripts/symbolextractor.py0000644000175000017500000001010613032764405023754 0ustar jpakkanejpakkane00000000000000# Copyright 2013-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This script extracts the symbols of a given shared library # into a file. If the symbols have not changed, the file is not # touched. This information is used to skip link steps if the # ABI has not changed. # This file is basically a reimplementation of # http://cgit.freedesktop.org/libreoffice/core/commit/?id=3213cd54b76bc80a6f0516aac75a48ff3b2ad67c import os, sys from .. import mesonlib from ..mesonlib import Popen_safe import argparse parser = argparse.ArgumentParser() parser.add_argument('--cross-host', default=None, dest='cross_host', help='cross compilation host platform') parser.add_argument('args', nargs='+') def dummy_syms(outfilename): """Just touch it so relinking happens always.""" with open(outfilename, 'w'): pass def write_if_changed(text, outfilename): try: with open(outfilename, 'r') as f: oldtext = f.read() if text == oldtext: return except FileNotFoundError: pass with open(outfilename, 'w') as f: f.write(text) def linux_syms(libfilename, outfilename): evar = 'READELF' if evar in os.environ: readelfbin = os.environ[evar].strip() else: readelfbin = 'readelf' evar = 'NM' if evar in os.environ: nmbin = os.environ[evar].strip() else: nmbin = 'nm' pe, output = Popen_safe([readelfbin, '-d', libfilename])[0:2] if pe.returncode != 0: raise RuntimeError('Readelf does not work') result = [x for x in output.split('\n') if 'SONAME' in x] assert(len(result) <= 1) pnm, output = Popen_safe([nmbin, '--dynamic', '--extern-only', '--defined-only', '--format=posix', libfilename])[0:2] if pnm.returncode != 0: raise RuntimeError('nm does not work.') result += [' '.join(x.split()[0:2]) for x in output.split('\n') if len(x) > 0] write_if_changed('\n'.join(result) + '\n', outfilename) def osx_syms(libfilename, outfilename): pe, output = Popen_safe(['otool', '-l', libfilename])[0:2] if pe.returncode != 0: raise RuntimeError('Otool does not work.') arr = output.split('\n') for (i, val) in enumerate(arr): if 'LC_ID_DYLIB' in val: match = i break result = [arr[match + 2], arr[match + 5]] # Libreoffice stores all 5 lines but the others seem irrelevant. pnm, output = Popen_safe(['nm', '-g', '-P', libfilename])[0:2] if pnm.returncode != 0: raise RuntimeError('nm does not work.') result += [' '.join(x.split()[0:2]) for x in output.split('\n') if len(x) > 0 and not x.endswith('U')] write_if_changed('\n'.join(result) + '\n', outfilename) def gen_symbols(libfilename, outfilename, cross_host): if cross_host is not None: # In case of cross builds just always relink. # In theory we could determine the correct # toolset but there are more important things # to do. dummy_syms(outfilename) elif mesonlib.is_linux(): linux_syms(libfilename, outfilename) elif mesonlib.is_osx(): osx_syms(libfilename, outfilename) else: dummy_syms(outfilename) def run(args): options = parser.parse_args(args) if len(options.args) != 2: print('symbolextractor.py ') sys.exit(1) libfile = options.args[0] outfile = options.args[1] gen_symbols(libfile, outfile, options.cross_host) return 0 if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/scripts/commandrunner.py0000644000175000017500000000414013074426732023370 0ustar jpakkanejpakkane00000000000000# Copyright 2014 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """This program is a wrapper to run external commands. It determines what to run, sets up the environment and executes the command.""" import sys, os, subprocess, shutil 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) # Is the command an executable in path? exe = shutil.which(command) if exe is not None: command_array = [exe] + arguments return subprocess.Popen(command_array, env=child_env, cwd=cwd) # No? Maybe it is a script in the source tree. fullpath = os.path.join(source_dir, subdir, command) command_array = [fullpath] + arguments try: return subprocess.Popen(command_array, env=child_env, cwd=cwd) except FileNotFoundError: print('Could not execute command "%s".' % command) sys.exit(1) def run(args): if len(args) < 4: print('commandrunner.py [arguments]') return 1 src_dir = args[0] build_dir = args[1] subdir = args[2] 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 if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/scripts/uninstall.py0000644000175000017500000000267113032214452022524 0ustar jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os logfile = 'meson-logs/install-log.txt' def do_uninstall(log): failures = 0 successes = 0 for line in open(log): if line.startswith('#'): continue fname = line.strip() try: os.unlink(fname) print('Deleted:', fname) successes += 1 except Exception as e: print('Could not delete %s: %s.' % (fname, e)) failures += 1 print('\nUninstall finished.\n') print('Deleted:', successes) print('Failed:', failures) print('\nRemember that files created by custom scripts have not been removed.') def run(args): if len(args) != 0: print('Weird error.') return 1 if not os.path.exists(logfile): print('Log file does not exist, no installation has been done.') return 0 do_uninstall(logfile) return 0 meson-0.40.1/mesonbuild/scripts/gettext.py0000644000175000017500000001066713076164167022222 0ustar jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import shutil import argparse import subprocess from . import destdir_join parser = argparse.ArgumentParser() parser.add_argument('command') parser.add_argument('--pkgname', default='') parser.add_argument('--datadirs', default='') parser.add_argument('--langs', default='') parser.add_argument('--localedir', default='') parser.add_argument('--subdir', default='') parser.add_argument('--extra-args', default='') def read_linguas(src_sub): # Syntax of this file is documented here: # https://www.gnu.org/software/gettext/manual/html_node/po_002fLINGUAS.html linguas = os.path.join(src_sub, 'LINGUAS') try: langs = [] with open(linguas) as f: for line in f: line = line.strip() if line and not line.startswith('#'): langs += line.split() return langs except (FileNotFoundError, PermissionError): print('Could not find file LINGUAS in {}'.format(src_sub)) return [] def run_potgen(src_sub, pkgname, datadirs, args): listfile = os.path.join(src_sub, 'POTFILES') if not os.path.exists(listfile): listfile = os.path.join(src_sub, 'POTFILES.in') if not os.path.exists(listfile): print('Could not find file POTFILES in %s' % src_sub) return 1 child_env = os.environ.copy() if datadirs: child_env['GETTEXTDATADIRS'] = datadirs ofile = os.path.join(src_sub, pkgname + '.pot') return subprocess.call(['xgettext', '--package-name=' + pkgname, '-p', src_sub, '-f', listfile, '-D', os.environ['MESON_SOURCE_ROOT'], '-k_', '-o', ofile] + args, env=child_env) def gen_gmo(src_sub, bld_sub, langs): for l in langs: subprocess.check_call(['msgfmt', os.path.join(src_sub, l + '.po'), '-o', os.path.join(bld_sub, l + '.gmo')]) return 0 def update_po(src_sub, pkgname, langs): potfile = os.path.join(src_sub, pkgname + '.pot') for l in langs: pofile = os.path.join(src_sub, l + '.po') subprocess.check_call(['msgmerge', '-q', '-o', pofile, pofile, potfile]) return 0 def do_install(src_sub, bld_sub, dest, pkgname, langs): for l in langs: srcfile = os.path.join(bld_sub, l + '.gmo') outfile = os.path.join(dest, l, 'LC_MESSAGES', pkgname + '.mo') os.makedirs(os.path.split(outfile)[0], exist_ok=True) shutil.copyfile(srcfile, outfile) shutil.copystat(srcfile, outfile) print('Installing %s to %s' % (srcfile, outfile)) return 0 def run(args): options = parser.parse_args(args) subcmd = options.command langs = options.langs.split('@@') if options.langs else None extra_args = options.extra_args.split('@@') subdir = os.environ.get('MESON_SUBDIR', '') if options.subdir: subdir = options.subdir src_sub = os.path.join(os.environ['MESON_SOURCE_ROOT'], subdir) bld_sub = os.path.join(os.environ['MESON_BUILD_ROOT'], subdir) if not langs: langs = read_linguas(src_sub) if subcmd == 'pot': return run_potgen(src_sub, options.pkgname, options.datadirs, extra_args) elif subcmd == 'gen_gmo': return gen_gmo(src_sub, bld_sub, langs) elif subcmd == 'update_po': if run_potgen(src_sub, options.pkgname, options.datadirs, extra_args) != 0: return 1 return update_po(src_sub, options.pkgname, langs) elif subcmd == 'install': destdir = os.environ.get('DESTDIR', '') dest = destdir_join(destdir, os.path.join(os.environ['MESON_INSTALL_PREFIX'], options.localedir)) if gen_gmo(src_sub, bld_sub, langs) != 0: return 1 do_install(src_sub, bld_sub, dest, options.pkgname, langs) else: print('Unknown subcommand.') return 1 meson-0.40.1/mesonbuild/scripts/dirchanger.py0000644000175000017500000000160713025554726022634 0ustar jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. '''CD into dir given as first argument and execute the command given in the rest of the arguments.''' import os, subprocess, sys def run(args): dirname = args[0] command = args[1:] os.chdir(dirname) return subprocess.call(command) if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/scripts/cleantrees.py0000644000175000017500000000261013026303756022642 0ustar jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys import shutil import pickle def rmtrees(build_dir, trees): for t in trees: # Never delete trees outside of the builddir if os.path.isabs(t): print('Cannot delete dir with absolute path {!r}'.format(t)) continue bt = os.path.join(build_dir, t) # Skip if it doesn't exist, or if it is not a directory if os.path.isdir(bt): shutil.rmtree(bt, ignore_errors=True) def run(args): if len(args) != 1: print('Cleaner script for Meson. Do not run on your own please.') print('cleantrees.py ') return 1 with open(args[0], 'rb') as f: data = pickle.load(f) rmtrees(data.build_dir, data.trees) # Never fail cleaning return 0 if __name__ == '__main__': run(sys.argv[1:]) meson-0.40.1/mesonbuild/scripts/scanbuild.py0000644000175000017500000000277213032214452022461 0ustar jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import subprocess import shutil import tempfile from ..environment import detect_ninja def scanbuild(exename, srcdir, blddir, privdir, logdir, args): with tempfile.TemporaryDirectory(dir=privdir) as scandir: meson_cmd = [exename] + args build_cmd = [exename, '-o', logdir, detect_ninja(), '-C', scandir] rc = subprocess.call(meson_cmd + [srcdir, scandir]) if rc != 0: return rc return subprocess.call(build_cmd) def run(args): srcdir = args[0] blddir = args[1] meson_cmd = args[2:] privdir = os.path.join(blddir, 'meson-private') logdir = os.path.join(blddir, 'meson-logs/scanbuild') shutil.rmtree(logdir, ignore_errors=True) exename = os.environ.get('SCANBUILD', 'scan-build') if not shutil.which(exename): print('Scan-build not installed.') return 1 return scanbuild(exename, srcdir, blddir, privdir, logdir, meson_cmd) meson-0.40.1/mesonbuild/scripts/vcstagger.py0000644000175000017500000000301013025554726022501 0ustar jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys, os, subprocess, re def config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_selector, cmd): try: output = subprocess.check_output(cmd, cwd=source_dir) new_string = re.search(regex_selector, output.decode()).group(1).strip() except Exception: new_string = fallback with open(infile) as f: new_data = f.read().replace(replace_string, new_string) if os.path.exists(outfile): with open(outfile) as f: needs_update = (f.read() != new_data) else: needs_update = True if needs_update: with open(outfile, 'w') as f: f.write(new_data) def run(args): infile, outfile, fallback, source_dir, replace_string, regex_selector = args[0:6] command = args[6:] config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_selector, command) if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/scripts/delwithsuffix.py0000644000175000017500000000212213025554726023404 0ustar jpakkanejpakkane00000000000000# Copyright 2013 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os, sys def run(args): if len(sys.argv) != 3: print('delwithsuffix.py ') sys.exit(1) topdir = sys.argv[1] suffix = sys.argv[2] if suffix[0] != '.': suffix = '.' + suffix for (root, _, files) in os.walk(topdir): for f in files: if f.endswith(suffix): fullname = os.path.join(root, f) os.unlink(fullname) return 0 if __name__ == '__main__': run(sys.argv[1:]) meson-0.40.1/mesonbuild/scripts/regen_checker.py0000644000175000017500000000433113031276647023307 0ustar jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys, os import pickle, subprocess # This could also be used for XCode. def need_regen(regeninfo, regen_timestamp): for i in regeninfo.depfiles: curfile = os.path.join(regeninfo.build_dir, i) curtime = os.stat(curfile).st_mtime if curtime > regen_timestamp: return True # The timestamp file gets automatically deleted by MSBuild during a 'Clean' build. # We must make sure to recreate it, even if we do not regenerate the solution. # Otherwise, Visual Studio will always consider the REGEN project out of date. print("Everything is up-to-date, regeneration of build files is not needed.") from ..backend.vs2010backend import Vs2010Backend Vs2010Backend.touch_regen_timestamp(regeninfo.build_dir) return False def regen(regeninfo, mesonscript, backend): cmd = [sys.executable, mesonscript, '--internal', 'regenerate', regeninfo.build_dir, regeninfo.source_dir, '--backend=' + backend] subprocess.check_call(cmd) def run(args): private_dir = args[0] dumpfile = os.path.join(private_dir, 'regeninfo.dump') coredata = os.path.join(private_dir, 'coredata.dat') with open(dumpfile, 'rb') as f: regeninfo = pickle.load(f) with open(coredata, 'rb') as f: coredata = pickle.load(f) mesonscript = coredata.meson_script_launcher backend = coredata.get_builtin_option('backend') regen_timestamp = os.stat(dumpfile).st_mtime if need_regen(regeninfo, regen_timestamp): regen(regeninfo, mesonscript, backend) sys.exit(0) if __name__ == '__main__': run(sys.argv[1:]) meson-0.40.1/mesonbuild/scripts/meson_exe.py0000644000175000017500000000471513074426732022512 0ustar jpakkanejpakkane00000000000000# Copyright 2013-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys import argparse import pickle import platform from ..mesonlib import Popen_safe options = None parser = argparse.ArgumentParser() parser.add_argument('args', nargs='+') 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() or is_cygwin()): return True return False def run_exe(exe): if exe.fname[0].endswith('.jar'): cmd = ['java', '-jar'] + exe.fname elif not exe.is_cross and run_with_mono(exe.fname[0]): cmd = ['mono'] + exe.fname else: if exe.is_cross: if exe.exe_runner is None: raise AssertionError('BUG: Trying to run cross-compiled exes with no wrapper') else: cmd = [exe.exe_runner] + exe.fname else: cmd = exe.fname child_env = os.environ.copy() child_env.update(exe.env) if len(exe.extra_paths) > 0: child_env['PATH'] = (os.pathsep.join(exe.extra_paths + ['']) + child_env['PATH']) p, stdout, stderr = Popen_safe(cmd + exe.cmd_args, env=child_env, cwd=exe.workdir) if exe.capture and p.returncode == 0: with open(exe.capture, 'w') as output: output.write(stdout) if stderr: sys.stderr.write(stderr) return p.returncode def run(args): global options options = parser.parse_args(args) if len(options.args) != 1: print('Test runner for Meson. Do not run on your own, mmm\'kay?') print(sys.argv[0] + ' [data file]') exe_data_file = options.args[0] with open(exe_data_file, 'rb') as f: exe = pickle.load(f) return run_exe(exe) if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/scripts/depfixer.py0000644000175000017500000003072513076164167022341 0ustar jpakkanejpakkane00000000000000# Copyright 2013-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys, struct SHT_STRTAB = 3 DT_NEEDED = 1 DT_RPATH = 15 DT_RUNPATH = 29 DT_STRTAB = 5 DT_SONAME = 14 DT_MIPS_RLD_MAP_REL = 1879048245 class DataSizes: def __init__(self, ptrsize, is_le): if is_le: p = '<' else: p = '>' self.Half = p + 'h' self.HalfSize = 2 self.Word = p + 'I' self.WordSize = 4 self.Sword = p + 'i' self.SwordSize = 4 if ptrsize == 64: self.Addr = p + 'Q' self.AddrSize = 8 self.Off = p + 'Q' self.OffSize = 8 self.XWord = p + 'Q' self.XWordSize = 8 self.Sxword = p + 'q' self.SxwordSize = 8 else: self.Addr = p + 'I' self.AddrSize = 4 self.Off = p + 'I' self.OffSize = 4 class DynamicEntry(DataSizes): def __init__(self, ifile, ptrsize, is_le): super().__init__(ptrsize, is_le) self.ptrsize = ptrsize if ptrsize == 64: self.d_tag = struct.unpack(self.Sxword, ifile.read(self.SxwordSize))[0] self.val = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0] else: self.d_tag = struct.unpack(self.Sword, ifile.read(self.SwordSize))[0] self.val = struct.unpack(self.Word, ifile.read(self.WordSize))[0] def write(self, ofile): if self.ptrsize == 64: ofile.write(struct.pack(self.Sxword, self.d_tag)) ofile.write(struct.pack(self.XWord, self.val)) else: ofile.write(struct.pack(self.Sword, self.d_tag)) ofile.write(struct.pack(self.Word, self.val)) class SectionHeader(DataSizes): def __init__(self, ifile, ptrsize, is_le): super().__init__(ptrsize, is_le) if ptrsize == 64: is_64 = True else: is_64 = False # Elf64_Word self.sh_name = struct.unpack(self.Word, ifile.read(self.WordSize))[0] # Elf64_Word self.sh_type = struct.unpack(self.Word, ifile.read(self.WordSize))[0] # Elf64_Xword if is_64: self.sh_flags = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0] else: self.sh_flags = struct.unpack(self.Word, ifile.read(self.WordSize))[0] # Elf64_Addr self.sh_addr = struct.unpack(self.Addr, ifile.read(self.AddrSize))[0] # Elf64_Off self.sh_offset = struct.unpack(self.Off, ifile.read(self.OffSize))[0] # Elf64_Xword if is_64: self.sh_size = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0] else: self.sh_size = struct.unpack(self.Word, ifile.read(self.WordSize))[0] # Elf64_Word self.sh_link = struct.unpack(self.Word, ifile.read(self.WordSize))[0] # Elf64_Word self.sh_info = struct.unpack(self.Word, ifile.read(self.WordSize))[0] # Elf64_Xword if is_64: self.sh_addralign = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0] else: self.sh_addralign = struct.unpack(self.Word, ifile.read(self.WordSize))[0] #Elf64_Xword if is_64: self.sh_entsize = struct.unpack(self.XWord, ifile.read(self.XWordSize))[0] else: self.sh_entsize = struct.unpack(self.Word, ifile.read(self.WordSize))[0] class Elf(DataSizes): def __init__(self, bfile, verbose=True): self.bfile = bfile self.verbose = verbose self.bf = open(bfile, 'r+b') try: (self.ptrsize, self.is_le) = self.detect_elf_type() super().__init__(self.ptrsize, self.is_le) self.parse_header() self.parse_sections() self.parse_dynamic() except: self.bf.close() raise def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.bf.close() def detect_elf_type(self): data = self.bf.read(6) if data[1:4] != b'ELF': # This script gets called to non-elf targets too # so just ignore them. if self.verbose: print('File "%s" is not an ELF file.' % self.bfile) sys.exit(0) if data[4] == 1: ptrsize = 32 elif data[4] == 2: ptrsize = 64 else: sys.exit('File "%s" has unknown ELF class.' % self.bfile) if data[5] == 1: is_le = True elif data[5] == 2: is_le = False else: sys.exit('File "%s" has unknown ELF endianness.' % self.bfile) return ptrsize, is_le def parse_header(self): self.bf.seek(0) self.e_ident = struct.unpack('16s', self.bf.read(16))[0] self.e_type = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] self.e_machine = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] self.e_version = struct.unpack(self.Word, self.bf.read(self.WordSize))[0] self.e_entry = struct.unpack(self.Addr, self.bf.read(self.AddrSize))[0] self.e_phoff = struct.unpack(self.Off, self.bf.read(self.OffSize))[0] self.e_shoff = struct.unpack(self.Off, self.bf.read(self.OffSize))[0] self.e_flags = struct.unpack(self.Word, self.bf.read(self.WordSize))[0] self.e_ehsize = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] self.e_phentsize = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] self.e_phnum = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] self.e_shentsize = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] self.e_shnum = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] self.e_shstrndx = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] def parse_sections(self): self.bf.seek(self.e_shoff) self.sections = [] for i in range(self.e_shnum): self.sections.append(SectionHeader(self.bf, self.ptrsize, self.is_le)) def read_str(self): arr = [] x = self.bf.read(1) while x != b'\0': arr.append(x) x = self.bf.read(1) if x == b'': raise RuntimeError('Tried to read past the end of the file') return b''.join(arr) def find_section(self, target_name): section_names = self.sections[self.e_shstrndx] for i in self.sections: self.bf.seek(section_names.sh_offset + i.sh_name) name = self.read_str() if name == target_name: return i def parse_dynamic(self): sec = self.find_section(b'.dynamic') self.dynamic = [] if sec is None: return self.bf.seek(sec.sh_offset) while True: e = DynamicEntry(self.bf, self.ptrsize, self.is_le) self.dynamic.append(e) if e.d_tag == 0: break def print_section_names(self): section_names = self.sections[self.e_shstrndx] for i in self.sections: self.bf.seek(section_names.sh_offset + i.sh_name) name = self.read_str() print(name.decode()) def print_soname(self): soname = None strtab = None for i in self.dynamic: if i.d_tag == DT_SONAME: soname = i if i.d_tag == DT_STRTAB: strtab = i if soname is None or strtab is None: print("This file does not have a soname") return self.bf.seek(strtab.val + soname.val) print(self.read_str()) def get_entry_offset(self, entrynum): sec = self.find_section(b'.dynstr') for i in self.dynamic: if i.d_tag == entrynum: return sec.sh_offset + i.val return None def print_rpath(self): offset = self.get_entry_offset(DT_RPATH) if offset is None: print("This file does not have an rpath.") else: self.bf.seek(offset) print(self.read_str()) def print_runpath(self): offset = self.get_entry_offset(DT_RUNPATH) if offset is None: print("This file does not have a runpath.") else: self.bf.seek(offset) print(self.read_str()) def print_deps(self): sec = self.find_section(b'.dynstr') deps = [] for i in self.dynamic: if i.d_tag == DT_NEEDED: deps.append(i) for i in deps: offset = sec.sh_offset + i.val self.bf.seek(offset) name = self.read_str() print(name) def fix_deps(self, prefix): sec = self.find_section(b'.dynstr') deps = [] for i in self.dynamic: if i.d_tag == DT_NEEDED: deps.append(i) for i in deps: offset = sec.sh_offset + i.val self.bf.seek(offset) name = self.read_str() if name.startswith(prefix): basename = name.split(b'/')[-1] padding = b'\0' * (len(name) - len(basename)) newname = basename + padding assert(len(newname) == len(name)) self.bf.seek(offset) self.bf.write(newname) def fix_rpath(self, new_rpath): # The path to search for can be either rpath or runpath. # Fix both of them to be sure. self.fix_rpathtype_entry(new_rpath, DT_RPATH) self.fix_rpathtype_entry(new_rpath, DT_RUNPATH) def fix_rpathtype_entry(self, new_rpath, entrynum): if isinstance(new_rpath, str): new_rpath = new_rpath.encode('utf8') rp_off = self.get_entry_offset(entrynum) if rp_off is None: if self.verbose: print('File does not have rpath. It should be a fully static executable.') return self.bf.seek(rp_off) old_rpath = self.read_str() if len(old_rpath) < len(new_rpath): sys.exit("New rpath must not be longer than the old one.") # The linker does read-only string deduplication. If there is a # string that shares a suffix with the rpath, they might get # dedupped. This means changing the rpath string might break something # completely unrelated. This has already happened once with X.org. # Thus we want to keep this change as small as possible to minimize # the chance of obliterating other strings. It might still happen # but our behaviour is identical to what chrpath does and it has # been in use for ages so based on that this should be rare. if len(new_rpath) == 0: self.remove_rpath_entry(entrynum) else: self.bf.seek(rp_off) self.bf.write(new_rpath) self.bf.write(b'\0') def remove_rpath_entry(self, entrynum): sec = self.find_section(b'.dynamic') if sec is None: return None for (i, entry) in enumerate(self.dynamic): if entry.d_tag == entrynum: rpentry = self.dynamic[i] rpentry.d_tag = 0 self.dynamic = self.dynamic[:i] + self.dynamic[i + 1:] + [rpentry] break # DT_MIPS_RLD_MAP_REL is relative to the offset of the tag. Adjust it consequently. for entry in self.dynamic[i:]: if entry.d_tag == DT_MIPS_RLD_MAP_REL: entry.val += 2 * (self.ptrsize // 8) break self.bf.seek(sec.sh_offset) for entry in self.dynamic: entry.write(self.bf) return None def run(args): if len(args) < 1 or len(args) > 2: print('This application resets target rpath.') print('Don\'t run this unless you know what you are doing.') print('%s: ' % sys.argv[0]) exit(1) with Elf(args[0]) as e: if len(args) == 1: e.print_rpath() e.print_runpath() else: new_rpath = args[1] e.fix_rpath(new_rpath) return 0 if __name__ == '__main__': run(sys.argv[1:]) meson-0.40.1/mesonbuild/scripts/__init__.py0000644000175000017500000000144413035766234022264 0ustar jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. def destdir_join(d1, d2): # c:\destdir + c:\prefix must produce c:\destdir\prefix if len(d1) > 1 and d1[1] == ':' \ and len(d2) > 1 and d2[1] == ':': return d1 + d2[2:] return d1 + d2 meson-0.40.1/mesonbuild/scripts/yelphelper.py0000644000175000017500000001167413076164167022706 0ustar jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import subprocess import shutil import argparse from .. import mlog from . import destdir_join parser = argparse.ArgumentParser() parser.add_argument('command') parser.add_argument('--id', dest='project_id') parser.add_argument('--subdir', dest='subdir') parser.add_argument('--installdir', dest='install_dir') parser.add_argument('--sources', dest='sources') parser.add_argument('--media', dest='media', default='') parser.add_argument('--langs', dest='langs', default='') parser.add_argument('--symlinks', type=bool, dest='symlinks', default=False) def build_pot(srcdir, project_id, sources): # Must be relative paths sources = [os.path.join('C', source) for source in sources] outfile = os.path.join(srcdir, project_id + '.pot') subprocess.call(['itstool', '-o', outfile] + sources) def update_po(srcdir, project_id, langs): potfile = os.path.join(srcdir, project_id + '.pot') for lang in langs: pofile = os.path.join(srcdir, lang, lang + '.po') subprocess.call(['msgmerge', '-q', '-o', pofile, pofile, potfile]) def build_translations(srcdir, blddir, langs): for lang in langs: outdir = os.path.join(blddir, lang) os.makedirs(outdir, exist_ok=True) subprocess.call([ 'msgfmt', os.path.join(srcdir, lang, lang + '.po'), '-o', os.path.join(outdir, lang + '.gmo') ]) def merge_translations(blddir, sources, langs): for lang in langs: subprocess.call([ 'itstool', '-m', os.path.join(blddir, lang, lang + '.gmo'), '-o', os.path.join(blddir, lang) ] + sources) def install_help(srcdir, blddir, sources, media, langs, install_dir, destdir, project_id, symlinks): c_install_dir = os.path.join(install_dir, 'C', project_id) for lang in langs + ['C']: indir = destdir_join(destdir, os.path.join(install_dir, lang, project_id)) os.makedirs(indir, exist_ok=True) for source in sources: infile = os.path.join(srcdir if lang == 'C' else blddir, lang, source) outfile = os.path.join(indir, source) mlog.log('Installing %s to %s' % (infile, outfile)) shutil.copyfile(infile, outfile) shutil.copystat(infile, outfile) for m in media: infile = os.path.join(srcdir, lang, m) outfile = os.path.join(indir, m) if not os.path.exists(infile): if lang == 'C': 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)) if '/' in m or '\\' in m: os.makedirs(os.path.dirname(outfile), exist_ok=True) os.symlink(srcfile, outfile) continue mlog.log('Installing %s to %s' % (infile, outfile)) if '/' in m or '\\' in m: os.makedirs(os.path.dirname(outfile), exist_ok=True) shutil.copyfile(infile, outfile) shutil.copystat(infile, outfile) def run(args): options = parser.parse_args(args) langs = options.langs.split('@@') if options.langs else [] media = options.media.split('@@') if options.media else [] sources = options.sources.split('@@') destdir = os.environ.get('DESTDIR', '') src_subdir = os.path.join(os.environ['MESON_SOURCE_ROOT'], options.subdir) build_subdir = os.path.join(os.environ['MESON_BUILD_ROOT'], options.subdir) abs_sources = [os.path.join(src_subdir, 'C', source) for source in sources] if options.command == 'pot': build_pot(src_subdir, options.project_id, sources) elif options.command == 'update-po': build_pot(src_subdir, options.project_id, sources) update_po(src_subdir, options.project_id, langs) elif options.command == 'build': if langs: build_translations(src_subdir, build_subdir, langs) elif options.command == 'install': install_dir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], options.install_dir) if langs: build_translations(src_subdir, build_subdir, langs) merge_translations(build_subdir, abs_sources, langs) install_help(src_subdir, build_subdir, sources, media, langs, install_dir, destdir, options.project_id, options.symlinks) meson-0.40.1/mesonbuild/environment.py0000644000175000017500000011013413076760243021376 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os, re, subprocess, platform from . import coredata from . import mesonlib from . import mlog from .compilers import * from .mesonlib import EnvironmentException, Popen_safe import configparser import shlex import shutil build_filename = 'meson.build' # Environment variables that each lang uses. cflags_mapping = {'c': 'CFLAGS', 'cpp': 'CXXFLAGS', 'objc': 'OBJCFLAGS', 'objcpp': 'OBJCXXFLAGS', 'fortran': 'FFLAGS', 'd': 'DFLAGS', 'vala': 'VALAFLAGS'} def find_coverage_tools(): gcovr_exe = 'gcovr' lcov_exe = 'lcov' genhtml_exe = 'genhtml' if not mesonlib.exe_exists([gcovr_exe, '--version']): gcovr_exe = None if not mesonlib.exe_exists([lcov_exe, '--version']): lcov_exe = None if not mesonlib.exe_exists([genhtml_exe, '--version']): genhtml_exe = None return gcovr_exe, lcov_exe, genhtml_exe def detect_ninja(version='1.5'): for n in ['ninja', 'ninja-build']: try: p, found = Popen_safe([n, '--version'])[0:2] except (FileNotFoundError, PermissionError): # Doesn't exist in PATH or isn't executable continue # Perhaps we should add a way for the caller to know the failure mode # (not found or too old) if p.returncode == 0 and mesonlib.version_compare(found, '>=' + version): return n def detect_native_windows_arch(): """ The architecture of Windows itself: x86 or amd64 """ # These env variables are always available. See: # https://msdn.microsoft.com/en-us/library/aa384274(VS.85).aspx # https://blogs.msdn.microsoft.com/david.wang/2006/03/27/howto-detect-process-bitness/ arch = os.environ.get('PROCESSOR_ARCHITEW6432', '').lower() if not arch: try: # If this doesn't exist, something is messing with the environment arch = os.environ['PROCESSOR_ARCHITECTURE'].lower() except KeyError: raise EnvironmentException('Unable to detect native OS architecture') return arch def detect_windows_arch(compilers): """ Detecting the 'native' architecture of Windows is not a trivial task. We cannot trust that the architecture that Python is built for is the 'native' one because you can run 32-bit apps on 64-bit Windows using WOW64 and people sometimes install 32-bit Python on 64-bit Windows. We also can't rely on the architecture of the OS itself, since it's perfectly normal to compile and run 32-bit applications on Windows as if they were native applications. It's a terrible experience to require the user to supply a cross-info file to compile 32-bit applications on 64-bit Windows. Thankfully, the only way to compile things with Visual Studio on Windows is by entering the 'msvc toolchain' environment, which can be easily detected. In the end, the sanest method is as follows: 1. Check if we're in an MSVC toolchain environment, and if so, return the MSVC toolchain architecture as our 'native' architecture. 2. If not, check environment variables that are set by Windows and WOW64 to find out the architecture that Windows is built for, and use that as our 'native' architecture. """ os_arch = detect_native_windows_arch() if os_arch != 'amd64': return os_arch # If we're on 64-bit Windows, 32-bit apps can be compiled without # cross-compilation. So if we're doing that, just set the native arch as # 32-bit and pretend like we're running under WOW64. Else, return the # actual Windows architecture that we deduced above. for compiler in compilers.values(): # Check if we're using and inside an MSVC toolchain environment if compiler.id == 'msvc' and 'VCINSTALLDIR' in os.environ: # 'Platform' is only set when the target arch is not 'x86'. # It's 'x64' when targetting x86_64 and 'arm' when targetting ARM. platform = os.environ.get('Platform', 'x86').lower() if platform == 'x86': return platform if compiler.id == 'gcc' and compiler.has_builtin_define('__i386__'): return 'x86' return os_arch def detect_cpu_family(compilers): """ Python is inconsistent in its platform module. It returns different values for the same cpu. For x86 it might return 'x86', 'i686' or somesuch. Do some canonicalization. """ if mesonlib.is_windows(): trial = detect_windows_arch(compilers) else: trial = platform.machine().lower() if trial.startswith('i') and trial.endswith('86'): return 'x86' if trial.startswith('arm'): return 'arm' if trial in ('amd64', 'x64'): trial = 'x86_64' if trial == 'x86_64': # On Linux (and maybe others) there can be any mixture of 32/64 bit # code in the kernel, Python, system etc. The only reliable way # to know is to check the compiler defines. for c in compilers.values(): try: if c.has_builtin_define('__i386__'): return 'x86' except mesonlib.MesonException: # Ignore compilers that do not support has_builtin_define. pass return 'x86_64' # Add fixes here as bugs are reported. return trial def detect_cpu(compilers): if mesonlib.is_windows(): trial = detect_windows_arch(compilers) else: trial = platform.machine().lower() if trial in ('amd64', 'x64'): trial = 'x86_64' if trial == 'x86_64': # Same check as above for cpu_family for c in compilers.values(): try: if c.has_builtin_define('__i386__'): return 'i686' # All 64 bit cpus have at least this level of x86 support. except mesonlib.MesonException: pass return 'x86_64' # Add fixes here as bugs are reported. return trial def detect_system(): system = platform.system().lower() if system.startswith('cygwin'): return 'cygwin' return system def for_windows(is_cross, env): """ Host machine is windows? Note: 'host' is the machine on which compiled binaries will run """ if not is_cross: return mesonlib.is_windows() elif env.cross_info.has_host(): return env.cross_info.config['host_machine']['system'] == 'windows' return False def for_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)? Note: 'host' is the machine on which compiled binaries will run """ if not is_cross: return mesonlib.is_osx() elif env.cross_info.has_host(): return env.cross_info.config['host_machine']['system'] == 'darwin' return False def search_version(text): # Usually of the type 4.1.4 but compiler output may contain # stuff like this: # (Sourcery CodeBench Lite 2014.05-29) 4.8.3 20140320 (prerelease) # Limiting major version number to two digits seems to work # thus far. When we get to GCC 100, this will break, but # if we are still relevant when that happens, it can be # considered an achievement in itself. # # This regex is reaching magic levels. If it ever needs # to be updated, do not complexify but convert to something # saner instead. version_regex = '(? 0: titles[3] = 'Possible Values' print(' %s%s %s%s %s%s %s' % (titles[0], ' ' * (longest_name - len(titles[0])), titles[1], ' ' * (longest_descr - len(titles[1])), titles[2], ' ' * (longest_value - len(titles[2])), titles[3])) print(' %s%s %s%s %s%s %s' % ('-' * len(titles[0]), ' ' * (longest_name - len(titles[0])), '-' * len(titles[1]), ' ' * (longest_descr - len(titles[1])), '-' * len(titles[2]), ' ' * (longest_value - len(titles[2])), '-' * len(titles[3]))) for i in arr: name = i[0] descr = i[1] value = i[2] if isinstance(i[2], str) else str(i[2]).lower() possible_values = '' if isinstance(i[3], list): if len(i[3]) > 0: i[3] = [s if isinstance(s, str) else str(s).lower() for s in i[3]] possible_values = '[%s]' % ', '.join(map(str, i[3])) elif i[3]: possible_values = i[3] if isinstance(i[3], str) else str(i[3]).lower() namepad = ' ' * (longest_name - len(name)) descrpad = ' ' * (longest_descr - len(descr)) valuepad = ' ' * (longest_value - len(str(value))) f = ' %s%s %s%s %s%s %s' % (name, namepad, descr, descrpad, value, valuepad, possible_values) print(f) def set_options(self, options): for o in options: if '=' not in o: raise ConfException('Value "%s" not of type "a=b".' % o) (k, v) = o.split('=', 1) if coredata.is_builtin_option(k): self.coredata.set_builtin_option(k, v) elif k in self.coredata.user_options: tgt = self.coredata.user_options[k] tgt.set_value(v) elif k in self.coredata.compiler_options: tgt = self.coredata.compiler_options[k] tgt.set_value(v) elif k in self.coredata.base_options: tgt = self.coredata.base_options[k] tgt.set_value(v) elif k.endswith('_link_args'): lang = k[:-10] if lang not in self.coredata.external_link_args: raise ConfException('Unknown language %s in linkargs.' % lang) # TODO, currently split on spaces, make it so that user # can pass in an array string. newvalue = v.split() self.coredata.external_link_args[lang] = newvalue elif k.endswith('_args'): lang = k[:-5] if lang not in self.coredata.external_args: raise ConfException('Unknown language %s in compile args' % lang) # TODO same fix as above newvalue = v.split() self.coredata.external_args[lang] = newvalue else: raise ConfException('Unknown option %s.' % k) def print_conf(self): print('Core properties:') print(' Source dir', self.build.environment.source_dir) print(' Build dir ', self.build.environment.build_dir) print('') print('Core options:') carr = [] for key in ['buildtype', 'warning_level', 'werror', 'strip', 'unity', 'default_library']: carr.append([key, coredata.get_builtin_option_description(key), self.coredata.get_builtin_option(key), coredata.get_builtin_option_choices(key)]) self.print_aligned(carr) print('') print('Base options:') okeys = sorted(self.coredata.base_options.keys()) if len(okeys) == 0: print(' No base options\n') else: coarr = [] for k in okeys: o = self.coredata.base_options[k] coarr.append([k, o.description, o.value, '']) self.print_aligned(coarr) print('') print('Compiler arguments:') for (lang, args) in self.coredata.external_args.items(): print(' ' + lang + '_args', str(args)) print('') print('Linker args:') for (lang, args) in self.coredata.external_link_args.items(): print(' ' + lang + '_link_args', str(args)) print('') print('Compiler options:') okeys = sorted(self.coredata.compiler_options.keys()) if len(okeys) == 0: print(' No compiler options\n') else: coarr = [] for k in okeys: o = self.coredata.compiler_options[k] coarr.append([k, o.description, o.value, '']) self.print_aligned(coarr) print('') print('Directories:') parr = [] for key in ['prefix', 'libdir', 'libexecdir', 'bindir', 'sbindir', 'includedir', 'datadir', 'mandir', 'infodir', 'localedir', 'sysconfdir', 'localstatedir', 'sharedstatedir', ]: parr.append([key, coredata.get_builtin_option_description(key), self.coredata.get_builtin_option(key), coredata.get_builtin_option_choices(key)]) self.print_aligned(parr) print('') print('Project options:') if len(self.coredata.user_options) == 0: print(' This project does not have any options') else: options = self.coredata.user_options keys = list(options.keys()) keys.sort() optarr = [] for key in keys: opt = options[key] if (opt.choices is None) or (len(opt.choices) == 0): # Zero length list or string choices = '' else: # A non zero length list or string, convert to string choices = str(opt.choices) optarr.append([key, opt.description, opt.value, choices]) self.print_aligned(optarr) print('') print('Testing options:') tarr = [] for key in ['stdsplit', 'errorlogs']: tarr.append([key, coredata.get_builtin_option_description(key), self.coredata.get_builtin_option(key), coredata.get_builtin_option_choices(key)]) self.print_aligned(tarr) def run(args): args = mesonlib.expand_arguments(args) if not args: args = [os.getcwd()] options = parser.parse_args(args) if len(options.directory) > 1: print('%s ' % args[0]) print('If you omit the build directory, the current directory is substituted.') return 1 if len(options.directory) == 0: builddir = os.getcwd() else: builddir = options.directory[0] try: c = Conf(builddir) save = False if len(options.sets) > 0: c.set_options(options.sets) save = True elif options.clearcache: c.clear_cache() save = True else: c.print_conf() if save: c.save() except ConfException as e: print('Meson configurator encountered an error:\n') print(e) return 1 return 0 if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/backend/0000755000175000017500000000000013100703042020025 5ustar jpakkanejpakkane00000000000000meson-0.40.1/mesonbuild/backend/vs2015backend.py0000644000175000017500000000155513065321007022664 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from xml.etree import ElementTree as ET from .vs2010backend import Vs2010Backend class Vs2015Backend(Vs2010Backend): def __init__(self, build): super().__init__(build) self.name = 'vs2015' self.platform_toolset = 'v140' self.vs_version = '2015' meson-0.40.1/mesonbuild/backend/vs2017backend.py0000644000175000017500000000175513070746245022703 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from .vs2010backend import Vs2010Backend class Vs2017Backend(Vs2010Backend): def __init__(self, build): super().__init__(build) self.name = 'vs2017' self.platform_toolset = 'v141' self.vs_version = '2017' # WindowsSDKVersion should be set by command prompt. self.windows_target_platform_version = os.getenv('WindowsSDKVersion', None).rstrip('\\') meson-0.40.1/mesonbuild/backend/vs2010backend.py0000644000175000017500000017237113076164167022702 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os, sys import pickle import xml.dom.minidom import xml.etree.ElementTree as ET from . import backends from .. import build from .. import dependencies from .. import mlog from .. import compilers from ..build import BuildTarget from ..compilers import CompilerArgs from ..mesonlib import MesonException, File, get_meson_script from ..environment import Environment def autodetect_vs_version(build): vs_version = os.getenv('VisualStudioVersion', None) if vs_version: if vs_version == '14.0': from mesonbuild.backend.vs2015backend import Vs2015Backend return Vs2015Backend(build) if vs_version == '15.0': from mesonbuild.backend.vs2017backend import Vs2017Backend return Vs2017Backend(build) raise MesonException('Could not detect Visual Studio (unknown Visual Studio version: "{}")!\n' 'Please specify the exact backend to use.'.format(vs_version)) vs_install_dir = os.getenv('VSINSTALLDIR', None) if not vs_install_dir: raise MesonException('Could not detect Visual Studio (neither VisualStudioVersion nor VSINSTALLDIR set in ' 'environment)!\nPlease specify the exact backend to use.') if 'Visual Studio 10.0' in vs_install_dir: return Vs2010Backend(build) raise MesonException('Could not detect Visual Studio (unknown VSINSTALLDIR: "{}")!\n' 'Please specify the exact backend to use.'.format(vs_install_dir)) def split_o_flags_args(args): """ Splits any /O args and returns them. Does not take care of flags overriding previous ones. Skips non-O flag arguments. ['/Ox', '/Ob1'] returns ['/Ox', '/Ob1'] ['/Oxj', '/MP'] returns ['/Ox', '/Oj'] """ o_flags = [] for arg in args: if not arg.startswith('/O'): continue flags = list(arg[2:]) # Assume that this one can't be clumped with the others since it takes # an argument itself if 'b' in flags: o_flags.append(arg) else: o_flags += ['/O' + f for f in flags] return o_flags class RegenInfo: def __init__(self, source_dir, build_dir, depfiles): self.source_dir = source_dir self.build_dir = build_dir self.depfiles = depfiles class Vs2010Backend(backends.Backend): def __init__(self, build): super().__init__(build) self.name = 'vs2010' self.project_file_version = '10.0.30319.1' self.sources_conflicts = {} self.platform_toolset = None self.vs_version = '2010' self.windows_target_platform_version = None def object_filename_from_source(self, target, source, is_unity=False): basename = os.path.basename(source.fname) filename_without_extension = '.'.join(basename.split('.')[:-1]) if basename in self.sources_conflicts[target.get_id()]: # If there are multiple source files with the same basename, we must resolve the conflict # by giving each a unique object output file. filename_without_extension = '.'.join(source.fname.split('.')[:-1]).replace('/', '_').replace('\\', '_') return filename_without_extension + '.' + self.environment.get_object_suffix() def resolve_source_conflicts(self): for name, target in self.build.targets.items(): if not isinstance(target, BuildTarget): continue conflicts = {} for s in target.get_sources(): if hasattr(s, 'held_object'): s = s.held_object if not isinstance(s, File): continue basename = os.path.basename(s.fname) conflicting_sources = conflicts.get(basename, None) if conflicting_sources is None: conflicting_sources = [] conflicts[basename] = conflicting_sources conflicting_sources.append(s) self.sources_conflicts[target.get_id()] = {name: src_conflicts for name, src_conflicts in conflicts.items() if len(src_conflicts) > 1} def generate_custom_generator_commands(self, target, parent_node): generator_output_files = [] custom_target_include_dirs = [] custom_target_output_files = [] target_private_dir = self.relpath(self.get_target_private_dir(target), self.get_target_dir(target)) down = self.target_to_build_root(target) for genlist in target.get_generated_sources(): if isinstance(genlist, build.CustomTarget): for i in genlist.get_outputs(): # Path to the generated source from the current vcxproj dir via the build root ipath = os.path.join(down, self.get_target_dir(genlist), i) custom_target_output_files.append(ipath) idir = self.relpath(self.get_target_dir(genlist), self.get_target_dir(target)) if idir not in custom_target_include_dirs: custom_target_include_dirs.append(idir) else: generator = genlist.get_generator() exe = generator.get_exe() infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() exe_arr = self.exe_object_to_cmd_array(exe) base_args = generator.get_arglist() idgroup = ET.SubElement(parent_node, 'ItemGroup') for i in range(len(infilelist)): if len(infilelist) == len(outfilelist): sole_output = os.path.join(target_private_dir, outfilelist[i]) else: sole_output = '' curfile = infilelist[i] infilename = os.path.join(down, curfile.rel_to_builddir(self.build_to_src)) outfiles_rel = genlist.get_outputs_for(curfile) outfiles = [os.path.join(target_private_dir, of) for of in outfiles_rel] generator_output_files += outfiles args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output) for x in base_args] args = self.replace_outputs(args, target_private_dir, outfiles_rel) args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()) .replace("@BUILD_DIR@", target_private_dir) for x in args] args = [x.replace("@SOURCE_ROOT@", self.environment.get_source_dir()) .replace("@BUILD_ROOT@", self.environment.get_build_dir()) for x in args] cmd = exe_arr + self.replace_extra_args(args, genlist) cbs = ET.SubElement(idgroup, 'CustomBuild', Include=infilename) ET.SubElement(cbs, 'Command').text = ' '.join(self.quote_arguments(cmd)) ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles) return generator_output_files, custom_target_output_files, custom_target_include_dirs def generate(self, interp): self.resolve_source_conflicts() self.interpreter = interp target_machine = self.interpreter.builtin['target_machine'].cpu_family_method(None, None) if target_machine.endswith('64'): # amd64 or x86_64 self.platform = 'x64' elif target_machine == 'x86': # x86 self.platform = 'Win32' elif 'arm' in target_machine.lower(): self.platform = 'ARM' else: raise MesonException('Unsupported Visual Studio platform: ' + target_machine) self.buildtype = self.environment.coredata.get_builtin_option('buildtype') sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln') projlist = self.generate_projects() self.gen_testproj('RUN_TESTS', os.path.join(self.environment.get_build_dir(), 'RUN_TESTS.vcxproj')) self.gen_regenproj('REGEN', os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj')) self.generate_solution(sln_filename, projlist) self.generate_regen_info() Vs2010Backend.touch_regen_timestamp(self.environment.get_build_dir()) @staticmethod def get_regen_stampfile(build_dir): return os.path.join(os.path.join(build_dir, Environment.private_dir), 'regen.stamp') @staticmethod def touch_regen_timestamp(build_dir): with open(Vs2010Backend.get_regen_stampfile(build_dir), 'w'): pass def generate_regen_info(self): deps = self.get_regen_filelist() regeninfo = RegenInfo(self.environment.get_source_dir(), self.environment.get_build_dir(), deps) filename = os.path.join(self.environment.get_scratch_dir(), 'regeninfo.dump') with open(filename, 'wb') as f: pickle.dump(regeninfo, f) def get_obj_target_deps(self, obj_list): result = {} for o in obj_list: if isinstance(o, build.ExtractedObjects): result[o.target.get_id()] = o.target return result.items() def get_target_deps(self, t, recursive=False): all_deps = {} for target in t.values(): if isinstance(target, build.CustomTarget): for d in target.get_target_dependencies(): all_deps[d.get_id()] = d elif isinstance(target, build.RunTarget): for d in [target.command] + target.args: if isinstance(d, (build.BuildTarget, build.CustomTarget)): all_deps[d.get_id()] = d elif isinstance(target, build.BuildTarget): for ldep in target.link_targets: all_deps[ldep.get_id()] = ldep for ldep in target.link_whole_targets: all_deps[ldep.get_id()] = ldep for obj_id, objdep in self.get_obj_target_deps(target.objects): all_deps[obj_id] = objdep for gendep in target.get_generated_sources(): if isinstance(gendep, build.CustomTarget): all_deps[gendep.get_id()] = gendep else: gen_exe = gendep.generator.get_exe() if isinstance(gen_exe, build.Executable): all_deps[gen_exe.get_id()] = gen_exe else: raise MesonException('Unknown target type for target %s' % target) if not t or not recursive: return all_deps ret = self.get_target_deps(all_deps, recursive) ret.update(all_deps) return ret def generate_solution(self, sln_filename, projlist): default_projlist = self.get_build_by_default_targets() with open(sln_filename, 'w') as ofile: ofile.write('Microsoft Visual Studio Solution File, Format ' 'Version 11.00\n') ofile.write('# Visual Studio ' + self.vs_version + '\n') prj_templ = 'Project("{%s}") = "%s", "%s", "{%s}"\n' for p in projlist: prj_line = prj_templ % (self.environment.coredata.guid, p[0], p[1], p[2]) ofile.write(prj_line) target = self.build.targets[p[0]] t = {target.get_id(): target} # Get direct deps all_deps = self.get_target_deps(t) # Get recursive deps recursive_deps = self.get_target_deps(t, recursive=True) ofile.write('\tProjectSection(ProjectDependencies) = ' 'postProject\n') regen_guid = self.environment.coredata.regen_guid ofile.write('\t\t{%s} = {%s}\n' % (regen_guid, regen_guid)) for dep in all_deps.keys(): guid = self.environment.coredata.target_guids[dep] ofile.write('\t\t{%s} = {%s}\n' % (guid, guid)) ofile.write('EndProjectSection\n') ofile.write('EndProject\n') for dep, target in recursive_deps.items(): if p[0] in default_projlist: default_projlist[dep] = target test_line = prj_templ % (self.environment.coredata.guid, 'RUN_TESTS', 'RUN_TESTS.vcxproj', self.environment.coredata.test_guid) ofile.write(test_line) ofile.write('EndProject\n') regen_line = prj_templ % (self.environment.coredata.guid, 'REGEN', 'REGEN.vcxproj', self.environment.coredata.regen_guid) ofile.write(regen_line) ofile.write('EndProject\n') ofile.write('Global\n') ofile.write('\tGlobalSection(SolutionConfigurationPlatforms) = ' 'preSolution\n') ofile.write('\t\t%s|%s = %s|%s\n' % (self.buildtype, self.platform, self.buildtype, self.platform)) ofile.write('\tEndGlobalSection\n') ofile.write('\tGlobalSection(ProjectConfigurationPlatforms) = ' 'postSolution\n') ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (self.environment.coredata.regen_guid, self.buildtype, self.platform, self.buildtype, self.platform)) ofile.write('\t\t{%s}.%s|%s.Build.0 = %s|%s\n' % (self.environment.coredata.regen_guid, self.buildtype, self.platform, self.buildtype, self.platform)) # Create the solution configuration for p in projlist: # Add to the list of projects in this solution ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (p[2], self.buildtype, self.platform, self.buildtype, self.platform)) if p[0] in default_projlist and \ not isinstance(self.build.targets[p[0]], build.RunTarget): # Add to the list of projects to be built ofile.write('\t\t{%s}.%s|%s.Build.0 = %s|%s\n' % (p[2], self.buildtype, self.platform, self.buildtype, self.platform)) ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % (self.environment.coredata.test_guid, self.buildtype, self.platform, self.buildtype, self.platform)) ofile.write('\tEndGlobalSection\n') ofile.write('\tGlobalSection(SolutionProperties) = preSolution\n') ofile.write('\t\tHideSolutionNode = FALSE\n') ofile.write('\tEndGlobalSection\n') ofile.write('EndGlobal\n') def generate_projects(self): projlist = [] 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) projlist.append((name, relname, uuid)) return projlist def split_sources(self, srclist): sources = [] headers = [] objects = [] languages = [] for i in srclist: if self.environment.is_header(i): headers.append(i) elif self.environment.is_object(i): objects.append(i) elif self.environment.is_source(i): sources.append(i) lang = self.lang_from_source_file(i) if lang not in languages: languages.append(lang) elif self.environment.is_library(i): pass else: # Everything that is not an object or source file is considered a header. headers.append(i) return sources, headers, objects, languages def target_to_build_root(self, target): if target.subdir == '': return '' directories = os.path.normpath(target.subdir).split(os.sep) return os.sep.join(['..'] * len(directories)) def quote_arguments(self, arr): return ['"%s"' % i for i in arr] def create_basic_crap(self, target): project_name = target.name root = ET.Element('Project', {'DefaultTargets': "Build", 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': self.buildtype + '|' + self.platform}) p = ET.SubElement(prjconf, 'Configuration') p.text = self.buildtype pl = ET.SubElement(prjconf, 'Platform') pl.text = self.platform globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem.text = self.environment.coredata.test_guid kw = ET.SubElement(globalgroup, 'Keyword') kw.text = self.platform + 'Proj' p = ET.SubElement(globalgroup, 'Platform') p.text = self.platform pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = project_name if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props') type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType') ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' ET.SubElement(type_config, 'UseOfMfc').text = 'false' if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props') direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version outdir = ET.SubElement(direlem, 'OutDir') outdir.text = '.\\' intdir = ET.SubElement(direlem, 'IntDir') intdir.text = target.get_id() + '\\' tname = ET.SubElement(direlem, 'TargetName') tname.text = target.name return root def gen_run_target_vcxproj(self, target, ofname, guid): root = self.create_basic_crap(target) action = ET.SubElement(root, 'ItemDefinitionGroup') 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), 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))) elif isinstance(i, dependencies.ExternalProgram): cmd += i.get_command() elif isinstance(i, File): relfname = i.rel_to_builddir(self.build_to_src) cmd.append(os.path.join(self.environment.get_build_dir(), relfname)) else: cmd.append(i) cmd_templ = '''"%s" ''' * len(cmd) ET.SubElement(customstep, 'Command').text = cmd_templ % tuple(cmd) ET.SubElement(customstep, 'Message').text = 'Running custom command.' ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets') self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) def gen_custom_target_vcxproj(self, target, ofname, guid): root = self.create_basic_crap(target) action = ET.SubElement(root, 'ItemDefinitionGroup') customstep = ET.SubElement(action, 'CustomBuildStep') # We need to always use absolute paths because our invocation is always # from the target dir, not the build root. target.absolute_paths = True (srcs, ofilenames, cmd) = self.eval_custom_target_command(target, True) depend_files = self.get_custom_target_depend_files(target, True) # Always use a wrapper because MSBuild eats random characters when # there are many arguments. tdir_abs = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) exe_data = self.serialise_executable(target.command[0], cmd[1:], # All targets run from the target dir tdir_abs, capture=ofilenames[0] if target.capture else None) wrapper_cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'exe', exe_data] ET.SubElement(customstep, 'Command').text = ' '.join(self.quote_arguments(wrapper_cmd)) ET.SubElement(customstep, 'Outputs').text = ';'.join(ofilenames) ET.SubElement(customstep, 'Inputs').text = ';'.join([exe_data] + srcs + depend_files) ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets') self.generate_custom_generator_commands(target, root) self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) @classmethod def lang_from_source_file(cls, src): ext = src.split('.')[-1] if ext in compilers.c_suffixes: return 'c' if ext in compilers.cpp_suffixes: return 'cpp' raise MesonException('Could not guess language from source file %s.' % src) def add_pch(self, inc_cl, proj_to_src_dir, pch_sources, source_file): if len(pch_sources) <= 1: # We only need per file precompiled headers if we have more than 1 language. return lang = Vs2010Backend.lang_from_source_file(source_file) header = os.path.join(proj_to_src_dir, pch_sources[lang][0]) pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') pch_file.text = header pch_include = ET.SubElement(inc_cl, 'ForcedIncludeFiles') pch_include.text = header + ';%(ForcedIncludeFiles)' pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % lang def add_additional_options(self, lang, parent_node, file_args): args = [] for arg in file_args[lang].to_native(): if arg == '%(AdditionalOptions)': args.append(arg) else: args.append(self.escape_additional_option(arg)) ET.SubElement(parent_node, "AdditionalOptions").text = ' '.join(args) def add_preprocessor_defines(self, lang, parent_node, file_defines): defines = [] for define in file_defines[lang]: if define == '%(PreprocessorDefinitions)': defines.append(define) else: defines.append(self.escape_preprocessor_define(define)) ET.SubElement(parent_node, "PreprocessorDefinitions").text = ';'.join(defines) def add_include_dirs(self, lang, parent_node, file_inc_dirs): dirs = file_inc_dirs[lang] ET.SubElement(parent_node, "AdditionalIncludeDirectories").text = ';'.join(dirs) @staticmethod def has_objects(objects, additional_objects, generated_objects): # Ignore generated objects, those are automatically used by MSBuild because they are part of # the CustomBuild Outputs. return len(objects) + len(additional_objects) > 0 @staticmethod def add_generated_objects(node, generated_objects): # Do not add generated objects to project file. Those are automatically used by MSBuild, because # they are part of the CustomBuild Outputs. return @staticmethod def escape_preprocessor_define(define): # See: https://msdn.microsoft.com/en-us/library/bb383819.aspx table = str.maketrans({'%': '%25', '$': '%24', '@': '%40', "'": '%27', ';': '%3B', '?': '%3F', '*': '%2A', # We need to escape backslash because it'll be un-escaped by # Windows during process creation when it parses the arguments # Basically, this converts `\` to `\\`. '\\': '\\\\'}) return define.translate(table) @staticmethod def escape_additional_option(option): # See: https://msdn.microsoft.com/en-us/library/bb383819.aspx table = str.maketrans({'%': '%25', '$': '%24', '@': '%40', "'": '%27', ';': '%3B', '?': '%3F', '*': '%2A', ' ': '%20'}) option = option.translate(table) # Since we're surrounding the option with ", if it ends in \ that will # escape the " when the process arguments are parsed and the starting # " will not terminate. So we escape it if that's the case. I'm not # kidding, this is how escaping works for process args on Windows. if option.endswith('\\'): option += '\\' return '"{}"'.format(option) @staticmethod def split_link_args(args): """ Split a list of link arguments into three lists: * library search paths * library filenames (or paths) * other link arguments """ lpaths = [] libs = [] other = [] for arg in args: if arg.startswith('/LIBPATH:'): lpath = arg[9:] # De-dup library search paths by removing older entries when # a new one is found. This is necessary because unlike other # search paths such as the include path, the library is # searched for in the newest (right-most) search path first. if lpath in lpaths: lpaths.remove(lpath) lpaths.append(lpath) # It's ok if we miss libraries with non-standard extensions here. # They will go into the general link arguments. elif arg.endswith('.lib') or arg.endswith('.a'): # De-dup if arg not in libs: libs.append(arg) else: other.append(arg) return lpaths, libs, other def _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 _prettyprint_vcxproj_xml(self, tree, ofname): tree.write(ofname, encoding='utf-8', xml_declaration=True) # ElementTree can not do prettyprinting so do it manually doc = xml.dom.minidom.parse(ofname) with open(ofname, 'w') as of: of.write(doc.toprettyxml()) def gen_vcxproj(self, target, ofname, guid): mlog.debug('Generating vcxproj %s.' % target.name) entrypoint = 'WinMainCRTStartup' subsystem = 'Windows' if isinstance(target, build.Executable): conftype = 'Application' if not target.gui_app: subsystem = 'Console' entrypoint = 'mainCRTStartup' elif isinstance(target, build.StaticLibrary): conftype = 'StaticLibrary' elif isinstance(target, build.SharedLibrary): conftype = 'DynamicLibrary' entrypoint = '_DllMainCrtStartup' elif isinstance(target, build.CustomTarget): return self.gen_custom_target_vcxproj(target, ofname, guid) elif isinstance(target, build.RunTarget): return self.gen_run_target_vcxproj(target, ofname, guid) else: raise MesonException('Unknown target type for %s' % target.get_basename()) # Prefix to use to access the build root from the vcxproj dir down = self.target_to_build_root(target) # Prefix to use to access the source tree's root from the vcxproj dir proj_to_src_root = os.path.join(down, self.build_to_src) # Prefix to use to access the source tree's subdir from the vcxproj dir proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir) (sources, headers, objects, languages) = self.split_sources(target.sources) if self.is_unity(target): sources = self.generate_unity_files(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 target_name = target.name root = ET.Element('Project', {'DefaultTargets': "Build", 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': self.buildtype + '|' + self.platform}) p = ET.SubElement(prjconf, 'Configuration') p.text = self.buildtype pl = ET.SubElement(prjconf, 'Platform') pl.text = self.platform # Globals globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem.text = guid kw = ET.SubElement(globalgroup, 'Keyword') kw.text = self.platform + 'Proj' ns = ET.SubElement(globalgroup, 'RootNamespace') ns.text = target_name p = ET.SubElement(globalgroup, 'Platform') p.text = self.platform pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = project_name if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props') # Start configuration type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType').text = conftype ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset # FIXME: Meson's LTO support needs to be integrated here ET.SubElement(type_config, 'WholeProgramOptimization').text = 'false' # Let VS auto-set the RTC level ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'Default' o_flags = split_o_flags_args(buildtype_args) if '/Oi' in o_flags: ET.SubElement(type_config, 'IntrinsicFunctions').text = 'true' if '/Ob1' in o_flags: ET.SubElement(type_config, 'InlineFunctionExpansion').text = 'OnlyExplicitInline' elif '/Ob2' in o_flags: ET.SubElement(type_config, 'InlineFunctionExpansion').text = 'AnySuitable' # Size-preserving flags if '/Os' in o_flags: ET.SubElement(type_config, 'FavorSizeOrSpeed').text = 'Size' else: ET.SubElement(type_config, 'FavorSizeOrSpeed').text = 'Speed' # Incremental linking increases code size if '/INCREMENTAL:NO' in buildtype_link_args: ET.SubElement(type_config, 'LinkIncremental').text = 'false' # CRT type; debug or release if '/MDd' in buildtype_args: ET.SubElement(type_config, 'UseDebugLibraries').text = 'true' ET.SubElement(type_config, 'RuntimeLibrary').text = 'MultiThreadedDebugDLL' else: ET.SubElement(type_config, 'UseDebugLibraries').text = 'false' ET.SubElement(type_config, 'RuntimeLibrary').text = 'MultiThreadedDLL' # Debug format if '/ZI' in buildtype_args: ET.SubElement(type_config, 'DebugInformationFormat').text = 'EditAndContinue' elif '/Zi' in buildtype_args: ET.SubElement(type_config, 'DebugInformationFormat').text = 'ProgramDatabase' elif '/Z7' in buildtype_args: ET.SubElement(type_config, 'DebugInformationFormat').text = 'OldStyle' # Generate Debug info if '/DEBUG' in buildtype_link_args: ET.SubElement(type_config, 'GenerateDebugInformation').text = 'true' # Runtime checks if '/RTC1' in buildtype_args: ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'EnableFastChecks' elif '/RTCu' in buildtype_args: ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'UninitializedLocalUsageCheck' elif '/RTCs' in buildtype_args: ET.SubElement(type_config, 'BasicRuntimeChecks').text = 'StackFrameRuntimeCheck' # Optimization flags if '/Ox' in o_flags: ET.SubElement(type_config, 'Optimization').text = 'Full' elif '/O2' in o_flags: ET.SubElement(type_config, 'Optimization').text = 'MaxSpeed' elif '/O1' in o_flags: ET.SubElement(type_config, 'Optimization').text = 'MinSpace' elif '/Od' in o_flags: ET.SubElement(type_config, 'Optimization').text = 'Disabled' # Warning level warning_level = self.get_option_for_target('warning_level', target) ET.SubElement(type_config, 'WarningLevel').text = 'Level' + warning_level # End configuration ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props') generated_files, custom_target_output_files, generated_files_include_dirs = self.generate_custom_generator_commands(target, root) (gen_src, gen_hdrs, gen_objs, gen_langs) = self.split_sources(generated_files) (custom_src, custom_hdrs, custom_objs, custom_langs) = self.split_sources(custom_target_output_files) gen_src += custom_src gen_hdrs += custom_hdrs gen_langs += custom_langs # Project information direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version outdir = ET.SubElement(direlem, 'OutDir') outdir.text = '.\\' intdir = ET.SubElement(direlem, 'IntDir') intdir.text = target.get_id() + '\\' tfilename = os.path.splitext(target.get_filename()) ET.SubElement(direlem, 'TargetName').text = tfilename[0] ET.SubElement(direlem, 'TargetExt').text = tfilename[1] # Build information compiles = ET.SubElement(root, 'ItemDefinitionGroup') clconf = ET.SubElement(compiles, 'ClCompile') # Arguments, include dirs, defines for all files in the current target target_args = [] target_defines = [] target_inc_dirs = [] # Arguments, include dirs, defines passed to individual files in # a target; perhaps because the args are language-specific # # file_args is also later split out into defines and include_dirs in # case someone passed those in there file_args = dict((lang, CompilerArgs(comp)) for lang, comp in target.compilers.items()) file_defines = dict((lang, []) for lang in target.compilers) file_inc_dirs = dict((lang, []) for lang in target.compilers) # The order in which these compile args are added must match # generate_single_compile() and generate_basic_compiler_args() for l, comp in target.compilers.items(): if l in file_args: file_args[l] += compilers.get_base_compile_args(self.environment.coredata.base_options, comp) file_args[l] += comp.get_option_compile_args(self.environment.coredata.compiler_options) # Add compile args added using add_project_arguments() for l, args in self.build.projects_args.get(target.subproject, {}).items(): if l in file_args: file_args[l] += args # Add compile args added using add_global_arguments() # These override per-project arguments for l, args in self.build.global_args.items(): if l in file_args: file_args[l] += args # Compile args added from the env: CFLAGS/CXXFLAGS, etc. We want these # to override all the defaults, but not the per-target compile args. for l, args in self.environment.coredata.external_args.items(): if l in file_args: file_args[l] += args for args in file_args.values(): # This is where Visual Studio will insert target_args, target_defines, # etc, which are added later from external deps (see below). args += ['%(AdditionalOptions)', '%(PreprocessorDefinitions)', '%(AdditionalIncludeDirectories)'] # Add include dirs from the `include_directories:` kwarg on the target # and from `include_directories:` of internal deps of the target. # # Target include dirs should override internal deps include dirs. # This is handled in BuildTarget.process_kwargs() # # Include dirs from internal deps should override include dirs from # external deps and must maintain the order in which they are # specified. Hence, we must reverse so that the order is preserved. # # These are per-target, but we still add them as per-file because we # need them to be looked in first. for d in reversed(target.get_include_dirs()): for i in d.get_incdirs(): curdir = os.path.join(d.get_curdir(), i) args.append('-I' + self.relpath(curdir, target.subdir)) # build dir args.append('-I' + os.path.join(proj_to_src_root, curdir)) # src dir for i in d.get_extra_build_dirs(): curdir = os.path.join(d.get_curdir(), i) args.append('-I' + self.relpath(curdir, target.subdir)) # build dir # Add per-target compile args, f.ex, `c_args : ['/DFOO']`. We set these # near the end since these are supposed to override everything else. for l, args in target.extra_args.items(): if l in file_args: file_args[l] += args # The highest priority includes. In order of directory search: # target private dir, target build dir, generated sources include dirs, # target source dir for args in file_args.values(): t_inc_dirs = ['.', self.relpath(self.get_target_private_dir(target), self.get_target_dir(target))] t_inc_dirs += generated_files_include_dirs + [proj_to_src_dir] args += ['-I' + arg for arg in t_inc_dirs] # Split preprocessor defines and include directories out of the list of # all extra arguments. The rest go into %(AdditionalOptions). for l, args in file_args.items(): for arg in args[:]: if arg.startswith(('-D', '/D')) or arg == '%(PreprocessorDefinitions)': file_args[l].remove(arg) # Don't escape the marker if arg == '%(PreprocessorDefinitions)': define = arg else: define = arg[2:] # De-dup if define in file_defines[l]: file_defines[l].remove(define) file_defines[l].append(define) elif arg.startswith(('-I', '/I')) or arg == '%(AdditionalIncludeDirectories)': file_args[l].remove(arg) # Don't escape the marker if arg == '%(AdditionalIncludeDirectories)': inc_dir = arg else: inc_dir = arg[2:] # De-dup if inc_dir not in file_inc_dirs[l]: file_inc_dirs[l].append(inc_dir) # Split compile args needed to find external dependencies # Link args are added while generating the link command for d in reversed(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_args_to_native(d.get_compile_args()) for arg in d_compile_args: if arg.startswith(('-D', '/D')): define = arg[2:] # De-dup if define in target_defines: target_defines.remove(define) target_defines.append(define) elif arg.startswith(('-I', '/I')): inc_dir = arg[2:] # De-dup if inc_dir not in target_inc_dirs: target_inc_dirs.append(inc_dir) else: target_args.append(arg) languages += gen_langs if len(target_args) > 0: target_args.append('%(AdditionalOptions)') ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(target_args) 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) ET.SubElement(clconf, 'MinimalRebuild').text = 'true' ET.SubElement(clconf, 'FunctionLevelLinking').text = 'true' pch_node = ET.SubElement(clconf, 'PrecompiledHeader') if self.get_option_for_target('werror', target): ET.SubElement(clconf, 'TreatWarningAsError').text = 'true' # Note: SuppressStartupBanner is /NOLOGO and is 'true' by default pch_sources = {} for lang in ['c', 'cpp']: pch = target.get_pch(lang) if len(pch) == 0: continue pch_node.text = 'Use' pch_sources[lang] = [pch[0], pch[1], lang] if len(pch_sources) == 1: # If there is only 1 language with precompiled headers, we can use it for the entire project, which # is cleaner than specifying it for each source file. pch_source = list(pch_sources.values())[0] header = os.path.join(proj_to_src_dir, pch_source[0]) pch_file = ET.SubElement(clconf, 'PrecompiledHeaderFile') pch_file.text = header pch_include = ET.SubElement(clconf, 'ForcedIncludeFiles') pch_include.text = header + ';%(ForcedIncludeFiles)' pch_out = ET.SubElement(clconf, 'PrecompiledHeaderOutputFile') pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % pch_source[2] resourcecompile = ET.SubElement(compiles, 'ResourceCompile') ET.SubElement(resourcecompile, 'PreprocessorDefinitions') # Linker options link = ET.SubElement(compiles, 'Link') extra_link_args = CompilerArgs(compiler) # FIXME: Can these buildtype linker args be added as tags in the # vcxproj file (similar to buildtype compiler args) instead of in # AdditionalOptions? extra_link_args += compiler.get_buildtype_linker_args(self.buildtype) if not isinstance(target, build.StaticLibrary): if isinstance(target, build.SharedModule): extra_link_args += compiler.get_std_shared_module_link_args() # Add link args added using add_project_link_arguments() extra_link_args += self.build.get_project_link_args(compiler, target.subproject) # Add link args added using add_global_link_arguments() # These override per-project link arguments extra_link_args += self.build.get_global_link_args(compiler) # Link args added from the env: LDFLAGS. We want these to # override all the defaults but not the per-target link args. extra_link_args += self.environment.coredata.external_link_args[compiler.get_language()] # Only non-static built targets need link args and link dependencies extra_link_args += target.link_args # External deps must be last because target link libraries may depend on them. for dep in target.get_external_deps(): extra_link_args += dep.get_link_args() for d in target.get_dependencies(): if isinstance(d, build.StaticLibrary): for dep in d.get_external_deps(): extra_link_args += dep.get_link_args() # Add link args for c_* or cpp_* build options. Currently this only # adds c_winlibs and cpp_winlibs when building for Windows. This needs # to be after all internal and external libraries so that unresolved # symbols from those can be found here. This is needed when the # *_winlibs that we want to link to are static mingw64 libraries. extra_link_args += compiler.get_option_link_args(self.environment.coredata.compiler_options) (additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args.to_native()) if len(extra_link_args) > 0: extra_link_args.append('%(AdditionalOptions)') ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_link_args) if len(additional_libpaths) > 0: additional_libpaths.insert(0, '%(AdditionalLibraryDirectories)') ET.SubElement(link, 'AdditionalLibraryDirectories').text = ';'.join(additional_libpaths) # Add more libraries to be linked if needed for t in target.get_dependencies(): lobj = self.build.targets[t.get_id()] linkname = os.path.join(down, self.get_target_filename_for_linking(lobj)) if t in target.link_whole_targets: linkname = compiler.get_link_whole_for(linkname)[0] additional_links.append(linkname) for lib in self.get_custom_target_provided_libraries(target): additional_links.append(self.relpath(lib, self.get_target_dir(target))) additional_objects = [] for o in self.flatten_object_list(target, down): assert(isinstance(o, str)) additional_objects.append(o) for o in custom_objs: additional_objects.append(o) if len(additional_links) > 0: additional_links.append('%(AdditionalDependencies)') ET.SubElement(link, 'AdditionalDependencies').text = ';'.join(additional_links) ofile = ET.SubElement(link, 'OutputFile') ofile.text = '$(OutDir)%s' % target.get_filename() subsys = ET.SubElement(link, 'SubSystem') subsys.text = subsystem if isinstance(target, build.SharedLibrary): # DLLs built with MSVC always have an import library except when # they're data-only DLLs, but we don't support those yet. ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename() # Add module definitions file, if provided if target.vs_module_defs: relpath = os.path.join(down, target.vs_module_defs.rel_to_builddir(self.build_to_src)) ET.SubElement(link, 'ModuleDefinitionFile').text = relpath if '/ZI' in buildtype_args or '/Zi' in buildtype_args: pdb = ET.SubElement(link, 'ProgramDataBaseFileName') pdb.text = '$(OutDir}%s.pdb' % target_name if isinstance(target, build.Executable): ET.SubElement(link, 'EntryPointSymbol').text = entrypoint targetmachine = ET.SubElement(link, 'TargetMachine') targetplatform = self.platform.lower() if targetplatform == 'win32': targetmachine.text = 'MachineX86' elif targetplatform == 'x64': targetmachine.text = 'MachineX64' elif targetplatform == 'arm': targetmachine.text = 'MachineARM' else: raise MesonException('Unsupported Visual Studio target machine: ' + targetmachine) extra_files = target.extra_files if len(headers) + len(gen_hdrs) + len(extra_files) > 0: inc_hdrs = ET.SubElement(root, 'ItemGroup') for h in headers: relpath = os.path.join(down, h.rel_to_builddir(self.build_to_src)) ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath) for h in gen_hdrs: ET.SubElement(inc_hdrs, 'CLInclude', Include=h) for h in target.extra_files: relpath = os.path.join(proj_to_src_dir, h) ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath) if len(sources) + len(gen_src) + len(pch_sources) > 0: inc_src = ET.SubElement(root, 'ItemGroup') 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(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(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) pch = ET.SubElement(inc_cl, 'PrecompiledHeader') pch.text = 'Create' pch_out = ET.SubElement(inc_cl, 'PrecompiledHeaderOutputFile') pch_out.text = '$(IntDir)$(TargetName)-%s.pch' % suffix pch_file = ET.SubElement(inc_cl, 'PrecompiledHeaderFile') # 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(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') for s in objects: relpath = os.path.join(down, s.rel_to_builddir(self.build_to_src)) ET.SubElement(inc_objs, 'Object', Include=relpath) for s in additional_objects: ET.SubElement(inc_objs, 'Object', Include=s) self.add_generated_objects(inc_objs, gen_objs) ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets') # Reference the regen target. ig = ET.SubElement(root, 'ItemGroup') pref = ET.SubElement(ig, 'ProjectReference', Include=os.path.join(self.environment.get_build_dir(), 'REGEN.vcxproj')) ET.SubElement(pref, 'Project').text = self.environment.coredata.regen_guid self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) def gen_regenproj(self, project_name, ofname): root = ET.Element('Project', {'DefaultTargets': 'Build', 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': self.buildtype + '|' + self.platform}) p = ET.SubElement(prjconf, 'Configuration') p.text = self.buildtype pl = ET.SubElement(prjconf, 'Platform') pl.text = self.platform globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem.text = self.environment.coredata.test_guid kw = ET.SubElement(globalgroup, 'Keyword') kw.text = self.platform + 'Proj' p = ET.SubElement(globalgroup, 'Platform') p.text = self.platform pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = project_name if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props') type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType').text = "Utility" ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' ET.SubElement(type_config, 'UseOfMfc').text = 'false' if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props') direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version outdir = ET.SubElement(direlem, 'OutDir') outdir.text = '.\\' intdir = ET.SubElement(direlem, 'IntDir') intdir.text = 'regen-temp\\' tname = ET.SubElement(direlem, 'TargetName') tname.text = project_name action = ET.SubElement(root, 'ItemDefinitionGroup') midl = ET.SubElement(action, 'Midl') ET.SubElement(midl, "AdditionalIncludeDirectories").text = '%(AdditionalIncludeDirectories)' ET.SubElement(midl, "OutputDirectory").text = '$(IntDir)' ET.SubElement(midl, 'HeaderFileName').text = '%(Filename).h' ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb' ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c' ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c' regen_command = [sys.executable, self.environment.get_build_command(), '--internal', 'regencheck'] private_dir = self.environment.get_scratch_dir() cmd_templ = '''setlocal "%s" "%s" if %%errorlevel%% neq 0 goto :cmEnd :cmEnd endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone :cmErrorLevel exit /b %%1 :cmDone if %%errorlevel%% neq 0 goto :VCEnd''' igroup = ET.SubElement(root, 'ItemGroup') rulefile = os.path.join(self.environment.get_scratch_dir(), 'regen.rule') if not os.path.exists(rulefile): with open(rulefile, 'w') as f: f.write("# Meson regen file.") custombuild = ET.SubElement(igroup, 'CustomBuild', Include=rulefile) message = ET.SubElement(custombuild, 'Message') message.text = 'Checking whether solution needs to be regenerated.' ET.SubElement(custombuild, 'Command').text = cmd_templ % \ ('" "'.join(regen_command), private_dir) ET.SubElement(custombuild, 'Outputs').text = Vs2010Backend.get_regen_stampfile(self.environment.get_build_dir()) deps = self.get_regen_filelist() ET.SubElement(custombuild, 'AdditionalInputs').text = ';'.join(deps) ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets') ET.SubElement(root, 'ImportGroup', Label='ExtensionTargets') self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) def gen_testproj(self, target_name, ofname): project_name = target_name root = ET.Element('Project', {'DefaultTargets': "Build", 'ToolsVersion': '4.0', 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) confitems = ET.SubElement(root, 'ItemGroup', {'Label': 'ProjectConfigurations'}) prjconf = ET.SubElement(confitems, 'ProjectConfiguration', {'Include': self.buildtype + '|' + self.platform}) p = ET.SubElement(prjconf, 'Configuration') p.text = self.buildtype pl = ET.SubElement(prjconf, 'Platform') pl.text = self.platform globalgroup = ET.SubElement(root, 'PropertyGroup', Label='Globals') guidelem = ET.SubElement(globalgroup, 'ProjectGuid') guidelem.text = self.environment.coredata.test_guid kw = ET.SubElement(globalgroup, 'Keyword') kw.text = self.platform + 'Proj' p = ET.SubElement(globalgroup, 'Platform') p.text = self.platform pname = ET.SubElement(globalgroup, 'ProjectName') pname.text = project_name if self.windows_target_platform_version: ET.SubElement(globalgroup, 'WindowsTargetPlatformVersion').text = self.windows_target_platform_version ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props') type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') ET.SubElement(type_config, 'ConfigurationType') ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' ET.SubElement(type_config, 'UseOfMfc').text = 'false' if self.platform_toolset: ET.SubElement(type_config, 'PlatformToolset').text = self.platform_toolset ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props') direlem = ET.SubElement(root, 'PropertyGroup') fver = ET.SubElement(direlem, '_ProjectFileVersion') fver.text = self.project_file_version outdir = ET.SubElement(direlem, 'OutDir') outdir.text = '.\\' intdir = ET.SubElement(direlem, 'IntDir') intdir.text = 'test-temp\\' tname = ET.SubElement(direlem, 'TargetName') tname.text = target_name action = ET.SubElement(root, 'ItemDefinitionGroup') midl = ET.SubElement(action, 'Midl') ET.SubElement(midl, "AdditionalIncludeDirectories").text = '%(AdditionalIncludeDirectories)' ET.SubElement(midl, "OutputDirectory").text = '$(IntDir)' ET.SubElement(midl, 'HeaderFileName').text = '%(Filename).h' ET.SubElement(midl, 'TypeLibraryName').text = '%(Filename).tlb' ET.SubElement(midl, 'InterfaceIdentifierFilename').text = '%(Filename)_i.c' ET.SubElement(midl, 'ProxyFileName').text = '%(Filename)_p.c' postbuild = ET.SubElement(action, 'PostBuildEvent') ET.SubElement(postbuild, 'Message') # FIXME: No benchmarks? test_command = [sys.executable, get_meson_script(self.environment, 'mesontest'), '--no-rebuild'] if not self.environment.coredata.get_builtin_option('stdsplit'): test_command += ['--no-stdsplit'] if self.environment.coredata.get_builtin_option('errorlogs'): test_command += ['--print-errorlogs'] cmd_templ = '''setlocal "%s" if %%errorlevel%% neq 0 goto :cmEnd :cmEnd endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone :cmErrorLevel exit /b %%1 :cmDone if %%errorlevel%% neq 0 goto :VCEnd''' self.serialise_tests() ET.SubElement(postbuild, 'Command').text =\ cmd_templ % ('" "'.join(test_command)) ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets') self._prettyprint_vcxproj_xml(ET.ElementTree(root), ofname) meson-0.40.1/mesonbuild/backend/backends.py0000644000175000017500000010516213076164167022203 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os, pickle, re from .. import build from .. import dependencies from .. import mesonlib from .. import mlog from .. import compilers import json import subprocess from ..mesonlib import MesonException, get_meson_script from ..mesonlib import get_compiler_for_source, classify_unity_sources from ..compilers import CompilerArgs from collections import OrderedDict class CleanTrees: ''' Directories outputted by custom targets that have to be manually cleaned because on Linux `ninja clean` only deletes empty directories. ''' def __init__(self, build_dir, trees): self.build_dir = build_dir self.trees = trees class InstallData: def __init__(self, source_dir, build_dir, prefix, strip_bin, mesonintrospect): self.source_dir = source_dir self.build_dir = build_dir self.prefix = prefix self.strip_bin = strip_bin self.targets = [] self.headers = [] self.man = [] self.data = [] self.po_package_name = '' 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, workdir, extra_paths, capture): self.name = name self.fname = fname self.cmd_args = cmd_args self.env = env self.is_cross = is_cross self.exe_runner = exe_wrapper self.workdir = workdir self.extra_paths = extra_paths self.capture = capture class TestSerialisation: def __init__(self, name, suite, fname, is_cross, exe_wrapper, is_parallel, cmd_args, env, should_fail, timeout, workdir, extra_paths): self.name = name self.suite = suite self.fname = fname self.is_cross = is_cross self.exe_runner = exe_wrapper self.is_parallel = is_parallel self.cmd_args = cmd_args self.env = env self.should_fail = should_fail self.timeout = timeout self.workdir = workdir self.extra_paths = extra_paths class OptionProxy: def __init__(self, name, value): self.name = name self.value = value class OptionOverrideProxy: '''Mimic an option list but transparently override selected option values.''' def __init__(self, overrides, options): self.overrides = overrides self.options = options def __getitem__(self, option_name): base_opt = self.options[option_name] if option_name in self.overrides: return OptionProxy(base_opt.name, base_opt.validate_value(self.overrides[option_name])) return base_opt # This class contains the basic functionality that is needed by all backends. # Feel free to move stuff in and out of it as you see fit. class Backend: def __init__(self, build): self.build = build self.environment = build.environment self.processed_targets = {} self.build_to_src = os.path.relpath(self.environment.get_source_dir(), self.environment.get_build_dir()) for t in self.build.targets: priv_dirname = self.get_target_private_dir_abs(t) os.makedirs(priv_dirname, exist_ok=True) def get_target_filename(self, t): if isinstance(t, build.CustomTarget): if len(t.get_outputs()) != 1: 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)) filename = t.get_filename() return os.path.join(self.get_target_dir(t), filename) def get_target_filename_abs(self, target): return os.path.join(self.environment.get_build_dir(), self.get_target_filename(target)) def get_option_for_target(self, option_name, target): if option_name in target.option_overrides: override = target.option_overrides[option_name] return self.environment.coredata.validate_option_value(option_name, override) return self.environment.coredata.get_builtin_option(option_name) def get_target_filename_for_linking(self, target): # On some platforms (msvc for instance), the file that is used for # dynamic linking is not the same as the dynamic library itself. This # file is called an import library, and we want to link against that. # On all other platforms, we link to the library directly. if isinstance(target, build.SharedLibrary): link_lib = target.get_import_filename() or target.get_filename() return os.path.join(self.get_target_dir(target), link_lib) elif isinstance(target, build.StaticLibrary): return os.path.join(self.get_target_dir(target), target.get_filename()) raise AssertionError('BUG: Tried to link to something that\'s not a library') def get_target_dir(self, target): if self.environment.coredata.get_builtin_option('layout') == 'mirror': dirname = target.get_subdir() else: dirname = 'meson-out' return dirname def get_target_private_dir(self, target): dirname = os.path.join(self.get_target_dir(target), target.get_basename() + target.type_suffix()) return dirname def get_target_private_dir_abs(self, target): dirname = os.path.join(self.environment.get_build_dir(), self.get_target_private_dir(target)) return dirname def get_target_generated_dir(self, target, gensrc, src): """ Takes a BuildTarget, a generator source (CustomTarget or GeneratedList), and a generated source filename. Returns the full path of the generated source relative to the build root """ # CustomTarget generators output to the build dir of the CustomTarget if isinstance(gensrc, build.CustomTarget): return os.path.join(self.get_target_dir(gensrc), src) # GeneratedList generators output to the private build directory of the # target that the GeneratedList is used in return os.path.join(self.get_target_private_dir(target), src) def get_unity_source_filename(self, target, suffix): return target.name + '-unity.' + suffix def generate_unity_files(self, target, unity_src): abs_files = [] result = [] compsrcs = classify_unity_sources(target.compilers.values(), unity_src) def init_language_file(suffix): unity_src_name = self.get_unity_source_filename(target, suffix) unity_src_subdir = self.get_target_private_dir_abs(target) outfilename = os.path.join(unity_src_subdir, unity_src_name) outfileabs = os.path.join(self.environment.get_build_dir(), outfilename) outfileabs_tmp = outfileabs + '.tmp' abs_files.append(outfileabs) outfileabs_tmp_dir = os.path.dirname(outfileabs_tmp) if not os.path.exists(outfileabs_tmp_dir): os.makedirs(outfileabs_tmp_dir) result.append(mesonlib.File(True, unity_src_subdir, unity_src_name)) return open(outfileabs_tmp, 'w') # For each language, generate a unity source file and return the list for comp, srcs in compsrcs.items(): with init_language_file(comp.get_default_suffix()) as ofile: for src in srcs: ofile.write('#include<%s>\n' % src) [mesonlib.replace_if_different(x, x + '.tmp') for x in abs_files] return result def relpath(self, todir, fromdir): return os.path.relpath(os.path.join('dummyprefixdir', todir), os.path.join('dummyprefixdir', fromdir)) def flatten_object_list(self, target, proj_dir_to_build_root=''): obj_list = [] for obj in target.get_objects(): if isinstance(obj, str): o = os.path.join(proj_dir_to_build_root, self.build_to_src, target.get_subdir(), obj) obj_list.append(o) elif isinstance(obj, mesonlib.File): obj_list.append(obj.rel_to_builddir(self.build_to_src)) elif isinstance(obj, build.ExtractedObjects): obj_list += self.determine_ext_objs(target, obj, proj_dir_to_build_root) else: raise MesonException('Unknown data type in object list.') return obj_list def serialise_executable(self, exe, cmd_args, workdir, env={}, capture=None): import hashlib # Can't just use exe.name here; it will likely be run more than once if isinstance(exe, (dependencies.ExternalProgram, build.BuildTarget, build.CustomTarget)): basename = exe.name else: basename = os.path.basename(exe) # Take a digest of the cmd args, env, workdir, and capture. This avoids # collisions and also makes the name deterministic over regenerations # which avoids a rebuild by Ninja because the cmdline stays the same. data = bytes(str(sorted(env.items())) + str(cmd_args) + str(workdir) + str(capture), encoding='utf-8') digest = hashlib.sha1(data).hexdigest() scratch_file = 'meson_exe_{0}_{1}.dat'.format(basename, digest) exe_data = os.path.join(self.environment.get_scratch_dir(), scratch_file) with open(exe_data, 'wb') as f: if isinstance(exe, dependencies.ExternalProgram): exe_cmd = exe.get_command() exe_needs_wrapper = False elif isinstance(exe, (build.BuildTarget, build.CustomTarget)): exe_cmd = [self.get_target_filename_abs(exe)] exe_needs_wrapper = exe.is_cross else: exe_cmd = [exe] exe_needs_wrapper = False is_cross = exe_needs_wrapper and \ self.environment.is_cross_build() and \ self.environment.cross_info.need_cross_compiler() and \ self.environment.cross_info.need_exe_wrapper() if is_cross: exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None) else: exe_wrapper = None if mesonlib.is_windows() or mesonlib.is_cygwin(): extra_paths = self.determine_windows_extra_paths(exe) else: extra_paths = [] es = ExecutableSerialisation(basename, exe_cmd, cmd_args, env, is_cross, exe_wrapper, workdir, extra_paths, capture) pickle.dump(es, f) return exe_data def serialise_tests(self): test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') with open(test_data, 'wb') as datafile: self.write_test_file(datafile) benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat') with open(benchmark_data, 'wb') as datafile: self.write_benchmark_file(datafile) return test_data, benchmark_data def determine_linker(self, target): ''' If we're building a static library, there is only one static linker. Otherwise, we query the target for the dynamic linker. ''' if isinstance(target, build.StaticLibrary): if target.is_cross: return self.build.static_cross_linker else: return self.build.static_linker l = target.get_clike_dynamic_linker() if not l: m = "Couldn't determine linker for target {!r}" raise MesonException(m.format(target.name)) return l def object_filename_from_source(self, target, source, is_unity): if isinstance(source, mesonlib.File): source = source.fname # foo.vala files compile down to foo.c and then foo.c.o, not foo.vala.o if source.endswith('.vala'): if is_unity: return source[:-5] + '.c.' + self.environment.get_object_suffix() source = os.path.join(self.get_target_private_dir(target), source[:-5] + '.c') return source.replace('/', '_').replace('\\', '_') + '.' + self.environment.get_object_suffix() def determine_ext_objs(self, target, extobj, proj_dir_to_build_root): result = [] targetdir = self.get_target_private_dir(extobj.target) # With unity builds, there's just one object that contains all the # sources, and we only support extracting all the objects in this mode, # so just return that. if self.is_unity(target): comp = get_compiler_for_source(extobj.target.compilers.values(), extobj.srclist[0]) # There is a potential conflict here, but it is unlikely that # anyone both enables unity builds and has a file called foo-unity.cpp. osrc = self.get_unity_source_filename(extobj.target, comp.get_default_suffix()) objname = self.object_filename_from_source(extobj.target, osrc, True) objpath = os.path.join(proj_dir_to_build_root, targetdir, objname) return [objpath] for osrc in extobj.srclist: objname = self.object_filename_from_source(extobj.target, osrc, False) objpath = os.path.join(proj_dir_to_build_root, targetdir, objname) result.append(objpath) return result def get_pch_include_args(self, compiler, target): args = [] pchpath = self.get_target_private_dir(target) includeargs = compiler.get_include_args(pchpath, False) for lang in ['c', 'cpp']: p = target.get_pch(lang) if len(p) == 0: continue if compiler.can_compile(p[-1]): header = p[0] args += compiler.get_pch_use_args(pchpath, header) if len(args) > 0: args = includeargs + args return args @staticmethod def escape_extra_args(compiler, args): # No extra escaping/quoting needed when not running on Windows if not mesonlib.is_windows(): return args extra_args = [] # Compiler-specific escaping is needed for -D args but not for any others if compiler.get_id() == 'msvc': # MSVC needs escaping when a -D argument ends in \ or \" for arg in args: if arg.startswith('-D') or arg.startswith('/D'): # Without extra escaping for these two, the next character # gets eaten if arg.endswith('\\'): arg += '\\' elif arg.endswith('\\"'): arg = arg[:-2] + '\\\\"' extra_args.append(arg) else: # MinGW GCC needs all backslashes in defines to be doubly-escaped # FIXME: Not sure about Cygwin or Clang for arg in args: if arg.startswith('-D') or arg.startswith('/D'): arg = arg.replace('\\', '\\\\') extra_args.append(arg) return extra_args def generate_basic_compiler_args(self, target, compiler, no_warn_args=False): # Create an empty commands list, and start adding arguments from # various sources in the order in which they must override each other # starting from hard-coded defaults followed by build options and so on. commands = CompilerArgs(compiler) copt_proxy = OptionOverrideProxy(target.option_overrides, self.environment.coredata.compiler_options) # First, the trivial ones that are impossible to override. # # Add -nostdinc/-nostdinc++ if needed; can't be overriden commands += self.get_cross_stdlib_args(target, compiler) # Add things like /NOLOGO or -pipe; usually can't be overriden commands += compiler.get_always_args() # Only add warning-flags by default if the buildtype enables it, and if # we weren't explicitly asked to not emit warnings (for Vala, f.ex) if no_warn_args: commands += compiler.get_no_warn_args() elif self.get_option_for_target('buildtype', target) != 'plain': commands += compiler.get_warn_args(self.get_option_for_target('warning_level', target)) # Add -Werror if werror=true is set in the build options set on the # command-line or default_options inside project(). This only sets the # action to be done for warnings if/when they are emitted, so it's ok # to set it after get_no_warn_args() or get_warn_args(). if self.get_option_for_target('werror', target): commands += compiler.get_werror_args() # Add compile args for c_* or cpp_* build options set on the # command-line or default_options inside project(). commands += compiler.get_option_compile_args(copt_proxy) # Add buildtype args: optimization level, debugging, etc. commands += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target)) # Add compile args added using add_project_arguments() commands += self.build.get_project_args(compiler, target.subproject) # Add compile args added using add_global_arguments() # These override per-project arguments commands += self.build.get_global_args(compiler) # Compile args added from the env: CFLAGS/CXXFLAGS, etc. We want these # to override all the defaults, but not the per-target compile args. commands += self.environment.coredata.external_args[compiler.get_language()] # Always set -fPIC for shared libraries if isinstance(target, build.SharedLibrary): commands += compiler.get_pic_args() # Set -fPIC for static libraries by default unless explicitly disabled if isinstance(target, build.StaticLibrary) and target.pic: commands += compiler.get_pic_args() # Add compile args needed to find external dependencies. Link args are # added while generating the link command. # NOTE: We must preserve the order in which external deps are # specified, so we reverse the list before iterating over it. for dep in reversed(target.get_external_deps()): commands += dep.get_compile_args() # Qt needs -fPIC for executables # XXX: We should move to -fPIC for all executables if isinstance(target, build.Executable): commands += dep.get_exe_args(compiler) # For 'automagic' deps: Boost and GTest. Also dependency('threads'). # pkg-config puts the thread flags itself via `Cflags:` if dep.need_threads(): commands += compiler.thread_flags() # Fortran requires extra include directives. if compiler.language == 'fortran': for lt in target.link_targets: priv_dir = os.path.join(self.get_target_dir(lt), lt.get_basename() + lt.type_suffix()) incflag = compiler.get_include_args(priv_dir, False) commands += incflag return commands def build_target_link_arguments(self, compiler, deps): args = [] for d in deps: if not isinstance(d, (build.StaticLibrary, build.SharedLibrary)): raise RuntimeError('Tried to link with a non-library target "%s".' % d.get_basename()) if isinstance(compiler, compilers.LLVMDCompiler) or isinstance(compiler, compilers.DmdDCompiler): args += ['-L' + self.get_target_filename_for_linking(d)] else: args.append(self.get_target_filename_for_linking(d)) # If you have executable e that links to shared lib s1 that links to shared library s2 # you have to specify s2 as well as s1 when linking e even if e does not directly use # s2. Gcc handles this case fine but Clang does not for some reason. Thus we need to # explictly specify all libraries every time. args += self.build_target_link_arguments(compiler, d.get_dependencies()) return args def determine_windows_extra_paths(self, target): '''On Windows there is no such thing as an rpath. We must determine all locations of DLLs that this exe links to and return them so they can be used in unit tests.''' if not isinstance(target, build.Executable): return [] prospectives = target.get_transitive_link_deps() result = [] for ld in prospectives: if ld == '' or ld == '.': continue dirseg = os.path.join(self.environment.get_build_dir(), self.get_target_dir(ld)) if dirseg not in result: result.append(dirseg) return result def write_benchmark_file(self, datafile): self.write_test_serialisation(self.build.get_benchmarks(), datafile) def write_test_file(self, datafile): self.write_test_serialisation(self.build.get_tests(), datafile) def write_test_serialisation(self, tests, datafile): arr = [] for t in tests: exe = t.get_exe() if isinstance(exe, dependencies.ExternalProgram): cmd = exe.get_command() else: cmd = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(t.get_exe()))] is_cross = self.environment.is_cross_build() and \ self.environment.cross_info.need_cross_compiler() and \ self.environment.cross_info.need_exe_wrapper() if is_cross: exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None) else: exe_wrapper = None if mesonlib.is_windows() or mesonlib.is_cygwin(): extra_paths = self.determine_windows_extra_paths(exe) else: extra_paths = [] cmd_args = [] for a in t.cmd_args: if hasattr(a, 'held_object'): a = a.held_object if isinstance(a, mesonlib.File): a = os.path.join(self.environment.get_build_dir(), a.rel_to_builddir(self.build_to_src)) cmd_args.append(a) elif isinstance(a, str): cmd_args.append(a) elif isinstance(a, build.Target): cmd_args.append(self.get_target_filename(a)) else: raise MesonException('Bad object in test command.') ts = TestSerialisation(t.get_name(), t.suite, cmd, is_cross, exe_wrapper, t.is_parallel, cmd_args, t.env, t.should_fail, t.timeout, t.workdir, extra_paths) arr.append(ts) pickle.dump(arr, datafile) def generate_depmf_install(self, d): if self.build.dep_manifest_name is None: return ifilename = os.path.join(self.environment.get_build_dir(), 'depmf.json') ofilename = os.path.join(self.environment.get_prefix(), self.build.dep_manifest_name) mfobj = {'type': 'dependency manifest', 'version': '1.0'} mfobj['projects'] = self.build.dep_manifest with open(ifilename, 'w') as f: f.write(json.dumps(mfobj)) # Copy file from, to, and with mode unchanged d.data.append([ifilename, ofilename, None]) def get_regen_filelist(self): '''List of all files whose alteration means that the build definition needs to be regenerated.''' deps = [os.path.join(self.build_to_src, df) for df in self.interpreter.get_build_def_files()] if self.environment.is_cross_build(): deps.append(os.path.join(self.build_to_src, self.environment.coredata.cross_file)) deps.append('meson-private/coredata.dat') if os.path.exists(os.path.join(self.environment.get_source_dir(), 'meson_options.txt')): deps.append(os.path.join(self.build_to_src, 'meson_options.txt')) for sp in self.build.subprojects.keys(): fname = os.path.join(self.environment.get_source_dir(), sp, 'meson_options.txt') if os.path.isfile(fname): deps.append(os.path.join(self.build_to_src, sp, 'meson_options.txt')) return deps def exe_object_to_cmd_array(self, exe): if self.environment.is_cross_build() and \ self.environment.cross_info.need_exe_wrapper() and \ isinstance(exe, build.BuildTarget) and exe.is_cross: if 'exe_wrapper' not in self.environment.cross_info.config['binaries']: s = 'Can not use target %s as a generator because it is cross-built\n' s += 'and no exe wrapper is defined. You might want to set it to native instead.' s = s % exe.name raise MesonException(s) if isinstance(exe, build.BuildTarget): exe_arr = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))] else: exe_arr = exe.get_command() return exe_arr def replace_extra_args(self, args, genlist): final_args = [] for a in args: if a == '@EXTRA_ARGS@': final_args += genlist.get_extra_args() else: final_args.append(a) return final_args def replace_outputs(self, args, private_dir, output_list): newargs = [] regex = re.compile('@OUTPUT(\d+)@') for arg in args: m = regex.search(arg) while m is not None: index = int(m.group(1)) src = '@OUTPUT%d@' % index arg = arg.replace(src, os.path.join(private_dir, output_list[index])) m = regex.search(arg) newargs.append(arg) return newargs def get_build_by_default_targets(self): result = OrderedDict() # Get all build and custom targets that must be built by default for name, t in self.build.get_targets().items(): if t.build_by_default or t.install or t.build_always: result[name] = t # Get all targets used as test executables and arguments. These must # also be built by default. XXX: Sometime in the future these should be # built only before running tests. for t in self.build.get_tests(): exe = t.exe if hasattr(exe, 'held_object'): exe = exe.held_object if isinstance(exe, (build.CustomTarget, build.BuildTarget)): result[exe.get_id()] = exe for arg in t.cmd_args: if hasattr(arg, 'held_object'): arg = arg.held_object if not isinstance(arg, (build.CustomTarget, build.BuildTarget)): continue result[arg.get_id()] = arg return result def get_custom_target_provided_libraries(self, target): libs = [] for t in target.get_generated_sources(): if not isinstance(t, build.CustomTarget): continue for f in t.get_outputs(): if self.environment.is_library(f): libs.append(os.path.join(self.get_target_dir(t), f)) return libs def is_unity(self, target): optval = self.get_option_for_target('unity', target) if optval == 'on' or (optval == 'subprojects' and target.subproject != ''): return True return False def get_custom_target_sources(self, target): ''' Custom target sources can be of various object types; strings, File, BuildTarget, even other CustomTargets. Returns the path to them relative to the build root directory. ''' srcs = [] for i in target.get_sources(): if hasattr(i, 'held_object'): i = i.held_object if isinstance(i, str): fname = [os.path.join(self.build_to_src, target.subdir, i)] elif isinstance(i, build.BuildTarget): fname = [self.get_target_filename(i)] elif isinstance(i, build.CustomTarget): fname = [os.path.join(self.get_target_dir(i), p) for p in i.get_outputs()] elif isinstance(i, build.GeneratedList): fname = [os.path.join(self.get_target_private_dir(target), p) for p in i.get_outputs()] else: fname = [i.rel_to_builddir(self.build_to_src)] if target.absolute_paths: fname = [os.path.join(self.environment.get_build_dir(), f) for f in fname] srcs += fname return srcs def get_custom_target_depend_files(self, target, absolute_paths=False): deps = [] for i in target.depend_files: if isinstance(i, mesonlib.File): if absolute_paths: deps.append(i.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir())) else: deps.append(i.rel_to_builddir(self.build_to_src)) else: if absolute_paths: deps.append(os.path.join(self.environment.get_build_dir(), i)) else: deps.append(os.path.join(self.build_to_src, i)) return deps def eval_custom_target_command(self, target, absolute_outputs=False): # We want the outputs to be absolute only when using the VS backend # XXX: Maybe allow the vs backend to use relative paths too? source_root = self.build_to_src build_root = '.' outdir = self.get_target_dir(target) if absolute_outputs: source_root = self.environment.get_source_dir() build_root = self.environment.get_source_dir() outdir = os.path.join(self.environment.get_build_dir(), outdir) outputs = [] for i in target.get_outputs(): outputs.append(os.path.join(outdir, i)) inputs = self.get_custom_target_sources(target) # Evaluate the command list cmd = [] for i in target.command: if isinstance(i, build.Executable): cmd += self.exe_object_to_cmd_array(i) continue elif isinstance(i, build.CustomTarget): # GIR scanner will attempt to execute this binary but # it assumes that it is in path, so always give it a full path. tmp = i.get_outputs()[0] i = os.path.join(self.get_target_dir(i), tmp) elif isinstance(i, mesonlib.File): i = i.rel_to_builddir(self.build_to_src) if target.absolute_paths: i = os.path.join(self.environment.get_build_dir(), i) # FIXME: str types are blindly added ignoring 'target.absolute_paths' # because we can't know if they refer to a file or just a string elif not isinstance(i, str): err_msg = 'Argument {0} is of unknown type {1}' raise RuntimeError(err_msg.format(str(i), str(type(i)))) elif '@SOURCE_ROOT@' in i: i = i.replace('@SOURCE_ROOT@', source_root) elif '@BUILD_ROOT@' in i: i = i.replace('@BUILD_ROOT@', build_root) elif '@DEPFILE@' in i: if target.depfile is None: msg = 'Custom target {!r} has @DEPFILE@ but no depfile ' \ 'keyword argument.'.format(target.name) raise MesonException(msg) dfilename = os.path.join(outdir, target.depfile) i = i.replace('@DEPFILE@', dfilename) elif '@PRIVATE_OUTDIR_' in i: match = re.search('@PRIVATE_OUTDIR_(ABS_)?([^/\s*]*)@', i) if not match: msg = 'Custom target {!r} has an invalid argument {!r}' \ ''.format(target.name, i) raise MesonException(msg) source = match.group(0) if match.group(1) is None and not target.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) # Substitute the rest of the template strings values = mesonlib.get_filenames_templates_dict(inputs, outputs) cmd = mesonlib.substitute_values(cmd, values) # This should not be necessary but removing it breaks # building GStreamer on Windows. The underlying issue # is problems with quoting backslashes on Windows # which is the seventh circle of hell. The downside is # that this breaks custom targets whose command lines # have backslashes. If you try to fix this be sure to # check that it does not break GST. # # The bug causes file paths such as c:\foo to get escaped # into c:\\foo. # # Unfortunately we have not been able to come up with an # isolated test case for this so unless you manage to come up # with one, the only way is to test the building with Gst's # setup. Note this in your MR or ping us and we will get it # fixed. # # https://github.com/mesonbuild/meson/pull/737 cmd = [i.replace('\\', '/') for i in cmd] return inputs, outputs, cmd 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) for s in self.build.postconf_scripts: cmd = s['exe'] + s['args'] subprocess.check_call(cmd, env=child_env) meson-0.40.1/mesonbuild/backend/xcodebackend.py0000644000175000017500000010752313035766234023044 0ustar jpakkanejpakkane00000000000000# Copyright 2014-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from . import backends from .. import build from .. import mesonlib import uuid, os, sys from ..mesonlib import MesonException class XCodeBackend(backends.Backend): def __init__(self, build): super().__init__(build) self.name = 'xcode' self.project_uid = self.environment.coredata.guid.replace('-', '')[:24] self.project_conflist = self.gen_id() self.indent = ' ' self.indent_level = 0 self.xcodetypemap = {'c': 'sourcecode.c.c', 'a': 'archive.ar', 'cc': 'sourcecode.cpp.cpp', 'cxx': 'sourcecode.cpp.cpp', 'cpp': 'sourcecode.cpp.cpp', 'c++': 'sourcecode.cpp.cpp', 'm': 'sourcecode.c.objc', 'mm': 'sourcecode.cpp.objcpp', 'h': 'sourcecode.c.h', 'hpp': 'sourcecode.cpp.h', 'hxx': 'sourcecode.cpp.h', 'hh': 'sourcecode.cpp.hh', 'inc': 'sourcecode.c.h', 'dylib': 'compiled.mach-o.dylib', 'o': 'compiled.mach-o.objfile', } self.maingroup_id = self.gen_id() self.all_id = self.gen_id() self.all_buildconf_id = self.gen_id() self.buildtypes = ['debug'] self.test_id = self.gen_id() self.test_command_id = self.gen_id() self.test_buildconf_id = self.gen_id() def gen_id(self): return str(uuid.uuid4()).upper().replace('-', '')[:24] def get_target_dir(self, target): dirname = os.path.join(target.get_subdir(), self.environment.coredata.get_builtin_option('buildtype')) os.makedirs(os.path.join(self.environment.get_build_dir(), dirname), exist_ok=True) return dirname def write_line(self, text): self.ofile.write(self.indent * self.indent_level + text) if not text.endswith('\n'): self.ofile.write('\n') def generate(self, interp): self.interpreter = interp test_data = self.serialise_tests()[0] self.generate_filemap() self.generate_buildmap() self.generate_buildstylemap() self.generate_build_phase_map() self.generate_build_configuration_map() self.generate_build_configurationlist_map() self.generate_project_configurations_map() self.generate_buildall_configurations_map() self.generate_test_configurations_map() self.generate_native_target_map() self.generate_source_phase_map() self.generate_target_dependency_map() self.generate_pbxdep_map() self.generate_containerproxy_map() self.proj_dir = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.xcodeproj') os.makedirs(self.proj_dir, exist_ok=True) self.proj_file = os.path.join(self.proj_dir, 'project.pbxproj') with open(self.proj_file, 'w') as self.ofile: self.generate_prefix() self.generate_pbx_aggregate_target() self.generate_pbx_build_file() self.generate_pbx_build_style() self.generate_pbx_container_item_proxy() self.generate_pbx_file_reference() self.generate_pbx_group() self.generate_pbx_native_target() self.generate_pbx_project() self.generate_pbx_shell_build_phase(test_data) self.generate_pbx_sources_build_phase() self.generate_pbx_target_dependency() self.generate_xc_build_configuration() self.generate_xc_configurationList() self.generate_suffix() def get_xcodetype(self, fname): return self.xcodetypemap[fname.split('.')[-1]] def generate_filemap(self): self.filemap = {} # Key is source file relative to src root. self.target_filemap = {} for name, t in self.build.targets.items(): for s in t.sources: if isinstance(s, mesonlib.File): s = os.path.join(s.subdir, s.fname) self.filemap[s] = self.gen_id() for o in t.objects: if isinstance(o, str): o = os.path.join(t.subdir, o) self.filemap[o] = self.gen_id() self.target_filemap[name] = self.gen_id() def generate_buildmap(self): self.buildmap = {} for t in self.build.targets.values(): for s in t.sources: s = os.path.join(s.subdir, s.fname) self.buildmap[s] = self.gen_id() for o in t.objects: o = os.path.join(t.subdir, o) if isinstance(o, str): self.buildmap[o] = self.gen_id() def generate_buildstylemap(self): self.buildstylemap = {'debug': self.gen_id()} def generate_build_phase_map(self): self.buildphasemap = {} for t in self.build.targets: self.buildphasemap[t] = self.gen_id() def generate_build_configuration_map(self): self.buildconfmap = {} for t in self.build.targets: bconfs = {'debug': self.gen_id()} self.buildconfmap[t] = bconfs def generate_project_configurations_map(self): self.project_configurations = {'debug': self.gen_id()} def generate_buildall_configurations_map(self): self.buildall_configurations = {'debug': self.gen_id()} def generate_test_configurations_map(self): self.test_configurations = {'debug': self.gen_id()} def generate_build_configurationlist_map(self): self.buildconflistmap = {} for t in self.build.targets: self.buildconflistmap[t] = self.gen_id() def generate_native_target_map(self): self.native_targets = {} for t in self.build.targets: self.native_targets[t] = self.gen_id() def generate_target_dependency_map(self): self.target_dependency_map = {} for tname, t in self.build.targets.items(): for target in t.link_targets: self.target_dependency_map[(tname, target.get_basename())] = self.gen_id() def generate_pbxdep_map(self): self.pbx_dep_map = {} for t in self.build.targets: self.pbx_dep_map[t] = self.gen_id() def generate_containerproxy_map(self): self.containerproxy_map = {} for t in self.build.targets: self.containerproxy_map[t] = self.gen_id() def generate_source_phase_map(self): self.source_phase = {} for t in self.build.targets: self.source_phase[t] = self.gen_id() def generate_pbx_aggregate_target(self): self.ofile.write('\n/* Begin PBXAggregateTarget section */\n') self.write_line('%s /* ALL_BUILD */ = {' % self.all_id) self.indent_level += 1 self.write_line('isa = PBXAggregateTarget;') self.write_line('buildConfigurationList = %s;' % self.all_buildconf_id) self.write_line('buildPhases = (') self.write_line(');') self.write_line('dependencies = (') self.indent_level += 1 for t in self.build.targets: self.write_line('%s /* PBXTargetDependency */,' % self.pbx_dep_map[t]) self.indent_level -= 1 self.write_line(');') self.write_line('name = ALL_BUILD;') self.write_line('productName = ALL_BUILD;') self.indent_level -= 1 self.write_line('};') self.write_line('%s /* RUN_TESTS */ = {' % self.test_id) self.indent_level += 1 self.write_line('isa = PBXAggregateTarget;') self.write_line('buildConfigurationList = %s;' % self.test_buildconf_id) self.write_line('buildPhases = (') self.indent_level += 1 self.write_line('%s /* test run command */,' % self.test_command_id) self.indent_level -= 1 self.write_line(');') self.write_line('dependencies = (') self.write_line(');') self.write_line('name = RUN_TESTS;') self.write_line('productName = RUN_TESTS;') self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXAggregateTarget section */\n') def generate_pbx_build_file(self): self.ofile.write('\n/* Begin PBXBuildFile section */\n') templ = '%s /* %s */ = { isa = PBXBuildFile; fileRef = %s /* %s */; settings = { COMPILER_FLAGS = "%s"; }; };\n' otempl = '%s /* %s */ = { isa = PBXBuildFile; fileRef = %s /* %s */;};\n' for t in self.build.targets.values(): for s in t.sources: if isinstance(s, mesonlib.File): s = s.fname if isinstance(s, str): s = os.path.join(t.subdir, s) idval = self.buildmap[s] fullpath = os.path.join(self.environment.get_source_dir(), s) fileref = self.filemap[s] fullpath2 = fullpath compiler_args = '' self.ofile.write(templ % (idval, fullpath, fileref, fullpath2, compiler_args)) for o in t.objects: o = os.path.join(t.subdir, o) idval = self.buildmap[o] fileref = self.filemap[o] fullpath = os.path.join(self.environment.get_source_dir(), o) fullpath2 = fullpath self.ofile.write(otempl % (idval, fullpath, fileref, fullpath2)) self.ofile.write('/* End PBXBuildFile section */\n') def generate_pbx_build_style(self): self.ofile.write('\n/* Begin PBXBuildStyle section */\n') for name, idval in self.buildstylemap.items(): self.write_line('%s /* %s */ = {\n' % (idval, name)) self.indent_level += 1 self.write_line('isa = PBXBuildStyle;\n') self.write_line('buildSettings = {\n') self.indent_level += 1 self.write_line('COPY_PHASE_STRIP = NO;\n') self.indent_level -= 1 self.write_line('};\n') self.write_line('name = "%s";\n' % name) self.indent_level -= 1 self.write_line('};\n') self.ofile.write('/* End PBXBuildStyle section */\n') def generate_pbx_container_item_proxy(self): self.ofile.write('\n/* Begin PBXContainerItemProxy section */\n') for t in self.build.targets: self.write_line('%s /* PBXContainerItemProxy */ = {' % self.containerproxy_map[t]) self.indent_level += 1 self.write_line('isa = PBXContainerItemProxy;') self.write_line('containerPortal = %s /* Project object */;' % self.project_uid) self.write_line('proxyType = 1;') self.write_line('remoteGlobalIDString = %s;' % self.native_targets[t]) self.write_line('remoteInfo = "%s";' % t) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXContainerItemProxy section */\n') def generate_pbx_file_reference(self): self.ofile.write('\n/* Begin PBXFileReference section */\n') src_templ = '%s /* %s */ = { isa = PBXFileReference; explicitFileType = "%s"; fileEncoding = 4; name = "%s"; path = "%s"; sourceTree = SOURCE_ROOT; };\n' for fname, idval in self.filemap.items(): fullpath = os.path.join(self.environment.get_source_dir(), fname) xcodetype = self.get_xcodetype(fname) name = os.path.split(fname)[-1] path = fname self.ofile.write(src_templ % (idval, fullpath, xcodetype, name, path)) target_templ = '%s /* %s */ = { isa = PBXFileReference; explicitFileType = "%s"; path = %s; refType = %d; sourceTree = BUILT_PRODUCTS_DIR; };\n' for tname, idval in self.target_filemap.items(): t = self.build.targets[tname] fname = t.get_filename() reftype = 0 if isinstance(t, build.Executable): typestr = 'compiled.mach-o.executable' path = fname elif isinstance(t, build.SharedLibrary): typestr = self.get_xcodetype('dummy.dylib') path = fname else: typestr = self.get_xcodetype(fname) path = '"%s"' % t.get_filename() self.ofile.write(target_templ % (idval, tname, typestr, path, reftype)) self.ofile.write('/* End PBXFileReference section */\n') def generate_pbx_group(self): groupmap = {} target_src_map = {} for t in self.build.targets: groupmap[t] = self.gen_id() target_src_map[t] = self.gen_id() self.ofile.write('\n/* Begin PBXGroup section */\n') sources_id = self.gen_id() resources_id = self.gen_id() products_id = self.gen_id() self.write_line('%s = {' % self.maingroup_id) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 self.write_line('%s /* Sources */,' % sources_id) self.write_line('%s /* Resources */,' % resources_id) self.write_line('%s /* Products */,' % products_id) self.indent_level -= 1 self.write_line(');') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') # Sources self.write_line('%s /* Sources */ = {' % sources_id) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 for t in self.build.targets: self.write_line('%s /* %s */,' % (groupmap[t], t)) self.indent_level -= 1 self.write_line(');') self.write_line('name = Sources;') self.write_line('sourcetree = "";') self.indent_level -= 1 self.write_line('};') self.write_line('%s /* Resources */ = {' % resources_id) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.write_line(');') self.write_line('name = Resources;') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') # Targets for t in self.build.targets: self.write_line('%s /* %s */ = {' % (groupmap[t], t)) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 self.write_line('%s /* Source files */,' % target_src_map[t]) self.indent_level -= 1 self.write_line(');') self.write_line('name = "%s";' % t) self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') self.write_line('%s /* Source files */ = {' % target_src_map[t]) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 for s in self.build.targets[t].sources: s = os.path.join(s.subdir, s.fname) if isinstance(s, str): self.write_line('%s /* %s */,' % (self.filemap[s], s)) for o in self.build.targets[t].objects: o = os.path.join(self.build.targets[t].subdir, o) self.write_line('%s /* %s */,' % (self.filemap[o], o)) self.indent_level -= 1 self.write_line(');') self.write_line('name = "Source files";') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') # And finally products self.write_line('%s /* Products */ = {' % products_id) self.indent_level += 1 self.write_line('isa = PBXGroup;') self.write_line('children = (') self.indent_level += 1 for t in self.build.targets: self.write_line('%s /* %s */,' % (self.target_filemap[t], t)) self.indent_level -= 1 self.write_line(');') self.write_line('name = Products;') self.write_line('sourceTree = "";') self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXGroup section */\n') def generate_pbx_native_target(self): self.ofile.write('\n/* Begin PBXNativeTarget section */\n') for tname, idval in self.native_targets.items(): t = self.build.targets[tname] self.write_line('%s /* %s */ = {' % (idval, tname)) self.indent_level += 1 self.write_line('isa = PBXNativeTarget;') self.write_line('buildConfigurationList = %s /* Build configuration list for PBXNativeTarget "%s" */;' % (self.buildconflistmap[tname], tname)) self.write_line('buildPhases = (') self.indent_level += 1 self.write_line('%s /* Sources */,' % self.buildphasemap[tname]) self.indent_level -= 1 self.write_line(');') self.write_line('buildRules = (') self.write_line(');') self.write_line('dependencies = (') self.indent_level += 1 for lt in self.build.targets[tname].link_targets: # NOT DOCUMENTED, may need to make different links # to same target have different targetdependency item. idval = self.pbx_dep_map[lt.get_id()] self.write_line('%s /* PBXTargetDependency */,' % idval) self.indent_level -= 1 self.write_line(");") self.write_line('name = "%s";' % tname) self.write_line('productName = "%s";' % tname) self.write_line('productReference = %s /* %s */;' % (self.target_filemap[tname], tname)) if isinstance(t, build.Executable): typestr = 'com.apple.product-type.tool' elif isinstance(t, build.StaticLibrary): typestr = 'com.apple.product-type.library.static' elif isinstance(t, build.SharedLibrary): typestr = 'com.apple.product-type.library.dynamic' else: raise MesonException('Unknown target type for %s' % tname) self.write_line('productType = "%s";' % typestr) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXNativeTarget section */\n') def generate_pbx_project(self): self.ofile.write('\n/* Begin PBXProject section */\n') self.write_line('%s /* Project object */ = {' % self.project_uid) self.indent_level += 1 self.write_line('isa = PBXProject;') self.write_line('attributes = {') self.indent_level += 1 self.write_line('BuildIndependentTargetsInParallel = YES;') self.indent_level -= 1 self.write_line('};') conftempl = 'buildConfigurationList = %s /* build configuration list for PBXProject "%s"*/;' self.write_line(conftempl % (self.project_conflist, self.build.project_name)) self.write_line('buildSettings = {') self.write_line('};') self.write_line('buildStyles = (') self.indent_level += 1 for name, idval in self.buildstylemap.items(): self.write_line('%s /* %s */,' % (idval, name)) self.indent_level -= 1 self.write_line(');') self.write_line('compatibilityVersion = "Xcode 3.2";') self.write_line('hasScannedForEncodings = 0;') self.write_line('mainGroup = %s;' % self.maingroup_id) self.write_line('projectDirPath = "%s";' % self.build_to_src) self.write_line('projectRoot = "";') self.write_line('targets = (') self.indent_level += 1 self.write_line('%s /* ALL_BUILD */,' % self.all_id) self.write_line('%s /* RUN_TESTS */,' % self.test_id) for t in self.build.targets: self.write_line('%s /* %s */,' % (self.native_targets[t], t)) self.indent_level -= 1 self.write_line(');') self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXProject section */\n') def generate_pbx_shell_build_phase(self, test_data): self.ofile.write('\n/* Begin PBXShellScriptBuildPhase section */\n') self.write_line('%s = {' % self.test_command_id) self.indent_level += 1 self.write_line('isa = PBXShellScriptBuildPhase;') self.write_line('buildActionMask = 2147483647;') self.write_line('files = (') self.write_line(');') self.write_line('inputPaths = (') self.write_line(');') self.write_line('outputPaths = (') self.write_line(');') self.write_line('runOnlyForDeploymentPostprocessing = 0;') self.write_line('shellPath = /bin/sh;') script_root = self.environment.get_script_dir() test_script = os.path.join(script_root, 'meson_test.py') cmd = [sys.executable, test_script, test_data, '--wd', self.environment.get_build_dir()] cmdstr = ' '.join(["'%s'" % i for i in cmd]) self.write_line('shellScript = "%s";' % cmdstr) self.write_line('showEnvVarsInLog = 0;') self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXShellScriptBuildPhase section */\n') def generate_pbx_sources_build_phase(self): self.ofile.write('\n/* Begin PBXSourcesBuildPhase section */\n') for name, phase_id in self.source_phase.items(): self.write_line('%s /* Sources */ = {' % self.buildphasemap[name]) self.indent_level += 1 self.write_line('isa = PBXSourcesBuildPhase;') self.write_line('buildActionMask = 2147483647;') self.write_line('files = (') self.indent_level += 1 for s in self.build.targets[name].sources: s = os.path.join(s.subdir, s.fname) if not self.environment.is_header(s): self.write_line('%s /* %s */,' % (self.buildmap[s], os.path.join(self.environment.get_source_dir(), s))) self.indent_level -= 1 self.write_line(');') self.write_line('runOnlyForDeploymentPostprocessing = 0;') self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXSourcesBuildPhase section */\n') def generate_pbx_target_dependency(self): self.ofile.write('\n/* Begin PBXTargetDependency section */\n') for t in self.build.targets: idval = self.pbx_dep_map[t] # VERIFY: is this correct? self.write_line('%s /* PBXTargetDependency */ = {' % idval) self.indent_level += 1 self.write_line('isa = PBXTargetDependency;') self.write_line('target = %s /* %s */;' % (self.native_targets[t], t)) self.write_line('targetProxy = %s /* PBXContainerItemProxy */;' % self.containerproxy_map[t]) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End PBXTargetDependency section */\n') def generate_xc_build_configuration(self): self.ofile.write('\n/* Begin XCBuildConfiguration section */\n') # First the setup for the toplevel project. for buildtype in self.buildtypes: self.write_line('%s /* %s */ = {' % (self.project_configurations[buildtype], buildtype)) self.indent_level += 1 self.write_line('isa = XCBuildConfiguration;') self.write_line('buildSettings = {') self.indent_level += 1 self.write_line('ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";') self.write_line('ONLY_ACTIVE_ARCH = YES;') self.write_line('SDKROOT = "macosx";') self.write_line('SYMROOT = "%s/build";' % self.environment.get_build_dir()) self.indent_level -= 1 self.write_line('};') self.write_line('name = "%s";' % buildtype) self.indent_level -= 1 self.write_line('};') # Then the all target. for buildtype in self.buildtypes: self.write_line('%s /* %s */ = {' % (self.buildall_configurations[buildtype], buildtype)) self.indent_level += 1 self.write_line('isa = XCBuildConfiguration;') self.write_line('buildSettings = {') self.indent_level += 1 self.write_line('COMBINE_HIDPI_IMAGES = YES;') self.write_line('GCC_GENERATE_DEBUGGING_SYMBOLS = NO;') self.write_line('GCC_INLINES_ARE_PRIVATE_EXTERN = NO;') self.write_line('GCC_OPTIMIZATION_LEVEL = 0;') self.write_line('GCC_PREPROCESSOR_DEFINITIONS = ("");') self.write_line('GCC_SYMBOLS_PRIVATE_EXTERN = NO;') self.write_line('INSTALL_PATH = "";') self.write_line('OTHER_CFLAGS = " ";') self.write_line('OTHER_LDFLAGS = " ";') self.write_line('OTHER_REZFLAGS = "";') self.write_line('PRODUCT_NAME = ALL_BUILD;') self.write_line('SECTORDER_FLAGS = "";') self.write_line('SYMROOT = "%s";' % self.environment.get_build_dir()) self.write_line('USE_HEADERMAP = NO;') self.write_line('WARNING_CFLAGS = ("-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", );') self.indent_level -= 1 self.write_line('};') self.write_line('name = "%s";' % buildtype) self.indent_level -= 1 self.write_line('};') # Then the test target. for buildtype in self.buildtypes: self.write_line('%s /* %s */ = {' % (self.test_configurations[buildtype], buildtype)) self.indent_level += 1 self.write_line('isa = XCBuildConfiguration;') self.write_line('buildSettings = {') self.indent_level += 1 self.write_line('COMBINE_HIDPI_IMAGES = YES;') self.write_line('GCC_GENERATE_DEBUGGING_SYMBOLS = NO;') self.write_line('GCC_INLINES_ARE_PRIVATE_EXTERN = NO;') self.write_line('GCC_OPTIMIZATION_LEVEL = 0;') self.write_line('GCC_PREPROCESSOR_DEFINITIONS = ("");') self.write_line('GCC_SYMBOLS_PRIVATE_EXTERN = NO;') self.write_line('INSTALL_PATH = "";') self.write_line('OTHER_CFLAGS = " ";') self.write_line('OTHER_LDFLAGS = " ";') self.write_line('OTHER_REZFLAGS = "";') self.write_line('PRODUCT_NAME = RUN_TESTS;') self.write_line('SECTORDER_FLAGS = "";') self.write_line('SYMROOT = "%s";' % self.environment.get_build_dir()) self.write_line('USE_HEADERMAP = NO;') self.write_line('WARNING_CFLAGS = ("-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", );') self.indent_level -= 1 self.write_line('};') self.write_line('name = "%s";' % buildtype) self.indent_level -= 1 self.write_line('};') # Now finally targets. langnamemap = {'c': 'C', 'cpp': 'CPLUSPLUS', 'objc': 'OBJC', 'objcpp': 'OBJCPLUSPLUS'} for target_name, target in self.build.targets.items(): for buildtype in self.buildtypes: dep_libs = [] links_dylib = False headerdirs = [] for d in target.include_dirs: for sd in d.incdirs: cd = os.path.join(d.curdir, sd) headerdirs.append(os.path.join(self.environment.get_source_dir(), cd)) headerdirs.append(os.path.join(self.environment.get_build_dir(), cd)) for l in target.link_targets: abs_path = os.path.join(self.environment.get_build_dir(), l.subdir, buildtype, l.get_filename()) dep_libs.append("'%s'" % abs_path) if isinstance(l, build.SharedLibrary): links_dylib = True if links_dylib: dep_libs = ['-Wl,-search_paths_first', '-Wl,-headerpad_max_install_names'] + dep_libs dylib_version = None if isinstance(target, build.SharedLibrary): ldargs = ['-dynamiclib', '-Wl,-headerpad_max_install_names'] + dep_libs install_path = os.path.join(self.environment.get_build_dir(), target.subdir, buildtype) dylib_version = target.version else: ldargs = dep_libs install_path = '' if dylib_version is not None: product_name = target.get_basename() + '.' + dylib_version else: product_name = target.get_basename() ldargs += target.link_args ldstr = ' '.join(ldargs) valid = self.buildconfmap[target_name][buildtype] langargs = {} for lang in self.environment.coredata.compilers: if lang not in langnamemap: continue gargs = self.build.global_args.get(lang, []) targs = target.get_extra_args(lang) args = gargs + targs if len(args) > 0: langargs[langnamemap[lang]] = args symroot = os.path.join(self.environment.get_build_dir(), target.subdir) self.write_line('%s /* %s */ = {' % (valid, buildtype)) self.indent_level += 1 self.write_line('isa = XCBuildConfiguration;') self.write_line('buildSettings = {') self.indent_level += 1 self.write_line('COMBINE_HIDPI_IMAGES = YES;') if dylib_version is not None: self.write_line('DYLIB_CURRENT_VERSION = "%s";' % dylib_version) self.write_line('EXECUTABLE_PREFIX = "%s";' % target.prefix) if target.suffix == '': suffix = '' else: suffix = '.' + target.suffix self.write_line('EXECUTABLE_SUFFIX = "%s";' % suffix) self.write_line('GCC_GENERATE_DEBUGGING_SYMBOLS = YES;') self.write_line('GCC_INLINES_ARE_PRIVATE_EXTERN = NO;') self.write_line('GCC_OPTIMIZATION_LEVEL = 0;') self.write_line('GCC_PREPROCESSOR_DEFINITIONS = ("");') self.write_line('GCC_SYMBOLS_PRIVATE_EXTERN = NO;') if len(headerdirs) > 0: quotedh = ','.join(['"\\"%s\\""' % i for i in headerdirs]) self.write_line('HEADER_SEARCH_PATHS=(%s);' % quotedh) self.write_line('INSTALL_PATH = "%s";' % install_path) self.write_line('LIBRARY_SEARCH_PATHS = "";') if isinstance(target, build.SharedLibrary): self.write_line('LIBRARY_STYLE = DYNAMIC;') for langname, args in langargs.items(): argstr = ' '.join(args) self.write_line('OTHER_%sFLAGS = "%s";' % (langname, argstr)) self.write_line('OTHER_LDFLAGS = "%s";' % ldstr) self.write_line('OTHER_REZFLAGS = "";') self.write_line('PRODUCT_NAME = %s;' % product_name) self.write_line('SECTORDER_FLAGS = "";') self.write_line('SYMROOT = "%s";' % symroot) self.write_line('USE_HEADERMAP = NO;') self.write_line('WARNING_CFLAGS = ("-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", );') self.indent_level -= 1 self.write_line('};') self.write_line('name = "%s";' % buildtype) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End XCBuildConfiguration section */\n') def generate_xc_configurationList(self): self.ofile.write('\n/* Begin XCConfigurationList section */\n') self.write_line('%s /* Build configuration list for PBXProject "%s" */ = {' % (self.project_conflist, self.build.project_name)) self.indent_level += 1 self.write_line('isa = XCConfigurationList;') self.write_line('buildConfigurations = (') self.indent_level += 1 for buildtype in self.buildtypes: self.write_line('%s /* %s */,' % (self.project_configurations[buildtype], buildtype)) self.indent_level -= 1 self.write_line(');') self.write_line('defaultConfigurationIsVisible = 0;') self.write_line('defaultConfigurationName = debug;') self.indent_level -= 1 self.write_line('};') # Now the all target self.write_line('%s /* Build configuration list for PBXAggregateTarget "ALL_BUILD" */ = {' % self.all_buildconf_id) self.indent_level += 1 self.write_line('isa = XCConfigurationList;') self.write_line('buildConfigurations = (') self.indent_level += 1 for buildtype in self.buildtypes: self.write_line('%s /* %s */,' % (self.buildall_configurations[buildtype], buildtype)) self.indent_level -= 1 self.write_line(');') self.write_line('defaultConfigurationIsVisible = 0;') self.write_line('defaultConfigurationName = debug;') self.indent_level -= 1 self.write_line('};') # Test target self.write_line('%s /* Build configuration list for PBXAggregateTarget "ALL_BUILD" */ = {' % self.test_buildconf_id) self.indent_level += 1 self.write_line('isa = XCConfigurationList;') self.write_line('buildConfigurations = (') self.indent_level += 1 for buildtype in self.buildtypes: self.write_line('%s /* %s */,' % (self.test_configurations[buildtype], buildtype)) self.indent_level -= 1 self.write_line(');') self.write_line('defaultConfigurationIsVisible = 0;') self.write_line('defaultConfigurationName = debug;') self.indent_level -= 1 self.write_line('};') for target_name in self.build.targets: listid = self.buildconflistmap[target_name] self.write_line('%s /* Build configuration list for PBXNativeTarget "%s" */ = {' % (listid, target_name)) self.indent_level += 1 self.write_line('isa = XCConfigurationList;') self.write_line('buildConfigurations = (') self.indent_level += 1 typestr = 'debug' idval = self.buildconfmap[target_name][typestr] self.write_line('%s /* %s */,' % (idval, typestr)) self.indent_level -= 1 self.write_line(');') self.write_line('defaultConfigurationIsVisible = 0;') self.write_line('defaultConfigurationName = "%s";' % typestr) self.indent_level -= 1 self.write_line('};') self.ofile.write('/* End XCConfigurationList section */\n') def generate_prefix(self): self.ofile.write('// !$*UTF8*$!\n{\n') self.indent_level += 1 self.write_line('archiveVersion = 1;\n') self.write_line('classes = {\n') self.write_line('};\n') self.write_line('objectVersion = 46;\n') self.write_line('objects = {\n') self.indent_level += 1 def generate_suffix(self): self.indent_level -= 1 self.write_line('};\n') self.write_line('rootObject = ' + self.project_uid + ';') self.indent_level -= 1 self.write_line('}\n') meson-0.40.1/mesonbuild/backend/__init__.py0000644000175000017500000000000012650745767022161 0ustar jpakkanejpakkane00000000000000meson-0.40.1/mesonbuild/backend/ninjabackend.py0000644000175000017500000035316113100700231023014 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from . import backends from .. import modules from .. import environment, mesonlib from .. import build from .. import mlog from .. import dependencies from .. import compilers from ..compilers import CompilerArgs 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 import subprocess, shutil from collections import OrderedDict if mesonlib.is_windows(): quote_char = '"' execute_wrapper = 'cmd /c' rmfile_prefix = 'del /f /s /q {} &&' else: quote_char = "'" execute_wrapper = '' rmfile_prefix = 'rm -f {} &&' def ninja_quote(text): return text.replace(' ', '$ ').replace(':', '$:') class RawFilename: """ Used when a filename is already relative to the root build directory, so that we know not to add the target's private build directory to it. """ def __init__(self, fname): self.fname = fname def __str__(self): return self.fname def __repr__(self): return ''.format(self.fname) def split(self, c): return self.fname.split(c) def startswith(self, s): return self.fname.startswith(s) class NinjaBuildElement: def __init__(self, all_outputs, outfilenames, rule, infilenames): if isinstance(outfilenames, str): self.outfilenames = [outfilenames] else: self.outfilenames = outfilenames assert(isinstance(rule, str)) self.rule = rule if isinstance(infilenames, str): self.infilenames = [infilenames] else: self.infilenames = infilenames self.deps = [] self.orderdeps = [] self.elems = [] self.all_outputs = all_outputs def add_dep(self, dep): if isinstance(dep, list): self.deps += dep else: self.deps.append(dep) def add_orderdep(self, dep): if isinstance(dep, list): self.orderdeps += dep else: self.orderdeps.append(dep) def add_item(self, name, elems): if isinstance(elems, str): elems = [elems] self.elems.append((name, elems)) def write(self, outfile): self.check_outputs() line = 'build %s: %s %s' % ( ' '.join([ninja_quote(i) for i in self.outfilenames]), self.rule, ' '.join([ninja_quote(i) for i in self.infilenames])) if len(self.deps) > 0: line += ' | ' + ' '.join([ninja_quote(x) for x in self.deps]) if len(self.orderdeps) > 0: line += ' || ' + ' '.join([ninja_quote(x) for x in self.orderdeps]) line += '\n' # This is the only way I could find to make this work on all # platforms including Windows command shell. Slash is a dir separator # on Windows, too, so all characters are unambiguous and, more importantly, # do not require quoting. line = line.replace('\\', '/') outfile.write(line) for e in self.elems: (name, elems) = e should_quote = True if name == 'DEPFILE' or name == 'DESC' or name == 'pool': should_quote = False line = ' %s = ' % name q_templ = quote_char + "%s" + quote_char noq_templ = "%s" newelems = [] for i in elems: if not should_quote or i == '&&': # Hackety hack hack templ = noq_templ else: templ = q_templ i = i.replace('\\', '\\\\') if quote_char == '"': i = i.replace('"', '\\"') newelems.append(templ % ninja_quote(i)) line += ' '.join(newelems) line += '\n' outfile.write(line) outfile.write('\n') def check_outputs(self): for n in self.outfilenames: if n in self.all_outputs: raise MesonException('Multiple producers for Ninja target "%s". Please rename your targets.' % n) self.all_outputs[n] = True class NinjaBackend(backends.Backend): def __init__(self, build): super().__init__(build) self.name = 'ninja' self.ninja_filename = 'build.ninja' self.target_arg_cache = {} self.fortran_deps = {} self.all_outputs = {} def detect_vs_dep_prefix(self, tempfilename): '''VS writes its dependency in a locale dependent format. Detect the search prefix to use.''' # Of course there is another program called 'cl' on # some platforms. Let's just require that on Windows # cl points to msvc. if not mesonlib.is_windows() or shutil.which('cl') is None: return open(tempfilename, 'a') filename = os.path.join(self.environment.get_scratch_dir(), 'incdetect.c') with open(filename, 'w') as f: f.write('''#include int dummy; ''') # The output of cl dependency information is language # and locale dependent. Any attempt at converting it to # Python strings leads to failure. We _must_ do this detection # in raw byte mode and write the result in raw bytes. pc = subprocess.Popen(['cl', '/showIncludes', '/c', 'incdetect.c'], cwd=self.environment.get_scratch_dir(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdo, _) = pc.communicate() for line in stdo.split(b'\r\n'): if line.endswith(b'stdio.h'): matchstr = b':'.join(line.split(b':')[0:2]) + b':' with open(tempfilename, 'ab') as binfile: binfile.write(b'msvc_deps_prefix = ' + matchstr + b'\n') return open(tempfilename, 'a') raise MesonException('Could not determine vs dep dependency prefix string.') def generate(self, interp): self.interpreter = interp outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename) tempfilename = outfilename + '~' with open(tempfilename, 'w') as outfile: outfile.write('# This is the build file for project "%s"\n' % self.build.get_project()) outfile.write('# It is autogenerated by the Meson build system.\n') outfile.write('# Do not edit by hand.\n\n') outfile.write('ninja_required_version = 1.5.1\n\n') with self.detect_vs_dep_prefix(tempfilename) as outfile: self.generate_rules(outfile) self.generate_phony(outfile) outfile.write('# Build rules for targets\n\n') for t in self.build.get_targets().values(): self.generate_target(t, outfile) outfile.write('# Test rules\n\n') self.generate_tests(outfile) outfile.write('# Install rules\n\n') self.generate_install(outfile) if 'b_coverage' in self.environment.coredata.base_options and \ self.environment.coredata.base_options['b_coverage'].value: outfile.write('# Coverage rules\n\n') self.generate_coverage_rules(outfile) outfile.write('# Suffix\n\n') self.generate_utils(outfile) self.generate_ending(outfile) # Only ovewrite the old build file after the new one has been # fully created. os.replace(tempfilename, outfilename) self.generate_compdb() # http://clang.llvm.org/docs/JSONCompilationDatabase.html def generate_compdb(self): ninja_exe = environment.detect_ninja() native_compilers = ['%s_COMPILER' % i for i in self.build.compilers] cross_compilers = ['%s_CROSS_COMPILER' % i for i in self.build.cross_compilers] ninja_compdb = [ninja_exe, '-t', 'compdb'] + native_compilers + cross_compilers builddir = self.environment.get_build_dir() try: jsondb = subprocess.check_output(ninja_compdb, cwd=builddir) with open(os.path.join(builddir, 'compile_commands.json'), 'wb') as f: f.write(jsondb) except Exception: 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. def get_generated_headers(self, target): header_deps = [] # XXX: Why don't we add deps to CustomTarget headers here? for genlist in target.get_generated_sources(): if isinstance(genlist, build.CustomTarget): continue for src in genlist.get_outputs(): if self.environment.is_header(src): header_deps.append(self.get_target_generated_dir(target, genlist, src)) # Recurse and find generated headers for dep in target.link_targets: if isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): header_deps += self.get_generated_headers(dep) return header_deps def get_target_generated_sources(self, target): """ Returns a dictionary with the keys being the path to the file (relative to the build directory) of that type and the value being the GeneratorList or CustomTarget that generated it. """ srcs = OrderedDict() for gensrc in target.get_generated_sources(): for s in gensrc.get_outputs(): f = self.get_target_generated_dir(target, gensrc, s) srcs[f] = s return srcs def get_target_sources(self, target): srcs = OrderedDict() for s in target.get_sources(): # BuildTarget sources are always mesonlib.File files which are # either in the source root, or generated with configure_file and # in the build root if not isinstance(s, File): raise InvalidArguments('All sources in target {!r} must be of type mesonlib.File'.format(s)) f = s.rel_to_builddir(self.build_to_src) srcs[f] = s return srcs # Languages that can mix with C or C++ but don't support unity builds yet # because the syntax we use for unity builds is specific to C/++/ObjC/++. # Assembly files cannot be unitified and neither can LLVM IR files langs_cant_unity = ('d', 'fortran') def get_target_source_can_unity(self, target, source): if isinstance(source, File): source = source.fname if self.environment.is_llvm_ir(source) or \ self.environment.is_assembly(source): return False suffix = os.path.splitext(source)[1][1:] for lang in self.langs_cant_unity: if lang not in target.compilers: continue if suffix in target.compilers[lang].file_suffixes: return False return True def generate_target(self, target, outfile): if isinstance(target, build.CustomTarget): self.generate_custom_target(target, outfile) if isinstance(target, build.RunTarget): self.generate_run_target(target, outfile) name = target.get_id() if name in self.processed_targets: return self.processed_targets[name] = True # Generate rules for all dependency targets self.process_target_dependencies(target, outfile) # If target uses a language that cannot link to C objects, # just generate for that language and return. if isinstance(target, build.Jar): self.generate_jar_target(target, outfile) return if 'rust' in target.compilers: self.generate_rust_target(target, outfile) return if 'cs' in target.compilers: self.generate_cs_target(target, outfile) return if 'swift' in target.compilers: self.generate_swift_target(target, outfile) return # Now we handle the following languages: # ObjC++, ObjC, C++, C, D, Fortran, Vala # Pre-existing target C/C++ sources to be built; dict of full path to # source relative to build root and the original File object. target_sources = OrderedDict() # GeneratedList and CustomTarget sources to be built; dict of the full # path to source relative to build root and the generating target/list generated_sources = OrderedDict() # Array of sources generated by valac that have to be compiled vala_generated_sources = [] if 'vala' in target.compilers: # Sources consumed by valac are filtered out. These only contain # C/C++ sources, objects, generated libs, and unknown sources now. target_sources, generated_sources, \ vala_generated_sources = self.generate_vala_compile(target, outfile) else: target_sources = self.get_target_sources(target) generated_sources = self.get_target_generated_sources(target) self.scan_fortran_module_outputs(target) # Generate rules for GeneratedLists self.generate_generator_list_rules(target, outfile) # Generate rules for building the remaining source files in this target outname = self.get_target_filename(target) obj_list = [] use_pch = self.environment.coredata.base_options.get('b_pch', False) is_unity = self.is_unity(target) if use_pch and target.has_pch(): pch_objects = self.generate_pch(target, outfile) else: pch_objects = [] header_deps = [] unity_src = [] unity_deps = [] # Generated sources that must be built before compiling a Unity target. header_deps += self.get_generated_headers(target) if is_unity: # Warn about incompatible sources if a unity build is enabled langs = set(target.compilers.keys()) langs_cant = langs.intersection(self.langs_cant_unity) if langs_cant: langs_are = langs = ', '.join(langs_cant).upper() langs_are += ' are' if len(langs_cant) > 1 else ' is' msg = '{} not supported in Unity builds yet, so {} ' \ 'sources in the {!r} target will be compiled normally' \ ''.format(langs_are, langs, target.name) mlog.log(mlog.red('FIXME'), msg) # Get a list of all generated headers that will be needed while building # this target's sources (generated sources and pre-existing sources). # This will be set as dependencies of all the target's sources. At the # same time, also deal with generated sources that need to be compiled. generated_source_files = [] for rel_src, gensrc in generated_sources.items(): raw_src = RawFilename(rel_src) if self.environment.is_source(rel_src) and not self.environment.is_header(rel_src): if is_unity and self.get_target_source_can_unity(target, rel_src): unity_deps.append(raw_src) abs_src = os.path.join(self.environment.get_build_dir(), rel_src) unity_src.append(abs_src) else: generated_source_files.append(raw_src) elif self.environment.is_object(rel_src): obj_list.append(rel_src) elif self.environment.is_library(rel_src): pass else: # Assume anything not specifically a source file is a header. This is because # people generate files with weird suffixes (.inc, .fh) that they then include # in their source files. header_deps.append(raw_src) # These are the generated source files that need to be built for use by # this target. We create the Ninja build file elements for this here # because we need `header_deps` to be fully generated in the above loop. for src in generated_source_files: if self.environment.is_llvm_ir(src): o = self.generate_llvm_ir_compile(target, outfile, src) else: o = self.generate_single_compile(target, outfile, src, True, header_deps=header_deps) obj_list.append(o) # Generate compilation targets for C sources generated from Vala # sources. This can be extended to other $LANG->C compilers later if # necessary. This needs to be separate for at least Vala vala_generated_source_files = [] for src in vala_generated_sources: raw_src = RawFilename(src) if is_unity: unity_src.append(os.path.join(self.environment.get_build_dir(), src)) header_deps.append(raw_src) else: # Generated targets are ordered deps because the must exist # before the sources compiling them are used. After the first # compile we get precise dependency info from dep files. # This should work in all cases. If it does not, then just # move them from orderdeps to proper deps. if self.environment.is_header(src): header_deps.append(raw_src) else: # We gather all these and generate compile rules below # after `header_deps` (above) is fully generated vala_generated_source_files.append(raw_src) for src in vala_generated_source_files: # Passing 'vala' here signifies that we want the compile # arguments to be specialized for C code generated by # valac. For instance, no warnings should be emitted. obj_list.append(self.generate_single_compile(target, outfile, src, 'vala', [], header_deps)) # Generate compile targets for all the pre-existing sources for this target for f, src in target_sources.items(): if not self.environment.is_header(src): if self.environment.is_llvm_ir(src): obj_list.append(self.generate_llvm_ir_compile(target, outfile, src)) elif is_unity and self.get_target_source_can_unity(target, src): abs_src = os.path.join(self.environment.get_build_dir(), src.rel_to_builddir(self.build_to_src)) unity_src.append(abs_src) else: obj_list.append(self.generate_single_compile(target, outfile, src, False, [], header_deps)) obj_list += self.flatten_object_list(target) if is_unity: for src in self.generate_unity_files(target, unity_src): obj_list.append(self.generate_single_compile(target, outfile, src, True, unity_deps + header_deps)) linker = self.determine_linker(target) elem = self.generate_link(target, outfile, outname, obj_list, linker, pch_objects) self.generate_shlib_aliases(target, self.get_target_dir(target)) elem.write(outfile) def process_target_dependencies(self, target, outfile): for t in target.get_dependencies(): tname = t.get_basename() + t.type_suffix() if tname not in self.processed_targets: self.generate_target(t, outfile) def custom_target_generator_inputs(self, target, outfile): for s in target.sources: if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, build.GeneratedList): self.generate_genlist_for_target(s, target, outfile) def unwrap_dep_list(self, target): deps = [] for i in target.get_dependencies(): # FIXME, should not grab element at zero but rather expand all. if isinstance(i, list): i = i[0] # Add a dependency on all the outputs of this target for output in i.get_outputs(): deps.append(os.path.join(self.get_target_dir(i), output)) return deps def generate_custom_target(self, target, outfile): self.custom_target_generator_inputs(target, outfile) (srcs, ofilenames, cmd) = self.eval_custom_target_command(target) deps = self.unwrap_dep_list(target) deps += self.get_custom_target_depend_files(target) desc = 'Generating {0} with a {1} command.' if target.build_always: deps.append('PHONY') if target.depfile is None: rulename = 'CUSTOM_COMMAND' else: rulename = 'CUSTOM_COMMAND_DEP' elem = NinjaBuildElement(self.all_outputs, ofilenames, rulename, srcs) elem.add_dep(deps) for d in target.extra_depends: # Add a dependency on all the outputs of this target for output in d.get_outputs(): elem.add_dep(os.path.join(self.get_target_dir(d), output)) # If the target requires capturing stdout, then use the serialized # executable wrapper to capture that output and save it to a file. # # Windows doesn't have -rpath, so for EXEs that need DLLs built within # 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() 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 self.environment.get_build_dir(), capture=ofilenames[0] if target.capture else None) cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'exe', exe_data] cmd_type = 'meson_exe.py custom' else: cmd_type = 'custom' if target.depfile is not None: 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) elem.add_item('description', desc.format(target.name, cmd_type)) elem.write(outfile) self.processed_targets[target.name + target.type_suffix()] = True def generate_run_target(self, target, outfile): cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner'] deps = self.unwrap_dep_list(target) arg_strings = [] for i in target.args: if isinstance(i, str): arg_strings.append(i) elif isinstance(i, (build.BuildTarget, build.CustomTarget)): relfname = self.get_target_filename(i) arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname)) deps.append(relfname) elif isinstance(i, mesonlib.File): relfname = i.rel_to_builddir(self.build_to_src) arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname)) else: raise AssertionError('Unreachable code in generate_run_target: ' + str(i)) elem = NinjaBuildElement(self.all_outputs, target.name, 'CUSTOM_COMMAND', []) 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 except AttributeError: pass if isinstance(texe, build.Executable): abs_exe = os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe)) deps.append(self.get_target_filename(texe)) if self.environment.is_cross_build() and \ self.environment.cross_info.need_exe_wrapper(): exe_wrap = self.environment.cross_info.config['binaries'].get('exe_wrapper', None) if exe_wrap is not None: cmd += [exe_wrap] cmd.append(abs_exe) elif isinstance(texe, dependencies.ExternalProgram): cmd += texe.get_command() elif isinstance(texe, build.CustomTarget): deps.append(self.get_target_filename(texe)) cmd += [os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe))] else: cmd.append(target.command) cmd += arg_strings elem.add_dep(deps) elem.add_item('COMMAND', cmd) elem.add_item('description', 'Running external command %s.' % target.name) elem.add_item('pool', 'console') elem.write(outfile) self.processed_targets[target.name + target.type_suffix()] = True def generate_coverage_rules(self, outfile): (gcovr_exe, lcov_exe, genhtml_exe) = environment.find_coverage_tools() added_rule = False if gcovr_exe: added_rule = True elem = NinjaBuildElement(self.all_outputs, 'coverage-xml', 'CUSTOM_COMMAND', '') elem.add_item('COMMAND', [gcovr_exe, '-x', '-r', self.environment.get_source_dir(), '-o', os.path.join(self.environment.get_log_dir(), 'coverage.xml')]) elem.add_item('DESC', 'Generating XML coverage report.') elem.write(outfile) elem = NinjaBuildElement(self.all_outputs, 'coverage-text', 'CUSTOM_COMMAND', '') elem.add_item('COMMAND', [gcovr_exe, '-r', self.environment.get_source_dir(), '-o', os.path.join(self.environment.get_log_dir(), 'coverage.txt')]) elem.add_item('DESC', 'Generating text coverage report.') elem.write(outfile) if lcov_exe and genhtml_exe: added_rule = True htmloutdir = os.path.join(self.environment.get_log_dir(), 'coveragereport') covinfo = os.path.join(self.environment.get_log_dir(), 'coverage.info') phony_elem = NinjaBuildElement(self.all_outputs, 'coverage-html', 'phony', os.path.join(htmloutdir, 'index.html')) phony_elem.write(outfile) elem = NinjaBuildElement(self.all_outputs, os.path.join(htmloutdir, 'index.html'), 'CUSTOM_COMMAND', '') command = [lcov_exe, '--directory', self.environment.get_build_dir(), '--capture', '--output-file', covinfo, '--no-checksum', '&&', genhtml_exe, '--prefix', self.environment.get_build_dir(), '--output-directory', htmloutdir, '--title', 'Code coverage', '--legend', '--show-details', covinfo] elem.add_item('COMMAND', command) elem.add_item('DESC', 'Generating HTML coverage report.') elem.write(outfile) if not added_rule: 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') if self.environment.is_cross_build(): bins = self.environment.cross_info.config['binaries'] if 'strip' not in bins: mlog.warning('Cross file does not specify strip binary, result will not be stripped.') strip_bin = None else: strip_bin = mesonlib.stringlistify(bins['strip']) else: strip_bin = self.environment.native_strip_bin d = InstallData(self.environment.get_source_dir(), self.environment.get_build_dir(), self.environment.get_prefix(), 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.') elem.add_item('COMMAND', [sys.executable, self.environment.get_build_command(), '--internal', 'install', install_data_file]) elem.add_item('pool', 'console') self.generate_depmf_install(d) self.generate_target_install(d) self.generate_header_install(d) self.generate_man_install(d) self.generate_data_install(d) self.generate_custom_install_script(d) self.generate_subdir_install(d) elem.write(outfile) with open(install_data_file, 'wb') as ofile: pickle.dump(d, ofile) def generate_target_install(self, d): for t in self.build.get_targets().values(): if not t.should_install(): continue # Find the installation directory. outdirs = t.get_custom_install_dir() custom_install_dir = False if outdirs[0] is not None and outdirs[0] is not True: # Either the value is set, or is set to False which means # we want this specific output out of many outputs to not # be installed. custom_install_dir = True elif isinstance(t, build.SharedModule): outdirs[0] = self.environment.get_shared_module_dir() elif isinstance(t, build.SharedLibrary): outdirs[0] = self.environment.get_shared_lib_dir() elif isinstance(t, build.StaticLibrary): outdirs[0] = self.environment.get_static_lib_dir() elif isinstance(t, build.Executable): outdirs[0] = self.environment.get_bindir() else: assert(isinstance(t, build.BuildTarget)) # XXX: Add BuildTarget-specific install dir cases here outdirs[0] = self.environment.get_libdir() # Sanity-check the outputs and install_dirs num_outdirs, num_out = len(outdirs), len(t.get_outputs()) if num_outdirs != 1 and num_outdirs != num_out: m = 'Target {!r} has {} outputs: {!r}, but only {} "install_dir"s were found.\n' \ "Pass 'false' for outputs that should not be installed and 'true' for\n" \ 'using the default installation directory for an output.' raise MesonException(m.format(t.name, num_out, t.get_outputs(), num_outdirs)) # Install the target output(s) if isinstance(t, build.BuildTarget): should_strip = self.get_option_for_target('strip', t) # Install primary build output (library/executable/jar, etc) # Done separately because of strip/aliases/rpath if outdirs[0] is not False: i = [self.get_target_filename(t), outdirs[0], t.get_aliases(), should_strip, t.install_rpath] d.targets.append(i) # On toolchains/platforms that use an import library for # linking (separate from the shared library with all the # code), we need to install that too (dll.a/.lib). if isinstance(t, build.SharedLibrary) and t.get_import_filename(): if custom_install_dir: # If the DLL is installed into a custom directory, # install the import library into the same place so # it doesn't go into a surprising place implib_install_dir = outdirs[0] else: implib_install_dir = self.environment.get_import_lib_dir() # Install the import library. i = [self.get_target_filename_for_linking(t), implib_install_dir, # It has no aliases, should not be stripped, and # doesn't have an install_rpath {}, False, ''] d.targets.append(i) # Install secondary outputs. Only used for Vala right now. if num_outdirs > 1: for output, outdir in zip(t.get_outputs()[1:], outdirs[1:]): # User requested that we not install this output if outdir is False: continue f = os.path.join(self.get_target_dir(t), output) d.targets.append([f, outdir, {}, False, None]) elif isinstance(t, build.CustomTarget): # If only one install_dir is specified, assume that all # outputs will be installed into it. This is for # backwards-compatibility and because it makes sense to # avoid repetition since this is a common use-case. # # To selectively install only some outputs, pass `false` as # the install_dir for the corresponding output by index if num_outdirs == 1 and num_out > 1: for output in t.get_outputs(): f = os.path.join(self.get_target_dir(t), output) d.targets.append([f, outdirs[0], {}, False, None]) else: for output, outdir in zip(t.get_outputs(), outdirs): # User requested that we not install this output if outdir is False: continue f = os.path.join(self.get_target_dir(t), output) d.targets.append([f, outdir, {}, False, None]) def generate_custom_install_script(self, d): result = [] srcdir = self.environment.get_source_dir() builddir = self.environment.get_build_dir() for i in self.build.install_scripts: exe = i['exe'] args = i['args'] fixed_args = [] for a in args: a = a.replace('@SOURCE_ROOT@', srcdir) a = a.replace('@BUILD_ROOT@', builddir) fixed_args.append(a) result.append(build.RunScript(exe, fixed_args)) d.install_scripts = result def generate_header_install(self, d): incroot = self.environment.get_includedir() headers = self.build.get_headers() srcdir = self.environment.get_source_dir() builddir = self.environment.get_build_dir() for h in headers: outdir = h.get_custom_install_dir() if outdir is None: outdir = os.path.join(incroot, h.get_install_subdir()) for f in h.get_sources(): if not isinstance(f, File): msg = 'Invalid header type {!r} can\'t be installed' raise MesonException(msg.format(f)) abspath = f.absolute_path(srcdir, builddir) i = [abspath, outdir] d.headers.append(i) def generate_man_install(self, d): manroot = self.environment.get_mandir() man = self.build.get_man() for m in man: for f in m.get_sources(): num = f.split('.')[-1] subdir = m.get_custom_install_dir() if subdir is None: subdir = os.path.join(manroot, 'man' + num) srcabs = os.path.join(self.environment.get_source_dir(), m.get_source_subdir(), f) dstabs = os.path.join(subdir, os.path.split(f)[1] + '.gz') i = [srcabs, dstabs] d.man.append(i) def generate_data_install(self, d): data = self.build.get_data() srcdir = self.environment.get_source_dir() builddir = self.environment.get_build_dir() for de in data: assert(isinstance(de, build.Data)) subdir = de.install_dir for f in de.sources: assert(isinstance(f, mesonlib.File)) plain_f = os.path.split(f.fname)[1] dstabs = os.path.join(subdir, plain_f) i = [f.absolute_path(srcdir, builddir), dstabs, de.install_mode] d.data.append(i) def generate_subdir_install(self, d): for sd in self.build.get_install_subdirs(): inst_subdir = sd.installable_subdir.rstrip('/') idir_parts = inst_subdir.split('/') if len(idir_parts) > 1: subdir = os.path.join(sd.source_subdir, '/'.join(idir_parts[:-1])) inst_dir = idir_parts[-1] else: subdir = sd.source_subdir inst_dir = sd.installable_subdir src_dir = os.path.join(self.environment.get_source_dir(), subdir) dst_dir = os.path.join(self.environment.get_prefix(), sd.install_dir) d.install_subdirs.append([src_dir, inst_dir, dst_dir, sd.install_mode]) def generate_tests(self, outfile): self.serialise_tests() 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'] if self.environment.coredata.get_builtin_option('errorlogs'): cmd += ['--print-errorlogs'] elem = NinjaBuildElement(self.all_outputs, 'test', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running all tests.') elem.add_item('pool', 'console') elem.write(outfile) # And then benchmarks. cmd = [sys.executable, test_exe, '--benchmark', '--logbase', 'benchmarklog', '--num-processes=1', '--no-rebuild'] elem = NinjaBuildElement(self.all_outputs, 'benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY']) elem.add_item('COMMAND', cmd) elem.add_item('DESC', 'Running benchmark suite.') elem.add_item('pool', 'console') elem.write(outfile) def generate_rules(self, outfile): outfile.write('# Rules for compiling.\n\n') self.generate_compile_rules(outfile) outfile.write('# Rules for linking.\n\n') if self.environment.is_cross_build(): self.generate_static_link_rules(True, outfile) self.generate_static_link_rules(False, outfile) self.generate_dynamic_link_rules(outfile) outfile.write('# Other rules\n\n') outfile.write('rule CUSTOM_COMMAND\n') outfile.write(' command = $COMMAND\n') outfile.write(' description = $DESC\n') outfile.write(' restat = 1\n\n') # Ninja errors out if you have deps = gcc but no depfile, so we must # have two rules for custom commands. outfile.write('rule CUSTOM_COMMAND_DEP\n') outfile.write(' command = $COMMAND\n') outfile.write(' description = $DESC\n') outfile.write(' deps = gcc\n') outfile.write(' depfile = $DEPFILE\n') outfile.write(' restat = 1\n\n') outfile.write('rule REGENERATE_BUILD\n') c = (quote_char + ninja_quote(sys.executable) + quote_char, quote_char + ninja_quote(self.environment.get_build_command()) + quote_char, '--internal', 'regenerate', quote_char + ninja_quote(self.environment.get_source_dir()) + quote_char, quote_char + ninja_quote(self.environment.get_build_dir()) + quote_char) outfile.write(" command = %s %s %s %s %s %s --backend ninja\n" % c) outfile.write(' description = Regenerating build files\n') outfile.write(' generator = 1\n\n') outfile.write('\n') def generate_phony(self, outfile): outfile.write('# Phony build target, always out of date\n') outfile.write('build PHONY: phony\n') outfile.write('\n') def generate_jar_target(self, target, outfile): fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() class_list = [] compiler = target.compilers['java'] c = 'c' m = '' e = '' f = 'f' main_class = target.get_main_class() if main_class != '': e = 'e' for src in src_list: plain_class_path = self.generate_single_java_compile(src, target, compiler, outfile) class_list.append(plain_class_path) class_dep_list = [os.path.join(self.get_target_private_dir(target), i) for i in class_list] jar_rule = 'java_LINKER' commands = [c + m + e + f] if e != '': commands.append(main_class) commands.append(self.get_target_filename(target)) # Java compilation can produce an arbitrary number of output # class files for a single source file. Thus tell jar to just # grab everything in the final package. commands += ['-C', self.get_target_private_dir(target), '.'] elem = NinjaBuildElement(self.all_outputs, outname_rel, jar_rule, []) elem.add_dep(class_dep_list) elem.add_item('ARGS', commands) elem.write(outfile) def generate_cs_resource_tasks(self, target, outfile): args = [] deps = [] for r in target.resources: rel_sourcefile = os.path.join(self.build_to_src, target.subdir, r) if r.endswith('.resources'): a = '-resource:' + rel_sourcefile elif r.endswith('.txt') or r.endswith('.resx'): ofilebase = os.path.splitext(os.path.basename(r))[0] + '.resources' ofilename = os.path.join(self.get_target_private_dir(target), ofilebase) elem = NinjaBuildElement(self.all_outputs, ofilename, "CUSTOM_COMMAND", rel_sourcefile) elem.add_item('COMMAND', ['resgen', rel_sourcefile, ofilename]) elem.add_item('DESC', 'Compiling resource %s.' % rel_sourcefile) elem.write(outfile) deps.append(ofilename) a = '-resource:' + ofilename else: raise InvalidArguments('Unknown resource file %s.' % r) args.append(a) return args, deps def generate_cs_target(self, target, outfile): buildtype = self.get_option_for_target('buildtype', target) fname = target.get_filename() outname_rel = os.path.join(self.get_target_dir(target), fname) src_list = target.get_sources() compiler = target.compilers['cs'] rel_srcs = [s.rel_to_builddir(self.build_to_src) for s in src_list] deps = [] commands = target.extra_args.get('cs', []) commands += compiler.get_buildtype_args(buildtype) if isinstance(target, build.Executable): commands.append('-target:exe') elif isinstance(target, build.SharedLibrary): commands.append('-target:library') else: raise MesonException('Unknown C# target type.') (resource_args, resource_deps) = self.generate_cs_resource_tasks(target, outfile) commands += resource_args deps += resource_deps commands += compiler.get_output_args(outname_rel) for l in target.link_targets: lname = os.path.join(self.get_target_dir(l), l.get_filename()) commands += compiler.get_link_args(lname) deps.append(lname) if '-g' in commands: outputs = [outname_rel, outname_rel + '.mdb'] else: outputs = [outname_rel] elem = NinjaBuildElement(self.all_outputs, outputs, 'cs_COMPILER', rel_srcs) elem.add_dep(deps) elem.add_item('ARGS', commands) elem.write(outfile) def generate_single_java_compile(self, src, target, compiler, outfile): args = [] args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target)) args += self.build.get_global_args(compiler) args += self.build.get_project_args(compiler, target.subproject) args += target.get_java_args() args += compiler.get_output_args(self.get_target_private_dir(target)) for i in target.include_dirs: for idir in i.get_incdirs(): args += ['-sourcepath', os.path.join(self.build_to_src, i.curdir, idir)] rel_src = src.rel_to_builddir(self.build_to_src) plain_class_path = src.fname[:-4] + 'class' rel_obj = os.path.join(self.get_target_private_dir(target), plain_class_path) element = NinjaBuildElement(self.all_outputs, rel_obj, compiler.get_language() + '_COMPILER', rel_src) element.add_item('ARGS', args) element.write(outfile) return plain_class_path def generate_java_link(self, outfile): rule = 'rule java_LINKER\n' command = ' command = jar $ARGS\n' description = ' description = Creating jar $out.\n' outfile.write(rule) outfile.write(command) outfile.write(description) outfile.write('\n') def determine_dep_vapis(self, target): """ Peek into the sources of BuildTargets we're linking with, and if any of them was built with Vala, assume that it also generated a .vapi file of the same name as the BuildTarget and return the path to it relative to the build directory. """ result = [] for dep in target.link_targets: for i in dep.sources: if hasattr(i, 'fname'): i = i.fname if i.endswith('vala'): vapiname = dep.name + '.vapi' fullname = os.path.join(self.get_target_dir(dep), vapiname) result.append(fullname) break return result def split_vala_sources(self, t): """ Splits the target's sources into .vala, .vapi, and other sources. Handles both pre-existing and generated sources. Returns a tuple (vala, vapi, others) each of which is a dictionary with the keys being the path to the file (relative to the build directory) and the value being the object that generated or represents the file. """ vala = OrderedDict() vapi = OrderedDict() others = OrderedDict() othersgen = OrderedDict() # Split pre-existing sources for s in t.get_sources(): # BuildTarget sources are always mesonlib.File files which are # either in the source root, or generated with configure_file and # in the build root if not isinstance(s, File): msg = 'All sources in target {!r} must be of type ' \ 'mesonlib.File, not {!r}'.format(t, s) raise InvalidArguments(msg) f = s.rel_to_builddir(self.build_to_src) if s.endswith('.vala'): srctype = vala elif s.endswith('.vapi'): srctype = vapi else: srctype = others srctype[f] = s # Split generated sources for gensrc in t.get_generated_sources(): for s in gensrc.get_outputs(): f = self.get_target_generated_dir(t, gensrc, s) if s.endswith('.vala'): srctype = vala elif s.endswith('.vapi'): srctype = vapi # Generated non-Vala (C/C++) sources. Won't be used for # generating the Vala compile rule below. else: srctype = othersgen # Duplicate outputs are disastrous if f in srctype and srctype[f] is not gensrc: msg = 'Duplicate output {0!r} from {1!r} {2!r}; ' \ 'conflicts with {0!r} from {4!r} {3!r}' \ ''.format(f, type(gensrc).__name__, gensrc.name, srctype[f].name, type(srctype[f]).__name__) raise InvalidArguments(msg) # Store 'somefile.vala': GeneratedList (or CustomTarget) srctype[f] = gensrc return vala, vapi, (others, othersgen) def generate_vala_compile(self, target, outfile): """Vala is compiled into C. Set up all necessary build steps here.""" (vala_src, vapi_src, other_src) = self.split_vala_sources(target) extra_dep_files = [] if len(vala_src) == 0: msg = 'Vala library {!r} has no Vala source files.' raise InvalidArguments(msg.format(target.name)) valac = target.compilers['vala'] c_out_dir = self.get_target_private_dir(target) # C files generated by valac vala_c_src = [] # Files generated by valac valac_outputs = [] # All sources that are passed to valac on the commandline all_files = list(vapi_src.keys()) for (vala_file, gensrc) in vala_src.items(): all_files.append(vala_file) # Figure out where the Vala compiler will write the compiled C file # If the Vala file is in a subdir of the build dir (in our case # because it was generated/built by something else), the subdir path # components will be preserved in the output path. But if the Vala # file is outside the build directory, the path components will be # stripped and just the basename will be used. if isinstance(gensrc, (build.CustomTarget, build.GeneratedList)) or gensrc.is_built: vala_c_file = os.path.splitext(vala_file)[0] + '.c' else: vala_c_file = os.path.splitext(os.path.basename(vala_file))[0] + '.c' # All this will be placed inside the c_out_dir vala_c_file = os.path.join(c_out_dir, vala_c_file) vala_c_src.append(vala_c_file) valac_outputs.append(vala_c_file) # TODO: Use self.generate_basic_compiler_args to get something more # consistent Until then, we should be careful to preserve the # precedence of arguments if it changes upstream. args = [] args += valac.get_buildtype_args(self.get_option_for_target('buildtype', target)) args += self.build.get_project_args(valac, target.subproject) args += self.build.get_global_args(valac) args += self.environment.coredata.external_args[valac.get_language()] # Tell Valac to output everything in our private directory. Sadly this # means it will also preserve the directory components of Vala sources # found inside the build tree (generated sources). args += ['-d', c_out_dir] args += ['-C'] if not isinstance(target, build.Executable): # Library name args += ['--library=' + target.name] # Outputted header hname = os.path.join(self.get_target_dir(target), target.vala_header) args += ['-H', hname] valac_outputs.append(hname) # Outputted vapi file vapiname = os.path.join(self.get_target_dir(target), target.vala_vapi) # Force valac to write the vapi and gir files in the target build dir. # Without this, it will write it inside c_out_dir args += ['--vapi', os.path.join('..', target.vala_vapi)] valac_outputs.append(vapiname) target.outputs += [target.vala_header, target.vala_vapi] # Install header and vapi to default locations if user requests this if len(target.install_dir) > 1 and target.install_dir[1] is True: target.install_dir[1] = self.environment.get_includedir() if len(target.install_dir) > 2 and target.install_dir[2] is True: target.install_dir[2] = os.path.join(self.environment.get_datadir(), 'vala', 'vapi') # Generate GIR if requested if isinstance(target.vala_gir, str): girname = os.path.join(self.get_target_dir(target), target.vala_gir) args += ['--gir', os.path.join('..', target.vala_gir)] valac_outputs.append(girname) target.outputs.append(target.vala_gir) # Install GIR to default location if requested by user if len(target.install_dir) > 3 and target.install_dir[3] is True: target.install_dir[3] = os.path.join(self.environment.get_datadir(), 'gir-1.0') if self.get_option_for_target('werror', target): args += valac.get_werror_args() for d in target.get_external_deps(): if isinstance(d, dependencies.PkgConfigDependency): if d.name == 'glib-2.0' and d.version_reqs is not None: for req in d.version_reqs: if req.startswith(('>=', '==')): args += ['--target-glib', req[2:]] break args += ['--pkg', d.name] elif isinstance(d, dependencies.ExternalLibrary): args += d.get_lang_args('vala') # Detect gresources and add --gresources arguments for each for (gres, gensrc) in other_src[1].items(): if isinstance(gensrc, modules.GResourceTarget): gres_xml, = self.get_custom_target_sources(gensrc) args += ['--gresources=' + gres_xml] extra_args = [] for a in target.extra_args.get('vala', []): if isinstance(a, File): relname = a.rel_to_builddir(self.build_to_src) extra_dep_files.append(relname) extra_args.append(relname) else: extra_args.append(a) dependency_vapis = self.determine_dep_vapis(target) extra_dep_files += dependency_vapis args += extra_args element = NinjaBuildElement(self.all_outputs, valac_outputs, valac.get_language() + '_COMPILER', all_files + dependency_vapis) element.add_item('ARGS', args) element.add_dep(extra_dep_files) element.write(outfile) return other_src[0], other_src[1], vala_c_src def generate_rust_target(self, target, outfile): rustc = target.compilers['rust'] relsrc = [] for i in target.get_sources(): if not rustc.can_compile(i): raise InvalidArguments('Rust target %s contains a non-rust source file.' % target.get_basename()) relsrc.append(i.rel_to_builddir(self.build_to_src)) target_name = os.path.join(target.subdir, target.get_filename()) args = ['--crate-type'] if isinstance(target, build.Executable): cratetype = 'bin' elif isinstance(target, build.SharedLibrary): cratetype = 'rlib' elif isinstance(target, build.StaticLibrary): cratetype = 'rlib' else: raise InvalidArguments('Unknown target type for rustc.') args.append(cratetype) args += rustc.get_buildtype_args(self.get_option_for_target('buildtype', target)) depfile = os.path.join(target.subdir, target.name + '.d') args += ['--emit', 'dep-info={}'.format(depfile), '--emit', 'link'] args += ['-o', os.path.join(target.subdir, target.get_filename())] orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets] linkdirs = OrderedDict() for d in target.link_targets: linkdirs[d.subdir] = True for d in linkdirs.keys(): if d == '': d = '.' args += ['-L', d] element = NinjaBuildElement(self.all_outputs, target_name, 'rust_COMPILER', relsrc) if len(orderdeps) > 0: element.add_orderdep(orderdeps) element.add_item('ARGS', args) element.add_item('targetdep', depfile) element.add_item('cratetype', cratetype) element.write(outfile) def swift_module_file_name(self, target): return os.path.join(self.get_target_private_dir(target), self.target_swift_modulename(target) + '.swiftmodule') def target_swift_modulename(self, target): return target.name def is_swift_target(self, target): for s in target.sources: if s.endswith('swift'): return True return False def determine_swift_dep_modules(self, target): result = [] for l in target.link_targets: if self.is_swift_target(l): result.append(self.swift_module_file_name(l)) return result def determine_swift_dep_dirs(self, target): result = [] for l in target.link_targets: result.append(self.get_target_private_dir_abs(l)) return result def get_swift_link_deps(self, target): result = [] for l in target.link_targets: result.append(self.get_target_filename(l)) return result def split_swift_generated_sources(self, target): all_srcs = self.get_target_generated_sources(target) srcs = [] others = [] for i in all_srcs: if i.endswith('.swift'): srcs.append(i) else: others.append(i) return srcs, others def generate_swift_target(self, target, outfile): module_name = self.target_swift_modulename(target) swiftc = target.compilers['swift'] abssrc = [] abs_headers = [] header_imports = [] for i in target.get_sources(): if swiftc.can_compile(i): relsrc = i.rel_to_builddir(self.build_to_src) abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), relsrc)) abssrc.append(abss) elif self.environment.is_header(i): relh = i.rel_to_builddir(self.build_to_src) absh = os.path.normpath(os.path.join(self.environment.get_build_dir(), relh)) abs_headers.append(absh) header_imports += swiftc.get_header_import_args(absh) else: raise InvalidArguments('Swift target %s contains a non-swift source file.' % target.get_basename()) os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True) compile_args = swiftc.get_compile_only_args() compile_args += swiftc.get_module_args(module_name) link_args = swiftc.get_output_args(os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))) rundir = self.get_target_private_dir(target) out_module_name = self.swift_module_file_name(target) in_module_files = self.determine_swift_dep_modules(target) abs_module_dirs = self.determine_swift_dep_dirs(target) module_includes = [] for x in abs_module_dirs: module_includes += swiftc.get_include_args(x) link_deps = self.get_swift_link_deps(target) abs_link_deps = [os.path.join(self.environment.get_build_dir(), x) for x in link_deps] (rel_generated, _) = self.split_swift_generated_sources(target) abs_generated = [os.path.join(self.environment.get_build_dir(), x) for x in rel_generated] # We need absolute paths because swiftc needs to be invoked in a subdir # and this is the easiest way about it. objects = [] # Relative to swift invocation dir rel_objects = [] # Relative to build.ninja for i in abssrc + abs_generated: base = os.path.split(i)[1] oname = os.path.splitext(base)[0] + '.o' objects.append(oname) rel_objects.append(os.path.join(self.get_target_private_dir(target), oname)) # Swiftc does not seem to be able to emit objects and module files in one go. elem = NinjaBuildElement(self.all_outputs, rel_objects, 'swift_COMPILER', abssrc) elem.add_dep(in_module_files + rel_generated) elem.add_dep(abs_headers) elem.add_item('ARGS', compile_args + header_imports + abs_generated + module_includes) elem.add_item('RUNDIR', rundir) elem.write(outfile) elem = NinjaBuildElement(self.all_outputs, out_module_name, 'swift_COMPILER', abssrc) elem.add_dep(in_module_files + rel_generated) elem.add_item('ARGS', compile_args + abs_generated + module_includes + swiftc.get_mod_gen_args()) elem.add_item('RUNDIR', rundir) elem.write(outfile) if isinstance(target, build.StaticLibrary): elem = self.generate_link(target, outfile, self.get_target_filename(target), rel_objects, self.build.static_linker) elem.write(outfile) elif isinstance(target, build.Executable): elem = NinjaBuildElement(self.all_outputs, self.get_target_filename(target), 'swift_COMPILER', []) elem.add_dep(rel_objects) elem.add_dep(link_deps) elem.add_item('ARGS', link_args + swiftc.get_std_exe_link_args() + objects + abs_link_deps) elem.add_item('RUNDIR', rundir) elem.write(outfile) else: raise MesonException('Swift supports only executable and static library targets.') def generate_static_link_rules(self, is_cross, outfile): if 'java' in self.build.compilers: if not is_cross: self.generate_java_link(outfile) if is_cross: if self.environment.cross_info.need_cross_compiler(): static_linker = self.build.static_cross_linker else: static_linker = self.build.static_linker crstr = '_CROSS' else: static_linker = self.build.static_linker crstr = '' if static_linker is None: return rule = 'rule STATIC%s_LINKER\n' % crstr # We don't use @file.rsp on Windows with ArLinker because llvm-ar and # gcc-ar blindly pass the --plugin argument to `ar` and you cannot pass # options as arguments while using the @file.rsp syntax. # See: https://github.com/mesonbuild/meson/issues/1646 if mesonlib.is_windows() and not isinstance(static_linker, compilers.ArLinker): command_template = ''' command = {executable} @$out.rsp rspfile = $out.rsp rspfile_content = $LINK_ARGS {output_args} $in ''' else: command_template = ' command = {executable} $LINK_ARGS {output_args} $in\n' cmdlist = [] # FIXME: Must normalize file names with pathlib.Path before writing # them out to fix this properly on Windows. See: # https://github.com/mesonbuild/meson/issues/1517 # https://github.com/mesonbuild/meson/issues/1526 if isinstance(static_linker, compilers.ArLinker) and not mesonlib.is_windows(): # `ar` has no options to overwrite archives. It always appends, # which is never what we want. Delete an existing library first if # it exists. https://github.com/mesonbuild/meson/issues/1355 cmdlist = [execute_wrapper, rmfile_prefix.format('$out')] cmdlist += static_linker.get_exelist() command = command_template.format( executable=' '.join(cmdlist), output_args=' '.join(static_linker.get_output_args('$out'))) description = ' description = Static linking library $out\n\n' outfile.write(rule) outfile.write(command) outfile.write(description) def generate_dynamic_link_rules(self, outfile): ctypes = [(self.build.compilers, False)] if self.environment.is_cross_build(): if self.environment.cross_info.need_cross_compiler(): ctypes.append((self.build.cross_compilers, True)) else: # Native compiler masquerades as the cross compiler. ctypes.append((self.build.compilers, True)) else: ctypes.append((self.build.cross_compilers, True)) for (complist, is_cross) in ctypes: for langname, compiler in complist.items(): if langname == 'java' \ or langname == 'vala' \ or langname == 'rust' \ or langname == 'cs': continue crstr = '' cross_args = [] if is_cross: crstr = '_CROSS' try: cross_args = self.environment.cross_info.config['properties'][langname + '_link_args'] except KeyError: pass rule = 'rule %s%s_LINKER\n' % (langname, crstr) if mesonlib.is_windows(): command_template = ''' command = {executable} @$out.rsp rspfile = $out.rsp rspfile_content = $ARGS {output_args} $in $LINK_ARGS {cross_args} $aliasing ''' else: command_template = ' command = {executable} $ARGS {output_args} $in $LINK_ARGS {cross_args} $aliasing\n' command = command_template.format( executable=' '.join(compiler.get_linker_exelist()), cross_args=' '.join(cross_args), output_args=' '.join(compiler.get_linker_output_args('$out')) ) description = ' description = Linking target $out' outfile.write(rule) outfile.write(command) outfile.write(description) outfile.write('\n') outfile.write('\n') symrule = 'rule SHSYM\n' symcmd = ' command = "%s" "%s" %s %s %s %s $CROSS\n' % (ninja_quote(sys.executable), self.environment.get_build_command(), '--internal', 'symbolextractor', '$in', '$out') synstat = ' restat = 1\n' syndesc = ' description = Generating symbol file $out.\n' outfile.write(symrule) outfile.write(symcmd) outfile.write(synstat) outfile.write(syndesc) outfile.write('\n') def generate_java_compile_rule(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) command = ' command = %s $ARGS $in\n' % invoc description = ' description = Compiling Java object $in.\n' outfile.write(rule) outfile.write(command) outfile.write(description) outfile.write('\n') def generate_cs_compile_rule(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) command = ' command = %s $ARGS $in\n' % invoc description = ' description = Compiling cs target $out.\n' outfile.write(rule) outfile.write(command) outfile.write(description) outfile.write('\n') def generate_vala_compile_rules(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) command = ' command = %s $ARGS $in\n' % invoc description = ' description = Compiling Vala source $in.\n' restat = ' restat = 1\n' # ValaC does this always to take advantage of it. outfile.write(rule) outfile.write(command) outfile.write(description) outfile.write(restat) outfile.write('\n') def generate_rust_compile_rules(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) command = ' command = %s $ARGS $in\n' % invoc description = ' description = Compiling Rust source $in.\n' depfile = ' depfile = $targetdep\n' depstyle = ' deps = gcc\n' outfile.write(rule) outfile.write(command) outfile.write(description) outfile.write(depfile) outfile.write(depstyle) outfile.write('\n') def generate_swift_compile_rules(self, compiler, outfile): rule = 'rule %s_COMPILER\n' % compiler.get_language() full_exe = [sys.executable, self.environment.get_build_command(), '--internal', 'dirchanger', '$RUNDIR'] + compiler.get_exelist() invoc = ' '.join([ninja_quote(i) for i in full_exe]) command = ' command = %s $ARGS $in\n' % invoc description = ' description = Compiling Swift source $in.\n' outfile.write(rule) outfile.write(command) outfile.write(description) outfile.write('\n') def generate_fortran_dep_hack(self, outfile): if mesonlib.is_windows(): cmd = 'cmd /C ""' else: cmd = 'true' template = '''# Workaround for these issues: # https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485 rule FORTRAN_DEP_HACK command = %s description = Dep hack restat = 1 ''' outfile.write(template % cmd) def generate_llvm_ir_compile_rule(self, compiler, is_cross, outfile): if getattr(self, 'created_llvm_ir_rule', False): return rule = 'rule llvm_ir{}_COMPILER\n'.format('_CROSS' if is_cross else '') if mesonlib.is_windows(): command_template = ' command = {executable} @$out.rsp\n' \ ' rspfile = $out.rsp\n' \ ' rspfile_content = {cross_args} $ARGS {output_args} {compile_only_args} $in\n' else: command_template = ' command = {executable} {cross_args} $ARGS {output_args} {compile_only_args} $in\n' command = command_template.format( executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]), cross_args=' '.join(self.get_cross_info_lang_args(compiler.language, is_cross)), output_args=' '.join(compiler.get_output_args('$out')), compile_only_args=' '.join(compiler.get_compile_only_args()) ) description = ' description = Compiling LLVM IR object $in.\n' outfile.write(rule) outfile.write(command) outfile.write(description) outfile.write('\n') self.created_llvm_ir_rule = True def get_cross_info_lang_args(self, lang, is_cross): if is_cross: try: return self.environment.cross_info.config['properties'][lang + '_args'] except KeyError: pass return [] def generate_compile_rule_for(self, langname, compiler, qstr, is_cross, outfile): if langname == 'java': if not is_cross: self.generate_java_compile_rule(compiler, outfile) return if langname == 'cs': if not is_cross: self.generate_cs_compile_rule(compiler, outfile) return if langname == 'vala': if not is_cross: self.generate_vala_compile_rules(compiler, outfile) return if langname == 'rust': if not is_cross: self.generate_rust_compile_rules(compiler, outfile) return if langname == 'swift': if not is_cross: self.generate_swift_compile_rules(compiler, outfile) return if langname == 'fortran': self.generate_fortran_dep_hack(outfile) if is_cross: crstr = '_CROSS' else: crstr = '' rule = 'rule %s%s_COMPILER\n' % (langname, crstr) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') quoted_depargs = [] for d in depargs: if d != '$out' and d != '$in': d = qstr % d quoted_depargs.append(d) cross_args = self.get_cross_info_lang_args(langname, is_cross) if mesonlib.is_windows(): command_template = ''' command = {executable} @$out.rsp rspfile = $out.rsp rspfile_content = {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in ''' else: command_template = ' command = {executable} {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in\n' command = command_template.format( executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]), cross_args=' '.join(cross_args), dep_args=' '.join(quoted_depargs), output_args=' '.join(compiler.get_output_args('$out')), compile_only_args=' '.join(compiler.get_compile_only_args()) ) description = ' description = Compiling %s object $out\n' % langname if compiler.get_id() == 'msvc': deps = ' deps = msvc\n' else: deps = ' deps = gcc\n' deps += ' depfile = $DEPFILE\n' outfile.write(rule) outfile.write(command) outfile.write(deps) outfile.write(description) outfile.write('\n') def generate_pch_rule_for(self, langname, compiler, qstr, is_cross, outfile): if langname != 'c' and langname != 'cpp': return if is_cross: crstr = '_CROSS' else: crstr = '' rule = 'rule %s%s_PCH\n' % (langname, crstr) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') cross_args = [] if is_cross: try: cross_args = self.environment.cross_info.config['properties'][langname + '_args'] except KeyError: pass quoted_depargs = [] for d in depargs: if d != '$out' and d != '$in': d = qstr % d quoted_depargs.append(d) if compiler.get_id() == 'msvc': output = '' else: output = ' '.join(compiler.get_output_args('$out')) command = " command = {executable} {cross_args} $ARGS {dep_args} {output_args} {compile_only_args} $in\n".format( executable=' '.join(compiler.get_exelist()), cross_args=' '.join(cross_args), dep_args=' '.join(quoted_depargs), output_args=output, compile_only_args=' '.join(compiler.get_compile_only_args()) ) description = ' description = Precompiling header %s\n' % '$in' if compiler.get_id() == 'msvc': deps = ' deps = msvc\n' else: deps = ' deps = gcc\n' deps += ' depfile = $DEPFILE\n' outfile.write(rule) outfile.write(command) outfile.write(deps) outfile.write(description) outfile.write('\n') def generate_compile_rules(self, outfile): qstr = quote_char + "%s" + quote_char for langname, compiler in self.build.compilers.items(): if compiler.get_id() == 'clang': self.generate_llvm_ir_compile_rule(compiler, False, outfile) self.generate_compile_rule_for(langname, compiler, qstr, False, outfile) self.generate_pch_rule_for(langname, compiler, qstr, False, outfile) if self.environment.is_cross_build(): # In case we are going a target-only build, make the native compilers # masquerade as cross compilers. if self.environment.cross_info.need_cross_compiler(): cclist = self.build.cross_compilers else: cclist = self.build.compilers for langname, compiler in cclist.items(): if compiler.get_id() == 'clang': self.generate_llvm_ir_compile_rule(compiler, True, outfile) self.generate_compile_rule_for(langname, compiler, qstr, True, outfile) self.generate_pch_rule_for(langname, compiler, qstr, True, outfile) outfile.write('\n') def generate_generator_list_rules(self, target, outfile): # CustomTargets have already written their rules, # so write rules for GeneratedLists here for genlist in target.get_generated_sources(): if isinstance(genlist, build.CustomTarget): continue self.generate_genlist_for_target(genlist, target, outfile) def generate_genlist_for_target(self, genlist, target, outfile): generator = genlist.get_generator() exe = generator.get_exe() exe_arr = self.exe_object_to_cmd_array(exe) infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() base_args = generator.get_arglist() extra_dependencies = [os.path.join(self.build_to_src, i) for i in genlist.extra_depends] for i in range(len(infilelist)): if len(generator.outputs) == 1: sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i]) else: sole_output = '' curfile = infilelist[i] infilename = curfile.rel_to_builddir(self.build_to_src) outfiles = genlist.get_outputs_for(curfile) outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles] if generator.depfile is None: rulename = 'CUSTOM_COMMAND' args = base_args else: rulename = 'CUSTOM_COMMAND_DEP' depfilename = generator.get_dep_outname(infilename) depfile = os.path.join(self.get_target_private_dir(target), depfilename) args = [x.replace('@DEPFILE@', depfile) for x in base_args] args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output) for x in args] args = self.replace_outputs(args, self.get_target_private_dir(target), outfilelist) # We have consumed output files, so drop them from the list of remaining outputs. if sole_output == '': outfilelist = outfilelist[len(generator.outputs):] relout = self.get_target_private_dir(target) args = [x.replace("@SOURCE_DIR@", self.build_to_src).replace("@BUILD_DIR@", relout) for x in args] args = [x.replace("@SOURCE_ROOT@", self.build_to_src).replace("@BUILD_ROOT@", '.') for x in args] cmdlist = exe_arr + self.replace_extra_args(args, genlist) elem = NinjaBuildElement(self.all_outputs, outfiles, rulename, infilename) if generator.depfile is not None: elem.add_item('DEPFILE', depfile) if len(extra_dependencies) > 0: elem.add_dep(extra_dependencies) elem.add_item('DESC', 'Generating $out') if isinstance(exe, build.BuildTarget): elem.add_dep(self.get_target_filename(exe)) elem.add_item('COMMAND', cmdlist) elem.write(outfile) def scan_fortran_module_outputs(self, target): compiler = None for lang, c in self.build.compilers.items(): if lang == 'fortran': compiler = c break if compiler is None: self.fortran_deps[target.get_basename()] = {} return modre = re.compile(r"\s*module\s+(\w+)", re.IGNORECASE) module_files = {} for s in target.get_sources(): # FIXME, does not work for generated Fortran sources, # but those are really rare. I hope. if not compiler.can_compile(s): continue filename = os.path.join(self.environment.get_source_dir(), s.subdir, s.fname) with open(filename) as f: for line in f: modmatch = modre.match(line) if modmatch is not None: modname = modmatch.group(1) if modname.lower() == 'procedure': # MODULE PROCEDURE construct continue if modname in module_files: raise InvalidArguments( 'Namespace collision: module %s defined in ' 'two files %s and %s.' % (modname, module_files[modname], s)) module_files[modname] = s self.fortran_deps[target.get_basename()] = module_files def get_fortran_deps(self, compiler, src, target): mod_files = [] usere = re.compile(r"\s*use\s+(\w+)", re.IGNORECASE) dirname = self.get_target_private_dir(target) tdeps = self.fortran_deps[target.get_basename()] with open(src) as f: for line in f: usematch = usere.match(line) if usematch is not None: usename = usematch.group(1) if usename not in tdeps: # The module is not provided by any source file. This # is due to: # a) missing file/typo/etc # b) using a module provided by the compiler, such as # OpenMP # There's no easy way to tell which is which (that I # know of) so just ignore this and go on. Ideally we # would print a warning message to the user but this is # a common occurrence, which would lead to lots of # distracting noise. continue mod_source_file = tdeps[usename] # Check if a source uses a module it exports itself. # Potential bug if multiple targets have a file with # the same name. if mod_source_file.fname == os.path.split(src)[1]: continue mod_name = compiler.module_name_to_filename( usematch.group(1)) mod_files.append(os.path.join(dirname, mod_name)) return mod_files def get_cross_stdlib_args(self, target, compiler): if not target.is_cross: return [] if not self.environment.cross_info.has_stdlib(compiler.language): return [] return compiler.get_no_stdinc_args() def get_compile_debugfile_args(self, compiler, target, objfile): if compiler.id != 'msvc': return [] # The way MSVC uses PDB files is documented exactly nowhere so # the following is what we have been able to decipher via # reverse engineering. # # Each object file gets the path of its PDB file written # inside it. This can be either the final PDB (for, say, # foo.exe) or an object pdb (for foo.obj). If the former, then # each compilation step locks the pdb file for writing, which # is a bottleneck and object files from one target can not be # used in a different target. The latter seems to be the # sensible one (and what Unix does) but there is a catch. If # you try to use precompiled headers MSVC will error out # because both source and pch pdbs go in the same file and # they must be the same. # # This means: # # - pch files must be compiled anew for every object file (negating # the entire point of having them in the first place) # - when using pch, output must go to the target pdb # # Since both of these are broken in some way, use the one that # works for each target. This unfortunately means that you # can't combine pch and object extraction in a single target. # # PDB files also lead to filename collisions. A target foo.exe # has a corresponding foo.pdb. A shared library foo.dll _also_ # has pdb file called foo.pdb. So will a static library # foo.lib, which clobbers both foo.pdb _and_ the dll file's # export library called foo.lib (by default, currently we name # them libfoo.a to avoidt this issue). You can give the files # unique names such as foo_exe.pdb but VC also generates a # bunch of other files which take their names from the target # basename (i.e. "foo") and stomp on each other. # # CMake solves this problem by doing two things. First of all # static libraries do not generate pdb files at # all. Presumably you don't need them and VC is smart enough # to look up the original data when linking (speculation, not # tested). The second solution is that you can only have # target named "foo" as an exe, shared lib _or_ static # lib. This makes filename collisions not happen. The downside # is that you can't have an executable foo that uses a shared # library libfoo.so, which is a common idiom on Unix. # # If you feel that the above is completely wrong and all of # this is actually doable, please send patches. if target.has_pch(): tfilename = self.get_target_filename_abs(target) return compiler.get_compile_debugfile_args(tfilename, pch=True) else: 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) def generate_llvm_ir_compile(self, target, outfile, src): compiler = get_compiler_for_source(target.compilers.values(), src) commands = CompilerArgs(compiler) # Compiler args for compiling this target commands += compilers.get_base_compile_args(self.environment.coredata.base_options, compiler) if isinstance(src, (RawFilename, File)): src_filename = src.fname elif os.path.isabs(src): src_filename = os.path.basename(src) else: src_filename = src obj_basename = src_filename.replace('/', '_').replace('\\', '_') rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename) rel_obj += '.' + self.environment.get_object_suffix() commands += self.get_compile_debugfile_args(compiler, target, rel_obj) if isinstance(src, RawFilename): rel_src = src.fname elif isinstance(src, File): rel_src = src.rel_to_builddir(self.build_to_src) else: raise InvalidArguments('Invalid source type: {!r}'.format(src)) # Write the Ninja build command compiler_name = 'llvm_ir{}_COMPILER'.format('_CROSS' if target.is_cross else '') element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src) # Convert from GCC-style link argument naming to the naming used by the # current compiler. commands = commands.to_native() element.add_item('ARGS', commands) element.write(outfile) return rel_obj def get_source_dir_include_args(self, target, compiler): curdir = target.get_subdir() tmppath = os.path.normpath(os.path.join(self.build_to_src, curdir)) return compiler.get_include_args(tmppath, False) def get_build_dir_include_args(self, target, compiler): curdir = target.get_subdir() if curdir == '': curdir = '.' return compiler.get_include_args(curdir, False) def get_custom_target_dir_include_args(self, target, compiler): custom_target_include_dirs = [] for i in target.get_generated_sources(): # Generator output goes into the target private dir which is # already in the include paths list. Only custom targets have their # own target build dir. if not isinstance(i, build.CustomTarget): continue idir = self.get_target_dir(i) if idir not in custom_target_include_dirs: custom_target_include_dirs.append(idir) incs = [] for i in custom_target_include_dirs: incs += compiler.get_include_args(i, False) return incs def _generate_single_compile(self, target, compiler, is_generated=False): base_proxy = backends.OptionOverrideProxy(target.option_overrides, self.environment.coredata.base_options) # Create an empty commands list, and start adding arguments from # various sources in the order in which they must override each other commands = CompilerArgs(compiler) # Add compiler args for compiling this target derived from 'base' build # options passed on the command-line, in default_options, etc. # These have the lowest priority. commands += compilers.get_base_compile_args(base_proxy, compiler) # The code generated by valac is usually crap and has tons of unused # variables and such, so disable warnings for Vala C sources. no_warn_args = (is_generated == 'vala') # Add compiler args and include paths from several sources; defaults, # build options, external dependencies, etc. commands += self.generate_basic_compiler_args(target, compiler, no_warn_args) # Add include dirs from the `include_directories:` kwarg on the target # and from `include_directories:` of internal deps of the target. # # Target include dirs should override internal deps include dirs. # This is handled in BuildTarget.process_kwargs() # # Include dirs from internal deps should override include dirs from # external deps and must maintain the order in which they are specified. # Hence, we must reverse the list so that the order is preserved. for i in reversed(target.get_include_dirs()): basedir = i.get_curdir() for d in i.get_incdirs(): # Avoid superfluous '/.' at the end of paths when d is '.' if d not in ('', '.'): expdir = os.path.join(basedir, d) else: expdir = basedir srctreedir = os.path.join(self.build_to_src, expdir) # Add source subdir first so that the build subdir overrides it sargs = compiler.get_include_args(srctreedir, i.is_system) commands += sargs # There may be include dirs where a build directory has not been # created for some source dir. For example if someone does this: # # inc = include_directories('foo/bar/baz') # # But never subdir()s into the actual dir. if os.path.isdir(os.path.join(self.environment.get_build_dir(), expdir)): bargs = compiler.get_include_args(expdir, i.is_system) else: bargs = [] commands += bargs for d in i.get_extra_build_dirs(): commands += compiler.get_include_args(d, i.is_system) # Add per-target compile args, f.ex, `c_args : ['-DFOO']`. We set these # near the end since these are supposed to override everything else. commands += self.escape_extra_args(compiler, target.get_extra_args(compiler.get_language())) # Add source dir and build dir. Project-specific and target-specific # include paths must override per-target compile args, include paths # from external dependencies, internal dependencies, and from # per-target `include_directories:` # # We prefer headers in the build dir and the custom target dir over the # source dir since, for instance, the user might have an # srcdir == builddir Autotools build in their source tree. Many # projects that are moving to Meson have both Meson and Autotools in # parallel as part of the transition. commands += self.get_source_dir_include_args(target, compiler) commands += self.get_custom_target_dir_include_args(target, compiler) commands += self.get_build_dir_include_args(target, compiler) # Finally add the private dir for the target to the include path. This # must override everything else and must be the final path added. commands += compiler.get_include_args(self.get_target_private_dir(target), False) return commands def generate_single_compile(self, target, outfile, src, is_generated=False, header_deps=[], order_deps=[]): """ Compiles C/C++, ObjC/ObjC++, Fortran, and D sources """ if isinstance(src, str) and src.endswith('.h'): raise AssertionError('BUG: sources should not contain headers {!r}'.format(src)) if isinstance(src, RawFilename) and src.fname.endswith('.h'): raise AssertionError('BUG: sources should not contain headers {!r}'.format(src.fname)) if isinstance(src, str) and src.endswith('.h'): raise AssertionError('BUG: sources should not contain headers {!r}'.format(src)) if isinstance(src, RawFilename) and src.fname.endswith('.h'): raise AssertionError('BUG: sources should not contain headers {!r}'.format(src.fname)) compiler = get_compiler_for_source(target.compilers.values(), src) key = (target, compiler, is_generated) if key in self.target_arg_cache: commands = self.target_arg_cache[key] else: commands = self._generate_single_compile(target, compiler, is_generated) self.target_arg_cache[key] = commands commands = CompilerArgs(commands.compiler, commands) # FIXME: This file handling is atrocious and broken. We need to # replace it with File objects used consistently everywhere. if isinstance(src, RawFilename): rel_src = src.fname if os.path.isabs(src.fname): abs_src = src.fname else: abs_src = os.path.join(self.environment.get_build_dir(), src.fname) elif isinstance(src, mesonlib.File): rel_src = src.rel_to_builddir(self.build_to_src) abs_src = src.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) elif is_generated: raise AssertionError('BUG: broken generated source file handling for {!r}'.format(src)) else: if isinstance(src, File): rel_src = src.rel_to_builddir(self.build_to_src) else: raise InvalidArguments('Invalid source type: {!r}'.format(src)) abs_src = os.path.join(self.environment.get_build_dir(), rel_src) if isinstance(src, (RawFilename, File)): src_filename = src.fname elif os.path.isabs(src): src_filename = os.path.basename(src) else: src_filename = src obj_basename = src_filename.replace('/', '_').replace('\\', '_') rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename) rel_obj += '.' + self.environment.get_object_suffix() dep_file = compiler.depfile_for_object(rel_obj) # Add MSVC debug file generation compile flags: /Fd /FS commands += self.get_compile_debugfile_args(compiler, target, rel_obj) # PCH handling if self.environment.coredata.base_options.get('b_pch', False): commands += self.get_pch_include_args(compiler, target) pchlist = target.get_pch(compiler.language) else: pchlist = [] if len(pchlist) == 0: pch_dep = [] elif compiler.id == 'intel': pch_dep = [] else: arr = [] i = os.path.join(self.get_target_private_dir(target), compiler.get_pch_name(pchlist[0])) arr.append(i) pch_dep = arr crstr = '' if target.is_cross: crstr = '_CROSS' compiler_name = '%s%s_COMPILER' % (compiler.get_language(), crstr) extra_deps = [] if compiler.get_language() == 'fortran': # Can't read source file to scan for deps if it's generated later # at build-time. Skip scanning for deps, and just set the module # outdir argument instead. # https://github.com/mesonbuild/meson/issues/1348 if not is_generated: extra_deps += self.get_fortran_deps(compiler, abs_src, target) # Dependency hack. Remove once multiple outputs in Ninja is fixed: # https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 for modname, srcfile in self.fortran_deps[target.get_basename()].items(): modfile = os.path.join(self.get_target_private_dir(target), compiler.module_name_to_filename(modname)) if srcfile == src: depelem = NinjaBuildElement(self.all_outputs, modfile, 'FORTRAN_DEP_HACK', rel_obj) depelem.write(outfile) commands += compiler.get_module_outdir_args(self.get_target_private_dir(target)) element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src) for d in header_deps: if isinstance(d, RawFilename): d = d.fname elif not self.has_dir_part(d): d = os.path.join(self.get_target_private_dir(target), d) element.add_dep(d) for d in extra_deps: element.add_dep(d) for d in order_deps: if isinstance(d, RawFilename): d = d.fname elif not self.has_dir_part(d): d = os.path.join(self.get_target_private_dir(target), d) element.add_orderdep(d) element.add_orderdep(pch_dep) # Convert from GCC-style link argument naming to the naming used by the # current compiler. commands = commands.to_native() for i in self.get_fortran_orderdeps(target, compiler): element.add_orderdep(i) element.add_item('DEPFILE', dep_file) element.add_item('ARGS', commands) element.write(outfile) return rel_obj def has_dir_part(self, fname): # FIXME FIXME: The usage of this is a terrible and unreliable hack return '/' in fname or '\\' in fname # Fortran is a bit weird (again). When you link against a library, just compiling a source file # requires the mod files that are output when single files are built. To do this right we would need to # scan all inputs and write out explicit deps for each file. That is stoo slow and too much effort so # instead just have an ordered dependendy on the library. This ensures all required mod files are created. # The real deps are then detected via dep file generation from the compiler. This breaks on compilers that # produce incorrect dep files but such is life. def get_fortran_orderdeps(self, target, compiler): if compiler.language != 'fortran': return [] return [os.path.join(self.get_target_dir(lt), lt.get_filename()) for lt in target.link_targets] def generate_msvc_pch_command(self, target, compiler, pch): if len(pch) != 2: raise RuntimeError('MSVC requires one header and one source to produce precompiled headers.') header = pch[0] source = pch[1] pchname = compiler.get_pch_name(header) dst = os.path.join(self.get_target_private_dir(target), pchname) commands = [] commands += self.generate_basic_compiler_args(target, compiler) just_name = os.path.split(header)[1] (objname, pch_args) = compiler.gen_pch_args(just_name, source, dst) commands += pch_args commands += self.get_compile_debugfile_args(compiler, target, objname) dep = dst + '.' + compiler.get_depfile_suffix() return commands, dep, dst, [objname] def generate_gcc_pch_command(self, target, compiler, pch): commands = [] commands += self.generate_basic_compiler_args(target, compiler) dst = os.path.join(self.get_target_private_dir(target), os.path.split(pch)[-1] + '.' + compiler.get_pch_suffix()) dep = dst + '.' + compiler.get_depfile_suffix() return commands, dep, dst, [] # Gcc does not create an object file during pch generation. def generate_pch(self, target, outfile): cstr = '' pch_objects = [] if target.is_cross: cstr = '_CROSS' for lang in ['c', 'cpp']: pch = target.get_pch(lang) if len(pch) == 0: continue if '/' not in pch[0] or '/' not in pch[-1]: msg = 'Precompiled header of {!r} must not be in the same ' \ 'directory as source, please put it in a subdirectory.' \ ''.format(target.get_basename()) raise InvalidArguments(msg) compiler = target.compilers[lang] if compiler.id == 'msvc': src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[-1]) (commands, dep, dst, objs) = self.generate_msvc_pch_command(target, compiler, pch) extradep = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0]) elif compiler.id == 'intel': # Intel generates on target generation continue else: src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0]) (commands, dep, dst, objs) = self.generate_gcc_pch_command(target, compiler, pch[0]) extradep = None pch_objects += objs rulename = compiler.get_language() + cstr + '_PCH' elem = NinjaBuildElement(self.all_outputs, dst, rulename, src) if extradep is not None: elem.add_dep(extradep) elem.add_item('ARGS', commands) elem.add_item('DEPFILE', dep) elem.write(outfile) return pch_objects def generate_shsym(self, outfile, target): target_name = self.get_target_filename(target) targetdir = self.get_target_private_dir(target) symname = os.path.join(targetdir, target_name + '.symbols') elem = NinjaBuildElement(self.all_outputs, symname, 'SHSYM', target_name) if self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler(): elem.add_item('CROSS', '--cross-host=' + self.environment.cross_info.config['host_machine']['system']) elem.write(outfile) def get_cross_stdlib_link_args(self, target, linker): if isinstance(target, build.StaticLibrary) or not target.is_cross: return [] if not self.environment.cross_info.has_stdlib(linker.language): return [] return linker.get_no_stdlib_link_args() def get_target_type_link_args(self, target, linker): abspath = os.path.join(self.environment.get_build_dir(), target.subdir) commands = [] if isinstance(target, build.Executable): # Currently only used with the Swift compiler to add '-emit-executable' commands += linker.get_std_exe_link_args() elif isinstance(target, build.SharedLibrary): if isinstance(target, build.SharedModule): commands += linker.get_std_shared_module_link_args() else: commands += linker.get_std_shared_lib_link_args() # All shared libraries are PIC commands += linker.get_pic_args() # Add -Wl,-soname arguments on Linux, -install_name on OS X commands += linker.get_soname_args(target.prefix, target.name, target.suffix, abspath, target.soversion, isinstance(target, build.SharedModule)) # This is only visited when using the Visual Studio toolchain if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'): commands += linker.gen_vs_module_defs_args(target.vs_module_defs.rel_to_builddir(self.build_to_src)) # This is only visited when building for Windows using either MinGW/GCC or Visual Studio if target.import_filename: commands += linker.gen_import_library_args(os.path.join(target.subdir, target.import_filename)) elif isinstance(target, build.StaticLibrary): commands += linker.get_std_link_args() else: raise RuntimeError('Unknown build target type.') return commands def get_link_whole_args(self, linker, target): target_args = self.build_target_link_arguments(linker, target.link_whole_targets) return linker.get_link_whole_for(target_args) if len(target_args) else [] def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]): if isinstance(target, build.StaticLibrary): linker_base = 'STATIC' else: linker_base = linker.get_language() # Fixme. if isinstance(target, build.SharedLibrary): self.generate_shsym(outfile, target) crstr = '' if target.is_cross: crstr = '_CROSS' linker_rule = linker_base + crstr + '_LINKER' # Create an empty commands list, and start adding link arguments from # various sources in the order in which they must override each other # starting from hard-coded defaults followed by build options and so on. # # Once all the linker options have been passed, we will start passing # libraries and library paths from internal and external sources. commands = CompilerArgs(linker) # First, the trivial ones that are impossible to override. # # Add linker args for linking this target derived from 'base' build # options passed on the command-line, in default_options, etc. # These have the lowest priority. if not isinstance(target, build.StaticLibrary): commands += compilers.get_base_link_args(self.environment.coredata.base_options, linker, isinstance(target, build.SharedModule)) # Add -nostdlib if needed; can't be overriden commands += self.get_cross_stdlib_link_args(target, linker) # Add things like /NOLOGO; usually can't be overriden commands += linker.get_linker_always_args() # Add buildtype linker args: optimization level, etc. commands += linker.get_buildtype_linker_args(self.get_option_for_target('buildtype', target)) # Add /DEBUG and the pdb filename when using MSVC commands += self.get_link_debugfile_args(linker, target, outname) # Add link args specific to this BuildTarget type, such as soname args, # PIC, import library generation, etc. commands += self.get_target_type_link_args(target, linker) # Archives that are copied wholesale in the result. Must be before any # other link targets so missing symbols from whole archives are found in those. if not isinstance(target, build.StaticLibrary): commands += self.get_link_whole_args(linker, target) if not isinstance(target, build.StaticLibrary): # Add link args added using add_project_link_arguments() commands += self.build.get_project_link_args(linker, target.subproject) # Add link args added using add_global_link_arguments() # These override per-project link arguments commands += self.build.get_global_link_args(linker) # Link args added from the env: LDFLAGS. We want these to # override all the defaults but not the per-target link args. commands += self.environment.coredata.external_link_args[linker.get_language()] # Now we will add libraries and library paths from various sources # Add link args to link to all internal libraries (link_with:) and # internal dependencies needed by this target. if linker_base == 'STATIC': # Link arguments of static libraries are not put in the command # line of the library. They are instead appended to the command # line where the static library is used. dependencies = [] else: dependencies = target.get_dependencies() commands += self.build_target_link_arguments(linker, dependencies) # For 'automagic' deps: Boost and GTest. Also dependency('threads'). # pkg-config puts the thread flags itself via `Cflags:` for d in target.external_deps: if d.need_threads(): commands += linker.thread_link_flags() # Only non-static built targets need link args and link dependencies if not isinstance(target, build.StaticLibrary): commands += target.link_args # External deps must be last because target link libraries may depend on them. for dep in target.get_external_deps(): commands += dep.get_link_args() for d in target.get_dependencies(): if isinstance(d, build.StaticLibrary): for dep in d.get_external_deps(): commands += dep.get_link_args() # Add link args for c_* or cpp_* build options. Currently this only # adds c_winlibs and cpp_winlibs when building for Windows. This needs # to be after all internal and external libraries so that unresolved # symbols from those can be found here. This is needed when the # *_winlibs that we want to link to are static mingw64 libraries. commands += linker.get_option_link_args(self.environment.coredata.compiler_options) # Set runtime-paths so we can run executables without needing to set # LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows. commands += linker.build_rpath_args(self.environment.get_build_dir(), self.determine_rpath_dirs(target), target.install_rpath) # Add libraries generated by custom targets custom_target_libraries = self.get_custom_target_provided_libraries(target) commands += extra_args commands += custom_target_libraries # Convert from GCC-style link argument naming to the naming used by the # current compiler. commands = commands.to_native() dep_targets = [self.get_dependency_filename(t) for t in dependencies] dep_targets += [os.path.join(self.environment.source_dir, target.subdir, t) for t in target.link_depends] elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list) elem.add_dep(dep_targets + custom_target_libraries) elem.add_item('LINK_ARGS', commands) return elem def determine_rpath_dirs(self, target): link_deps = target.get_all_link_deps() result = [] for ld in link_deps: prospective = self.get_target_dir(ld) if prospective not in result: result.append(prospective) return result def get_dependency_filename(self, t): if isinstance(t, build.SharedLibrary): return os.path.join(self.get_target_private_dir(t), self.get_target_filename(t) + '.symbols') return self.get_target_filename(t) def generate_shlib_aliases(self, target, outdir): aliases = target.get_aliases() for alias, to in aliases.items(): aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias) try: os.remove(aliasfile) except Exception: pass try: os.symlink(to, aliasfile) except NotImplementedError: mlog.debug("Library versioning disabled because symlinks are not supported.") except OSError: mlog.debug("Library versioning disabled because we do not have symlink creation privileges.") def generate_custom_target_clean(self, outfile, trees): e = NinjaBuildElement(self.all_outputs, 'clean-ctlist', 'CUSTOM_COMMAND', 'PHONY') d = CleanTrees(self.environment.get_build_dir(), trees) d_file = os.path.join(self.environment.get_scratch_dir(), 'cleantrees.dat') e.add_item('COMMAND', [sys.executable, self.environment.get_build_command(), '--internal', 'cleantrees', d_file]) e.add_item('description', 'Cleaning CustomTarget directories') e.write(outfile) # Write out the data file passed to the script with open(d_file, 'wb') as ofile: pickle.dump(d, ofile) return 'clean-ctlist' def generate_gcov_clean(self, outfile): gcno_elem = NinjaBuildElement(self.all_outputs, 'clean-gcno', 'CUSTOM_COMMAND', 'PHONY') script_root = self.environment.get_script_dir() clean_script = os.path.join(script_root, 'delwithsuffix.py') gcno_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcno']) gcno_elem.add_item('description', 'Deleting gcno files') gcno_elem.write(outfile) gcda_elem = NinjaBuildElement(self.all_outputs, 'clean-gcda', 'CUSTOM_COMMAND', 'PHONY') script_root = self.environment.get_script_dir() clean_script = os.path.join(script_root, 'delwithsuffix.py') gcda_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcda']) gcda_elem.add_item('description', 'Deleting gcda files') gcda_elem.write(outfile) def get_user_option_args(self): cmds = [] for (k, v) in self.environment.coredata.user_options.items(): cmds.append('-D' + k + '=' + (v.value if isinstance(v.value, str) else str(v.value).lower())) # The order of these arguments must be the same between runs of Meson # to ensure reproducible output. The order we pass them shouldn't # affect behaviour in any other way. return sorted(cmds) # For things like scan-build and other helper tools we might have. def generate_utils(self, outfile): cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir, sys.executable, self.environment.get_build_command()] + self.get_user_option_args() elem = NinjaBuildElement(self.all_outputs, 'scan-build', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') elem.write(outfile) cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'uninstall'] elem = NinjaBuildElement(self.all_outputs, 'uninstall', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', cmd) elem.add_item('pool', 'console') elem.write(outfile) def generate_ending(self, outfile): targetlist = [] for t in self.get_build_by_default_targets().values(): # Add the first output of each target to the 'all' target so that # they are all built targetlist.append(os.path.join(self.get_target_dir(t), t.get_outputs()[0])) elem = NinjaBuildElement(self.all_outputs, 'all', 'phony', targetlist) elem.write(outfile) default = 'default all\n\n' outfile.write(default) ninja_command = environment.detect_ninja() if ninja_command is None: raise MesonException('Could not detect Ninja v1.6 or newer') elem = NinjaBuildElement(self.all_outputs, 'clean', 'CUSTOM_COMMAND', 'PHONY') elem.add_item('COMMAND', [ninja_command, '-t', 'clean']) elem.add_item('description', 'Cleaning') # If we have custom targets in this project, add all their outputs to # the list that is passed to the `cleantrees.py` script. The script # will manually delete all custom_target outputs that are directories # instead of files. This is needed because on platforms other than # Windows, Ninja only deletes directories while cleaning if they are # empty. https://github.com/mesonbuild/meson/issues/1220 ctlist = [] for t in self.build.get_targets().values(): if isinstance(t, build.CustomTarget): # Create a list of all custom target outputs for o in t.get_outputs(): ctlist.append(os.path.join(self.get_target_dir(t), o)) if ctlist: elem.add_dep(self.generate_custom_target_clean(outfile, ctlist)) if 'b_coverage' in self.environment.coredata.base_options and \ self.environment.coredata.base_options['b_coverage'].value: self.generate_gcov_clean(outfile) elem.add_dep('clean-gcda') elem.add_dep('clean-gcno') elem.write(outfile) deps = self.get_regen_filelist() elem = NinjaBuildElement(self.all_outputs, 'build.ninja', 'REGENERATE_BUILD', deps) elem.add_item('pool', 'console') elem.write(outfile) elem = NinjaBuildElement(self.all_outputs, 'reconfigure', 'REGENERATE_BUILD', 'PHONY') elem.add_item('pool', 'console') elem.write(outfile) elem = NinjaBuildElement(self.all_outputs, deps, 'phony', '') elem.write(outfile) meson-0.40.1/mesonbuild/compilers.py0000644000175000017500000034647413100700231021024 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2014 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import shutil import contextlib import subprocess, os.path import tempfile from .import mesonlib from . import mlog from .mesonlib import EnvironmentException, MesonException, version_compare, Popen_safe from . import coredata """This file contains the data files of all compilers Meson knows about. To support a new compiler, add its information below. Also add corresponding autodetection code in environment.py.""" header_suffixes = ('h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di') obj_suffixes = ('o', 'obj', 'res') lib_suffixes = ('a', 'lib', 'dll', 'dylib', 'so') # Mapping of language to suffixes of files that should always be in that language # This means we can't include .h headers here since they could be C, C++, ObjC, etc. lang_suffixes = { 'c': ('c',), 'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx'), # f90, f95, f03, f08 are for free-form fortran ('f90' recommended) # f, for, ftn, fpp are for fixed-form fortran ('f' or 'for' recommended) 'fortran': ('f90', 'f95', 'f03', 'f08', 'f', 'for', 'ftn', 'fpp'), 'd': ('d', 'di'), 'objc': ('m',), 'objcpp': ('mm',), 'rust': ('rs',), 'vala': ('vala', 'vapi'), 'cs': ('cs',), 'swift': ('swift',), 'java': ('java',), } cpp_suffixes = lang_suffixes['cpp'] + ('h',) c_suffixes = lang_suffixes['c'] + ('h',) # List of languages that can be linked with C code directly by the linker # used in build.py:process_compilers() and build.py:get_dynamic_linker() clike_langs = ('objcpp', 'objc', 'd', 'cpp', 'c', 'fortran',) clike_suffixes = () for l in clike_langs: clike_suffixes += lang_suffixes[l] clike_suffixes += ('h', 'll', 's') # All these are only for C-like languages; see `clike_langs` above. def sort_clike(lang): ''' Sorting function to sort the list of languages according to reversed(compilers.clike_langs) and append the unknown langs in the end. The purpose is to prefer C over C++ for files that can be compiled by both such as assembly, C, etc. Also applies to ObjC, ObjC++, etc. ''' if lang not in clike_langs: return 1 return -clike_langs.index(lang) def is_header(fname): if hasattr(fname, 'fname'): fname = fname.fname suffix = fname.split('.')[-1] return suffix in header_suffixes def is_source(fname): if hasattr(fname, 'fname'): fname = fname.fname suffix = fname.split('.')[-1].lower() return suffix in clike_suffixes def is_assembly(fname): if hasattr(fname, 'fname'): fname = fname.fname return fname.split('.')[-1].lower() == 's' def is_llvm_ir(fname): if hasattr(fname, 'fname'): fname = fname.fname return fname.split('.')[-1] == 'll' def is_object(fname): if hasattr(fname, 'fname'): fname = fname.fname suffix = fname.split('.')[-1] return suffix in obj_suffixes def is_library(fname): if hasattr(fname, 'fname'): fname = fname.fname suffix = fname.split('.')[-1] return suffix in lib_suffixes gnulike_buildtype_args = {'plain': [], # -O0 is passed for improved debugging information with gcc # See https://github.com/mesonbuild/meson/pull/509 'debug': ['-O0', '-g'], 'debugoptimized': ['-O2', '-g'], 'release': ['-O3'], 'minsize': ['-Os', '-g']} msvc_buildtype_args = {'plain': [], 'debug': ["/MDd", "/ZI", "/Ob0", "/Od", "/RTC1"], 'debugoptimized': ["/MD", "/Zi", "/O2", "/Ob1"], 'release': ["/MD", "/O2", "/Ob2"], 'minsize': ["/MD", "/Zi", "/Os", "/Ob1"], } apple_buildtype_linker_args = {'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': [], } gnulike_buildtype_linker_args = {'plain': [], 'debug': [], 'debugoptimized': [], 'release': ['-Wl,-O1'], 'minsize': [], } msvc_buildtype_linker_args = {'plain': [], 'debug': [], 'debugoptimized': [], 'release': [], 'minsize': ['/INCREMENTAL:NO'], } java_buildtype_args = {'plain': [], 'debug': ['-g'], 'debugoptimized': ['-g'], 'release': [], 'minsize': [], } rust_buildtype_args = {'plain': [], 'debug': ['-g'], 'debugoptimized': ['-g', '--opt-level', '2'], 'release': ['--opt-level', '3'], 'minsize': [], } d_gdc_buildtype_args = {'plain': [], 'debug': ['-g', '-O0'], 'debugoptimized': ['-g', '-O'], 'release': ['-O3', '-frelease'], 'minsize': [], } d_ldc_buildtype_args = {'plain': [], 'debug': ['-g', '-O0'], 'debugoptimized': ['-g', '-O'], 'release': ['-O3', '-release'], 'minsize': [], } d_dmd_buildtype_args = {'plain': [], 'debug': ['-g'], 'debugoptimized': ['-g', '-O'], 'release': ['-O', '-release'], 'minsize': [], } mono_buildtype_args = {'plain': [], 'debug': ['-debug'], 'debugoptimized': ['-debug', '-optimize+'], 'release': ['-optimize+'], 'minsize': [], } swift_buildtype_args = {'plain': [], 'debug': ['-g'], 'debugoptimized': ['-g', '-O'], 'release': ['-O'], 'minsize': [], } gnu_winlibs = ['-lkernel32', '-luser32', '-lgdi32', '-lwinspool', '-lshell32', '-lole32', '-loleaut32', '-luuid', '-lcomdlg32', '-ladvapi32'] msvc_winlibs = ['kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib', 'uuid.lib', 'comdlg32.lib', 'advapi32.lib'] gnu_color_args = {'auto': ['-fdiagnostics-color=auto'], 'always': ['-fdiagnostics-color=always'], 'never': ['-fdiagnostics-color=never'], } clang_color_args = {'auto': ['-Xclang', '-fcolor-diagnostics'], 'always': ['-Xclang', '-fcolor-diagnostics'], 'never': ['-Xclang', '-fno-color-diagnostics'], } base_options = {'b_pch': coredata.UserBooleanOption('b_pch', 'Use precompiled headers', True), 'b_lto': coredata.UserBooleanOption('b_lto', 'Use link time optimization', False), 'b_sanitize': coredata.UserComboOption('b_sanitize', 'Code sanitizer to use', ['none', 'address', 'thread', 'undefined', 'memory'], 'none'), 'b_lundef': coredata.UserBooleanOption('b_lundef', 'Use -Wl,--no-undefined when linking', True), 'b_asneeded': coredata.UserBooleanOption('b_asneeded', 'Use -Wl,--as-needed when linking', True), 'b_pgo': coredata.UserComboOption('b_pgo', 'Use profile guide optimization', ['off', 'generate', 'use'], 'off'), 'b_coverage': coredata.UserBooleanOption('b_coverage', 'Enable coverage tracking.', False), 'b_colorout': coredata.UserComboOption('b_colorout', 'Use colored output', ['auto', 'always', 'never'], 'always'), 'b_ndebug': coredata.UserBooleanOption('b_ndebug', 'Disable asserts', False), 'b_staticpic': coredata.UserBooleanOption('b_staticpic', 'Build static libraries as position independent', True), } def sanitizer_compile_args(value): if value == 'none': return [] args = ['-fsanitize=' + value] if value == 'address': args.append('-fno-omit-frame-pointer') return args def sanitizer_link_args(value): if value == 'none': return [] args = ['-fsanitize=' + value] return args def get_base_compile_args(options, compiler): args = [] # FIXME, gcc/clang specific. try: if options['b_lto'].value: args.append('-flto') except KeyError: pass try: args += compiler.get_colorout_args(options['b_colorout'].value) except KeyError: pass try: args += sanitizer_compile_args(options['b_sanitize'].value) except KeyError: pass try: pgo_val = options['b_pgo'].value if pgo_val == 'generate': args.append('-fprofile-generate') elif pgo_val == 'use': args.append('-fprofile-use') except KeyError: pass try: if options['b_coverage'].value: args += compiler.get_coverage_args() except KeyError: pass try: if options['b_ndebug'].value: args += ['-DNDEBUG'] except KeyError: pass return args def get_base_link_args(options, linker, is_shared_module): args = [] # FIXME, gcc/clang specific. try: if options['b_lto'].value: args.append('-flto') except KeyError: pass try: args += sanitizer_link_args(options['b_sanitize'].value) except KeyError: pass try: pgo_val = options['b_pgo'].value if pgo_val == 'generate': args.append('-fprofile-generate') elif pgo_val == 'use': args.append('-fprofile-use') except KeyError: pass try: if not is_shared_module and 'b_lundef' in linker.base_options and options['b_lundef'].value: args.append('-Wl,--no-undefined') except KeyError: pass try: if 'b_asneeded' in linker.base_options and options['b_asneeded'].value: args.append('-Wl,--as-needed') except KeyError: pass try: if options['b_coverage'].value: args += linker.get_coverage_link_args() except KeyError: pass return args def build_unix_rpath_args(build_dir, rpath_paths, install_rpath): if len(rpath_paths) == 0 and len(install_rpath) == 0: return [] paths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths]) if len(paths) < len(install_rpath): padding = 'X' * (len(install_rpath) - len(paths)) if len(paths) == 0: paths = padding else: paths = paths + ':' + padding return ['-Wl,-rpath,' + paths] class CrossNoRunException(MesonException): def __init(self, *args, **kwargs): Exception.__init__(self, *args, **kwargs) class RunResult: def __init__(self, compiled, returncode=999, stdout='UNDEFINED', stderr='UNDEFINED'): self.compiled = compiled self.returncode = returncode self.stdout = stdout self.stderr = stderr class CompilerArgs(list): ''' Class derived from list() that manages a list of compiler arguments. Should be used while constructing compiler arguments from various sources. Can be operated with ordinary lists, so this does not need to be used everywhere. All arguments must be inserted and stored in GCC-style (-lfoo, -Idir, etc) and can converted to the native type of each compiler by using the .to_native() method to which you must pass an instance of the compiler or the compiler class. New arguments added to this class (either with .append(), .extend(), or +=) are added in a way that ensures that they override previous arguments. For example: >>> a = ['-Lfoo', '-lbar'] >>> a += ['-Lpho', '-lbaz'] >>> print(a) ['-Lpho', '-Lfoo', '-lbar', '-lbaz'] Arguments will also be de-duped if they can be de-duped safely. Note that because of all this, this class is not commutative and does not preserve the order of arguments if it is safe to not. For example: >>> ['-Ifoo', '-Ibar'] + ['-Ifez', '-Ibaz', '-Werror'] ['-Ifez', '-Ibaz', '-Ifoo', '-Ibar', '-Werror'] >>> ['-Ifez', '-Ibaz', '-Werror'] + ['-Ifoo', '-Ibar'] ['-Ifoo', '-Ibar', '-Ifez', '-Ibaz', '-Werror'] ''' # NOTE: currently this class is only for C-like compilers, but it can be # extended to other languages easily. Just move the following to the # compiler class and initialize when self.compiler is set. # Arg prefixes that override by prepending instead of appending prepend_prefixes = ('-I', '-L') # Arg prefixes and args that must be de-duped by returning 2 dedup2_prefixes = ('-I', '-L', '-D') dedup2_args = () # Arg prefixes and args that must be de-duped by returning 1 dedup1_prefixes = () dedup1_args = ('-c', '-S', '-E', '-pipe', '-pthread') compiler = None def _check_args(self, args): cargs = [] if len(args) > 2: raise TypeError("CompilerArgs() only accepts at most 2 arguments: " "The compiler, and optionally an initial list") elif len(args) == 0: return cargs elif len(args) == 1: if isinstance(args[0], (Compiler, StaticLinker)): self.compiler = args[0] else: raise TypeError("you must pass a Compiler instance as one of " "the arguments") elif len(args) == 2: if isinstance(args[0], (Compiler, StaticLinker)): self.compiler = args[0] cargs = args[1] elif isinstance(args[1], (Compiler, StaticLinker)): cargs = args[0] self.compiler = args[1] else: raise TypeError("you must pass a Compiler instance as one of " "the two arguments") else: raise AssertionError('Not reached') return cargs def __init__(self, *args): super().__init__(self._check_args(args)) @classmethod def _can_dedup(cls, arg): ''' Returns whether the argument can be safely de-duped. This is dependent on two things: a) Whether an argument can be 'overriden' by a later argument. For example, -DFOO defines FOO and -UFOO undefines FOO. In this case, we can safely remove the previous occurance and add a new one. The same is true for include paths and library paths with -I and -L. For these we return `2`. See `dedup2_prefixes` and `dedup2_args`. b) Arguments that once specified cannot be undone, such as `-c` or `-pipe`. New instances of these can be completely skipped. For these we return `1`. See `dedup1_prefixes` and `dedup1_args`. c) Whether it matters where or how many times on the command-line a particular argument is present. This can matter for symbol resolution in static or shared libraries, so we cannot de-dup or reorder them. For these we return `0`. This is the default. ''' if arg.startswith(cls.dedup2_prefixes) or arg in cls.dedup2_args: return 2 if arg.startswith(cls.dedup1_prefixes) or arg in cls.dedup1_args: return 1 return 0 @classmethod def _should_prepend(cls, arg): if arg.startswith(cls.prepend_prefixes): return True return False def to_native(self): return self.compiler.unix_args_to_native(self) def __add__(self, args): new = CompilerArgs(self, self.compiler) new += args return new def __iadd__(self, args): ''' Add two CompilerArgs while taking into account overriding of arguments and while preserving the order of arguments as much as possible ''' pre = [] post = [] if not isinstance(args, list): raise TypeError('can only concatenate list (not "{}") to list'.format(args)) for arg in args: # If the argument can be de-duped, do it either by removing the # previous occurance of it and adding a new one, or not adding the # new occurance. dedup = self._can_dedup(arg) if dedup == 1: # Argument already exists and adding a new instance is useless if arg in self or arg in pre or arg in post: continue if dedup == 2: # Remove all previous occurances of the arg and add it anew if arg in self: self.remove(arg) if arg in pre: pre.remove(arg) if arg in post: post.remove(arg) if self._should_prepend(arg): pre.append(arg) else: post.append(arg) # Insert at the beginning self[:0] = pre # Append to the end super().__iadd__(post) return self def __radd__(self, args): new = CompilerArgs(args, self.compiler) new += self return new def __mul__(self, args): raise TypeError("can't multiply compiler arguments") def __imul__(self, args): raise TypeError("can't multiply compiler arguments") def __rmul__(self, args): raise TypeError("can't multiply compiler arguments") def append(self, arg): self.__iadd__([arg]) def extend(self, args): self.__iadd__(args) class Compiler: def __init__(self, exelist, version): if isinstance(exelist, str): self.exelist = [exelist] elif isinstance(exelist, list): self.exelist = exelist else: raise TypeError('Unknown argument to Compiler') # In case it's been overriden by a child class already if not hasattr(self, 'file_suffixes'): self.file_suffixes = lang_suffixes[self.language] if not hasattr(self, 'can_compile_suffixes'): self.can_compile_suffixes = set(self.file_suffixes) self.default_suffix = self.file_suffixes[0] self.version = version self.base_options = [] def __repr__(self): repr_str = "<{0}: v{1} `{2}`>" return repr_str.format(self.__class__.__name__, self.version, ' '.join(self.exelist)) def can_compile(self, src): if hasattr(src, 'fname'): src = src.fname suffix = os.path.splitext(src)[1].lower() if suffix and suffix[1:] in self.can_compile_suffixes: return True return False def get_id(self): return self.id def get_language(self): return self.language def get_default_suffix(self): return self.default_suffix def get_exelist(self): return self.exelist[:] def get_builtin_define(self, *args, **kwargs): raise EnvironmentException('%s does not support get_builtin_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 [] def get_linker_always_args(self): return [] def gen_import_library_args(self, implibname): """ Used only on Windows for libraries that need an import library. This currently means C, C++, Fortran. """ return [] def get_options(self): return {} # build afresh every time def get_option_compile_args(self, options): return [] def get_option_link_args(self, options): return [] def has_header(self, *args, **kwargs): raise EnvironmentException('Language %s does not support header checks.' % self.language) def has_header_symbol(self, *args, **kwargs): raise EnvironmentException('Language %s does not support header symbol checks.' % self.language) def compiles(self, *args, **kwargs): raise EnvironmentException('Language %s does not support compile checks.' % self.language) def links(self, *args, **kwargs): raise EnvironmentException('Language %s does not support link checks.' % self.language) def run(self, *args, **kwargs): raise EnvironmentException('Language %s does not support run checks.' % self.language) def sizeof(self, *args, **kwargs): raise EnvironmentException('Language %s does not support sizeof checks.' % self.language) def alignment(self, *args, **kwargs): raise EnvironmentException('Language %s does not support alignment checks.' % self.language) def has_function(self, *args, **kwargs): raise EnvironmentException('Language %s does not support function checks.' % self.language) @classmethod def unix_args_to_native(cls, args): "Always returns a copy that can be independently mutated" return args[:] def find_library(self, *args, **kwargs): raise EnvironmentException('Language {} does not support library finding.'.format(self.language)) def get_library_dirs(self): return [] def has_argument(self, arg, env): return self.has_multi_arguments([arg], env) def has_multi_arguments(self, args, env): raise EnvironmentException( 'Language {} does not support has_multi_arguments.'.format( self.language)) def get_cross_extra_flags(self, environment, link): extra_flags = [] if self.is_cross and environment: if 'properties' in environment.cross_info.config: props = environment.cross_info.config['properties'] lang_args_key = self.language + '_args' extra_flags += props.get(lang_args_key, []) lang_link_args_key = self.language + '_link_args' if link: extra_flags += props.get(lang_link_args_key, []) return extra_flags def _get_compile_output(self, dirname, mode): # In pre-processor mode, the output is sent to stdout and discarded if mode == 'preprocess': return None # Extension only matters if running results; '.exe' is # guaranteed to be executable on every platform. if mode == 'link': suffix = 'exe' else: suffix = 'obj' return os.path.join(dirname, 'output.' + suffix) @contextlib.contextmanager def compile(self, code, extra_args=None, mode='link'): if extra_args is None: extra_args = [] try: with tempfile.TemporaryDirectory() as tmpdirname: if isinstance(code, str): srcname = os.path.join(tmpdirname, 'testfile.' + self.default_suffix) with open(srcname, 'w') as ofile: ofile.write(code) elif isinstance(code, mesonlib.File): srcname = code.fname output = self._get_compile_output(tmpdirname, mode) # Construct the compiler command-line commands = CompilerArgs(self) commands.append(srcname) commands += extra_args commands += self.get_always_args() if mode == 'compile': commands += self.get_compile_only_args() # Preprocess mode outputs to stdout, so no output args if mode == 'preprocess': commands += self.get_preprocess_only_args() else: commands += self.get_output_args(output) # Generate full command-line with the exelist commands = self.get_exelist() + commands.to_native() mlog.debug('Running compile:') mlog.debug('Working directory: ', tmpdirname) mlog.debug('Command line: ', ' '.join(commands), '\n') mlog.debug('Code:\n', code) p, p.stdo, p.stde = Popen_safe(commands, cwd=tmpdirname) mlog.debug('Compiler stdout:\n', p.stdo) mlog.debug('Compiler stderr:\n', p.stde) p.input_name = srcname p.output_name = output yield p except (PermissionError, OSError): # On Windows antivirus programs and the like hold on to files so # they can't be deleted. There's not much to do in this case. Also, # catch OSError because the directory is then no longer empty. pass def get_colorout_args(self, colortype): return [] # 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, **kwargs): return [] def get_link_debugfile_args(self, rel_obj): return [] def get_std_shared_lib_link_args(self): return [] def get_std_shared_module_link_args(self): return self.get_std_shared_lib_link_args() def get_link_whole_for(self, args): if isinstance(args, list) and len(args) == 0: return [] raise EnvironmentException('Language %s does not support linking whole archives.' % self.language) class CCompiler(Compiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None): # If a child ObjC or CPP class has already set it, don't set it ourselves if not hasattr(self, 'language'): self.language = 'c' super().__init__(exelist, version) self.id = 'unknown' self.is_cross = is_cross self.can_compile_suffixes.add('h') if isinstance(exe_wrapper, str): self.exe_wrapper = [exe_wrapper] else: self.exe_wrapper = exe_wrapper def needs_static_linker(self): return True # When compiling static libraries, so yes. def get_always_args(self): ''' Args that are always-on for all C compilers other than MSVC ''' return ['-pipe'] + get_largefile_args(self) def get_linker_debug_crt_args(self): """ Arguments needed to select a debug crt for the linker This is only needed for MSVC """ return [] def get_no_stdinc_args(self): return ['-nostdinc'] def get_no_stdlib_link_args(self): return ['-nostdlib'] def get_warn_args(self, level): return self.warn_args[level] def get_no_warn_args(self): # Almost every compiler uses this for disabling warnings return ['-w'] def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module): return [] def split_shlib_to_parts(self, fname): return None, fname # The default behaviour is this, override in # OSX and MSVC. def build_rpath_args(self, build_dir, rpath_paths, install_rpath): return build_unix_rpath_args(build_dir, rpath_paths, install_rpath) def get_dependency_gen_args(self, outtarget, outfile): return ['-MMD', '-MQ', outtarget, '-MF', outfile] def depfile_for_object(self, objfile): return objfile + '.' + self.get_depfile_suffix() def get_depfile_suffix(self): return 'd' def get_exelist(self): return self.exelist[:] def get_linker_exelist(self): return self.exelist[:] def get_preprocess_only_args(self): return ['-E'] def get_compile_only_args(self): return ['-c'] 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] def get_linker_output_args(self, outputname): return ['-o', outputname] def get_coverage_args(self): return ['--coverage'] def get_coverage_link_args(self): return ['--coverage'] def get_werror_args(self): return ['-Werror'] def get_std_exe_link_args(self): return [] def get_include_args(self, path, is_system): if path == '': path = '.' if is_system: return ['-isystem', path] return ['-I' + path] def get_std_shared_lib_link_args(self): return ['-shared'] def get_library_dirs(self): stdo = Popen_safe(self.exelist + ['--print-search-dirs'])[1] for line in stdo.split('\n'): if line.startswith('libraries:'): libstr = line.split('=', 1)[1] return libstr.split(':') return [] def get_pic_args(self): return ['-fPIC'] def name_string(self): return ' '.join(self.exelist) def get_pch_use_args(self, pch_dir, header): return ['-include', os.path.split(header)[-1]] def get_pch_name(self, header_name): return os.path.split(header_name)[-1] + '.' + self.get_pch_suffix() def get_linker_search_args(self, dirname): return ['-L' + dirname] def gen_import_library_args(self, implibname): """ The name of the outputted import library This implementation is used only on Windows by compilers that use GNU ld """ return ['-Wl,--out-implib=' + implibname] def sanity_check_impl(self, work_dir, environment, sname, code): mlog.debug('Sanity testing ' + self.language + ' compiler:', ' '.join(self.exelist)) mlog.debug('Is cross compiler: %s.' % str(self.is_cross)) extra_flags = [] source_name = os.path.join(work_dir, sname) binname = sname.rsplit('.', 1)[0] if self.is_cross: binname += '_cross' if self.exe_wrapper is None: # Linking cross built apps is painful. You can't really # tell if you should use -nostdlib or not and for example # on OSX the compiler binary is the same but you need # a ton of compiler flags to differentiate between # arm and x86_64. So just compile. extra_flags += self.get_cross_extra_flags(environment, link=False) extra_flags += self.get_compile_only_args() else: extra_flags += self.get_cross_extra_flags(environment, link=True) # Is a valid executable output for all toolchains and platforms binname += '.exe' # Write binary check source binary_name = os.path.join(work_dir, binname) with open(source_name, 'w') as ofile: ofile.write(code) # Compile sanity check cmdlist = self.exelist + extra_flags + [source_name] + self.get_output_args(binary_name) pc, stdo, stde = Popen_safe(cmdlist, cwd=work_dir) mlog.debug('Sanity check compiler command line:', ' '.join(cmdlist)) mlog.debug('Sanity check compile stdout:') mlog.debug(stdo) mlog.debug('-----\nSanity check compile stderr:') mlog.debug(stde) mlog.debug('-----') if pc.returncode != 0: raise EnvironmentException('Compiler {0} can not compile programs.'.format(self.name_string())) # Run sanity check if self.is_cross: if self.exe_wrapper is None: # Can't check if the binaries run so we have to assume they do return cmdlist = self.exe_wrapper + [binary_name] else: cmdlist = [binary_name] mlog.debug('Running test binary command: ' + ' '.join(cmdlist)) pe = subprocess.Popen(cmdlist) pe.wait() if pe.returncode != 0: raise EnvironmentException('Executables created by {0} compiler {1} are not runnable.'.format(self.language, self.name_string())) def sanity_check(self, work_dir, environment): code = 'int main(int argc, char **argv) { int class=0; return class; }\n' return self.sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code) def has_header(self, hname, prefix, env, extra_args=None, dependencies=None): fargs = {'prefix': prefix, 'header': hname} code = '''{prefix} #ifdef __has_include #if !__has_include("{header}") #error "Header '{header}' could not be found" #endif #else #include <{header}> #endif''' return self.compiles(code.format(**fargs), env, extra_args, dependencies, 'preprocess') def has_header_symbol(self, hname, symbol, prefix, env, extra_args=None, dependencies=None): fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol} t = '''{prefix} #include <{header}> int main () {{ /* If it's not defined as a macro, try to use as a symbol */ #ifndef {symbol} {symbol}; #endif }}''' return self.compiles(t.format(**fargs), env, extra_args, dependencies) def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): 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] # 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, 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" 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): with self._links_wrapper(code, env, extra_args, dependencies) as p: return p.returncode == 0 def run(self, code, env, extra_args=None, dependencies=None): if self.is_cross and self.exe_wrapper is None: raise CrossNoRunException('Can not run test applications in this cross environment.') with self._links_wrapper(code, env, extra_args, dependencies) as p: if p.returncode != 0: mlog.debug('Could not compile test file %s: %d\n' % ( p.input_name, p.returncode)) return RunResult(False) if self.is_cross: cmdlist = self.exe_wrapper + [p.output_name] else: cmdlist = p.output_name try: pe, so, se = Popen_safe(cmdlist) except Exception as e: mlog.debug('Could not run: %s (error: %s)\n' % (cmdlist, e)) return RunResult(False) mlog.debug('Program stdout:\n') mlog.debug(so) mlog.debug('Program stderr:\n') mlog.debug(se) return RunResult(True, pe.returncode, so, se) def _compile_int(self, expression, prefix, env, extra_args, dependencies): fargs = {'prefix': prefix, 'expression': expression} t = '''#include {prefix} int main() {{ static int a[1-2*!({expression})]; a[0]=0; return 0; }}''' return self.compiles(t.format(**fargs), env, extra_args, dependencies) def cross_compute_int(self, expression, l, h, guess, prefix, env, extra_args, dependencies): if isinstance(guess, int): if self._compile_int('%s == %d' % (expression, guess), prefix, env, extra_args, dependencies): return guess cur = l while l < h: cur = int((l + h) / 2) if cur == l: break if self._compile_int('%s >= %d' % (expression, cur), prefix, env, extra_args, dependencies): l = cur else: h = cur if self._compile_int('%s == %d' % (expression, cur), prefix, env, extra_args, dependencies): return cur raise EnvironmentException('Cross-compile check overflowed') def compute_int(self, expression, l, h, guess, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] if self.is_cross: return self.cross_compute_int(expression, l, h, guess, prefix, env, extra_args, dependencies) fargs = {'prefix': prefix, 'expression': expression} t = '''#include {prefix} int main(int argc, char **argv) {{ printf("%ld\\n", (long)({expression})); return 0; }};''' res = self.run(t.format(**fargs), env, extra_args, dependencies) if not res.compiled: return -1 if res.returncode != 0: raise EnvironmentException('Could not run compute_int test binary.') return int(res.stdout) def cross_sizeof(self, typename, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'type': typename} t = '''#include {prefix} int main(int argc, char **argv) {{ {type} something; }}''' if not self.compiles(t.format(**fargs), env, extra_args, dependencies): return -1 return self.cross_compute_int('sizeof(%s)' % typename, 1, 128, None, prefix, env, extra_args, dependencies) def sizeof(self, typename, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'type': typename} if self.is_cross: return self.cross_sizeof(typename, prefix, env, extra_args, dependencies) t = '''#include {prefix} int main(int argc, char **argv) {{ printf("%ld\\n", (long)(sizeof({type}))); return 0; }};''' res = self.run(t.format(**fargs), env, extra_args, dependencies) if not res.compiled: return -1 if res.returncode != 0: raise EnvironmentException('Could not run sizeof test binary.') return int(res.stdout) def cross_alignment(self, typename, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'type': typename} t = '''#include {prefix} int main(int argc, char **argv) {{ {type} something; }}''' if not self.compiles(t.format(**fargs), env, extra_args, dependencies): return -1 t = '''#include {prefix} struct tmp {{ char c; {type} target; }};''' return self.cross_compute_int('offsetof(struct tmp, target)', 1, 1024, None, t.format(**fargs), env, extra_args, dependencies) def alignment(self, typename, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] if self.is_cross: return self.cross_alignment(typename, prefix, env, extra_args, dependencies) fargs = {'prefix': prefix, 'type': typename} t = '''#include #include {prefix} struct tmp {{ char c; {type} target; }}; int main(int argc, char **argv) {{ printf("%d", (int)offsetof(struct tmp, target)); return 0; }}''' res = self.run(t.format(**fargs), env, extra_args, dependencies) if not res.compiled: raise EnvironmentException('Could not compile alignment test.') if res.returncode != 0: raise EnvironmentException('Could not run alignment test binary.') align = int(res.stdout) if align == 0: 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(): """ Try to find the function without a prototype from a header by defining our own dummy prototype and trying to link with the C library (and whatever else the compiler links in by default). This is very similar to the check performed by Autoconf for AC_CHECK_FUNCS. """ # Define the symbol to something else since it is defined by the # includes or defines listed by the user or by the compiler. This may # include, for instance _GNU_SOURCE which must be defined before # limits.h, which includes features.h # Then, undef the symbol to get rid of it completely. head = ''' #define {func} meson_disable_define_of_{func} {prefix} #include #undef {func} ''' # Override any GCC internal prototype and declare our own definition for # the symbol. Use char because that's unlikely to be an actual return # value for a function which ensures that we override the definition. head += ''' #ifdef __cplusplus extern "C" #endif char {func} (); ''' # The actual function call main = ''' int main () {{ return {func} (); }}''' return head, main @staticmethod def _have_prototype_templ(): """ Returns a head-er and main() call that uses the headers listed by the user for the function prototype while checking if a function exists. """ # Add the 'prefix', aka defines, includes, etc that the user provides # This may include, for instance _GNU_SOURCE which must be defined # before limits.h, which includes features.h head = '{prefix}\n#include \n' # We don't know what the function takes or returns, so return it as an int. # Just taking the address or comparing it to void is not enough because # compilers are smart enough to optimize it away. The resulting binary # is not run so we don't care what the return value is. main = '''\nint main() {{ void *a = (void*) &{func}; long b = (long) a; return (int) b; }}''' return head, main def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None): """ First, this function looks for the symbol in the default libraries provided by the compiler (stdlib + a few others usually). If that fails, it checks if any of the headers specified in the prefix provide an implementation of the function, and if that fails, it checks if it's implemented as a compiler-builtin. """ if extra_args is None: extra_args = [] # Short-circuit if the check is already provided by the cross-info file varname = 'has function ' + funcname varname = varname.replace(' ', '_') if self.is_cross: val = env.cross_info.config['properties'].get(varname, None) if val is not None: if isinstance(val, bool): return val raise EnvironmentException('Cross variable {0} is not a boolean.'.format(varname)) fargs = {'prefix': prefix, 'func': funcname} # glibc defines functions that are not available on Linux as stubs that # fail with ENOSYS (such as e.g. lchmod). In this case we want to fail # instead of detecting the stub as a valid symbol. # We already included limits.h earlier to ensure that these are defined # for stub functions. stubs_fail = ''' #if defined __stub_{func} || defined __stub___{func} fail fail fail this function is not going to work #endif ''' # If we have any includes in the prefix supplied by the user, assume # that the user wants us to use the symbol prototype defined in those # includes. If not, then try to do the Autoconf-style check with # a dummy prototype definition of our own. # This is needed when the linker determines symbol availability from an # SDK based on the prototype in the header provided by the SDK. # Ignoring this prototype would result in the symbol always being # marked as available. if '#include' in prefix: head, main = self._have_prototype_templ() else: head, main = self._no_prototype_templ() templ = head + stubs_fail + main if self.links(templ.format(**fargs), env, extra_args, dependencies): return True # MSVC does not have compiler __builtin_-s. if self.get_id() == 'msvc': return False # Detect function as a built-in # # Some functions like alloca() are defined as compiler built-ins which # are inlined by the compiler and you can't take their address, so we # need to look for them differently. On nice compilers like clang, we # can just directly use the __has_builtin() macro. fargs['no_includes'] = '#include' not in prefix t = '''{prefix} int main() {{ #ifdef __has_builtin #if !__has_builtin(__builtin_{func}) #error "__builtin_{func} not found" #endif #elif ! defined({func}) /* Check for __builtin_{func} only if no includes were added to the * prefix above, which means no definition of {func} can be found. * We would always check for this, but we get false positives on * MSYS2 if we do. Their toolchain is broken, but we can at least * give them a workaround. */ #if {no_includes:d} __builtin_{func}; #else #error "No definition for __builtin_{func} found in the prefix" #endif #endif }}''' return self.links(t.format(**fargs), env, extra_args, dependencies) def has_members(self, typename, membernames, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] fargs = {'prefix': prefix, 'type': typename, 'name': 'foo'} # Create code that accesses all members members = '' for member in membernames: members += '{}.{};\n'.format(fargs['name'], member) fargs['members'] = members t = '''{prefix} void bar() {{ {type} {name}; {members} }};''' return self.compiles(t.format(**fargs), env, extra_args, dependencies) def has_type(self, typename, prefix, env, extra_args, dependencies=None): fargs = {'prefix': prefix, 'type': typename} t = '''{prefix} void bar() {{ sizeof({type}); }};''' return self.compiles(t.format(**fargs), env, extra_args, dependencies) def symbols_have_underscore_prefix(self, env): ''' Check if the compiler prefixes an underscore to global C symbols ''' symbol_name = b'meson_uscore_prefix' code = '''#ifdef __cplusplus extern "C" { #endif void ''' + symbol_name.decode() + ''' () {} #ifdef __cplusplus } #endif ''' args = self.get_cross_extra_flags(env, link=False) args += self.get_compiler_check_args() n = 'symbols_have_underscore_prefix' with self.compile(code, args, 'compile') as p: if p.returncode != 0: m = 'BUG: Unable to compile {!r} check: {}' raise RuntimeError(m.format(n, p.stdo)) if not os.path.isfile(p.output_name): m = 'BUG: Can\'t find compiled test code for {!r} check' raise RuntimeError(m.format(n)) with open(p.output_name, 'rb') as o: for line in o: # Check if the underscore form of the symbol is somewhere # in the output file. if b'_' + symbol_name in line: return True # Else, check if the non-underscored form is present elif symbol_name in line: return False raise RuntimeError('BUG: {!r} check failed unexpectedly'.format(n)) def find_library(self, libname, env, extra_dirs): # First try if we can just add the library as -l. code = '''int main(int argc, char **argv) { return 0; } ''' if extra_dirs and isinstance(extra_dirs, str): extra_dirs = [extra_dirs] # Gcc + co seem to prefer builtin lib dirs to -L dirs. # Only try to find std libs if no extra dirs specified. if len(extra_dirs) == 0: args = ['-l' + libname] if self.links(code, env, extra_args=args): return args # Not found? Try to find the library file itself. extra_dirs += self.get_library_dirs() suffixes = ['so', 'dylib', 'lib', 'dll', 'a'] for d in extra_dirs: for suffix in suffixes: trial = os.path.join(d, 'lib' + libname + '.' + suffix) if os.path.isfile(trial): return trial trial2 = os.path.join(d, libname + '.' + suffix) if os.path.isfile(trial2): return trial2 return None def thread_flags(self): return ['-pthread'] def thread_link_flags(self): return ['-pthread'] def has_multi_arguments(self, args, env): return self.compiles('int i;\n', env, extra_args=args) class CPPCompiler(CCompiler): def __init__(self, exelist, version, is_cross, exe_wrap): # If a child ObjCPP class has already set it, don't set it ourselves if not hasattr(self, 'language'): self.language = 'cpp' CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) def get_no_stdinc_args(self): return ['-nostdinc++'] def sanity_check(self, work_dir, environment): code = 'class breakCCompiler;int main(int argc, char **argv) { return 0; }\n' return self.sanity_check_impl(work_dir, environment, 'sanitycheckcpp.cc', code) 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 super().get_compiler_check_args() + ['-fpermissive'] 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 = [] fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol} t = '''{prefix} #include <{header}> using {symbol}; int main () {{ return 0; }}''' return self.compiles(t.format(**fargs), env, extra_args, dependencies) class ObjCCompiler(CCompiler): def __init__(self, exelist, version, is_cross, exe_wrap): self.language = 'objc' CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) def sanity_check(self, work_dir, environment): # TODO try to use sanity_check_impl instead of duplicated code source_name = os.path.join(work_dir, 'sanitycheckobjc.m') binary_name = os.path.join(work_dir, 'sanitycheckobjc') extra_flags = self.get_cross_extra_flags(environment, link=False) if self.is_cross: extra_flags += self.get_compile_only_args() with open(source_name, 'w') as ofile: ofile.write('#import\n' 'int main(int argc, char **argv) { return 0; }\n') pc = subprocess.Popen(self.exelist + extra_flags + [source_name, '-o', binary_name]) pc.wait() if pc.returncode != 0: raise EnvironmentException('ObjC compiler %s can not compile programs.' % self.name_string()) if self.is_cross: # Can't check if the binaries run so we have to assume they do return pe = subprocess.Popen(binary_name) pe.wait() if pe.returncode != 0: raise EnvironmentException('Executables created by ObjC compiler %s are not runnable.' % self.name_string()) class ObjCPPCompiler(CPPCompiler): def __init__(self, exelist, version, is_cross, exe_wrap): self.language = 'objcpp' CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) def sanity_check(self, work_dir, environment): # TODO try to use sanity_check_impl instead of duplicated code source_name = os.path.join(work_dir, 'sanitycheckobjcpp.mm') binary_name = os.path.join(work_dir, 'sanitycheckobjcpp') extra_flags = self.get_cross_extra_flags(environment, link=False) if self.is_cross: extra_flags += self.get_compile_only_args() with open(source_name, 'w') as ofile: ofile.write('#import\n' 'class MyClass;' 'int main(int argc, char **argv) { return 0; }\n') pc = subprocess.Popen(self.exelist + extra_flags + [source_name, '-o', binary_name]) pc.wait() if pc.returncode != 0: raise EnvironmentException('ObjC++ compiler %s can not compile programs.' % self.name_string()) if self.is_cross: # Can't check if the binaries run so we have to assume they do return pe = subprocess.Popen(binary_name) pe.wait() if pe.returncode != 0: raise EnvironmentException('Executables created by ObjC++ compiler %s are not runnable.' % self.name_string()) class MonoCompiler(Compiler): def __init__(self, exelist, version): self.language = 'cs' super().__init__(exelist, version) self.id = 'mono' self.monorunner = 'mono' def get_output_args(self, fname): return ['-out:' + fname] def get_link_args(self, fname): return ['-r:' + fname] def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module): return [] def get_werror_args(self): return ['-warnaserror'] def split_shlib_to_parts(self, fname): return None, fname def build_rpath_args(self, build_dir, rpath_paths, install_rpath): return [] def get_dependency_gen_args(self, outtarget, outfile): return [] def get_linker_exelist(self): return self.exelist[:] def get_compile_only_args(self): return [] def get_linker_output_args(self, outputname): return [] def get_coverage_args(self): return [] def get_coverage_link_args(self): return [] def get_std_exe_link_args(self): return [] def get_include_args(self, path): return [] def get_pic_args(self): return [] def name_string(self): return ' '.join(self.exelist) def get_pch_use_args(self, pch_dir, header): return [] def get_pch_name(self, header_name): return '' def sanity_check(self, work_dir, environment): src = 'sanity.cs' obj = 'sanity.exe' source_name = os.path.join(work_dir, src) with open(source_name, 'w') as ofile: ofile.write('''public class Sanity { static public void Main () { } } ''') pc = subprocess.Popen(self.exelist + [src], cwd=work_dir) pc.wait() if pc.returncode != 0: raise EnvironmentException('Mono compiler %s can not compile programs.' % self.name_string()) cmdlist = [self.monorunner, obj] pe = subprocess.Popen(cmdlist, cwd=work_dir) pe.wait() if pe.returncode != 0: raise EnvironmentException('Executables created by Mono compiler %s are not runnable.' % self.name_string()) def needs_static_linker(self): return False def get_buildtype_args(self, buildtype): return mono_buildtype_args[buildtype] class JavaCompiler(Compiler): def __init__(self, exelist, version): self.language = 'java' super().__init__(exelist, version) self.id = 'unknown' self.javarunner = 'java' def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module): return [] def get_werror_args(self): return ['-Werror'] def split_shlib_to_parts(self, fname): return None, fname def build_rpath_args(self, build_dir, rpath_paths, install_rpath): return [] def get_dependency_gen_args(self, outtarget, outfile): return [] def get_linker_exelist(self): return self.exelist[:] def get_compile_only_args(self): return [] def get_output_args(self, subdir): if subdir == '': subdir = './' return ['-d', subdir, '-s', subdir] def get_linker_output_args(self, outputname): return [] def get_coverage_args(self): return [] def get_coverage_link_args(self): return [] def get_std_exe_link_args(self): return [] def get_include_args(self, path): return [] def get_pic_args(self): return [] def name_string(self): return ' '.join(self.exelist) def get_pch_use_args(self, pch_dir, header): return [] def get_pch_name(self, header_name): return '' def get_buildtype_args(self, buildtype): return java_buildtype_args[buildtype] def sanity_check(self, work_dir, environment): src = 'SanityCheck.java' obj = 'SanityCheck' source_name = os.path.join(work_dir, src) with open(source_name, 'w') as ofile: ofile.write('''class SanityCheck { public static void main(String[] args) { int i; } } ''') pc = subprocess.Popen(self.exelist + [src], cwd=work_dir) pc.wait() if pc.returncode != 0: raise EnvironmentException('Java compiler %s can not compile programs.' % 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 class ValaCompiler(Compiler): def __init__(self, exelist, version): self.language = 'vala' super().__init__(exelist, version) self.version = version self.id = 'valac' self.is_cross = False def name_string(self): return ' '.join(self.exelist) def needs_static_linker(self): return False # Because compiles into C. def get_output_args(self, target): return ['-o', target] def get_compile_only_args(self): return ['-C'] def get_werror_args(self): return ['--fatal-warnings'] def sanity_check(self, work_dir, environment): code = 'class MesonSanityCheck : Object { }' args = self.get_cross_extra_flags(environment, link=False) with self.compile(code, args, 'compile') as p: if p.returncode != 0: msg = 'Vala compiler {!r} can not compile programs' \ ''.format(self.name_string()) raise EnvironmentException(msg) def get_buildtype_args(self, buildtype): if buildtype == 'debug' or buildtype == 'debugoptimized' or buildtype == 'minsize': return ['--debug'] return [] def find_library(self, libname, env, extra_dirs): if extra_dirs and isinstance(extra_dirs, str): extra_dirs = [extra_dirs] # Valac always looks in the default vapi dir, so only search there if # no extra dirs are specified. if len(extra_dirs) == 0: code = 'class MesonFindLibrary : Object { }' vapi_args = ['--pkg', libname] args = self.get_cross_extra_flags(env, link=False) args += vapi_args with self.compile(code, args, 'compile') as p: if p.returncode == 0: return vapi_args # Not found? Try to find the vapi file itself. for d in extra_dirs: vapi = os.path.join(d, libname + '.vapi') if os.path.isfile(vapi): return vapi mlog.debug('Searched {!r} and {!r} wasn\'t found'.format(extra_dirs, libname)) return None class RustCompiler(Compiler): def __init__(self, exelist, version): self.language = 'rust' super().__init__(exelist, version) self.id = 'rustc' def needs_static_linker(self): return False def name_string(self): return ' '.join(self.exelist) def sanity_check(self, work_dir, environment): source_name = os.path.join(work_dir, 'sanity.rs') output_name = os.path.join(work_dir, 'rusttest') with open(source_name, 'w') as ofile: ofile.write('''fn main() { } ''') pc = subprocess.Popen(self.exelist + ['-o', output_name, source_name], cwd=work_dir) pc.wait() if pc.returncode != 0: raise EnvironmentException('Rust compiler %s can not compile programs.' % self.name_string()) if subprocess.call(output_name) != 0: raise EnvironmentException('Executables created by Rust compiler %s are not runnable.' % self.name_string()) def get_dependency_gen_args(self, outfile): return ['--dep-info', outfile] def get_buildtype_args(self, buildtype): return rust_buildtype_args[buildtype] class SwiftCompiler(Compiler): def __init__(self, exelist, version): self.language = 'swift' super().__init__(exelist, version) self.version = version self.id = 'llvm' self.is_cross = False def get_linker_exelist(self): return self.exelist[:] def name_string(self): return ' '.join(self.exelist) def needs_static_linker(self): return True def get_werror_args(self): return ['--fatal-warnings'] def get_dependency_gen_args(self, outtarget, outfile): return ['-emit-dependencies'] def depfile_for_object(self, objfile): return os.path.splitext(objfile)[0] + '.' + self.get_depfile_suffix() def get_depfile_suffix(self): return 'd' def get_output_args(self, target): return ['-o', target] def get_linker_output_args(self, target): return ['-o', target] def get_header_import_args(self, headername): return ['-import-objc-header', headername] def get_warn_args(self, level): return [] def get_buildtype_args(self, buildtype): return swift_buildtype_args[buildtype] def get_buildtype_linker_args(self, buildtype): return [] def get_std_exe_link_args(self): return ['-emit-executable'] def get_module_args(self, modname): return ['-module-name', modname] def get_mod_gen_args(self): return ['-emit-module'] def build_rpath_args(self, *args): return [] # FIXME def get_include_args(self, dirname): return ['-I' + dirname] def get_compile_only_args(self): return ['-c'] def sanity_check(self, work_dir, environment): src = 'swifttest.swift' source_name = os.path.join(work_dir, src) output_name = os.path.join(work_dir, 'swifttest') with open(source_name, 'w') as ofile: ofile.write('''print("Swift compilation is working.") ''') extra_flags = self.get_cross_extra_flags(environment, link=True) pc = subprocess.Popen(self.exelist + extra_flags + ['-emit-executable', '-o', output_name, src], cwd=work_dir) pc.wait() if pc.returncode != 0: raise EnvironmentException('Swift compiler %s can not compile programs.' % self.name_string()) if subprocess.call(output_name) != 0: raise EnvironmentException('Executables created by Swift compiler %s are not runnable.' % self.name_string()) class DCompiler(Compiler): def __init__(self, exelist, version, is_cross): self.language = 'd' super().__init__(exelist, version) self.id = 'unknown' self.is_cross = is_cross def sanity_check(self, work_dir, environment): source_name = os.path.join(work_dir, 'sanity.d') output_name = os.path.join(work_dir, 'dtest') with open(source_name, 'w') as ofile: ofile.write('''void main() { } ''') pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + [source_name], cwd=work_dir) pc.wait() if pc.returncode != 0: raise EnvironmentException('D compiler %s can not compile programs.' % self.name_string()) if subprocess.call(output_name) != 0: raise EnvironmentException('Executables created by D compiler %s are not runnable.' % self.name_string()) def needs_static_linker(self): return True def name_string(self): return ' '.join(self.exelist) def get_linker_exelist(self): return self.exelist[:] def get_preprocess_only_args(self): return ['-E'] def get_compile_only_args(self): return ['-c'] def depfile_for_object(self, objfile): return objfile + '.' + self.get_depfile_suffix() def get_depfile_suffix(self): return 'dep' def get_pic_args(self): return ['-fPIC'] def get_std_shared_lib_link_args(self): return ['-shared'] def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module): # FIXME: Make this work for Windows, MacOS and cross-compiling return get_gcc_soname_args(GCC_STANDARD, prefix, shlib_name, suffix, path, soversion, is_shared_module) def get_unittest_args(self): return ['-unittest'] def get_buildtype_linker_args(self, buildtype): return [] def get_std_exe_link_args(self): return [] def build_rpath_args(self, build_dir, rpath_paths, install_rpath): # This method is to be used by LDC and DMD. # GDC can deal with the verbatim flags. if len(rpath_paths) == 0 and len(install_rpath) == 0: return [] paths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths]) if len(paths) < len(install_rpath): padding = 'X' * (len(install_rpath) - len(paths)) if len(paths) == 0: paths = padding else: paths = paths + ':' + padding return ['-L-rpath={}'.format(paths)] @classmethod def translate_args_to_nongnu(cls, args): dcargs = [] # Translate common arguments to flags the LDC/DMD compilers # can understand. # The flags might have been added by pkg-config files, # and are therefore out of the user's control. for arg in args: if arg == '-pthread': continue if arg.startswith('-Wl,'): linkargs = arg[arg.index(',') + 1:].split(',') for la in linkargs: dcargs.append('-L' + la.strip()) continue elif arg.startswith('-l'): # translate library link flag dcargs.append('-L' + arg) continue elif arg.startswith('-L/') or arg.startswith('-L./'): # we need to handle cases where -L is set by e.g. a pkg-config # setting to select a linker search path. We can however not # unconditionally prefix '-L' with '-L' because the user might # have set this flag too to do what it is intended to for this # compiler (pass flag through to the linker) # Hence, we guess here whether the flag was intended to pass # a linker search path. dcargs.append('-L' + arg) continue dcargs.append(arg) return dcargs class GnuDCompiler(DCompiler): def __init__(self, exelist, version, is_cross): DCompiler.__init__(self, exelist, version, is_cross) self.id = 'gcc' default_warn_args = ['-Wall', '-Wdeprecated'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} self.base_options = ['b_colorout', 'b_sanitize', 'b_staticpic'] def get_colorout_args(self, colortype): if mesonlib.version_compare(self.version, '>=4.9.0'): return gnu_color_args[colortype][:] return [] def get_dependency_gen_args(self, outtarget, outfile): return ['-fmake-deps=' + outfile] def get_output_args(self, target): return ['-o', target] def get_linker_output_args(self, target): return ['-o', target] def get_include_args(self, path, is_system): return ['-I' + path] def get_warn_args(self, level): return self.warn_args[level] def get_werror_args(self): return ['-Werror'] def get_linker_search_args(self, dirname): return ['-L' + dirname] def get_buildtype_args(self, buildtype): return d_gdc_buildtype_args[buildtype] def build_rpath_args(self, build_dir, rpath_paths, install_rpath): return build_unix_rpath_args(build_dir, rpath_paths, install_rpath) def get_unittest_args(self): return ['-funittest'] class LLVMDCompiler(DCompiler): def __init__(self, exelist, version, is_cross): DCompiler.__init__(self, exelist, version, is_cross) self.id = 'llvm' self.base_options = ['b_coverage', 'b_colorout'] def get_colorout_args(self, colortype): if colortype == 'always': return ['-enable-color'] return [] def get_dependency_gen_args(self, outtarget, outfile): # LDC using the -deps flag returns a non-Makefile dependency-info file, which # the backends can not use. So we disable this feature for now. return [] def get_output_args(self, target): return ['-of', target] def get_linker_output_args(self, target): return ['-of', target] def get_include_args(self, path, is_system): return ['-I' + path] def get_warn_args(self, level): if level == '2' or level == '3': return ['-wi', '-dw'] else: return ['-wi'] def get_werror_args(self): return ['-w'] def get_coverage_args(self): return ['-cov'] def get_buildtype_args(self, buildtype): return d_ldc_buildtype_args[buildtype] def get_pic_args(self): return ['-relocation-model=pic'] def get_linker_search_args(self, dirname): # -L is recognized as "add this to the search path" by the linker, # while the compiler recognizes it as "pass to linker". So, the first # -L is for the compiler, telling it to pass the second -L to the linker. return ['-L-L' + dirname] @classmethod def unix_args_to_native(cls, args): return cls.translate_args_to_nongnu(args) class DmdDCompiler(DCompiler): def __init__(self, exelist, version, is_cross): DCompiler.__init__(self, exelist, version, is_cross) self.id = 'dmd' self.base_options = ['b_coverage', 'b_colorout'] def get_colorout_args(self, colortype): if colortype == 'always': return ['-color=on'] return [] def get_dependency_gen_args(self, outtarget, outfile): # LDC using the -deps flag returns a non-Makefile dependency-info file, which # the backends can not use. So we disable this feature for now. return [] def get_output_args(self, target): return ['-of' + target] def get_werror_args(self): return ['-w'] def get_linker_output_args(self, target): return ['-of' + target] def get_include_args(self, path, is_system): return ['-I' + path] def get_warn_args(self, level): return ['-wi'] def get_coverage_args(self): return ['-cov'] def get_linker_search_args(self, dirname): # -L is recognized as "add this to the search path" by the linker, # while the compiler recognizes it as "pass to linker". So, the first # -L is for the compiler, telling it to pass the second -L to the linker. return ['-L-L' + dirname] def get_buildtype_args(self, buildtype): return d_dmd_buildtype_args[buildtype] def get_std_shared_lib_link_args(self): return ['-shared', '-defaultlib=libphobos2.so'] @classmethod def unix_args_to_native(cls, args): return cls.translate_args_to_nongnu(args) class VisualStudioCCompiler(CCompiler): std_warn_args = ['/W3'] std_opt_args = ['/O2'] def __init__(self, exelist, version, is_cross, exe_wrap): CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) self.id = 'msvc' # /showIncludes is needed for build dependency tracking in Ninja # See: https://ninja-build.org/manual.html#_deps self.always_args = ['/nologo', '/showIncludes'] self.warn_args = {'1': ['/W2'], '2': ['/W3'], '3': ['/W4']} self.base_options = ['b_pch'] # FIXME add lto, pgo and the like # Override CCompiler.get_always_args def get_always_args(self): return self.always_args def get_linker_debug_crt_args(self): """ Arguments needed to select a debug crt for the linker Sometimes we need to manually select the CRT (C runtime) to use with MSVC. One example is when trying to link with static libraries since MSVC won't auto-select a CRT for us in that case and will error out asking us to select one. """ return ['/MDd'] def get_buildtype_args(self, buildtype): return msvc_buildtype_args[buildtype] def get_buildtype_linker_args(self, buildtype): return msvc_buildtype_linker_args[buildtype] def get_pch_suffix(self): return 'pch' def get_pch_name(self, header): chopped = os.path.split(header)[-1].split('.')[:-1] chopped.append(self.get_pch_suffix()) pchname = '.'.join(chopped) return pchname def get_pch_use_args(self, pch_dir, header): base = os.path.split(header)[-1] pchname = self.get_pch_name(header) return ['/FI' + base, '/Yu' + base, '/Fp' + os.path.join(pch_dir, pchname)] def get_preprocess_only_args(self): return ['/E'] def get_compile_only_args(self): return ['/c'] def get_no_optimization_args(self): return ['/Od'] def get_output_args(self, target): if target.endswith('.exe'): return ['/Fe' + target] return ['/Fo' + target] def get_dependency_gen_args(self, outtarget, outfile): return [] def get_linker_exelist(self): return ['link'] # FIXME, should have same path as compiler. def get_linker_always_args(self): return ['/nologo'] def get_linker_output_args(self, outputname): return ['/OUT:' + outputname] def get_linker_search_args(self, dirname): return ['/LIBPATH:' + dirname] def get_pic_args(self): return [] # PIC is handled by the loader on Windows def get_std_shared_lib_link_args(self): return ['/DLL'] def gen_vs_module_defs_args(self, defsfile): if not isinstance(defsfile, str): raise RuntimeError('Module definitions file should be str') # With MSVC, DLLs only export symbols that are explicitly exported, # so if a module defs file is specified, we use that to export symbols return ['/DEF:' + defsfile] def gen_pch_args(self, header, source, pchname): objname = os.path.splitext(pchname)[0] + '.obj' return objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname] def gen_import_library_args(self, implibname): "The name of the outputted import library" return ['/IMPLIB:' + implibname] def build_rpath_args(self, build_dir, rpath_paths, install_rpath): return [] # FIXME, no idea what these should be. def thread_flags(self): return [] def thread_link_flags(self): return [] def get_options(self): return {'c_winlibs': coredata.UserStringArrayOption('c_winlibs', 'Windows libs to link against.', msvc_winlibs) } def get_option_link_args(self, options): return options['c_winlibs'].value[:] @classmethod def unix_args_to_native(cls, args): result = [] for i in args: # -mms-bitfields is specific to MinGW-GCC # -pthread is only valid for GCC if i in ('-mms-bitfields', '-pthread'): continue if i.startswith('-L'): i = '/LIBPATH:' + i[2:] # Translate GNU-style -lfoo library name to the import library elif i.startswith('-l'): name = i[2:] if name in ('m', 'c', 'pthread'): # With MSVC, these are provided by the C runtime which is # linked in by default continue else: i = name + '.lib' # -pthread in link flags is only used on Linux elif i == '-pthread': continue result.append(i) return result def get_werror_args(self): return ['/WX'] def get_include_args(self, path, is_system): if path == '': path = '.' # msvc does not have a concept of system header dirs. return ['-I' + path] # Visual Studio is special. It ignores some arguments it does not # understand and you can't tell it to error out on those. # http://stackoverflow.com/questions/15259720/how-can-i-make-the-microsoft-c-compiler-treat-unknown-flags-as-errors-rather-t def has_multi_arguments(self, args, env): warning_text = '9002' code = 'int i;\n' (fd, srcname) = tempfile.mkstemp(suffix='.' + self.default_suffix) os.close(fd) with open(srcname, 'w') as ofile: ofile.write(code) # Read c_args/cpp_args/etc from the cross-info file (if needed) extra_args = self.get_cross_extra_flags(env, link=False) extra_args += self.get_compile_only_args() commands = self.exelist + args + extra_args + [srcname] mlog.debug('Running VS compile:') mlog.debug('Command line: ', ' '.join(commands)) mlog.debug('Code:\n', code) p, stdo, stde = Popen_safe(commands, cwd=os.path.split(srcname)[0]) if p.returncode != 0: return False return not(warning_text in stde or warning_text in stdo) def get_compile_debugfile_args(self, rel_obj, pch=False): pdbarr = rel_obj.split('.')[:-1] pdbarr += ['pdb'] 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)] def get_link_whole_for(self, args): # Only since VS2015 if not isinstance(args, list): args = [args] return ['/WHOLEARCHIVE:' + x for x in args] 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 def get_options(self): return {'cpp_eh': coredata.UserComboOption('cpp_eh', 'C++ exception handling type.', ['none', 'a', 's', 'sc'], 'sc'), 'cpp_winlibs': coredata.UserStringArrayOption('cpp_winlibs', 'Windows libs to link against.', msvc_winlibs) } def get_option_compile_args(self, options): args = [] std = options['cpp_eh'] if std.value != 'none': args.append('/EH' + std.value) return args def get_option_link_args(self, options): return options['cpp_winlibs'].value[:] def get_compiler_check_args(self): # Visual Studio C++ compiler doesn't support -fpermissive, # so just use the plain C args. return super(VisualStudioCCompiler, self).get_compiler_check_args() GCC_STANDARD = 0 GCC_OSX = 1 GCC_MINGW = 2 GCC_CYGWIN = 3 CLANG_STANDARD = 0 CLANG_OSX = 1 CLANG_WIN = 2 # Possibly clang-cl? ICC_STANDARD = 0 ICC_OSX = 1 ICC_WIN = 2 def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module): if soversion is None: sostr = '' else: sostr = '.' + soversion 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: if is_shared_module: return [] return ['-install_name', os.path.join(path, 'lib' + shlib_name + '.dylib')] else: raise RuntimeError('Not implemented yet.') def get_compiler_is_linuxlike(compiler): if (getattr(compiler, 'gcc_type', None) == GCC_STANDARD) or \ (getattr(compiler, 'clang_type', None) == CLANG_STANDARD) or \ (getattr(compiler, 'icc_type', None) == ICC_STANDARD): return True return False def get_largefile_args(compiler): ''' Enable transparent large-file-support for 32-bit UNIX systems ''' if get_compiler_is_linuxlike(compiler): # Enable large-file support unconditionally on all platforms other # than macOS and Windows. macOS is now 64-bit-only so it doesn't # need anything special, and Windows doesn't have automatic LFS. # You must use the 64-bit counterparts explicitly. # glibc, musl, and uclibc, and all BSD libcs support this. On Android, # support for transparent LFS is available depending on the version of # Bionic: https://github.com/android/platform_bionic#32-bit-abi-bugs # https://code.google.com/p/android/issues/detail?id=64613 # # If this breaks your code, fix it! It's been 20+ years! return ['-D_FILE_OFFSET_BITS=64'] # We don't enable -D_LARGEFILE64_SOURCE since that enables # transitionary features and must be enabled by programs that use # those features explicitly. return [] class GnuCompiler: # Functionality that is common to all GNU family compilers. def __init__(self, gcc_type, defines): self.id = 'gcc' self.gcc_type = gcc_type self.defines = defines or {} self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', 'b_colorout', 'b_ndebug', 'b_staticpic'] if self.gcc_type != GCC_OSX: self.base_options.append('b_lundef') self.base_options.append('b_asneeded') # All GCC backends can do assembly self.can_compile_suffixes.add('s') def get_colorout_args(self, colortype): if mesonlib.version_compare(self.version, '>=4.9.0'): return gnu_color_args[colortype][:] return [] def get_warn_args(self, level): args = super().get_warn_args(level) if mesonlib.version_compare(self.version, '<4.8.0') and '-Wpedantic' in args: # -Wpedantic was added in 4.8.0 # https://gcc.gnu.org/gcc-4.8/changes.html args[args.index('-Wpedantic')] = '-pedantic' return args def has_builtin_define(self, define): return define in self.defines 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_CYGWIN, GCC_MINGW, GCC_OSX): return [] # On Window and OS X, pic is always on. return ['-fPIC'] def get_buildtype_args(self, buildtype): return gnulike_buildtype_args[buildtype] def get_buildtype_linker_args(self, buildtype): if self.gcc_type == GCC_OSX: return apple_buildtype_linker_args[buildtype] return gnulike_buildtype_linker_args[buildtype] def get_pch_suffix(self): return 'gch' def split_shlib_to_parts(self, fname): return os.path.split(fname)[0], fname def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module): return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module) def get_std_shared_lib_link_args(self): if self.gcc_type == GCC_OSX: return ['-bundle'] return ['-shared'] def get_link_whole_for(self, args): return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive'] class GnuCCompiler(GnuCompiler, CCompiler): def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None): CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) GnuCompiler.__init__(self, gcc_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): opts = {'c_std': coredata.UserComboOption('c_std', 'C language standard to use', ['none', 'c89', 'c99', 'c11', 'gnu89', 'gnu99', 'gnu11'], 'none')} if self.gcc_type == GCC_MINGW: opts.update({ 'c_winlibs': coredata.UserStringArrayOption('c_winlibs', 'Standard Win libraries to link against', gnu_winlibs), }) return opts def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value != 'none': args.append('-std=' + std.value) return args def get_option_link_args(self, options): if self.gcc_type == GCC_MINGW: return options['c_winlibs'].value[:] return [] def get_std_shared_lib_link_args(self): return ['-shared'] class GnuCPPCompiler(GnuCompiler, CPPCompiler): def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap, defines): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) GnuCompiler.__init__(self, gcc_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): opts = {'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', ['none', 'c++03', 'c++11', 'c++14', 'c++1z', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++1z'], 'none'), 'cpp_debugstl': coredata.UserBooleanOption('cpp_debugstl', 'STL debug mode', False)} if self.gcc_type == GCC_MINGW: opts.update({ 'cpp_winlibs': coredata.UserStringArrayOption('cpp_winlibs', 'Standard Win libraries to link against', gnu_winlibs), }) return opts def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value != 'none': args.append('-std=' + std.value) if options['cpp_debugstl'].value: args.append('-D_GLIBCXX_DEBUG=1') return args def get_option_link_args(self, options): if self.gcc_type == GCC_MINGW: return options['cpp_winlibs'].value[:] return [] class GnuObjCCompiler(GnuCompiler, ObjCCompiler): def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None): ObjCCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) GnuCompiler.__init__(self, gcc_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler): def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None): ObjCPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) GnuCompiler.__init__(self, gcc_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} class ClangCompiler: def __init__(self, clang_type): self.id = 'clang' self.clang_type = clang_type self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', 'b_ndebug', 'b_staticpic', 'b_colorout'] if self.clang_type != CLANG_OSX: self.base_options.append('b_lundef') self.base_options.append('b_asneeded') # All Clang backends can do assembly and LLVM IR self.can_compile_suffixes.update(['ll', 's']) def get_pic_args(self): if self.clang_type in (CLANG_WIN, CLANG_OSX): return [] # On Window and OS X, pic is always on. return ['-fPIC'] def get_colorout_args(self, colortype): return clang_color_args[colortype][:] def get_buildtype_args(self, buildtype): return gnulike_buildtype_args[buildtype] def get_buildtype_linker_args(self, buildtype): if self.clang_type == CLANG_OSX: return apple_buildtype_linker_args[buildtype] return gnulike_buildtype_linker_args[buildtype] def get_pch_suffix(self): return 'pch' def get_pch_use_args(self, pch_dir, header): # Workaround for Clang bug http://llvm.org/bugs/show_bug.cgi?id=15136 # This flag is internal to Clang (or at least not documented on the man page) # so it might change semantics at any time. return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))] def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module): if self.clang_type == CLANG_STANDARD: gcc_type = GCC_STANDARD elif self.clang_type == CLANG_OSX: gcc_type = GCC_OSX elif self.clang_type == CLANG_WIN: gcc_type = GCC_MINGW else: raise MesonException('Unreachable code when converting clang type to gcc type.') return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module) def has_multi_arguments(self, args, env): return super().has_multi_arguments( ['-Werror=unknown-warning-option'] + args, env) def has_function(self, funcname, prefix, env, extra_args=None, dependencies=None): if extra_args is None: extra_args = [] # Starting with XCode 8, we need to pass this to force linker # visibility to obey OS X and iOS minimum version targets with # -mmacosx-version-min, -miphoneos-version-min, etc. # https://github.com/Homebrew/homebrew-core/issues/3727 if self.clang_type == CLANG_OSX and version_compare(self.version, '>=8.0'): extra_args.append('-Wl,-no_weak_imports') return super().has_function(funcname, prefix, env, extra_args, dependencies) def get_std_shared_module_link_args(self): if self.clang_type == CLANG_OSX: return ['-bundle', '-Wl,-undefined,dynamic_lookup'] return ['-shared'] def get_link_whole_for(self, args): if self.clang_type == CLANG_OSX: result = [] for a in args: result += ['-Wl,-force_load', a] return result return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive'] class ClangCCompiler(ClangCompiler, CCompiler): def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None): CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) ClangCompiler.__init__(self, clang_type) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): return {'c_std': coredata.UserComboOption('c_std', 'C language standard to use', ['none', 'c89', 'c99', 'c11', 'gnu89', 'gnu99', 'gnu11'], 'none')} def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value != 'none': args.append('-std=' + std.value) return args def get_option_link_args(self, options): return [] class ClangCPPCompiler(ClangCompiler, CPPCompiler): def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) ClangCompiler.__init__(self, cltype) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): return {'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', ['none', 'c++03', 'c++11', 'c++14', 'c++1z', 'gnu++11', 'gnu++14', 'gnu++1z'], 'none')} def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value != 'none': args.append('-std=' + std.value) return args def get_option_link_args(self, options): return [] class ClangObjCCompiler(ClangCompiler, GnuObjCCompiler): def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None): GnuObjCCompiler.__init__(self, exelist, version, cltype, is_cross, exe_wrapper) ClangCompiler.__init__(self, cltype) self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage'] class ClangObjCPPCompiler(ClangCompiler, GnuObjCPPCompiler): def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None): GnuObjCPPCompiler.__init__(self, exelist, version, cltype, is_cross, exe_wrapper) ClangCompiler.__init__(self, cltype) self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage'] # Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1 class IntelCompiler: def __init__(self, icc_type): self.id = 'intel' self.icc_type = icc_type self.lang_header = 'none' self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', 'b_colorout', 'b_ndebug', 'b_staticpic', 'b_lundef', 'b_asneeded'] # Assembly self.can_compile_suffixes.add('s') def get_pic_args(self): return ['-fPIC'] def get_buildtype_args(self, buildtype): return gnulike_buildtype_args[buildtype] def get_buildtype_linker_args(self, buildtype): return gnulike_buildtype_linker_args[buildtype] def get_pch_suffix(self): return 'pchi' def get_pch_use_args(self, pch_dir, header): return ['-pch', '-pch_dir', os.path.join(pch_dir), '-x', self.lang_header, '-include', header, '-x', 'none'] def get_pch_name(self, header_name): return os.path.split(header_name)[-1] + '.' + self.get_pch_suffix() def split_shlib_to_parts(self, fname): return os.path.split(fname)[0], fname def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module): if self.icc_type == ICC_STANDARD: gcc_type = GCC_STANDARD elif self.icc_type == ICC_OSX: gcc_type = GCC_OSX elif self.icc_type == ICC_WIN: gcc_type = GCC_MINGW else: raise MesonException('Unreachable code when converting icc type to gcc type.') return get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module) def get_std_shared_lib_link_args(self): # FIXME: Don't know how icc works on OSX # if self.icc_type == ICC_OSX: # return ['-bundle'] return ['-shared'] class IntelCCompiler(IntelCompiler, CCompiler): def __init__(self, exelist, version, icc_type, is_cross, exe_wrapper=None): CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) IntelCompiler.__init__(self, icc_type) self.lang_header = 'c-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', '-Wpch-messages'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): c_stds = ['c89', 'c99'] g_stds = ['gnu89', 'gnu99'] if mesonlib.version_compare(self.version, '>=16.0.0'): c_stds += ['c11'] opts = {'c_std': coredata.UserComboOption('c_std', 'C language standard to use', ['none'] + c_stds + g_stds, 'none')} return opts def get_option_compile_args(self, options): args = [] std = options['c_std'] if std.value != 'none': args.append('-std=' + std.value) return args def get_std_shared_lib_link_args(self): return ['-shared'] def has_multi_arguments(self, args, env): return super().has_multi_arguments(args + ['-diag-error', '10006'], env) class IntelCPPCompiler(IntelCompiler, CPPCompiler): def __init__(self, exelist, version, icc_type, is_cross, exe_wrap): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) IntelCompiler.__init__(self, icc_type) self.lang_header = 'c++-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', '-Wpch-messages', '-Wnon-virtual-dtor'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} def get_options(self): c_stds = [] g_stds = ['gnu++98'] if mesonlib.version_compare(self.version, '>=15.0.0'): c_stds += ['c++11', 'c++14'] g_stds += ['gnu++11'] if mesonlib.version_compare(self.version, '>=16.0.0'): c_stds += ['c++17'] if mesonlib.version_compare(self.version, '>=17.0.0'): g_stds += ['gnu++14'] opts = {'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', ['none'] + c_stds + g_stds, 'none'), 'cpp_debugstl': coredata.UserBooleanOption('cpp_debugstl', 'STL debug mode', False)} return opts def get_option_compile_args(self, options): args = [] std = options['cpp_std'] if std.value != 'none': args.append('-std=' + std.value) if options['cpp_debugstl'].value: args.append('-D_GLIBCXX_DEBUG=1') return args def get_option_link_args(self, options): return [] def has_multi_arguments(self, args, env): return super().has_multi_arguments(args + ['-diag-error', '10006'], env) class FortranCompiler(Compiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None): self.language = 'fortran' super().__init__(exelist, version) self.is_cross = is_cross self.exe_wrapper = exe_wrapper # Not really correct but I don't have Fortran compilers to test with. Sorry. self.gcc_type = GCC_STANDARD self.id = "IMPLEMENTATION CLASSES MUST SET THIS" def name_string(self): return ' '.join(self.exelist) def get_pic_args(self): if self.gcc_type in (GCC_CYGWIN, GCC_MINGW, GCC_OSX): return [] # On Window and OS X, pic is always on. return ['-fPIC'] def get_std_shared_lib_link_args(self): return ['-shared'] def needs_static_linker(self): return True def sanity_check(self, work_dir, environment): source_name = os.path.join(work_dir, 'sanitycheckf.f90') binary_name = os.path.join(work_dir, 'sanitycheckf') with open(source_name, 'w') as ofile: ofile.write('''program prog print *, "Fortran compilation is working." end program prog ''') extra_flags = self.get_cross_extra_flags(environment, link=True) pc = subprocess.Popen(self.exelist + extra_flags + [source_name, '-o', binary_name]) pc.wait() if pc.returncode != 0: raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string()) if self.is_cross: if self.exe_wrapper is None: # Can't check if the binaries run so we have to assume they do return cmdlist = self.exe_wrapper + [binary_name] else: cmdlist = [binary_name] pe = subprocess.Popen(cmdlist, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) pe.wait() if pe.returncode != 0: raise EnvironmentException('Executables created by Fortran compiler %s are not runnable.' % self.name_string()) def get_std_warn_args(self, level): return FortranCompiler.std_warn_args def get_buildtype_args(self, buildtype): return gnulike_buildtype_args[buildtype] def get_buildtype_linker_args(self, buildtype): if mesonlib.is_osx(): return apple_buildtype_linker_args[buildtype] return gnulike_buildtype_linker_args[buildtype] def split_shlib_to_parts(self, fname): return os.path.split(fname)[0], fname def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module): return get_gcc_soname_args(self.gcc_type, prefix, shlib_name, suffix, path, soversion, is_shared_module) def get_dependency_gen_args(self, outtarget, outfile): # Disabled until this is fixed: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62162 # return ['-cpp', '-MMD', '-MQ', outtarget] return [] def get_output_args(self, target): return ['-o', target] def get_preprocess_only_args(self): return ['-E'] def get_compile_only_args(self): return ['-c'] def get_linker_exelist(self): return self.exelist[:] def get_linker_output_args(self, outputname): return ['-o', outputname] def get_include_args(self, path, is_system): return ['-I' + path] def get_module_outdir_args(self, path): return ['-J' + path] def depfile_for_object(self, objfile): return objfile + '.' + self.get_depfile_suffix() def get_depfile_suffix(self): return 'd' def get_std_exe_link_args(self): return [] def build_rpath_args(self, build_dir, rpath_paths, install_rpath): return build_unix_rpath_args(build_dir, rpath_paths, install_rpath) def module_name_to_filename(self, module_name): return module_name.lower() + '.mod' def get_warn_args(self, level): return ['-Wall'] def get_no_warn_args(self): return ['-w'] class GnuFortranCompiler(FortranCompiler): def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None): super().__init__(exelist, version, is_cross, exe_wrapper=None) self.gcc_type = gcc_type self.defines = defines or {} self.id = 'gcc' def has_builtin_define(self, define): return define in self.defines def get_builtin_define(self, define): if define in self.defines: return self.defines[define] def get_always_args(self): return ['-pipe'] def gen_import_library_args(self, implibname): """ The name of the outputted import library Used only on Windows """ return ['-Wl,--out-implib=' + implibname] class G95FortranCompiler(FortranCompiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None): super().__init__(exelist, version, is_cross, exe_wrapper=None) self.id = 'g95' def get_module_outdir_args(self, path): return ['-fmod=' + path] def get_always_args(self): return ['-pipe'] def get_no_warn_args(self): # FIXME: Confirm that there's no compiler option to disable all warnings return [] def gen_import_library_args(self, implibname): """ The name of the outputted import library Used only on Windows """ return ['-Wl,--out-implib=' + implibname] class SunFortranCompiler(FortranCompiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None): super().__init__(exelist, version, is_cross, exe_wrapper=None) self.id = 'sun' def get_dependency_gen_args(self, outtarget, outfile): return ['-fpp'] def get_always_args(self): return [] def get_warn_args(self, level): return [] def get_module_outdir_args(self, path): return ['-moddir=' + path] class IntelFortranCompiler(IntelCompiler, FortranCompiler): std_warn_args = ['-warn', 'all'] def __init__(self, exelist, version, is_cross, exe_wrapper=None): self.file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp') FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) # FIXME: Add support for OS X and Windows in detect_fortran_compiler so # we are sent the type of compiler IntelCompiler.__init__(self, ICC_STANDARD) self.id = 'intel' def get_module_outdir_args(self, path): return ['-module', path] def get_warn_args(self, level): return IntelFortranCompiler.std_warn_args class PathScaleFortranCompiler(FortranCompiler): std_warn_args = ['-fullwarn'] def __init__(self, exelist, version, is_cross, exe_wrapper=None): super().__init__(exelist, version, is_cross, exe_wrapper=None) self.id = 'pathscale' def get_module_outdir_args(self, path): return ['-module', path] def get_std_warn_args(self, level): return PathScaleFortranCompiler.std_warn_args class PGIFortranCompiler(FortranCompiler): std_warn_args = ['-Minform=inform'] def __init__(self, exelist, version, is_cross, exe_wrapper=None): super().__init__(exelist, version, is_cross, exe_wrapper=None) self.id = 'pgi' def get_module_outdir_args(self, path): return ['-module', path] def get_warn_args(self, level): return PGIFortranCompiler.std_warn_args def get_no_warn_args(self): return ['-silent'] class Open64FortranCompiler(FortranCompiler): std_warn_args = ['-fullwarn'] def __init__(self, exelist, version, is_cross, exe_wrapper=None): super().__init__(exelist, version, is_cross, exe_wrapper=None) self.id = 'open64' def get_module_outdir_args(self, path): return ['-module', path] def get_warn_args(self, level): return Open64FortranCompiler.std_warn_args class NAGFortranCompiler(FortranCompiler): std_warn_args = [] def __init__(self, exelist, version, is_cross, exe_wrapper=None): super().__init__(exelist, version, is_cross, exe_wrapper=None) self.id = 'nagfor' def get_module_outdir_args(self, path): return ['-mdir', path] def get_warn_args(self, level): return NAGFortranCompiler.std_warn_args class StaticLinker: pass class VisualStudioLinker(StaticLinker): always_args = ['/NOLOGO'] def __init__(self, exelist): self.exelist = exelist def get_exelist(self): return self.exelist[:] def get_std_link_args(self): return [] def get_buildtype_linker_args(self, buildtype): return [] def get_output_args(self, target): return ['/OUT:' + target] def get_coverage_link_args(self): return [] def get_always_args(self): return VisualStudioLinker.always_args def get_linker_always_args(self): return VisualStudioLinker.always_args def build_rpath_args(self, build_dir, rpath_paths, install_rpath): return [] def thread_link_flags(self): return [] def get_option_link_args(self, options): return [] @classmethod def unix_args_to_native(cls, args): return VisualStudioCCompiler.unix_args_to_native(args) def get_link_debugfile_args(self, targetfile): # Static libraries do not have PDB files return [] class ArLinker(StaticLinker): def __init__(self, exelist): self.exelist = exelist self.id = 'ar' pc, stdo = Popen_safe(self.exelist + ['-h'])[0:2] # Enable deterministic builds if they are available. if '[D]' in stdo: self.std_args = ['csrD'] else: self.std_args = ['csr'] def build_rpath_args(self, build_dir, rpath_paths, install_rpath): return [] def get_exelist(self): return self.exelist[:] def get_std_link_args(self): return self.std_args def get_output_args(self, target): return [target] def get_buildtype_linker_args(self, buildtype): return [] def get_linker_always_args(self): return [] def get_coverage_link_args(self): return [] def get_always_args(self): return [] def thread_link_flags(self): return [] def get_option_link_args(self, options): return [] @classmethod def unix_args_to_native(cls, args): return args[:] def get_link_debugfile_args(self, targetfile): return [] meson-0.40.1/mesonbuild/mesonlib.py0000644000175000017500000006164213100700231020626 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """A library of random helper functionality.""" import stat import platform, subprocess, operator, os, shutil, re import collections from glob import glob class MesonException(Exception): '''Exceptions thrown by Meson''' class EnvironmentException(MesonException): '''Exceptions thrown while processing and creating the build environment''' class FileMode: # The first triad is for owner permissions, the second for group permissions, # and the third for others (everyone else). # For the 1st character: # 'r' means can read # '-' means not allowed # For the 2nd character: # 'w' means can write # '-' means not allowed # For the 3rd character: # 'x' means can execute # 's' means can execute and setuid/setgid is set (owner/group triads only) # 'S' means cannot execute and setuid/setgid is set (owner/group triads only) # 't' means can execute and sticky bit is set ("others" triads only) # 'T' means cannot execute and sticky bit is set ("others" triads only) # '-' means none of these are allowed # # The meanings of 'rwx' perms is not obvious for directories; see: # https://www.hackinglinuxexposed.com/articles/20030424.html # # For information on this notation such as setuid/setgid/sticky bits, see: # https://en.wikipedia.org/wiki/File_system_permissions#Symbolic_notation symbolic_perms_regex = re.compile('[r-][w-][xsS-]' # Owner perms '[r-][w-][xsS-]' # Group perms '[r-][w-][xtT-]') # Others perms def __init__(self, perms=None, owner=None, group=None): self.perms_s = perms self.perms = self.perms_s_to_bits(perms) self.owner = owner self.group = group def __repr__(self): ret = '='): cmpop = operator.ge vstr2 = vstr2[2:] elif vstr2.startswith('<='): cmpop = operator.le vstr2 = vstr2[2:] elif vstr2.startswith('!='): cmpop = operator.ne vstr2 = vstr2[2:] elif vstr2.startswith('=='): cmpop = operator.eq vstr2 = vstr2[2:] elif vstr2.startswith('='): cmpop = operator.eq vstr2 = vstr2[1:] elif vstr2.startswith('>'): cmpop = operator.gt vstr2 = vstr2[1:] elif vstr2.startswith('<'): cmpop = operator.lt vstr2 = vstr2[1:] else: cmpop = operator.eq varr1 = grab_leading_numbers(vstr1, strict) varr2 = grab_leading_numbers(vstr2, strict) return cmpop(varr1, varr2) def version_compare_many(vstr1, conditions): if not isinstance(conditions, (list, tuple)): conditions = [conditions] found = [] not_found = [] for req in conditions: if not version_compare(vstr1, req, strict=True): not_found.append(req) else: found.append(req) return not_found == [], not_found, found def default_libdir(): if is_debianlike(): try: pc = subprocess.Popen(['dpkg-architecture', '-qDEB_HOST_MULTIARCH'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) (stdo, _) = pc.communicate() if pc.returncode == 0: archpath = stdo.decode().strip() return 'lib/' + archpath except Exception: pass if os.path.isdir('/usr/lib64') and not os.path.islink('/usr/lib64'): return 'lib64' return 'lib' def default_libexecdir(): # There is no way to auto-detect this, so it must be set at build time return 'libexec' def default_prefix(): return 'c:/' if is_windows() else '/usr/local' def get_library_dirs(): if is_windows(): return ['C:/mingw/lib'] # Fixme if is_osx(): return ['/usr/lib'] # Fix me as well. # The following is probably Debian/Ubuntu specific. # /usr/local/lib is first because it contains stuff # installed by the sysadmin and is probably more up-to-date # than /usr/lib. If you feel that this search order is # problematic, please raise the issue on the mailing list. unixdirs = ['/usr/local/lib', '/usr/lib', '/lib'] plat = subprocess.check_output(['uname', '-m']).decode().strip() # This is a terrible hack. I admit it and I'm really sorry. # I just don't know what the correct solution is. if plat == 'i686': plat = 'i386' if plat.startswith('arm'): plat = 'arm' unixdirs += glob('/usr/lib/' + plat + '*') if os.path.exists('/usr/lib64'): unixdirs.append('/usr/lib64') unixdirs += glob('/lib/' + plat + '*') if os.path.exists('/lib64'): unixdirs.append('/lib64') unixdirs += glob('/lib/' + plat + '*') return unixdirs def do_replacement(regex, line, confdata): match = re.search(regex, line) while match: varname = match.group(1) if varname in confdata.keys(): (var, desc) = confdata.get(varname) if isinstance(var, str): pass elif isinstance(var, int): var = str(var) else: raise RuntimeError('Tried to replace a variable with something other than a string or int.') else: var = '' line = line.replace('@' + varname + '@', var) match = re.search(regex, line) return line def do_mesondefine(line, confdata): arr = line.split() if len(arr) != 2: raise MesonException('#mesondefine does not contain exactly two tokens: %s', line.strip()) varname = arr[1] try: (v, desc) = confdata.get(varname) except KeyError: return '/* #undef %s */\n' % varname if isinstance(v, bool): if v: return '#define %s\n' % varname else: return '#undef %s\n' % varname elif isinstance(v, int): return '#define %s %d\n' % (varname, v) elif isinstance(v, str): return '#define %s %s\n' % (varname, v) else: raise MesonException('#mesondefine argument "%s" is of unknown type.' % varname) def do_conf_file(src, dst, confdata): try: with open(src, encoding='utf-8') as f: data = f.readlines() except Exception as e: raise MesonException('Could not read input file %s: %s' % (src, str(e))) # Only allow (a-z, A-Z, 0-9, _, -) as valid characters for a define # Also allow escaping '@' with '\@' regex = re.compile(r'[^\\]?@([-a-zA-Z0-9_]+)@') result = [] for line in data: if line.startswith('#mesondefine'): line = do_mesondefine(line, confdata) else: line = do_replacement(regex, line, confdata) result.append(line) dst_tmp = dst + '~' with open(dst_tmp, 'w', encoding='utf-8') as f: f.writelines(result) shutil.copymode(src, dst_tmp) replace_if_different(dst, dst_tmp) def dump_conf_header(ofilename, cdata): with open(ofilename, 'w', encoding='utf-8') as ofile: ofile.write('''/* * Autogenerated by the Meson build system. * Do not edit, your changes will be lost. */ #pragma once ''') for k in sorted(cdata.keys()): (v, desc) = cdata.get(k) if desc: ofile.write('/* %s */\n' % desc) if isinstance(v, bool): if v: ofile.write('#define %s\n\n' % k) else: ofile.write('#undef %s\n\n' % k) elif isinstance(v, (int, str)): ofile.write('#define %s %s\n\n' % (k, v)) else: raise MesonException('Unknown data type in configuration file entry: ' + k) def replace_if_different(dst, dst_tmp): # If contents are identical, don't touch the file to prevent # unnecessary rebuilds. different = True try: with open(dst, 'r') as f1, open(dst_tmp, 'r') as f2: if f1.read() == f2.read(): different = False except FileNotFoundError: pass if different: os.replace(dst_tmp, dst) else: os.unlink(dst_tmp) def typeslistify(item, types): ''' Ensure that type(@item) is one of @types or a list of items all of which are of type @types ''' if isinstance(item, types): item = [item] if not isinstance(item, list): raise MesonException('Item must be a list or one of {!r}'.format(types)) for i in item: if i is not None and not isinstance(i, types): raise MesonException('List item must be one of {!r}'.format(types)) return item def stringlistify(item): return typeslistify(item, str) def expand_arguments(args): expended_args = [] for arg in args: if not arg.startswith('@'): expended_args.append(arg) continue args_file = arg[1:] try: with open(args_file) as f: extended_args = f.read().split() expended_args += extended_args except Exception as e: print('Error expanding command line arguments, %s not found' % args_file) print(e) return None return expended_args def Popen_safe(args, write=None, stderr=subprocess.PIPE, **kwargs): p = subprocess.Popen(args, universal_newlines=True, close_fds=False, stdout=subprocess.PIPE, stderr=stderr, **kwargs) o, e = p.communicate(write) return p, o, e def commonpath(paths): ''' For use on Python 3.4 where os.path.commonpath is not available. We currently use it everywhere so this receives enough testing. ''' # XXX: Replace me with os.path.commonpath when we start requiring Python 3.5 import pathlib if not paths: raise ValueError('arg is an empty sequence') common = pathlib.PurePath(paths[0]) for path in paths[1:]: new = [] path = pathlib.PurePath(path) for c, p in zip(common.parts, path.parts): if c != p: break new.append(c) # Don't convert '' into '.' if not new: common = '' break new = os.path.join(*new) common = pathlib.PurePath(new) return str(common) def iter_regexin_iter(regexiter, initer): ''' Takes each regular expression in @regexiter and tries to search for it in every item in @initer. If there is a match, returns that match. Else returns False. ''' for regex in regexiter: for ii in initer: if not isinstance(ii, str): continue match = re.search(regex, ii) if match: return match.group() return False def _substitute_values_check_errors(command, values): # Error checking inregex = ('@INPUT([0-9]+)?@', '@PLAINNAME@', '@BASENAME@') outregex = ('@OUTPUT([0-9]+)?@', '@OUTDIR@') if '@INPUT@' not in values: # Error out if any input-derived templates are present in the command match = iter_regexin_iter(inregex, command) if match: m = 'Command cannot have {!r}, since no input files were specified' raise MesonException(m.format(match)) else: if len(values['@INPUT@']) > 1: # Error out if @PLAINNAME@ or @BASENAME@ is present in the command match = iter_regexin_iter(inregex[1:], command) if match: raise MesonException('Command cannot have {!r} when there is ' 'more than one input file'.format(match)) # Error out if an invalid @INPUTnn@ template was specified for each in command: if not isinstance(each, str): continue match = re.search(inregex[0], each) if match and match.group() not in values: m = 'Command cannot have {!r} since there are only {!r} inputs' raise MesonException(m.format(match.group(), len(values['@INPUT@']))) if '@OUTPUT@' not in values: # Error out if any output-derived templates are present in the command match = iter_regexin_iter(outregex, command) if match: m = 'Command cannot have {!r} since there are no outputs' raise MesonException(m.format(match)) else: # Error out if an invalid @OUTPUTnn@ template was specified for each in command: if not isinstance(each, str): continue match = re.search(outregex[0], each) if match and match.group() not in values: m = 'Command cannot have {!r} since there are only {!r} outputs' raise MesonException(m.format(match.group(), len(values['@OUTPUT@']))) def substitute_values(command, values): ''' Substitute the template strings in the @values dict into the list of strings @command and return a new list. For a full list of the templates, see get_filenames_templates_dict() If multiple inputs/outputs are given in the @values dictionary, we substitute @INPUT@ and @OUTPUT@ only if they are the entire string, not just a part of it, and in that case we substitute *all* of them. ''' # Error checking _substitute_values_check_errors(command, values) # Substitution outcmd = [] for vv in command: if not isinstance(vv, str): outcmd.append(vv) elif '@INPUT@' in vv: inputs = values['@INPUT@'] if vv == '@INPUT@': outcmd += inputs elif len(inputs) == 1: outcmd.append(vv.replace('@INPUT@', inputs[0])) else: raise MesonException("Command has '@INPUT@' as part of a " "string and more than one input file") elif '@OUTPUT@' in vv: outputs = values['@OUTPUT@'] if vv == '@OUTPUT@': outcmd += outputs elif len(outputs) == 1: outcmd.append(vv.replace('@OUTPUT@', outputs[0])) else: raise MesonException("Command has '@OUTPUT@' as part of a " "string and more than one output file") # Append values that are exactly a template string. # This is faster than a string replace. elif vv in values: outcmd.append(values[vv]) # Substitute everything else with replacement else: for key, value in values.items(): if key in ('@INPUT@', '@OUTPUT@'): # Already done above continue vv = vv.replace(key, value) outcmd.append(vv) return outcmd def get_filenames_templates_dict(inputs, outputs): ''' Create a dictionary with template strings as keys and values as values for the following templates: @INPUT@ - the full path to one or more input files, from @inputs @OUTPUT@ - the full path to one or more output files, from @outputs @OUTDIR@ - the full path to the directory containing the output files If there is only one input file, the following keys are also created: @PLAINNAME@ - the filename of the input file @BASENAME@ - the filename of the input file with the extension removed If there is more than one input file, the following keys are also created: @INPUT0@, @INPUT1@, ... one for each input file If there is more than one output file, the following keys are also created: @OUTPUT0@, @OUTPUT1@, ... one for each output file ''' values = {} # Gather values derived from the input if inputs: # We want to substitute all the inputs. values['@INPUT@'] = inputs for (ii, vv) in enumerate(inputs): # Write out @INPUT0@, @INPUT1@, ... values['@INPUT{}@'.format(ii)] = vv if len(inputs) == 1: # Just one value, substitute @PLAINNAME@ and @BASENAME@ values['@PLAINNAME@'] = plain = os.path.split(inputs[0])[1] values['@BASENAME@'] = os.path.splitext(plain)[0] if outputs: # Gather values derived from the outputs, similar to above. values['@OUTPUT@'] = outputs for (ii, vv) in enumerate(outputs): values['@OUTPUT{}@'.format(ii)] = vv # Outdir should be the same for all outputs values['@OUTDIR@'] = os.path.split(outputs[0])[0] # Many external programs fail on empty arguments. if values['@OUTDIR@'] == '': values['@OUTDIR@'] = '.' return values class OrderedSet(collections.MutableSet): """A set that preserves the order in which items are added, by first insertion. """ def __init__(self, iterable=None): self.__container = collections.OrderedDict() if iterable: self.update(iterable) def __contains__(self, value): return value in self.__container def __iter__(self): return iter(self.__container.keys()) def __len__(self): return len(self.__container) def __repr__(self): # Don't print 'OrderedSet("")' for an empty set. if self.__container: return 'OrderedSet("{}")'.format('", "'.join(self.__container.keys())) return 'OrderedSet()' def add(self, value): self.__container[value] = None def discard(self, value): if value in self.__container: del self.__container[value] def update(self, iterable): for item in iterable: self.__container[item] = None meson-0.40.1/mesonbuild/mesonmain.py0000644000175000017500000003207013076164167021025 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys, stat, traceback, pickle, argparse import time, datetime import os.path from . import environment, interpreter, mesonlib from . import build import platform from . import mlog, coredata from .mesonlib import MesonException from .wrap import WrapMode parser = argparse.ArgumentParser() default_warning = '1' def add_builtin_argument(name, **kwargs): k = kwargs.get('dest', name.replace('-', '_')) c = coredata.get_builtin_option_choices(k) b = True if kwargs.get('action', None) in ['store_true', 'store_false'] else False h = coredata.get_builtin_option_description(k) if not b: h = h.rstrip('.') + ' (default: %s).' % coredata.get_builtin_option_default(k) if c and not b: kwargs['choices'] = c parser.add_argument('--' + name, default=coredata.get_builtin_option_default(k), help=h, **kwargs) add_builtin_argument('prefix') add_builtin_argument('libdir') add_builtin_argument('libexecdir') add_builtin_argument('bindir') add_builtin_argument('sbindir') add_builtin_argument('includedir') add_builtin_argument('datadir') add_builtin_argument('mandir') add_builtin_argument('infodir') add_builtin_argument('localedir') add_builtin_argument('sysconfdir') add_builtin_argument('localstatedir') add_builtin_argument('sharedstatedir') add_builtin_argument('backend') add_builtin_argument('buildtype') add_builtin_argument('strip', action='store_true') add_builtin_argument('unity') add_builtin_argument('werror', action='store_true') add_builtin_argument('layout') add_builtin_argument('default-library') add_builtin_argument('warnlevel', dest='warning_level') add_builtin_argument('stdsplit', action='store_false') add_builtin_argument('errorlogs', action='store_false') parser.add_argument('--cross-file', default=None, help='File describing cross compilation environment.') parser.add_argument('-D', action='append', dest='projectoptions', default=[], help='Set project options.') parser.add_argument('-v', '--version', action='version', version=coredata.version) # See the mesonlib.WrapMode enum for documentation parser.add_argument('--wrap-mode', default=WrapMode.default, type=lambda t: getattr(WrapMode, t), choices=WrapMode, help='Special wrap mode to use') parser.add_argument('directories', nargs='*') class MesonApp: def __init__(self, dir1, dir2, script_launcher, handshake, options, original_cmd_line_args): (self.source_dir, self.build_dir) = self.validate_dirs(dir1, dir2, handshake) self.meson_script_launcher = script_launcher self.options = options self.original_cmd_line_args = original_cmd_line_args def has_build_file(self, dirname): fname = os.path.join(dirname, environment.build_filename) return os.path.exists(fname) 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): raise RuntimeError('%s is not a directory' % dir2) if os.path.samefile(dir1, dir2): raise RuntimeError('Source and build directories must not be the same. Create a pristine build directory.') if self.has_build_file(ndir1): if self.has_build_file(ndir2): raise RuntimeError('Both directories contain a build file %s.' % environment.build_filename) return ndir1, ndir2 if self.has_build_file(ndir2): return ndir2, ndir1 raise RuntimeError('Neither directory contains a build file %s.' % environment.build_filename) def validate_dirs(self, dir1, dir2, handshake): (src_dir, build_dir) = self.validate_core_dirs(dir1, dir2) priv_dir = os.path.join(build_dir, 'meson-private/coredata.dat') if os.path.exists(priv_dir): if not handshake: msg = '''Trying to run Meson on a build directory that has already been configured. If you want to build it, just run your build command (e.g. ninja) inside the build directory. Meson will autodetect any changes in your setup and regenerate itself as required. If you want to change option values, use the mesonconf tool instead.''' raise RuntimeError(msg) else: if handshake: raise RuntimeError('Something went terribly wrong. Please file a bug.') return src_dir, build_dir def check_pkgconfig_envvar(self, env): curvar = os.environ.get('PKG_CONFIG_PATH', '') if curvar != env.coredata.pkgconf_envvar: mlog.warning('PKG_CONFIG_PATH has changed between invocations from "%s" to "%s".' % (env.coredata.pkgconf_envvar, curvar)) env.coredata.pkgconf_envvar = curvar def generate(self): env = environment.Environment(self.source_dir, self.build_dir, self.meson_script_launcher, self.options, self.original_cmd_line_args) mlog.initialize(env.get_log_dir()) mlog.debug('Build started at', datetime.datetime.now().isoformat()) mlog.debug('Python binary:', sys.executable) mlog.debug('Python system:', platform.system()) mlog.log(mlog.bold('The Meson build system')) self.check_pkgconfig_envvar(env) mlog.log('Version:', coredata.version) mlog.log('Source dir:', mlog.bold(self.source_dir)) mlog.log('Build dir:', mlog.bold(self.build_dir)) if env.is_cross_build(): mlog.log('Build type:', mlog.bold('cross build')) else: mlog.log('Build type:', mlog.bold('native build')) b = build.Build(env) if self.options.backend == 'ninja': from .backend import ninjabackend g = ninjabackend.NinjaBackend(b) elif self.options.backend == 'vs': from .backend import vs2010backend g = vs2010backend.autodetect_vs_version(b) mlog.log('Auto detected Visual Studio backend:', mlog.bold(g.name)) elif self.options.backend == 'vs2010': from .backend import vs2010backend g = vs2010backend.Vs2010Backend(b) elif self.options.backend == 'vs2015': from .backend import vs2015backend g = vs2015backend.Vs2015Backend(b) elif self.options.backend == 'vs2017': from .backend import vs2017backend g = vs2017backend.Vs2017Backend(b) elif self.options.backend == 'xcode': from .backend import xcodebackend g = xcodebackend.XCodeBackend(b) else: raise RuntimeError('Unknown backend "%s".' % self.options.backend) intr = interpreter.Interpreter(b, g) if env.is_cross_build(): mlog.log('Host machine cpu family:', mlog.bold(intr.builtin['host_machine'].cpu_family_method([], {}))) mlog.log('Host machine cpu:', mlog.bold(intr.builtin['host_machine'].cpu_method([], {}))) mlog.log('Target machine cpu family:', mlog.bold(intr.builtin['target_machine'].cpu_family_method([], {}))) mlog.log('Target machine cpu:', mlog.bold(intr.builtin['target_machine'].cpu_method([], {}))) mlog.log('Build machine cpu family:', mlog.bold(intr.builtin['build_machine'].cpu_family_method([], {}))) mlog.log('Build machine cpu:', mlog.bold(intr.builtin['build_machine'].cpu_method([], {}))) intr.run() coredata_mtime = time.time() g.generate(intr) g.run_postconf_scripts() dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat') with open(dumpfile, 'wb') as f: pickle.dump(b, f) # Write this last since we use the existence of this file to check if # we generated the build file successfully, so we don't want an error # that pops up during generation, post-conf scripts, etc to cause us to # incorrectly signal a successful meson run which will cause an error # about an already-configured build directory when the user tries again. # # However, we set the mtime to an earlier value to ensure that doing an # mtime comparison between the coredata dump and other build files # shows the build files to be newer, not older. env.dump_coredata(coredata_mtime) def run_script_command(args): cmdname = args[0] cmdargs = args[1:] if cmdname == 'exe': import mesonbuild.scripts.meson_exe as abc cmdfunc = abc.run elif cmdname == 'cleantrees': import mesonbuild.scripts.cleantrees as abc cmdfunc = abc.run elif cmdname == 'install': import mesonbuild.scripts.meson_install as abc cmdfunc = abc.run elif cmdname == 'commandrunner': import mesonbuild.scripts.commandrunner as abc cmdfunc = abc.run elif cmdname == 'delsuffix': import mesonbuild.scripts.delwithsuffix as abc cmdfunc = abc.run elif cmdname == 'depfixer': import mesonbuild.scripts.depfixer as abc cmdfunc = abc.run elif cmdname == 'dirchanger': import mesonbuild.scripts.dirchanger as abc cmdfunc = abc.run elif cmdname == 'gtkdoc': import mesonbuild.scripts.gtkdochelper as abc cmdfunc = abc.run elif cmdname == 'regencheck': import mesonbuild.scripts.regen_checker as abc cmdfunc = abc.run elif cmdname == 'symbolextractor': import mesonbuild.scripts.symbolextractor as abc cmdfunc = abc.run elif cmdname == 'scanbuild': import mesonbuild.scripts.scanbuild as abc cmdfunc = abc.run elif cmdname == 'vcstagger': import mesonbuild.scripts.vcstagger as abc cmdfunc = abc.run elif cmdname == 'gettext': import mesonbuild.scripts.gettext as abc cmdfunc = abc.run elif cmdname == 'yelphelper': import mesonbuild.scripts.yelphelper as abc cmdfunc = abc.run elif cmdname == 'uninstall': import mesonbuild.scripts.uninstall as abc cmdfunc = abc.run else: raise MesonException('Unknown internal command {}.'.format(cmdname)) return cmdfunc(cmdargs) def run(mainfile, args): if sys.version_info < (3, 3): print('Meson works correctly only with python 3.3+.') print('You have python %s.' % sys.version) print('Please update your environment') return 1 if len(args) >= 2 and args[0] == '--internal': if args[1] != 'regenerate': script = args[1] try: sys.exit(run_script_command(args[1:])) except MesonException as e: mlog.log(mlog.red('\nError in {} helper script:'.format(script))) mlog.log(e) sys.exit(1) args = args[2:] handshake = True else: handshake = False args = mesonlib.expand_arguments(args) options = parser.parse_args(args) args = options.directories if len(args) == 0 or len(args) > 2: # if there's a meson.build in the dir above, and not in the current # directory, assume we're in the build directory if len(args) == 0 and not os.path.exists('meson.build') and os.path.exists('../meson.build'): dir1 = '..' dir2 = '.' else: print('{} '.format(sys.argv[0])) print('If you omit either directory, the current directory is substituted.') print('Run {} --help for more information.'.format(sys.argv[0])) return 1 else: dir1 = args[0] if len(args) > 1: dir2 = args[1] else: dir2 = '.' try: app = MesonApp(dir1, dir2, mainfile, handshake, options, sys.argv) except Exception as e: # Log directory does not exist, so just print # to stdout. print('Error during basic setup:\n') print(e) return 1 try: app.generate() except Exception as e: if isinstance(e, MesonException): if hasattr(e, 'file') and hasattr(e, 'lineno') and hasattr(e, 'colno'): mlog.log(mlog.red('\nMeson encountered an error in file %s, line %d, column %d:' % (e.file, e.lineno, e.colno))) else: mlog.log(mlog.red('\nMeson encountered an error:')) mlog.log(e) else: traceback.print_exc() return 1 return 0 meson-0.40.1/mesonbuild/astinterpreter.py0000644000175000017500000002411313040633773022104 0ustar jpakkanejpakkane00000000000000# Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. from . import interpreterbase, mlog, mparser, mesonlib from . import environment from .interpreterbase import InterpreterException, InvalidArguments import os, sys class DontCareObject(interpreterbase.InterpreterObject): pass class MockExecutable(interpreterbase.InterpreterObject): pass class MockStaticLibrary(interpreterbase.InterpreterObject): pass class MockSharedLibrary(interpreterbase.InterpreterObject): pass class MockCustomTarget(interpreterbase.InterpreterObject): pass class MockRunTarget(interpreterbase.InterpreterObject): pass ADD_SOURCE = 0 REMOVE_SOURCE = 1 class AstInterpreter(interpreterbase.InterpreterBase): def __init__(self, source_root, subdir): super().__init__(source_root, subdir) self.asts = {} self.funcs.update({'project': self.func_do_nothing, 'test': self.func_do_nothing, 'benchmark': self.func_do_nothing, 'install_headers': self.func_do_nothing, 'install_man': self.func_do_nothing, 'install_data': self.func_do_nothing, 'install_subdir': self.func_do_nothing, 'configuration_data': self.func_do_nothing, 'configure_file': self.func_do_nothing, 'find_program': self.func_do_nothing, 'include_directories': self.func_do_nothing, 'add_global_arguments': self.func_do_nothing, 'add_global_link_arguments': self.func_do_nothing, 'add_project_arguments': self.func_do_nothing, 'add_project_link_arguments': self.func_do_nothing, 'message': self.func_do_nothing, 'generator': self.func_do_nothing, 'error': self.func_do_nothing, 'run_command': self.func_do_nothing, 'assert': self.func_do_nothing, 'subproject': self.func_do_nothing, 'dependency': self.func_do_nothing, 'get_option': self.func_do_nothing, 'join_paths': self.func_do_nothing, 'environment': self.func_do_nothing, 'import': self.func_do_nothing, 'vcs_tag': self.func_do_nothing, 'add_languages': self.func_do_nothing, 'declare_dependency': self.func_do_nothing, 'files': self.func_files, 'executable': self.func_executable, 'static_library': self.func_static_lib, 'shared_library': self.func_shared_lib, 'library': self.func_library, 'build_target': self.func_build_target, 'custom_target': self.func_custom_target, 'run_target': self.func_run_target, 'subdir': self.func_subdir, 'set_variable': self.func_set_variable, 'get_variable': self.func_get_variable, 'is_variable': self.func_is_variable, }) def func_do_nothing(self, node, args, kwargs): return True def method_call(self, node): return True def func_executable(self, node, args, kwargs): if args[0] == self.targetname: if self.operation == ADD_SOURCE: self.add_source_to_target(node, args, kwargs) elif self.operation == REMOVE_SOURCE: self.remove_source_from_target(node, args, kwargs) else: raise NotImplementedError('Bleep bloop') return MockExecutable() def func_static_lib(self, node, args, kwargs): return MockStaticLibrary() def func_shared_lib(self, node, args, kwargs): return MockSharedLibrary() def func_library(self, node, args, kwargs): return self.func_shared_lib(node, args, kwargs) def func_custom_target(self, node, args, kwargs): return MockCustomTarget() def func_run_target(self, node, args, kwargs): return MockRunTarget() def func_subdir(self, node, args, kwargs): prev_subdir = self.subdir subdir = os.path.join(prev_subdir, args[0]) self.subdir = subdir buildfilename = os.path.join(self.subdir, environment.build_filename) absname = os.path.join(self.source_root, buildfilename) if not os.path.isfile(absname): self.subdir = prev_subdir raise InterpreterException('Nonexistent build def file %s.' % buildfilename) with open(absname, encoding='utf8') as f: code = f.read() assert(isinstance(code, str)) try: codeblock = mparser.Parser(code, self.subdir).parse() self.asts[subdir] = codeblock except mesonlib.MesonException as me: me.file = buildfilename raise me self.evaluate_codeblock(codeblock) self.subdir = prev_subdir def func_files(self, node, args, kwargs): if not isinstance(args, list): return [args] return args def evaluate_arithmeticstatement(self, cur): return 0 def evaluate_plusassign(self, node): return 0 def evaluate_indexing(self, node): return 0 def reduce_arguments(self, args): assert(isinstance(args, mparser.ArgumentNode)) if args.incorrect_order(): raise InvalidArguments('All keyword arguments must be after positional arguments.') return args.arguments, args.kwargs def transform(self): self.load_root_meson_file() self.asts[''] = self.ast self.sanity_check_ast() self.parse_project() self.run() def add_source(self, targetname, filename): self.operation = ADD_SOURCE self.targetname = targetname self.filename = filename self.transform() def remove_source(self, targetname, filename): self.operation = REMOVE_SOURCE self.targetname = targetname self.filename = filename self.transform() def unknown_function_called(self, func_name): mlog.warning('Unknown function called: ' + func_name) def add_source_to_target(self, node, args, kwargs): namespan = node.args.arguments[0].bytespan buildfilename = os.path.join(self.source_root, self.subdir, environment.build_filename) raw_data = open(buildfilename, 'r').read() updated = raw_data[0:namespan[1]] + (", '%s'" % self.filename) + raw_data[namespan[1]:] open(buildfilename, 'w').write(updated) sys.exit(0) def remove_argument_item(self, args, i): assert(isinstance(args, mparser.ArgumentNode)) namespan = args.arguments[i].bytespan # Usually remove the comma after this item but if it is # the last argument, we need to remove the one before. if i >= len(args.commas): i -= 1 if i < 0: commaspan = (0, 0) # Removed every entry in the list. else: commaspan = args.commas[i].bytespan if commaspan[0] < namespan[0]: commaspan, namespan = namespan, commaspan buildfilename = os.path.join(self.source_root, args.subdir, environment.build_filename) raw_data = open(buildfilename, 'r').read() intermediary = raw_data[0:commaspan[0]] + raw_data[commaspan[1]:] updated = intermediary[0:namespan[0]] + intermediary[namespan[1]:] open(buildfilename, 'w').write(updated) sys.exit(0) def hacky_find_and_remove(self, node_to_remove): for a in self.asts[node_to_remove.subdir].lines: if a.lineno == node_to_remove.lineno: if isinstance(a, mparser.AssignmentNode): v = a.value if not isinstance(v, mparser.ArrayNode): raise NotImplementedError('Not supported yet, bro.') args = v.args for i in range(len(args.arguments)): if isinstance(args.arguments[i], mparser.StringNode) and self.filename == args.arguments[i].value: self.remove_argument_item(args, i) raise NotImplementedError('Sukkess') def remove_source_from_target(self, node, args, kwargs): for i in range(1, len(node.args)): # Is file name directly in function call as a string. if isinstance(node.args.arguments[i], mparser.StringNode) and self.filename == node.args.arguments[i].value: self.remove_argument_item(node.args, i) # Is file name in a variable that gets expanded here. if isinstance(node.args.arguments[i], mparser.IdNode): avar = self.get_variable(node.args.arguments[i].value) if not isinstance(avar, list): raise NotImplementedError('Non-arrays not supported yet, sorry.') for entry in avar: if isinstance(entry, mparser.StringNode) and entry.value == self.filename: self.hacky_find_and_remove(entry) sys.exit('Could not find source %s in target %s.' % (self.filename, args[0])) meson-0.40.1/mesonbuild/interpreterbase.py0000644000175000017500000006436713046167604022247 0ustar jpakkanejpakkane00000000000000# Copyright 2016-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool. from . import mparser, mesonlib, mlog from . import environment, dependencies import os, copy, re from functools import wraps # Decorators for method calls. def check_stringlist(a, msg='Arguments must be strings.'): if not isinstance(a, list): mlog.debug('Not a list:', str(a)) raise InvalidArguments('Argument not a list.') if not all(isinstance(s, str) for s in a): mlog.debug('Element not a string:', str(a)) raise InvalidArguments(msg) def noPosargs(f): @wraps(f) def wrapped(self, node, args, kwargs): if len(args) != 0: raise InvalidArguments('Function does not take positional arguments.') return f(self, node, args, kwargs) return wrapped def noKwargs(f): @wraps(f) def wrapped(self, node, args, kwargs): if len(kwargs) != 0: raise InvalidArguments('Function does not take keyword arguments.') return f(self, node, args, kwargs) return wrapped def stringArgs(f): @wraps(f) def wrapped(self, node, args, kwargs): assert(isinstance(args, list)) check_stringlist(args) return f(self, node, args, kwargs) return wrapped class InterpreterException(mesonlib.MesonException): pass class InvalidCode(InterpreterException): pass class InvalidArguments(InterpreterException): pass class InterpreterObject: def __init__(self): self.methods = {} def method_call(self, method_name, args, kwargs): if method_name in self.methods: return self.methods[method_name](args, kwargs) raise InvalidCode('Unknown method "%s" in object.' % method_name) class MutableInterpreterObject(InterpreterObject): def __init__(self): super().__init__() class InterpreterBase: def __init__(self, source_root, subdir): self.source_root = source_root self.funcs = {} self.builtin = {} self.subdir = subdir self.variables = {} self.argument_depth = 0 def load_root_meson_file(self): mesonfile = os.path.join(self.source_root, self.subdir, environment.build_filename) if not os.path.isfile(mesonfile): raise InvalidArguments('Missing Meson file in %s' % mesonfile) with open(mesonfile, encoding='utf8') as mf: code = mf.read() if len(code.strip()) == 0: raise InvalidCode('Builder file is empty.') assert(isinstance(code, str)) try: self.ast = mparser.Parser(code, self.subdir).parse() except mesonlib.MesonException as me: me.file = environment.build_filename raise me def parse_project(self): """ Parses project() and initializes languages, compilers etc. Do this early because we need this before we parse the rest of the AST. """ self.evaluate_codeblock(self.ast, end=1) def sanity_check_ast(self): if not isinstance(self.ast, mparser.CodeBlockNode): raise InvalidCode('AST is of invalid type. Possibly a bug in the parser.') if len(self.ast.lines) == 0: raise InvalidCode('No statements in code.') first = self.ast.lines[0] if not isinstance(first, mparser.FunctionNode) or first.func_name != 'project': raise InvalidCode('First statement must be a call to project') def run(self): # Evaluate everything after the first line, which is project() because # we already parsed that in self.parse_project() self.evaluate_codeblock(self.ast, start=1) def evaluate_codeblock(self, node, start=0, end=None): if node is None: return if not isinstance(node, mparser.CodeBlockNode): e = InvalidCode('Tried to execute a non-codeblock. Possibly a bug in the parser.') e.lineno = node.lineno e.colno = node.colno raise e statements = node.lines[start:end] i = 0 while i < len(statements): cur = statements[i] try: self.evaluate_statement(cur) except Exception as e: if not(hasattr(e, 'lineno')): e.lineno = cur.lineno e.colno = cur.colno e.file = os.path.join(self.subdir, 'meson.build') raise e i += 1 # In THE FUTURE jump over blocks and stuff. def evaluate_statement(self, cur): if isinstance(cur, mparser.FunctionNode): return self.function_call(cur) elif isinstance(cur, mparser.AssignmentNode): return self.assignment(cur) elif isinstance(cur, mparser.MethodNode): return self.method_call(cur) elif isinstance(cur, mparser.StringNode): return cur.value elif isinstance(cur, mparser.BooleanNode): return cur.value elif isinstance(cur, mparser.IfClauseNode): return self.evaluate_if(cur) elif isinstance(cur, mparser.IdNode): return self.get_variable(cur.value) elif isinstance(cur, mparser.ComparisonNode): return self.evaluate_comparison(cur) elif isinstance(cur, mparser.ArrayNode): return self.evaluate_arraystatement(cur) elif isinstance(cur, mparser.NumberNode): return cur.value elif isinstance(cur, mparser.AndNode): return self.evaluate_andstatement(cur) elif isinstance(cur, mparser.OrNode): return self.evaluate_orstatement(cur) elif isinstance(cur, mparser.NotNode): return self.evaluate_notstatement(cur) elif isinstance(cur, mparser.UMinusNode): return self.evaluate_uminusstatement(cur) elif isinstance(cur, mparser.ArithmeticNode): return self.evaluate_arithmeticstatement(cur) elif isinstance(cur, mparser.ForeachClauseNode): return self.evaluate_foreach(cur) elif isinstance(cur, mparser.PlusAssignmentNode): return self.evaluate_plusassign(cur) elif isinstance(cur, mparser.IndexNode): return self.evaluate_indexing(cur) elif isinstance(cur, mparser.TernaryNode): return self.evaluate_ternary(cur) elif self.is_elementary_type(cur): return cur else: raise InvalidCode("Unknown statement.") def evaluate_arraystatement(self, cur): (arguments, kwargs) = self.reduce_arguments(cur.args) if len(kwargs) > 0: raise InvalidCode('Keyword arguments are invalid in array construction.') return arguments def evaluate_notstatement(self, cur): v = self.evaluate_statement(cur.value) if isinstance(v, mparser.BooleanNode): v = v.value if not isinstance(v, bool): raise InterpreterException('Argument to "not" is not a boolean.') return not v def evaluate_if(self, node): assert(isinstance(node, mparser.IfClauseNode)) for i in node.ifs: result = self.evaluate_statement(i.condition) if not(isinstance(result, bool)): raise InvalidCode('If clause {!r} does not evaluate to true or false.'.format(result)) if result: self.evaluate_codeblock(i.block) return if not isinstance(node.elseblock, mparser.EmptyNode): self.evaluate_codeblock(node.elseblock) def evaluate_comparison(self, node): v1 = self.evaluate_statement(node.left) v2 = self.evaluate_statement(node.right) if self.is_elementary_type(v1): val1 = v1 else: val1 = v1.value if self.is_elementary_type(v2): val2 = v2 else: val2 = v2.value if node.ctype == '==': return val1 == val2 elif node.ctype == '!=': return val1 != val2 elif node.ctype == '<': return val1 < val2 elif node.ctype == '<=': return val1 <= val2 elif node.ctype == '>': return val1 > val2 elif node.ctype == '>=': return val1 >= val2 else: raise InvalidCode('You broke my compare eval.') def evaluate_andstatement(self, cur): l = self.evaluate_statement(cur.left) if isinstance(l, mparser.BooleanNode): l = l.value if not isinstance(l, bool): raise InterpreterException('First argument to "and" is not a boolean.') if not l: return False r = self.evaluate_statement(cur.right) if isinstance(r, mparser.BooleanNode): r = r.value if not isinstance(r, bool): raise InterpreterException('Second argument to "and" is not a boolean.') return r def evaluate_orstatement(self, cur): l = self.evaluate_statement(cur.left) if isinstance(l, mparser.BooleanNode): l = l.get_value() if not isinstance(l, bool): raise InterpreterException('First argument to "or" is not a boolean.') if l: return True r = self.evaluate_statement(cur.right) if isinstance(r, mparser.BooleanNode): r = r.get_value() if not isinstance(r, bool): raise InterpreterException('Second argument to "or" is not a boolean.') return r def evaluate_uminusstatement(self, cur): v = self.evaluate_statement(cur.value) if isinstance(v, mparser.NumberNode): v = v.value if not isinstance(v, int): raise InterpreterException('Argument to negation is not an integer.') return -v def evaluate_arithmeticstatement(self, cur): l = self.to_native(self.evaluate_statement(cur.left)) r = self.to_native(self.evaluate_statement(cur.right)) if cur.operation == 'add': try: return l + r except Exception as e: raise InvalidCode('Invalid use of addition: ' + str(e)) elif cur.operation == 'sub': if not isinstance(l, int) or not isinstance(r, int): raise InvalidCode('Subtraction works only with integers.') return l - r elif cur.operation == 'mul': if not isinstance(l, int) or not isinstance(r, int): raise InvalidCode('Multiplication works only with integers.') return l * r elif cur.operation == 'div': if not isinstance(l, int) or not isinstance(r, int): raise InvalidCode('Division works only with integers.') return l // r elif cur.operation == 'mod': if not isinstance(l, int) or not isinstance(r, int): raise InvalidCode('Modulo works only with integers.') return l % r else: raise InvalidCode('You broke me.') def evaluate_ternary(self, node): assert(isinstance(node, mparser.TernaryNode)) result = self.evaluate_statement(node.condition) if not isinstance(result, bool): raise InterpreterException('Ternary condition is not boolean.') if result: return self.evaluate_statement(node.trueblock) else: return self.evaluate_statement(node.falseblock) def evaluate_foreach(self, node): assert(isinstance(node, mparser.ForeachClauseNode)) varname = node.varname.value items = self.evaluate_statement(node.items) if not isinstance(items, list): raise InvalidArguments('Items of foreach loop is not an array') for item in items: self.set_variable(varname, item) self.evaluate_codeblock(node.block) def evaluate_plusassign(self, node): assert(isinstance(node, mparser.PlusAssignmentNode)) varname = node.var_name addition = self.evaluate_statement(node.value) # Remember that all variables are immutable. We must always create a # full new variable and then assign it. old_variable = self.get_variable(varname) if isinstance(old_variable, str): if not isinstance(addition, str): raise InvalidArguments('The += operator requires a string on the right hand side if the variable on the left is a string') new_value = old_variable + addition elif isinstance(old_variable, int): if not isinstance(addition, int): raise InvalidArguments('The += operator requires an int on the right hand side if the variable on the left is an int') new_value = old_variable + addition elif not isinstance(old_variable, list): raise InvalidArguments('The += operator currently only works with arrays, strings or ints ') # Add other data types here. else: if isinstance(addition, list): new_value = old_variable + addition else: new_value = old_variable + [addition] self.set_variable(varname, new_value) def evaluate_indexing(self, node): assert(isinstance(node, mparser.IndexNode)) iobject = self.evaluate_statement(node.iobject) if not isinstance(iobject, list): raise InterpreterException('Tried to index a non-array object.') index = self.evaluate_statement(node.index) if not isinstance(index, int): raise InterpreterException('Index value is not an integer.') if index < -len(iobject) or index >= len(iobject): raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject))) return iobject[index] def function_call(self, node): func_name = node.func_name (posargs, kwargs) = self.reduce_arguments(node.args) if func_name in self.funcs: return self.funcs[func_name](node, self.flatten(posargs), kwargs) else: self.unknown_function_called(func_name) def method_call(self, node): invokable = node.source_object if isinstance(invokable, mparser.IdNode): object_name = invokable.value obj = self.get_variable(object_name) else: obj = self.evaluate_statement(invokable) method_name = node.name args = node.args if isinstance(obj, mparser.StringNode): obj = obj.get_value() if isinstance(obj, str): return self.string_method_call(obj, method_name, args) if isinstance(obj, bool): return self.bool_method_call(obj, method_name, args) if isinstance(obj, int): return self.int_method_call(obj, method_name, args) if isinstance(obj, list): return self.array_method_call(obj, method_name, self.reduce_arguments(args)[0]) if isinstance(obj, mesonlib.File): raise InvalidArguments('File object "%s" is not callable.' % obj) if not isinstance(obj, InterpreterObject): raise InvalidArguments('Variable "%s" is not callable.' % object_name) (args, kwargs) = self.reduce_arguments(args) if method_name == 'extract_objects': self.validate_extraction(obj.held_object) return obj.method_call(method_name, self.flatten(args), kwargs) def bool_method_call(self, obj, method_name, args): obj = self.to_native(obj) (posargs, _) = self.reduce_arguments(args) if method_name == 'to_string': if len(posargs) == 0: if obj: return 'true' else: return 'false' elif len(posargs) == 2 and isinstance(posargs[0], str) and isinstance(posargs[1], str): if obj: return posargs[0] else: return posargs[1] else: raise InterpreterException('bool.to_string() must have either no arguments or exactly two string arguments that signify what values to return for true and false.') elif method_name == 'to_int': if obj: return 1 else: return 0 else: raise InterpreterException('Unknown method "%s" for a boolean.' % method_name) def int_method_call(self, obj, method_name, args): obj = self.to_native(obj) (posargs, _) = self.reduce_arguments(args) if method_name == 'is_even': if len(posargs) == 0: return obj % 2 == 0 else: raise InterpreterException('int.is_even() must have no arguments.') elif method_name == 'is_odd': if len(posargs) == 0: return obj % 2 != 0 else: raise InterpreterException('int.is_odd() must have no arguments.') else: raise InterpreterException('Unknown method "%s" for an integer.' % method_name) def string_method_call(self, obj, method_name, args): obj = self.to_native(obj) (posargs, _) = self.reduce_arguments(args) if method_name == 'strip': return obj.strip() elif method_name == 'format': return self.format_string(obj, args) elif method_name == 'to_upper': return obj.upper() elif method_name == 'to_lower': return obj.lower() elif method_name == 'underscorify': return re.sub(r'[^a-zA-Z0-9]', '_', obj) elif method_name == 'split': if len(posargs) > 1: raise InterpreterException('Split() must have at most one argument.') elif len(posargs) == 1: s = posargs[0] if not isinstance(s, str): raise InterpreterException('Split() argument must be a string') return obj.split(s) else: return obj.split() elif method_name == 'startswith' or method_name == 'contains' or method_name == 'endswith': s = posargs[0] if not isinstance(s, str): raise InterpreterException('Argument must be a string.') if method_name == 'startswith': return obj.startswith(s) elif method_name == 'contains': return obj.find(s) >= 0 return obj.endswith(s) elif method_name == 'to_int': try: return int(obj) except Exception: raise InterpreterException('String {!r} cannot be converted to int'.format(obj)) elif method_name == 'join': if len(posargs) != 1: raise InterpreterException('Join() takes exactly one argument.') strlist = posargs[0] check_stringlist(strlist) return obj.join(strlist) elif method_name == 'version_compare': if len(posargs) != 1: raise InterpreterException('Version_compare() takes exactly one argument.') cmpr = posargs[0] if not isinstance(cmpr, str): raise InterpreterException('Version_compare() argument must be a string.') return mesonlib.version_compare(obj, cmpr) raise InterpreterException('Unknown method "%s" for a string.' % method_name) def unknown_function_called(self, func_name): raise InvalidCode('Unknown function "%s".' % func_name) def array_method_call(self, obj, method_name, args): if method_name == 'contains': return self.check_contains(obj, args) elif method_name == 'length': return len(obj) elif method_name == 'get': index = args[0] fallback = None if len(args) == 2: fallback = args[1] elif len(args) > 2: m = 'Array method \'get()\' only takes two arguments: the ' \ 'index and an optional fallback value if the index is ' \ 'out of range.' raise InvalidArguments(m) if not isinstance(index, int): raise InvalidArguments('Array index must be a number.') if index < -len(obj) or index >= len(obj): if fallback is None: m = 'Array index {!r} is out of bounds for array of size {!r}.' raise InvalidArguments(m.format(index, len(obj))) return fallback return obj[index] m = 'Arrays do not have a method called {!r}.' raise InterpreterException(m.format(method_name)) def reduce_arguments(self, args): assert(isinstance(args, mparser.ArgumentNode)) if args.incorrect_order(): raise InvalidArguments('All keyword arguments must be after positional arguments.') self.argument_depth += 1 reduced_pos = [self.evaluate_statement(arg) for arg in args.arguments] reduced_kw = {} for key in args.kwargs.keys(): if not isinstance(key, str): raise InvalidArguments('Keyword argument name is not a string.') a = args.kwargs[key] reduced_kw[key] = self.evaluate_statement(a) if not isinstance(reduced_pos, list): reduced_pos = [reduced_pos] self.argument_depth -= 1 return reduced_pos, reduced_kw def flatten(self, args): if isinstance(args, mparser.StringNode): return args.value if isinstance(args, (int, str, mesonlib.File, InterpreterObject)): return args result = [] for a in args: if isinstance(a, list): rest = self.flatten(a) result = result + rest elif isinstance(a, mparser.StringNode): result.append(a.value) else: result.append(a) return result def assignment(self, node): assert(isinstance(node, mparser.AssignmentNode)) if self.argument_depth != 0: raise InvalidArguments('''Tried to assign values inside an argument list. To specify a keyword argument, use : instead of =.''') var_name = node.var_name if not isinstance(var_name, str): raise InvalidArguments('Tried to assign value to a non-variable.') value = self.evaluate_statement(node.value) value = self.to_native(value) if not self.is_assignable(value): raise InvalidCode('Tried to assign an invalid value to variable.') # For mutable objects we need to make a copy on assignment if isinstance(value, MutableInterpreterObject): value = copy.deepcopy(value) self.set_variable(var_name, value) return None def set_variable(self, varname, variable): if variable is None: raise InvalidCode('Can not assign None to variable.') if not isinstance(varname, str): raise InvalidCode('First argument to set_variable must be a string.') if not self.is_assignable(variable): raise InvalidCode('Assigned value not of assignable type.') if re.match('[_a-zA-Z][_0-9a-zA-Z]*$', varname) is None: raise InvalidCode('Invalid variable name: ' + varname) if varname in self.builtin: raise InvalidCode('Tried to overwrite internal variable "%s"' % varname) self.variables[varname] = variable def get_variable(self, varname): if varname in self.builtin: return self.builtin[varname] if varname in self.variables: return self.variables[varname] raise InvalidCode('Unknown variable "%s".' % varname) def to_native(self, arg): if isinstance(arg, (mparser.StringNode, mparser.NumberNode, mparser.BooleanNode)): return arg.value return arg def is_assignable(self, value): return isinstance(value, (InterpreterObject, dependencies.Dependency, str, int, list, mesonlib.File)) def func_build_target(self, node, args, kwargs): if 'target_type' not in kwargs: raise InterpreterException('Missing target_type keyword argument') target_type = kwargs.pop('target_type') if target_type == 'executable': return self.func_executable(node, args, kwargs) elif target_type == 'shared_library': return self.func_shared_lib(node, args, kwargs) elif target_type == 'static_library': return self.func_static_lib(node, args, kwargs) elif target_type == 'library': return self.func_library(node, args, kwargs) elif target_type == 'jar': return self.func_jar(node, args, kwargs) else: raise InterpreterException('Unknown target_type.') def func_set_variable(self, node, args, kwargs): if len(args) != 2: raise InvalidCode('Set_variable takes two arguments.') varname = args[0] value = self.to_native(args[1]) self.set_variable(varname, value) # @noKwargs def func_get_variable(self, node, args, kwargs): if len(args) < 1 or len(args) > 2: raise InvalidCode('Get_variable takes one or two arguments.') varname = args[0] if not isinstance(varname, str): raise InterpreterException('First argument must be a string.') try: return self.variables[varname] except KeyError: pass if len(args) == 2: return args[1] raise InterpreterException('Tried to get unknown variable "%s".' % varname) @stringArgs @noKwargs def func_is_variable(self, node, args, kwargs): if len(args) != 1: raise InvalidCode('Is_variable takes two arguments.') varname = args[0] return varname in self.variables def is_elementary_type(self, v): return isinstance(v, (int, float, str, bool, list)) meson-0.40.1/mesonbuild/wrap/0000755000175000017500000000000013100703042017407 5ustar jpakkanejpakkane00000000000000meson-0.40.1/mesonbuild/wrap/wrap.py0000644000175000017500000003143413100700231020734 0ustar jpakkanejpakkane00000000000000# Copyright 2015 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from .. import mlog import contextlib import urllib.request, os, hashlib, shutil import subprocess import sys from pathlib import Path from . import WrapMode try: import ssl has_ssl = True API_ROOT = 'https://wrapdb.mesonbuild.com/v1/' except ImportError: has_ssl = False API_ROOT = 'http://wrapdb.mesonbuild.com/v1/' ssl_warning_printed = False def build_ssl_context(): ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ctx.options |= ssl.OP_NO_SSLv2 ctx.options |= ssl.OP_NO_SSLv3 ctx.verify_mode = ssl.CERT_REQUIRED ctx.load_default_certs() return ctx def quiet_git(cmd, workingdir): pc = subprocess.Popen(['git', '-C', workingdir] + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = pc.communicate() if pc.returncode != 0: return False, err return True, out def open_wrapdburl(urlstring): global ssl_warning_printed if has_ssl: try: return urllib.request.urlopen(urlstring)#, context=build_ssl_context()) except urllib.error.URLError: if not ssl_warning_printed: print('SSL connection failed. Falling back to unencrypted connections.') ssl_warning_printed = True if not ssl_warning_printed: print('Warning: SSL not available, traffic not authenticated.', file=sys.stderr) ssl_warning_printed = True # Trying to open SSL connection to wrapdb fails because the # certificate is not known. if urlstring.startswith('https'): urlstring = 'http' + urlstring[5:] return urllib.request.urlopen(urlstring) class PackageDefinition: def __init__(self, fname): self.values = {} with open(fname) as ifile: first = ifile.readline().strip() if first == '[wrap-file]': self.type = 'file' elif first == '[wrap-git]': self.type = 'git' elif first == '[wrap-hg]': self.type = 'hg' else: raise RuntimeError('Invalid format of package file') for line in ifile: line = line.strip() if line == '': continue (k, v) = line.split('=', 1) k = k.strip() v = v.strip() self.values[k] = v def get(self, key): return self.values[key] def has_patch(self): return 'patch_url' in self.values class Resolver: def __init__(self, subdir_root, wrap_mode=WrapMode(1)): self.wrap_mode = wrap_mode self.subdir_root = subdir_root self.cachedir = os.path.join(self.subdir_root, 'packagecache') def resolve(self, packagename): # Check if the directory is already resolved dirname = Path(os.path.join(self.subdir_root, packagename)) subprojdir = os.path.join(*dirname.parts[-2:]) if dirname.is_dir(): if (dirname / 'meson.build').is_file(): # The directory is there and has meson.build? Great, use it. return packagename # Is the dir not empty and also not a git submodule dir that is # not checkout properly? Can't do anything, exception! elif next(dirname.iterdir(), None) and not (dirname / '.git').is_file(): m = '{!r} is not empty and has no meson.build files' raise RuntimeError(m.format(subprojdir)) elif dirname.exists(): m = '{!r} already exists and is not a dir; cannot use as subproject' raise RuntimeError(m.format(subprojdir)) dirname = str(dirname) # Check if the subproject is a git submodule if self.resolve_git_submodule(dirname): return packagename # Don't download subproject data based on wrap file if requested. # Git submodules are ok (see above)! if self.wrap_mode is WrapMode.nodownload: m = 'Automatic wrap-based subproject downloading is disabled' raise RuntimeError(m) # Check if there's a .wrap file for this subproject fname = os.path.join(self.subdir_root, packagename + '.wrap') if not os.path.isfile(fname): # No wrap file with this name? Give up. m = 'No {}.wrap found for {!r}' raise RuntimeError(m.format(packagename, subprojdir)) p = PackageDefinition(fname) if p.type == 'file': if not os.path.isdir(self.cachedir): os.mkdir(self.cachedir) self.download(p, packagename) self.extract_package(p) elif p.type == 'git': self.get_git(p) elif p.type == "hg": self.get_hg(p) else: raise AssertionError('Unreachable code.') return p.get('directory') def resolve_git_submodule(self, dirname): # Are we in a git repository? ret, out = quiet_git(['rev-parse'], self.subdir_root) if not ret: return False # Is `dirname` a submodule? ret, out = quiet_git(['submodule', 'status', dirname], self.subdir_root) if not ret: return False # Submodule has not been added, add it if out.startswith(b'-'): if subprocess.call(['git', '-C', self.subdir_root, 'submodule', 'update', '--init', dirname]) != 0: return False # Submodule was added already, but it wasn't populated. Do a checkout. elif out.startswith(b' '): if subprocess.call(['git', 'checkout', '.'], cwd=dirname): return True else: m = 'Unknown git submodule output: {!r}' raise AssertionError(m.format(out)) return True def get_git(self, p): checkoutdir = os.path.join(self.subdir_root, p.get('directory')) revno = p.get('revision') is_there = os.path.isdir(checkoutdir) if is_there: try: subprocess.check_call(['git', 'rev-parse'], cwd=checkoutdir) is_there = True except subprocess.CalledProcessError: raise RuntimeError('%s is not empty but is not a valid ' 'git repository, we can not work with it' ' as a subproject directory.' % ( checkoutdir)) if revno.lower() == 'head': # Failure to do pull is not a fatal error, # because otherwise you can't develop without # a working net connection. subprocess.call(['git', 'pull'], cwd=checkoutdir) else: if subprocess.call(['git', 'checkout', revno], cwd=checkoutdir) != 0: subprocess.check_call(['git', 'fetch'], cwd=checkoutdir) subprocess.check_call(['git', 'checkout', revno], cwd=checkoutdir) else: subprocess.check_call(['git', 'clone', p.get('url'), p.get('directory')], cwd=self.subdir_root) if revno.lower() != 'head': subprocess.check_call(['git', 'checkout', revno], cwd=checkoutdir) push_url = p.values.get('push-url') if push_url: subprocess.check_call(['git', 'remote', 'set-url', '--push', 'origin', push_url], cwd=checkoutdir) def get_hg(self, p): checkoutdir = os.path.join(self.subdir_root, p.get('directory')) revno = p.get('revision') is_there = os.path.isdir(checkoutdir) if is_there: if revno.lower() == 'tip': # Failure to do pull is not a fatal error, # because otherwise you can't develop without # a working net connection. subprocess.call(['hg', 'pull'], cwd=checkoutdir) else: if subprocess.call(['hg', 'checkout', revno], cwd=checkoutdir) != 0: subprocess.check_call(['hg', 'pull'], cwd=checkoutdir) subprocess.check_call(['hg', 'checkout', revno], cwd=checkoutdir) else: subprocess.check_call(['hg', 'clone', p.get('url'), p.get('directory')], cwd=self.subdir_root) if revno.lower() != 'tip': subprocess.check_call(['hg', 'checkout', revno], cwd=checkoutdir) def get_data(self, url): blocksize = 10 * 1024 if url.startswith('https://wrapdb.mesonbuild.com'): resp = open_wrapdburl(url) else: resp = urllib.request.urlopen(url) with contextlib.closing(resp) as resp: try: dlsize = int(resp.info()['Content-Length']) except TypeError: dlsize = None if dlsize is None: print('Downloading file of unknown size.') return resp.read() print('Download size:', dlsize) print('Downloading: ', end='') sys.stdout.flush() printed_dots = 0 blocks = [] downloaded = 0 while True: block = resp.read(blocksize) if block == b'': break downloaded += len(block) blocks.append(block) ratio = int(downloaded / dlsize * 10) while printed_dots < ratio: print('.', end='') sys.stdout.flush() printed_dots += 1 print('') return b''.join(blocks) def get_hash(self, data): h = hashlib.sha256() h.update(data) hashvalue = h.hexdigest() return hashvalue def download(self, p, packagename): ofname = os.path.join(self.cachedir, p.get('source_filename')) if os.path.exists(ofname): mlog.log('Using', mlog.bold(packagename), 'from cache.') return srcurl = p.get('source_url') mlog.log('Dowloading', mlog.bold(packagename), 'from', mlog.bold(srcurl)) srcdata = self.get_data(srcurl) dhash = self.get_hash(srcdata) expected = p.get('source_hash') if dhash != expected: raise RuntimeError('Incorrect hash for source %s:\n %s expected\n %s actual.' % (packagename, expected, dhash)) with open(ofname, 'wb') as f: f.write(srcdata) if p.has_patch(): purl = p.get('patch_url') mlog.log('Downloading patch from', mlog.bold(purl)) pdata = self.get_data(purl) phash = self.get_hash(pdata) expected = p.get('patch_hash') if phash != expected: raise RuntimeError('Incorrect hash for patch %s:\n %s expected\n %s actual' % (packagename, expected, phash)) filename = os.path.join(self.cachedir, p.get('patch_filename')) with open(filename, 'wb') as f: f.write(pdata) else: mlog.log('Package does not require patch.') def extract_package(self, package): if sys.version_info < (3, 5): try: import lzma del lzma try: shutil.register_unpack_format('xztar', ['.tar.xz', '.txz'], shutil._unpack_tarfile, [], "xz'ed tar-file") except shutil.RegistryError: pass except ImportError: pass target_dir = os.path.join(self.subdir_root, package.get('directory')) if os.path.isdir(target_dir): return extract_dir = self.subdir_root # Some upstreams ship packages that do not have a leading directory. # Create one for them. try: package.get('lead_directory_missing') os.mkdir(target_dir) extract_dir = target_dir except KeyError: pass shutil.unpack_archive(os.path.join(self.cachedir, package.get('source_filename')), extract_dir) if package.has_patch(): shutil.unpack_archive(os.path.join(self.cachedir, package.get('patch_filename')), self.subdir_root) meson-0.40.1/mesonbuild/wrap/__init__.py0000644000175000017500000000234613066536047021551 0ustar jpakkanejpakkane00000000000000from enum import Enum # Used for the --wrap-mode command-line argument # # Special wrap modes: # nofallback: Don't download wraps for dependency() fallbacks # nodownload: Don't download wraps for all subproject() calls # # subprojects are used for two purposes: # 1. To download and build dependencies by using .wrap # files if they are not provided by the system. This is # usually expressed via dependency(..., fallback: ...). # 2. To download and build 'copylibs' which are meant to be # used by copying into your project. This is always done # with an explicit subproject() call. # # --wrap-mode=nofallback will never do (1) # --wrap-mode=nodownload will do neither (1) nor (2) # # If you are building from a release tarball, you should be # able to safely use 'nodownload' since upstream is # expected to ship all required sources with the tarball. # # If you are building from a git repository, you will want # to use 'nofallback' so that any 'copylib' wraps will be # download as subprojects. # # Note that these options do not affect subprojects that # are git submodules since those are only usable in git # repositories, and you almost always want to download them. WrapMode = Enum('WrapMode', 'default nofallback nodownload') meson-0.40.1/mesonbuild/wrap/wraptool.py0000644000175000017500000001461113040633773021653 0ustar jpakkanejpakkane00000000000000# Copyright 2015-2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json import sys, os import configparser import shutil from glob import glob from .wrap import API_ROOT, open_wrapdburl help_templ = '''This program allows you to manage your Wrap dependencies using the online wrap database http://wrapdb.mesonbuild.com. Run this command in your top level source directory. Usage: %s [options] Commands: list - show all available projects search - search the db by name install - install the specified project update - update the project to its newest available release info - show available versions of a project status - show installed and available versions of your projects ''' def print_help(): print(help_templ % sys.argv[0]) def get_result(urlstring): u = open_wrapdburl(urlstring) data = u.read().decode('utf-8') jd = json.loads(data) if jd['output'] != 'ok': print('Got bad output from server.') print(data) sys.exit(1) return jd def get_projectlist(): jd = get_result(API_ROOT + 'projects') projects = jd['projects'] return projects def list_projects(): projects = get_projectlist() for p in projects: print(p) def search(name): jd = get_result(API_ROOT + 'query/byname/' + name) for p in jd['projects']: print(p) def get_latest_version(name): jd = get_result(API_ROOT + 'query/get_latest/' + name) branch = jd['branch'] revision = jd['revision'] return branch, revision def install(name): if not os.path.isdir('subprojects'): print('Subprojects dir not found. Run this script in your source root directory.') sys.exit(1) if os.path.isdir(os.path.join('subprojects', name)): print('Subproject directory for this project already exists.') sys.exit(1) wrapfile = os.path.join('subprojects', name + '.wrap') if os.path.exists(wrapfile): print('Wrap file already exists.') sys.exit(1) (branch, revision) = get_latest_version(name) u = open_wrapdburl(API_ROOT + 'projects/%s/%s/%s/get_wrap' % (name, branch, revision)) data = u.read() with open(wrapfile, 'wb') as f: f.write(data) print('Installed', name, 'branch', branch, 'revision', revision) def get_current_version(wrapfile): cp = configparser.ConfigParser() cp.read(wrapfile) cp = cp['wrap-file'] patch_url = cp['patch_url'] arr = patch_url.split('/') branch = arr[-3] revision = int(arr[-2]) return branch, revision, cp['directory'], cp['source_filename'], cp['patch_filename'] def update(name): if not os.path.isdir('subprojects'): print('Subprojects dir not found. Run this command in your source root directory.') sys.exit(1) wrapfile = os.path.join('subprojects', name + '.wrap') if not os.path.exists(wrapfile): print('Project', name, 'is not in use.') sys.exit(1) (branch, revision, subdir, src_file, patch_file) = get_current_version(wrapfile) (new_branch, new_revision) = get_latest_version(name) if new_branch == branch and new_revision == revision: print('Project', name, 'is already up to date.') sys.exit(0) u = open_wrapdburl(API_ROOT + 'projects/%s/%s/%d/get_wrap' % (name, new_branch, new_revision)) data = u.read() shutil.rmtree(os.path.join('subprojects', subdir), ignore_errors=True) try: os.unlink(os.path.join('subprojects/packagecache', src_file)) except FileNotFoundError: pass try: os.unlink(os.path.join('subprojects/packagecache', patch_file)) except FileNotFoundError: pass with open(wrapfile, 'wb') as f: f.write(data) print('Updated', name, 'to branch', new_branch, 'revision', new_revision) def info(name): jd = get_result(API_ROOT + 'projects/' + name) versions = jd['versions'] if len(versions) == 0: print('No available versions of', name) sys.exit(0) print('Available versions of %s:' % name) for v in versions: print(' ', v['branch'], v['revision']) def status(): print('Subproject status') for w in glob('subprojects/*.wrap'): name = os.path.split(w)[1][:-5] try: (latest_branch, latest_revision) = get_latest_version(name) except Exception: print('', name, 'not available in wrapdb.') continue try: (current_branch, current_revision, _, _, _) = get_current_version(w) except Exception: print('Wrap file not from wrapdb.') continue if current_branch == latest_branch and current_revision == latest_revision: print('', name, 'up to date. Branch %s, revision %d.' % (current_branch, current_revision)) else: print('', name, 'not up to date. Have %s %d, but %s %d is available.' % (current_branch, current_revision, latest_branch, latest_revision)) def run(args): if len(args) == 0 or args[0] == '-h' or args[0] == '--help': print_help() return 0 command = args[0] args = args[1:] if command == 'list': list_projects() elif command == 'search': if len(args) != 1: print('Search requires exactly one argument.') return 1 search(args[0]) elif command == 'install': if len(args) != 1: print('Install requires exactly one argument.') return 1 install(args[0]) elif command == 'update': if len(args) != 1: print('update requires exactly one argument.') return 1 update(args[0]) elif command == 'info': if len(args) != 1: print('info requires exactly one argument.') return 1 info(args[0]) elif command == 'status': status() else: print('Unknown command', command) return 1 return 0 if __name__ == '__main__': sys.exit(run(sys.argv[1:])) meson-0.40.1/mesonbuild/optinterpreter.py0000644000175000017500000001511713074426732022125 0ustar jpakkanejpakkane00000000000000# Copyright 2013-2014 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from . import mparser from . import coredata from . import mesonlib import os, re forbidden_option_names = coredata.get_builtin_options() forbidden_prefixes = {'c_': True, 'cpp_': True, 'd_': True, 'rust_': True, 'fortran_': True, 'objc_': True, 'objcpp_': True, 'vala_': True, 'csharp_': True, 'swift_': True, 'b_': True, } def is_invalid_name(name): if name in forbidden_option_names: return True pref = name.split('_')[0] + '_' if pref in forbidden_prefixes: return True return False class OptionException(mesonlib.MesonException): pass optname_regex = re.compile('[^a-zA-Z0-9_-]') def StringParser(name, description, kwargs): return coredata.UserStringOption(name, description, kwargs.get('value', ''), kwargs.get('choices', [])) def BooleanParser(name, description, kwargs): return coredata.UserBooleanOption(name, description, kwargs.get('value', True)) def ComboParser(name, description, kwargs): if 'choices' not in kwargs: raise OptionException('Combo option missing "choices" keyword.') choices = kwargs['choices'] if not isinstance(choices, list): raise OptionException('Combo choices must be an array.') for i in choices: if not isinstance(i, str): raise OptionException('Combo choice elements must be strings.') return coredata.UserComboOption(name, description, choices, kwargs.get('value', choices[0])) option_types = {'string': StringParser, 'boolean': BooleanParser, 'combo': ComboParser, } class OptionInterpreter: def __init__(self, subproject, command_line_options): self.options = {} self.subproject = subproject self.sbprefix = subproject + ':' 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 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): try: with open(option_file, 'r', encoding='utf8') as f: ast = mparser.Parser(f.read(), '').parse() except mesonlib.MesonException as me: me.file = option_file raise me if not isinstance(ast, mparser.CodeBlockNode): e = OptionException('Option file is malformed.') e.lineno = ast.lineno() raise e for cur in ast.lines: try: self.evaluate_statement(cur) except Exception as e: e.lineno = cur.lineno e.colno = cur.colno e.file = os.path.join('meson_options.txt') raise e def reduce_single(self, arg): if isinstance(arg, str): return arg elif isinstance(arg, (mparser.StringNode, mparser.BooleanNode, mparser.NumberNode)): return arg.value elif isinstance(arg, mparser.ArrayNode): return [self.reduce_single(curarg) for curarg in arg.args.arguments] else: raise OptionException('Arguments may only be string, int, bool, or array of those.') def reduce_arguments(self, args): assert(isinstance(args, mparser.ArgumentNode)) if args.incorrect_order(): raise OptionException('All keyword arguments must be after positional arguments.') reduced_pos = [self.reduce_single(arg) for arg in args.arguments] reduced_kw = {} for key in args.kwargs.keys(): if not isinstance(key, str): raise OptionException('Keyword argument name is not a string.') a = args.kwargs[key] reduced_kw[key] = self.reduce_single(a) return reduced_pos, reduced_kw def evaluate_statement(self, node): if not isinstance(node, mparser.FunctionNode): raise OptionException('Option file may only contain option definitions') func_name = node.func_name if func_name != 'option': raise OptionException('Only calls to option() are allowed in option files.') (posargs, kwargs) = self.reduce_arguments(node.args) if 'type' not in kwargs: raise OptionException('Option call missing mandatory "type" keyword argument') opt_type = kwargs['type'] if opt_type not in option_types: raise OptionException('Unknown type %s.' % opt_type) if len(posargs) != 1: raise OptionException('Option() must have one (and only one) positional argument') opt_name = posargs[0] if not isinstance(opt_name, str): raise OptionException('Positional argument must be a string.') if optname_regex.search(opt_name) is not None: raise OptionException('Option names can only contain letters, numbers or dashes.') if is_invalid_name(opt_name): raise OptionException('Option name %s is reserved.' % opt_name) if self.subproject != '': opt_name = self.subproject + ':' + opt_name opt = option_types[opt_type](opt_name, kwargs.get('description', ''), kwargs) if opt.description == '': opt.description = opt_name if opt_name in self.cmd_line_options: opt.set_value(opt.parse_string(self.cmd_line_options[opt_name])) self.options[opt_name] = opt meson-0.40.1/mesonbuild/build.py0000644000175000017500000021043213076637146020140 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import copy, os, re from collections import OrderedDict from . import environment from . import dependencies 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, for_cygwin from .compilers import is_object, clike_langs, sort_clike, lang_suffixes known_basic_kwargs = {'install': True, 'c_pch': True, 'cpp_pch': True, 'c_args': True, 'cpp_args': True, 'cs_args': True, 'vala_args': True, 'fortran_args': True, 'd_args': True, 'java_args': True, 'link_args': True, 'link_depends': True, 'link_with': True, 'link_whole': True, 'include_directories': True, 'dependencies': True, 'install_dir': True, 'main_class': True, 'gui_app': True, 'extra_files': True, 'install_rpath': True, 'resources': True, 'sources': True, 'objects': True, 'native': True, 'build_by_default': True, 'override_options': True, } # These contain kwargs supported by both static and shared libraries. These are # combined here because a library() call might be shared_library() or # static_library() at runtime based on the configuration. # FIXME: Find a way to pass that info down here so we can have proper target # kwargs checking when specifically using shared_library() or static_library(). known_lib_kwargs = known_basic_kwargs.copy() known_lib_kwargs.update({'version': True, # Only for shared libs 'soversion': True, # Only for shared libs 'name_prefix': True, 'name_suffix': True, 'vs_module_defs': True, # Only for shared libs 'vala_header': True, 'vala_vapi': True, 'vala_gir': True, 'pic': True, # Only for static libs }) class InvalidArguments(MesonException): pass class Build: """A class that holds the status of one build including all dependencies and so on. """ def __init__(self, environment): self.project_name = 'name of master project' self.project_version = None self.environment = environment self.projects = {} self.targets = OrderedDict() self.compilers = OrderedDict() self.cross_compilers = OrderedDict() self.global_args = {} self.projects_args = {} self.global_link_args = {} self.projects_link_args = {} self.tests = [] self.benchmarks = [] self.headers = [] self.man = [] self.data = [] self.static_linker = None self.static_cross_linker = None self.subprojects = {} self.install_scripts = [] self.postconf_scripts = [] self.install_dirs = [] self.dep_manifest_name = None self.dep_manifest = {} self.cross_stdlibs = {} self.test_setups = {} def add_compiler(self, compiler): if self.static_linker is None and compiler.needs_static_linker(): self.static_linker = self.environment.detect_static_linker(compiler) lang = compiler.get_language() if lang not in self.compilers: self.compilers[lang] = compiler def add_cross_compiler(self, compiler): if len(self.cross_compilers) == 0: self.static_cross_linker = self.environment.detect_static_linker(compiler) lang = compiler.get_language() if lang not in self.cross_compilers: self.cross_compilers[lang] = compiler def get_project(self): return self.projects[''] def get_targets(self): return self.targets def get_tests(self): return self.tests def get_benchmarks(self): return self.benchmarks def get_headers(self): return self.headers def get_man(self): return self.man def get_data(self): return self.data def get_install_subdirs(self): return self.install_dirs def get_global_args(self, compiler): return self.global_args.get(compiler.get_language(), []) def get_project_args(self, compiler, project): args = self.projects_args.get(project) if not args: return [] return args.get(compiler.get_language(), []) def get_global_link_args(self, compiler): return self.global_link_args.get(compiler.get_language(), []) def get_project_link_args(self, compiler, project): link_args = self.projects_link_args.get(project) if not link_args: return [] return link_args.get(compiler.get_language(), []) class IncludeDirs: def __init__(self, curdir, dirs, is_system, extra_build_dirs=None): self.curdir = curdir self.incdirs = dirs self.is_system = is_system # Interpreter has validated that all given directories # actually exist. if extra_build_dirs is None: self.extra_build_dirs = [] else: self.extra_build_dirs = extra_build_dirs def __repr__(self): r = '<{} {}/{}>' return r.format(self.__class__.__name__, self.curdir, self.incdirs) def get_curdir(self): return self.curdir def get_incdirs(self): return self.incdirs def get_extra_build_dirs(self): return self.extra_build_dirs class ExtractedObjects: ''' Holds a list of sources for which the objects must be extracted ''' def __init__(self, target, srclist, is_unity): self.target = target self.srclist = srclist if is_unity: self.check_unity_compatible() def __repr__(self): r = '<{0} {1!r}: {2}>' return r.format(self.__class__.__name__, self.target.name, self.srclist) def check_unity_compatible(self): # Figure out if the extracted object list is compatible with a Unity # build. When we're doing a Unified build, we go through the sources, # and create a single source file from each subset of the sources that # can be compiled with a specific compiler. Then we create one object # from each unified source file. # If the list of sources for which we want objects is the same as the # list of sources that go into each unified build, we're good. srclist_set = set(self.srclist) # Objects for all the sources are required, so we're compatible if srclist_set == set(self.target.sources): return # Check if the srclist is a subset (of the target's sources) that is # going to form a unified source file and a single object compsrcs = classify_unity_sources(self.target.compilers.values(), self.target.sources) for srcs in compsrcs.values(): if srclist_set == set(srcs): return msg = 'Single object files can not be extracted in Unity builds. ' \ 'You can only extract all the object files at once.' raise MesonException(msg) def get_want_all_objects(self): return self.want_all_objects class EnvironmentVariables: def __init__(self): self.envvars = [] def __repr__(self): repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.envvars) def get_value(self, name, values, kwargs): separator = kwargs.get('separator', os.pathsep) value = '' for var in values: value += separator + var return separator, value.strip(separator) def set(self, env, name, values, kwargs): return self.get_value(name, values, kwargs)[1] def append(self, env, name, values, kwargs): sep, value = self.get_value(name, values, kwargs) if name in env: return env[name] + sep + value return value def prepend(self, env, name, values, kwargs): sep, value = self.get_value(name, values, kwargs) if name in env: return value + sep + env[name] return value def get_env(self, full_env): env = {} for method, name, values, kwargs in self.envvars: env[name] = method(full_env, name, values, kwargs) return env class Target: def __init__(self, name, subdir, build_by_default): self.name = name self.subdir = subdir self.build_by_default = build_by_default self.install = False self.build_always = False self.option_overrides = {} def get_basename(self): return self.name def get_subdir(self): return self.subdir def process_kwargs(self, kwargs): if 'build_by_default' in kwargs: self.build_by_default = kwargs['build_by_default'] if not isinstance(self.build_by_default, bool): raise InvalidArguments('build_by_default must be a boolean value.') self.option_overrides = self.parse_overrides(kwargs) def parse_overrides(self, kwargs): result = {} overrides = stringlistify(kwargs.get('override_options', [])) for o in overrides: if '=' not in o: raise InvalidArguments('Overrides must be of form "key=value"') k, v = o.split('=', 1) k = k.strip() v = v.strip() result[k] = v return result class BuildTarget(Target): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): super().__init__(name, subdir, True) self.subproject = subproject # Can not be calculated from subdir as subproject dirname can be changed per project. self.is_cross = is_cross unity_opt = environment.coredata.get_builtin_option('unity') self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '') self.environment = environment self.sources = [] self.compilers = OrderedDict() self.objects = [] self.external_deps = [] self.include_dirs = [] self.link_targets = [] self.link_whole_targets = [] self.link_depends = [] self.name_prefix_set = False self.name_suffix_set = False self.filename = 'no_name' # The list of all files outputted by this target. Useful in cases such # as Vala which generates .vapi and .h besides the compiled output. self.outputs = [self.filename] self.need_install = False self.pch = {} self.extra_args = {} self.generated = [] self.extra_files = [] # Sources can be: # 1. Pre-existing source files in the source tree # 2. Pre-existing sources generated by configure_file in the build tree # 3. Sources files generated by another target or a Generator self.process_sourcelist(sources) # Objects can be: # 1. Pre-existing objects provided by the user with the `objects:` kwarg # 2. Compiled objects created by and extracted from another target self.process_objectlist(objects) self.process_kwargs(kwargs, environment) self.check_unknown_kwargs(kwargs) if len(self.sources) == 0 \ and len(self.generated) == 0 \ and len(self.objects) == 0: raise InvalidArguments('Build target %s has no sources.' % name) self.process_compilers() self.validate_sources() self.validate_cross_install(environment) def __lt__(self, other): return self.get_id() < other.get_id() def __repr__(self): repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.filename) def validate_cross_install(self, environment): if environment.is_cross_build() and not self.is_cross and self.install: raise InvalidArguments('Tried to install a natively built target in a cross build.') def get_id(self): # This ID must also be a valid file name on all OSs. # It should also avoid shell metacharacters for obvious # reasons. base = self.name + self.type_suffix() if self.subproject == '': return base return self.subproject + '@@' + base def check_unknown_kwargs(self, kwargs): # Override this method in derived classes that have more # keywords. self.check_unknown_kwargs_int(kwargs, known_basic_kwargs) def check_unknown_kwargs_int(self, kwargs, known_kwargs): unknowns = [] for k in kwargs: if k not in known_kwargs: unknowns.append(k) if len(unknowns) > 0: mlog.warning('Unknown keyword argument(s) in target %s: %s.' % (self.name, ', '.join(unknowns))) def process_objectlist(self, objects): assert(isinstance(objects, list)) for s in objects: if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, (str, File, ExtractedObjects)): self.objects.append(s) elif isinstance(s, (GeneratedList, CustomTarget)): msg = 'Generated files are not allowed in the \'objects\' kwarg ' + \ 'for target {!r}.\nIt is meant only for '.format(self.name) + \ 'pre-built object files that are shipped with the\nsource ' + \ 'tree. Try adding it in the list of sources.' raise InvalidArguments(msg) else: msg = 'Bad object of type {!r} in target {!r}.'.format(type(s).__name__, self.name) raise InvalidArguments(msg) def process_sourcelist(self, sources): if not isinstance(sources, list): sources = [sources] added_sources = {} # If the same source is defined multiple times, use it only once. for s in sources: # Holder unpacking. Ugly. if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, File): if s not in added_sources: self.sources.append(s) added_sources[s] = True elif isinstance(s, (GeneratedList, CustomTarget)): self.generated.append(s) else: msg = 'Bad source of type {!r} in target {!r}.'.format(type(s).__name__, self.name) raise InvalidArguments(msg) @staticmethod def can_compile_remove_sources(compiler, sources): removed = False for s in sources[:]: if compiler.can_compile(s): sources.remove(s) removed = True return removed def process_compilers(self): ''' Populate self.compilers, which is the list of compilers that this target will use for compiling all its sources. We also add compilers that were used by extracted objects to simplify dynamic linker determination. ''' if len(self.sources) + len(self.generated) + len(self.objects) == 0: return # Populate list of compilers if self.is_cross: compilers = self.environment.coredata.cross_compilers else: compilers = self.environment.coredata.compilers # Pre-existing sources sources = list(self.sources) # All generated sources for gensrc in self.generated: for s in gensrc.get_outputs(): # Generated objects can't be compiled, so don't use them for # compiler detection. If our target only has generated objects, # we will fall back to using the first c-like compiler we find, # which is what we need. if not is_object(s): sources.append(s) # Sources that were used to create our extracted objects for o in self.objects: if not isinstance(o, ExtractedObjects): continue for s in o.srclist: # Don't add Vala sources since that will pull in the Vala # compiler even though we will never use it since we are # dealing with compiled C code. if not s.endswith(lang_suffixes['vala']): sources.append(s) if sources: # For each source, try to add one compiler that can compile it. # It's ok if no compilers can do so, because users are expected to # be able to add arbitrary non-source files to the sources list. for s in sources: for lang, compiler in compilers.items(): if compiler.can_compile(s): if lang not in self.compilers: self.compilers[lang] = compiler break # Re-sort according to clike_langs self.compilers = OrderedDict(sorted(self.compilers.items(), key=lambda t: sort_clike(t[0]))) else: # No source files, target consists of only object files of unknown # origin. Just add the first clike compiler that we have and hope # that it can link these objects for lang in clike_langs: if lang in compilers: self.compilers[lang] = compilers[lang] break # If all our sources are Vala, our target also needs the C compiler but # it won't get added above. if 'vala' in self.compilers and 'c' not in self.compilers: self.compilers['c'] = compilers['c'] def validate_sources(self): if len(self.sources) == 0: return for lang in ('cs', 'java'): if lang in self.compilers: check_sources = list(self.sources) compiler = self.compilers[lang] if not self.can_compile_remove_sources(compiler, check_sources): m = 'No {} sources found in target {!r}'.format(lang, self.name) raise InvalidArguments(m) if check_sources: m = '{0} targets can only contain {0} files:\n'.format(lang.capitalize()) m += '\n'.join([repr(c) for c in check_sources]) raise InvalidArguments(m) # CSharp and Java targets can't contain any other file types assert(len(self.compilers) == 1) return def get_original_kwargs(self): return self.kwargs def unpack_holder(self, d): if not isinstance(d, list): d = [d] newd = [] for i in d: if hasattr(i, 'held_object'): newd.append(i.held_object) else: newd.append(i) return newd def copy_kwargs(self, kwargs): self.kwargs = copy.copy(kwargs) # This sucks quite badly. Arguments # are holders but they can't be pickled # so unpack those known. if 'dependencies' in self.kwargs: self.kwargs['dependencies'] = self.unpack_holder(self.kwargs['dependencies']) if 'link_with' in self.kwargs: self.kwargs['link_with'] = self.unpack_holder(self.kwargs['link_with']) def extract_objects(self, srclist): obj_src = [] for src in srclist: if not isinstance(src, str): raise MesonException('Object extraction arguments must be strings.') src = File(False, self.subdir, src) if src not in self.sources: raise MesonException('Tried to extract unknown source %s.' % src) obj_src.append(src) return ExtractedObjects(self, obj_src, self.is_unity) def extract_all_objects(self): return ExtractedObjects(self, self.sources, self.is_unity) def get_all_link_deps(self): return self.get_transitive_link_deps() def get_transitive_link_deps(self): result = [] for i in self.link_targets: result += i.get_all_link_deps() return result def get_custom_install_dir(self): return self.install_dir def process_kwargs(self, kwargs, environment): super().process_kwargs(kwargs) self.copy_kwargs(kwargs) kwargs.get('modules', []) self.need_install = kwargs.get('install', self.need_install) llist = kwargs.get('link_with', []) if not isinstance(llist, list): llist = [llist] for linktarget in llist: # Sorry for this hack. Keyword targets are kept in holders # in kwargs. Unpack here without looking at the exact type. if hasattr(linktarget, "held_object"): linktarget = linktarget.held_object self.link(linktarget) lwhole = kwargs.get('link_whole', []) if not isinstance(lwhole, list): lwhole = [lwhole] for linktarget in lwhole: # Sorry for this hack. Keyword targets are kept in holders # in kwargs. Unpack here without looking at the exact type. if hasattr(linktarget, "held_object"): linktarget = linktarget.held_object self.link_whole(linktarget) c_pchlist = kwargs.get('c_pch', []) if not isinstance(c_pchlist, list): c_pchlist = [c_pchlist] self.add_pch('c', c_pchlist) cpp_pchlist = kwargs.get('cpp_pch', []) if not isinstance(cpp_pchlist, list): cpp_pchlist = [cpp_pchlist] self.add_pch('cpp', cpp_pchlist) clist = kwargs.get('c_args', []) if not isinstance(clist, list): clist = [clist] self.add_compiler_args('c', clist) cpplist = kwargs.get('cpp_args', []) if not isinstance(cpplist, list): cpplist = [cpplist] self.add_compiler_args('cpp', cpplist) cslist = kwargs.get('cs_args', []) if not isinstance(cslist, list): cslist = [cslist] self.add_compiler_args('cs', cslist) valalist = kwargs.get('vala_args', []) if not isinstance(valalist, list): valalist = [valalist] self.add_compiler_args('vala', valalist) fortranlist = kwargs.get('fortran_args', []) if not isinstance(fortranlist, list): fortranlist = [fortranlist] self.add_compiler_args('fortran', fortranlist) if not isinstance(self, Executable): self.vala_header = kwargs.get('vala_header', self.name + '.h') self.vala_vapi = kwargs.get('vala_vapi', self.name + '.vapi') self.vala_gir = kwargs.get('vala_gir', None) dlist = stringlistify(kwargs.get('d_args', [])) self.add_compiler_args('d', dlist) self.link_args = kwargs.get('link_args', []) if not isinstance(self.link_args, list): self.link_args = [self.link_args] for i in self.link_args: if not isinstance(i, str): raise InvalidArguments('Link_args arguments must be strings.') self.link_depends = kwargs.get('link_depends', []) if not isinstance(self.link_depends, list): self.link_depends = [self.link_depends] for i in self.link_depends: if not isinstance(i, str): raise InvalidArguments('Link_depends arguments must be strings.') # Target-specific include dirs must be added BEFORE include dirs from # internal deps (added inside self.add_deps()) to override them. inclist = kwargs.get('include_directories', []) if not isinstance(inclist, list): inclist = [inclist] self.add_include_dirs(inclist) # Add dependencies (which also have include_directories) deplist = kwargs.get('dependencies', []) if not isinstance(deplist, list): deplist = [deplist] self.add_deps(deplist) # If an item in this list is False, the output corresponding to # the list index of that item will not be installed self.install_dir = typeslistify(kwargs.get('install_dir', [None]), (str, bool)) main_class = kwargs.get('main_class', '') if not isinstance(main_class, str): raise InvalidArguments('Main class must be a string') self.main_class = main_class if isinstance(self, Executable): self.gui_app = kwargs.get('gui_app', False) if not isinstance(self.gui_app, bool): raise InvalidArguments('Argument gui_app must be boolean.') elif 'gui_app' in kwargs: raise InvalidArguments('Argument gui_app can only be used on executables.') extra_files = kwargs.get('extra_files', []) if isinstance(extra_files, str): extra_files = [extra_files] for i in extra_files: if not isinstance(i, str): raise InvalidArguments('Arguments to extra_files must be strings.') trial = os.path.join(environment.get_source_dir(), self.subdir, i) if not(os.path.isfile(trial)): raise InvalidArguments('Tried to add non-existing extra file %s.' % i) self.extra_files = extra_files self.install_rpath = kwargs.get('install_rpath', '') if not isinstance(self.install_rpath, str): raise InvalidArguments('Install_rpath is not a string.') resources = kwargs.get('resources', []) if not isinstance(resources, list): resources = [resources] for r in resources: if not isinstance(r, str): raise InvalidArguments('Resource argument is not a string.') trial = os.path.join(environment.get_source_dir(), self.subdir, r) if not os.path.isfile(trial): raise InvalidArguments('Tried to add non-existing resource %s.' % r) self.resources = resources if 'name_prefix' in kwargs: name_prefix = kwargs['name_prefix'] if isinstance(name_prefix, list): if len(name_prefix) != 0: raise InvalidArguments('name_prefix array must be empty to signify null.') elif not isinstance(name_prefix, str): raise InvalidArguments('name_prefix must be a string.') self.prefix = name_prefix self.name_prefix_set = True if 'name_suffix' in kwargs: name_suffix = kwargs['name_suffix'] if isinstance(name_suffix, list): if len(name_suffix) != 0: raise InvalidArguments('name_suffix array must be empty to signify null.') else: if not isinstance(name_suffix, str): raise InvalidArguments('name_suffix must be a string.') self.suffix = name_suffix self.name_suffix_set = True if isinstance(self, StaticLibrary): # You can't disable PIC on OS X. The compiler ignores -fno-PIC. # PIC is always on for Windows (all code is position-independent # since library loading is done differently) 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.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) if not isinstance(self.pic, bool): raise InvalidArguments('Argument pic to static library {!r} must be boolean'.format(self.name)) def get_filename(self): return self.filename def get_outputs(self): return self.outputs def get_extra_args(self, language): return self.extra_args.get(language, []) def get_dependencies(self): transitive_deps = [] for t in self.link_targets + self.link_whole_targets: transitive_deps.append(t) if isinstance(t, StaticLibrary): transitive_deps += t.get_dependencies() return transitive_deps def get_source_subdir(self): return self.subdir def get_sources(self): return self.sources def get_objects(self): return self.objects def get_generated_sources(self): return self.generated def should_install(self): return self.need_install def has_pch(self): return len(self.pch) > 0 def get_pch(self, language): try: return self.pch[language] except KeyError: return[] def get_include_dirs(self): return self.include_dirs def add_deps(self, deps): if not isinstance(deps, list): deps = [deps] for dep in deps: if hasattr(dep, 'held_object'): dep = dep.held_object if isinstance(dep, dependencies.InternalDependency): # Those parts that are internal. self.process_sourcelist(dep.sources) self.add_include_dirs(dep.include_directories) for l in dep.libraries: self.link(l) # Those parts that are external. extpart = dependencies.InternalDependency('undefined', [], dep.compile_args, dep.link_args, [], [], []) self.external_deps.append(extpart) # Deps of deps. self.add_deps(dep.ext_deps) elif isinstance(dep, dependencies.Dependency): self.external_deps.append(dep) self.process_sourcelist(dep.get_sources()) elif isinstance(dep, BuildTarget): raise InvalidArguments('''Tried to use a build target as a dependency. You probably should put it in link_with instead.''') else: # This is a bit of a hack. We do not want Build to know anything # about the interpreter so we can't import it and use isinstance. # This should be reliable enough. if hasattr(dep, 'args_frozen'): raise InvalidArguments('Tried to use subproject object as a dependency.\n' 'You probably wanted to use a dependency declared in it instead.\n' 'Access it by calling get_variable() on the subproject object.') raise InvalidArguments('Argument is of an unacceptable type {!r}.\nMust be ' 'either an external dependency (returned by find_library() or ' 'dependency()) or an internal dependency (returned by ' 'declare_dependency()).'.format(type(dep).__name__)) def get_external_deps(self): return self.external_deps def link(self, target): if not isinstance(target, list): target = [target] for t in target: if hasattr(t, 'held_object'): t = t.held_object if not isinstance(t, (StaticLibrary, SharedLibrary)): raise InvalidArguments('Link target {!r} is not library.'.format(t)) if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) and not t.pic: msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name) msg += "Use the 'pic' option to static_library to build with PIC." raise InvalidArguments(msg) if self.is_cross != t.is_cross: raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name)) self.link_targets.append(t) def link_whole(self, target): if not isinstance(target, list): target = [target] for t in target: if hasattr(t, 'held_object'): t = t.held_object if not isinstance(t, StaticLibrary): raise InvalidArguments('{!r} is not a static library.'.format(t)) if isinstance(self, SharedLibrary) and not t.pic: msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name) msg += "Use the 'pic' option to static_library to build with PIC." raise InvalidArguments(msg) if self.is_cross != t.is_cross: raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name)) self.link_whole_targets.append(t) def add_pch(self, language, pchlist): if len(pchlist) == 0: return elif len(pchlist) == 1: if not environment.is_header(pchlist[0]): raise InvalidArguments('PCH argument %s is not a header.' % pchlist[0]) elif len(pchlist) == 2: if environment.is_header(pchlist[0]): if not environment.is_source(pchlist[1]): raise InvalidArguments('PCH definition must contain one header and at most one source.') elif environment.is_source(pchlist[0]): if not environment.is_header(pchlist[1]): raise InvalidArguments('PCH definition must contain one header and at most one source.') pchlist = [pchlist[1], pchlist[0]] else: raise InvalidArguments('PCH argument %s is of unknown type.' % pchlist[0]) elif len(pchlist) > 2: raise InvalidArguments('PCH definition may have a maximum of 2 files.') self.pch[language] = pchlist def add_include_dirs(self, args): ids = [] for a in args: # FIXME same hack, forcibly unpack from holder. if hasattr(a, 'held_object'): a = a.held_object if not isinstance(a, IncludeDirs): raise InvalidArguments('Include directory to be added is not an include directory object.') ids.append(a) self.include_dirs += ids def add_compiler_args(self, language, args): args = flatten(args) for a in args: if not isinstance(a, (str, File)): raise InvalidArguments('A non-string passed to compiler args.') if language in self.extra_args: self.extra_args[language] += args else: self.extra_args[language] = args def get_aliases(self): return {} def get_langs_used_by_deps(self): ''' Sometimes you want to link to a C++ library that exports C API, which means the linker must link in the C++ stdlib, and we must use a C++ compiler for linking. The same is also applicable for objc/objc++, etc, so we can keep using clike_langs for the priority order. See: https://github.com/mesonbuild/meson/issues/1653 ''' langs = [] # Check if any of the external libraries were written in this language for dep in self.external_deps: if dep.language not in langs: langs.append(dep.language) # Check if any of the internal libraries this target links to were # written in this language for link_target in self.link_targets: for language in link_target.compilers: if language not in langs: langs.append(language) return langs def get_clike_dynamic_linker(self): ''' We use the order of languages in `clike_langs` to determine which linker to use in case the target has sources compiled with multiple compilers. All languages other than those in this list have their own linker. Note that Vala outputs C code, so Vala sources can use any linker that can link compiled C. We don't actually need to add an exception for Vala here because of that. ''' # Populate list of all compilers, not just those being used to compile # sources in this target if self.is_cross: all_compilers = self.environment.coredata.cross_compilers else: all_compilers = self.environment.coredata.compilers # Languages used by dependencies dep_langs = self.get_langs_used_by_deps() # Pick a compiler based on the language priority-order for l in clike_langs: if l in self.compilers or l in dep_langs: return all_compilers[l] m = 'Could not get a dynamic linker for build target {!r}' raise AssertionError(m.format(self.name)) def get_using_msvc(self): ''' Check if the dynamic linker is MSVC. Used by Executable, StaticLibrary, and SharedLibrary for deciding when to use MSVC-specific file naming and debug filenames. If at least some code is built with MSVC and the final library is linked with MSVC, we can be sure that some debug info will be generated. We only check the dynamic linker here because the static linker is guaranteed to be of the same type. Interesting cases: 1. The Vala compiler outputs C code to be compiled by whatever C compiler we're using, so all objects will still be created by the MSVC compiler. 2. If the target contains only objects, process_compilers guesses and picks the first compiler that smells right. ''' linker = self.get_clike_dynamic_linker() if linker and linker.get_id() == 'msvc': return True return False class Generator: def __init__(self, args, kwargs): if len(args) != 1: raise InvalidArguments('Generator requires exactly one positional argument: the executable') exe = args[0] if hasattr(exe, 'held_object'): exe = exe.held_object if not isinstance(exe, (Executable, dependencies.ExternalProgram)): raise InvalidArguments('First generator argument must be an executable.') self.exe = exe self.depfile = None self.process_kwargs(kwargs) def __repr__(self): repr_str = "<{0}: {1}>" return repr_str.format(self.__class__.__name__, self.exe) def get_exe(self): return self.exe def process_kwargs(self, kwargs): if 'arguments' not in kwargs: raise InvalidArguments('Generator must have "arguments" keyword argument.') args = kwargs['arguments'] if isinstance(args, str): args = [args] if not isinstance(args, list): raise InvalidArguments('"Arguments" keyword argument must be a string or a list of strings.') for a in args: if not isinstance(a, str): raise InvalidArguments('A non-string object in "arguments" keyword argument.') self.arglist = args if 'output' not in kwargs: raise InvalidArguments('Generator must have "output" keyword argument.') outputs = kwargs['output'] if not isinstance(outputs, list): outputs = [outputs] for rule in outputs: if not isinstance(rule, str): raise InvalidArguments('"output" may only contain strings.') if '@BASENAME@' not in rule and '@PLAINNAME@' not in rule: raise InvalidArguments('Every element of "output" must contain @BASENAME@ or @PLAINNAME@.') if '/' in rule or '\\' in rule: raise InvalidArguments('"outputs" must not contain a directory separator.') if len(outputs) > 1: for o in outputs: if '@OUTPUT@' in o: raise InvalidArguments('Tried to use @OUTPUT@ in a rule with more than one output.') self.outputs = outputs if 'depfile' in kwargs: depfile = kwargs['depfile'] if not isinstance(depfile, str): raise InvalidArguments('Depfile must be a string.') if os.path.split(depfile)[1] != depfile: raise InvalidArguments('Depfile must be a plain filename without a subdirectory.') self.depfile = depfile def get_base_outnames(self, inname): plainname = os.path.split(inname)[1] basename = os.path.splitext(plainname)[0] return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.outputs] def get_dep_outname(self, inname): if self.depfile is None: raise InvalidArguments('Tried to get dep name for rule that does not have dependency file defined.') plainname = os.path.split(inname)[1] basename = os.path.splitext(plainname)[0] return self.depfile.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) def get_arglist(self): return self.arglist def process_files(self, name, files, state, extra_args=[]): output = GeneratedList(self, extra_args=extra_args) for f in files: if isinstance(f, str): f = File.from_source_file(state.environment.source_dir, state.subdir, f) elif not isinstance(f, File): raise InvalidArguments('{} arguments must be strings or files not {!r}.'.format(name, f)) output.add_file(f) return output class GeneratedList: def __init__(self, generator, extra_args=[]): if hasattr(generator, 'held_object'): generator = generator.held_object self.generator = generator self.name = self.generator.exe self.infilelist = [] self.outfilelist = [] self.outmap = {} self.extra_depends = [] self.extra_args = extra_args def add_file(self, newfile): self.infilelist.append(newfile) outfiles = self.generator.get_base_outnames(newfile.fname) self.outfilelist += outfiles self.outmap[newfile] = outfiles def get_inputs(self): return self.infilelist def get_outputs(self): return self.outfilelist def get_outputs_for(self, filename): return self.outmap[filename] def get_generator(self): return self.generator def get_extra_args(self): return self.extra_args class Executable(BuildTarget): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) # Unless overriden, executables have no suffix or prefix. Except on # Windows and with C#/Mono executables where the suffix is 'exe' if not hasattr(self, 'prefix'): self.prefix = '' if not hasattr(self, 'suffix'): # Executable for Windows or C#/Mono if (for_windows(is_cross, environment) or for_cygwin(is_cross, environment) or 'cs' in self.compilers): self.suffix = 'exe' else: self.suffix = '' self.filename = self.name if self.suffix: self.filename += '.' + self.suffix self.outputs = [self.filename] def type_suffix(self): return "@exe" class StaticLibrary(BuildTarget): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): if 'pic' not in kwargs and 'b_staticpic' in environment.coredata.base_options: kwargs['pic'] = environment.coredata.base_options['b_staticpic'].value super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) if 'cs' in self.compilers: raise InvalidArguments('Static libraries not supported for C#.') # By default a static library is named libfoo.a even on Windows because # MSVC does not have a consistent convention for what static libraries # are called. The MSVC CRT uses libfoo.lib syntax but nothing else uses # it and GCC only looks for static libraries called foo.lib and # libfoo.a. However, we cannot use foo.lib because that's the same as # the import library. Using libfoo.a is ok because people using MSVC # always pass the library filename while linking anyway. if not hasattr(self, 'prefix'): self.prefix = 'lib' if not hasattr(self, 'suffix'): # Rust static library crates have .rlib suffix if 'rust' in self.compilers: self.suffix = 'rlib' else: self.suffix = 'a' self.filename = self.prefix + self.name + '.' + self.suffix self.outputs = [self.filename] def type_suffix(self): return "@sta" def check_unknown_kwargs(self, kwargs): self.check_unknown_kwargs_int(kwargs, known_lib_kwargs) class SharedLibrary(BuildTarget): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): self.soversion = None self.ltversion = None self.vs_module_defs = None # The import library this target will generate self.import_filename = None # The import library that Visual Studio would generate (and accept) self.vs_import_filename = None # The import library that GCC would generate (and prefer) self.gcc_import_filename = None super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) if not hasattr(self, 'prefix'): self.prefix = None if not hasattr(self, 'suffix'): self.suffix = None self.basic_filename_tpl = '{0.prefix}{0.name}.{0.suffix}' self.determine_filenames(is_cross, environment) def determine_filenames(self, is_cross, env): """ See https://github.com/mesonbuild/meson/pull/417 for details. First we determine the filename template (self.filename_tpl), then we set the output filename (self.filename). The template is needed while creating aliases (self.get_aliases), which are needed while generating .so shared libraries for Linux. Besides this, there's also the import library name, which is only used on Windows since on that platform the linker uses a separate library called the "import library" during linking instead of the shared library (DLL). The toolchain will output an import library in one of two formats: GCC or Visual Studio. When we're building with Visual Studio, the import library that will be generated by the toolchain is self.vs_import_filename, and with MinGW/GCC, it's self.gcc_import_filename. self.import_filename will always contain the import library name this target will generate. """ prefix = '' suffix = '' self.filename_tpl = self.basic_filename_tpl # If the user already provided the prefix and suffix to us, we don't # need to do any filename suffix/prefix detection. # NOTE: manual prefix/suffix override is currently only tested for C/C++ if self.prefix is not None and self.suffix is not None: pass # C# and Mono elif 'cs' in self.compilers: prefix = '' suffix = 'dll' self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' # Rust elif 'rust' in self.compilers: # Currently, we always build --crate-type=rlib prefix = 'lib' suffix = 'rlib' self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' # C, C++, Swift, Vala # Only Windows uses a separate import library for linking # For all other targets/platforms import_filename stays None elif for_windows(is_cross, env): suffix = 'dll' self.vs_import_filename = '{0}.lib'.format(self.name) self.gcc_import_filename = 'lib{0}.dll.a'.format(self.name) if self.get_using_msvc(): # Shared library is of the form foo.dll prefix = '' # Import library is called foo.lib self.import_filename = self.vs_import_filename # Assume GCC-compatible naming else: # Shared library is of the form libfoo.dll prefix = 'lib' # Import library is called libfoo.dll.a self.import_filename = self.gcc_import_filename # Shared library has the soversion if it is defined if self.soversion: self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}' else: self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' elif for_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' # On macOS, the filename can only contain the major version if self.soversion: # libfoo.X.dylib self.filename_tpl = '{0.prefix}{0.name}.{0.soversion}.{0.suffix}' else: # libfoo.dylib self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' else: prefix = 'lib' suffix = 'so' if self.ltversion: # libfoo.so.X[.Y[.Z]] (.Y and .Z are optional) self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.ltversion}' elif self.soversion: # libfoo.so.X self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}.{0.soversion}' else: # No versioning, libfoo.so self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' if self.prefix is None: self.prefix = prefix if self.suffix is None: self.suffix = suffix self.filename = self.filename_tpl.format(self) self.outputs = [self.filename] def process_kwargs(self, kwargs, environment): super().process_kwargs(kwargs, environment) # Shared library version if 'version' in kwargs: self.ltversion = kwargs['version'] if not isinstance(self.ltversion, str): raise InvalidArguments('Shared library version needs to be a string, not ' + type(self.ltversion).__name__) if not re.fullmatch(r'[0-9]+(\.[0-9]+){0,2}', self.ltversion): raise InvalidArguments('Invalid Shared library version "{0}". Must be of the form X.Y.Z where all three are numbers. Y and Z are optional.'.format(self.ltversion)) # Try to extract/deduce the soversion if 'soversion' in kwargs: self.soversion = kwargs['soversion'] if isinstance(self.soversion, int): self.soversion = str(self.soversion) if not isinstance(self.soversion, str): raise InvalidArguments('Shared library soversion is not a string or integer.') elif self.ltversion: # library version is defined, get the soversion from that # We replicate what Autotools does here and take the first # number of the version by default. self.soversion = self.ltversion.split('.')[0] # Visual Studio module-definitions file if 'vs_module_defs' in kwargs: path = kwargs['vs_module_defs'] if isinstance(path, str): if os.path.isabs(path): self.vs_module_defs = File.from_absolute_file(path) else: self.vs_module_defs = File.from_source_file(environment.source_dir, self.subdir, path) # link_depends can be an absolute path or relative to self.subdir self.link_depends.append(path) elif isinstance(path, File): # When passing a generated file. self.vs_module_defs = path # link_depends can be an absolute path or relative to self.subdir self.link_depends.append(path.absolute_path(environment.source_dir, environment.build_dir)) else: raise InvalidArguments( 'Shared library vs_module_defs must be either a string, ' 'or a file object') def check_unknown_kwargs(self, kwargs): self.check_unknown_kwargs_int(kwargs, known_lib_kwargs) def get_import_filename(self): """ The name of the import library that will be outputted by the compiler Returns None if there is no import library required for this platform """ return self.import_filename def get_import_filenameslist(self): if self.import_filename: return [self.vs_import_filename, self.gcc_import_filename] return [] def get_all_link_deps(self): return [self] + self.get_transitive_link_deps() def get_aliases(self): """ If the versioned library name is libfoo.so.0.100.0, aliases are: * libfoo.so.0 (soversion) -> libfoo.so.0.100.0 * libfoo.so (unversioned; for linking) -> libfoo.so.0 Same for dylib: * libfoo.dylib (unversioned; for linking) -> libfoo.0.dylib """ aliases = {} # Aliases are only useful with .so and .dylib libraries. Also if # there's no self.soversion (no versioning), we don't need aliases. if self.suffix not in ('so', 'dylib') or not self.soversion: return {} # With .so libraries, the minor and micro versions are also in the # filename. If ltversion != soversion we create an soversion alias: # libfoo.so.0 -> libfoo.so.0.100.0 # Where libfoo.so.0.100.0 is the actual library if self.suffix == 'so' and self.ltversion and self.ltversion != self.soversion: alias_tpl = self.filename_tpl.replace('ltversion', 'soversion') ltversion_filename = alias_tpl.format(self) aliases[ltversion_filename] = self.filename # libfoo.so.0/libfoo.0.dylib is the actual library else: ltversion_filename = self.filename # Unversioned alias: # libfoo.so -> libfoo.so.0 # libfoo.dylib -> libfoo.0.dylib aliases[self.basic_filename_tpl.format(self)] = ltversion_filename return aliases def type_suffix(self): return "@sha" # A shared library that is meant to be used with dlopen rather than linking # into something else. class SharedModule(SharedLibrary): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): if 'version' in kwargs: raise MesonException('Shared modules must not specify the version kwarg.') if 'soversion' in kwargs: raise MesonException('Shared modules must not specify the soversion kwarg.') super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) self.import_filename = None class CustomTarget(Target): known_kwargs = {'input': True, 'output': True, 'command': True, 'capture': False, 'install': True, 'install_dir': True, 'build_always': True, 'depends': True, 'depend_files': True, 'depfile': True, 'build_by_default': True, 'override_options': True, } def __init__(self, name, subdir, kwargs, absolute_paths=False): super().__init__(name, subdir, False) self.dependencies = [] self.extra_depends = [] self.depend_files = [] # Files that this target depends on but are not on the command line. self.depfile = None self.process_kwargs(kwargs) self.extra_files = [] # Whether to use absolute paths for all files on the commandline self.absolute_paths = absolute_paths unknowns = [] for k in kwargs: if k not in CustomTarget.known_kwargs: unknowns.append(k) if len(unknowns) > 0: mlog.warning('Unknown keyword arguments in target %s: %s' % (self.name, ', '.join(unknowns))) def __lt__(self, other): return self.get_id() < other.get_id() def __repr__(self): repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.command) def get_id(self): return self.name + self.type_suffix() def get_target_dependencies(self): deps = self.dependencies[:] deps += self.extra_depends for c in self.sources: if hasattr(c, 'held_object'): c = c.held_object if isinstance(c, (BuildTarget, CustomTarget)): deps.append(c) return deps def flatten_command(self, cmd): if not isinstance(cmd, list): cmd = [cmd] final_cmd = [] for c in cmd: if hasattr(c, 'held_object'): c = c.held_object if isinstance(c, str): final_cmd.append(c) elif isinstance(c, File): self.depend_files.append(c) final_cmd.append(c) elif isinstance(c, dependencies.ExternalProgram): if not c.found(): m = 'Tried to use not-found external program {!r} in "command"' raise InvalidArguments(m.format(c.name)) self.depend_files.append(File.from_absolute_file(c.get_path())) final_cmd += c.get_command() elif isinstance(c, (BuildTarget, CustomTarget)): self.dependencies.append(c) final_cmd.append(c) elif isinstance(c, list): final_cmd += self.flatten_command(c) else: raise InvalidArguments('Argument {!r} in "command" is invalid'.format(c)) return final_cmd def process_kwargs(self, kwargs): super().process_kwargs(kwargs) self.sources = kwargs.get('input', []) if not isinstance(self.sources, list): self.sources = [self.sources] if 'output' not in kwargs: raise InvalidArguments('Missing keyword argument "output".') self.outputs = kwargs['output'] if not isinstance(self.outputs, list): self.outputs = [self.outputs] # This will substitute values from the input into output and return it. inputs = get_sources_string_names(self.sources) values = get_filenames_templates_dict(inputs, []) for i in self.outputs: if not(isinstance(i, str)): raise InvalidArguments('Output argument not a string.') if '/' in i: raise InvalidArguments('Output must not contain a path segment.') if '@INPUT@' in i or '@INPUT0@' in i: m = 'Output cannot contain @INPUT@ or @INPUT0@, did you ' \ 'mean @PLAINNAME@ or @BASENAME@?' raise InvalidArguments(m) # We already check this during substitution, but the error message # will be unclear/confusing, so check it here. if len(inputs) != 1 and ('@PLAINNAME@' in i or '@BASENAME@' in i): m = "Output cannot contain @PLAINNAME@ or @BASENAME@ when " \ "there is more than one input (we can't know which to use)" raise InvalidArguments(m) self.outputs = substitute_values(self.outputs, values) self.capture = kwargs.get('capture', False) if self.capture and len(self.outputs) != 1: raise InvalidArguments('Capturing can only output to a single file.') if 'command' not in kwargs: raise InvalidArguments('Missing keyword argument "command".') if 'depfile' in kwargs: depfile = kwargs['depfile'] if not isinstance(depfile, str): raise InvalidArguments('Depfile must be a string.') if os.path.split(depfile)[1] != depfile: raise InvalidArguments('Depfile must be a plain filename without a subdirectory.') self.depfile = depfile self.command = self.flatten_command(kwargs['command']) if self.capture: for c in self.command: if isinstance(c, str) and '@OUTPUT@' in c: raise InvalidArguments('@OUTPUT@ is not allowed when capturing output.') if 'install' in kwargs: self.install = kwargs['install'] if not isinstance(self.install, bool): raise InvalidArguments('"install" must be boolean.') if self.install: if 'install_dir' not in kwargs: raise InvalidArguments('"install_dir" must be specified ' 'when installing a target') # If an item in this list is False, the output corresponding to # the list index of that item will not be installed self.install_dir = typeslistify(kwargs['install_dir'], (str, bool)) else: self.install = False self.install_dir = [None] self.build_always = kwargs.get('build_always', False) if not isinstance(self.build_always, bool): raise InvalidArguments('Argument build_always must be a boolean.') extra_deps = kwargs.get('depends', []) if not isinstance(extra_deps, list): extra_deps = [extra_deps] for ed in extra_deps: while hasattr(ed, 'held_object'): ed = ed.held_object if not isinstance(ed, (CustomTarget, BuildTarget)): raise InvalidArguments('Can only depend on toplevel targets: custom_target or build_target (executable or a library)') self.extra_depends.append(ed) depend_files = kwargs.get('depend_files', []) if not isinstance(depend_files, list): depend_files = [depend_files] for i in depend_files: if isinstance(i, (File, str)): self.depend_files.append(i) else: mlog.debug(i) raise InvalidArguments('Unknown type {!r} in depend_files.'.format(type(i).__name__)) def get_dependencies(self): return self.dependencies def should_install(self): return self.install def get_custom_install_dir(self): return self.install_dir def get_outputs(self): return self.outputs def get_filename(self): return self.outputs[0] def get_sources(self): return self.sources def get_generated_lists(self): genlists = [] for c in self.sources: if hasattr(c, 'held_object'): c = c.held_object if isinstance(c, GeneratedList): genlists.append(c) return genlists def get_generated_sources(self): return self.get_generated_lists() def type_suffix(self): return "@cus" class RunTarget(Target): def __init__(self, name, command, args, dependencies, subdir): super().__init__(name, subdir, False) self.command = command self.args = args self.dependencies = dependencies def __lt__(self, other): return self.get_id() < other.get_id() def __repr__(self): repr_str = "<{0} {1}: {2}>" return repr_str.format(self.__class__.__name__, self.get_id(), self.command) def get_id(self): return self.name + self.type_suffix() def get_dependencies(self): return self.dependencies def get_generated_sources(self): return [] def get_sources(self): return [] def should_install(self): return False def get_filename(self): return self.name def type_suffix(self): return "@run" class Jar(BuildTarget): def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) for s in self.sources: if not s.endswith('.java'): raise InvalidArguments('Jar source %s is not a java file.' % s) self.filename = self.name + '.jar' self.outputs = [self.filename] self.java_args = kwargs.get('java_args', []) def get_main_class(self): return self.main_class def type_suffix(self): return "@jar" def get_java_args(self): return self.java_args def validate_cross_install(self, environment): # All jar targets are installable. pass class ConfigureFile: def __init__(self, subdir, sourcename, targetname, configuration_data): self.subdir = subdir self.sourcename = sourcename self.targetname = targetname self.configuration_data = configuration_data def __repr__(self): repr_str = "<{0}: {1} -> {2}>" src = os.path.join(self.subdir, self.sourcename) dst = os.path.join(self.subdir, self.targetname) return repr_str.format(self.__class__.__name__, src, dst) def get_configuration_data(self): return self.configuration_data def get_subdir(self): return self.subdir def get_source_name(self): return self.sourcename def get_target_name(self): return self.targetname class ConfigurationData: def __init__(self): super().__init__() self.values = {} def __repr__(self): return repr(self.values) def __contains__(self, value): return value in self.values def get(self, name): return self.values[name] # (val, desc) def keys(self): return self.values.keys() # A bit poorly named, but this represents plain data files to copy # during install. class Data: def __init__(self, sources, install_dir, install_mode=None): self.sources = sources self.install_dir = install_dir self.install_mode = install_mode if not isinstance(self.sources, list): self.sources = [self.sources] for s in self.sources: assert(isinstance(s, File)) class RunScript(dict): def __init__(self, script, args): super().__init__() assert(isinstance(script, list)) assert(isinstance(args, list)) self['exe'] = script self['args'] = args class TestSetup: def __init__(self, *, exe_wrapper=None, gdb=None, timeout_multiplier=None, env=None): self.exe_wrapper = exe_wrapper self.gdb = gdb self.timeout_multiplier = timeout_multiplier self.env = env def get_sources_string_names(sources): ''' For the specified list of @sources which can be strings, Files, or targets, get all the output basenames. ''' names = [] for s in sources: if hasattr(s, 'held_object'): s = s.held_object if isinstance(s, str): names.append(s) elif isinstance(s, (BuildTarget, CustomTarget, GeneratedList)): names += s.get_outputs() elif isinstance(s, File): names.append(s.fname) else: raise AssertionError('Unknown source type: {!r}'.format(s)) return names meson-0.40.1/mesonbuild/mlog.py0000644000175000017500000000643413074426732017777 0ustar jpakkanejpakkane00000000000000# Copyright 2013-2014 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys, os, platform, io """This is (mostly) a standalone module used to write logging information about Meson runs. Some output goes to screen, some to logging dir and some goes to both.""" colorize_console = platform.system().lower() != 'windows' and os.isatty(sys.stdout.fileno()) and \ os.environ.get('TERM') != 'dumb' log_dir = None log_file = None def initialize(logdir): global log_dir, log_file log_dir = logdir log_file = open(os.path.join(logdir, 'meson-log.txt'), 'w', encoding='utf8') def shutdown(): global log_file if log_file is not None: log_file.close() class AnsiDecorator: plain_code = "\033[0m" def __init__(self, text, code): self.text = text self.code = code def get_text(self, with_codes): if with_codes: return self.code + self.text + AnsiDecorator.plain_code return self.text def bold(text): return AnsiDecorator(text, "\033[1m") def red(text): return AnsiDecorator(text, "\033[1;31m") 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") def process_markup(args, keep): arr = [] for arg in args: if isinstance(arg, str): arr.append(arg) elif isinstance(arg, AnsiDecorator): arr.append(arg.get_text(keep)) else: arr.append(str(arg)) return arr def force_print(*args, **kwargs): # _Something_ is going to get printed. try: print(*args, **kwargs) except UnicodeEncodeError: iostr = io.StringIO() kwargs['file'] = iostr print(*args, **kwargs) cleaned = iostr.getvalue().encode('ascii', 'replace').decode('ascii') print(cleaned) def debug(*args, **kwargs): arr = process_markup(args, False) if log_file is not None: print(*arr, file=log_file, **kwargs) # Log file never gets ANSI codes. log_file.flush() def log(*args, **kwargs): arr = process_markup(args, False) if log_file is not None: print(*arr, file=log_file, **kwargs) # Log file never gets ANSI codes. log_file.flush() if colorize_console: arr = process_markup(args, True) force_print(*arr, **kwargs) def warning(*args, **kwargs): log(yellow('WARNING:'), *args, **kwargs) # Format a list for logging purposes as a string. It separates # all but the last item with commas, and the last with 'and'. def format_list(list): l = len(list) if l > 2: return ' and '.join([', '.join(list[:-1]), list[-1]]) elif l == 2: return ' and '.join(list) elif l == 1: return list[0] else: return '' meson-0.40.1/mesonbuild/__init__.py0000644000175000017500000000000012650745767020572 0ustar jpakkanejpakkane00000000000000meson-0.40.1/mesonbuild/coredata.py0000644000175000017500000003572013100701155020604 0ustar jpakkanejpakkane00000000000000# Copyright 2012-2017 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import pickle, os, uuid from pathlib import PurePath from collections import OrderedDict from .mesonlib import MesonException, commonpath from .mesonlib import default_libdir, default_libexecdir, default_prefix import ast version = '0.40.1' backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'xcode'] class UserOption: def __init__(self, name, description, choices): super().__init__() self.name = name self.choices = choices self.description = description def parse_string(self, valuestring): return valuestring # Check that the input is a valid value and return the # "cleaned" or "native" version. For example the Boolean # option could take the string "true" and return True. def validate_value(self, value): raise RuntimeError('Derived option class did not override validate_value.') class UserStringOption(UserOption): def __init__(self, name, description, value, choices=None): super().__init__(name, description, choices) self.set_value(value) def validate(self, value): if not isinstance(value, str): raise MesonException('Value "%s" for string option "%s" is not a string.' % (str(value), self.name)) def set_value(self, newvalue): self.validate(newvalue) self.value = newvalue def validate_value(self, value): self.validate(value) return value class UserBooleanOption(UserOption): def __init__(self, name, description, value): super().__init__(name, description, [True, False]) self.set_value(value) def tobool(self, thing): if isinstance(thing, bool): return thing if thing.lower() == 'true': return True if thing.lower() == 'false': return False raise MesonException('Value %s is not boolean (true or false).' % thing) def set_value(self, newvalue): self.value = self.tobool(newvalue) def parse_string(self, valuestring): if valuestring == 'false': return False if valuestring == 'true': return True raise MesonException('Value "%s" for boolean option "%s" is not a boolean.' % (valuestring, self.name)) def __bool__(self): return self.value def validate_value(self, value): return self.tobool(value) class UserComboOption(UserOption): def __init__(self, name, description, choices, value): super().__init__(name, description, choices) if not isinstance(self.choices, list): raise MesonException('Combo choices must be an array.') for i in self.choices: if not isinstance(i, str): raise MesonException('Combo choice elements must be strings.') self.set_value(value) def set_value(self, newvalue): if newvalue not in self.choices: optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices]) raise MesonException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (newvalue, self.name, optionsstring)) self.value = newvalue def validate_value(self, value): if value not in self.choices: raise MesonException('Value %s not one of accepted values.' % value) return value class UserStringArrayOption(UserOption): def __init__(self, name, description, value, **kwargs): super().__init__(name, description, kwargs.get('choices', [])) self.set_value(value) def validate(self, value): if isinstance(value, str): if not value.startswith('['): raise MesonException('Valuestring does not define an array: ' + value) newvalue = ast.literal_eval(value) else: newvalue = value if not isinstance(newvalue, list): raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue))) for i in newvalue: if not isinstance(i, str): raise MesonException('String array element "{0}" is not a string.'.format(str(newvalue))) return newvalue def set_value(self, newvalue): self.value = self.validate(newvalue) def validate_value(self, value): self.validate(value) return value # This class contains all data that must persist over multiple # invocations of Meson. It is roughly the same thing as # cmakecache. class CoreData: def __init__(self, options): self.guid = str(uuid.uuid4()).upper() self.test_guid = str(uuid.uuid4()).upper() self.regen_guid = str(uuid.uuid4()).upper() self.target_guids = {} self.version = version self.init_builtins(options) self.user_options = {} self.compiler_options = {} self.base_options = {} # These external_*args, are set via env vars CFLAGS, LDFLAGS, etc # but only when not cross-compiling. 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: self.cross_file = None self.wrap_mode = options.wrap_mode self.compilers = OrderedDict() self.cross_compilers = OrderedDict() self.deps = {} self.modules = {} # Only to print a warning if it changes between Meson invocations. self.pkgconf_envvar = os.environ.get('PKG_CONFIG_PATH', '') def sanitize_prefix(self, prefix): if not os.path.isabs(prefix): raise MesonException('prefix value {!r} must be an absolute path' ''.format(prefix)) if prefix.endswith('/') or prefix.endswith('\\'): # On Windows we need to preserve the trailing slash if the # string is of type 'C:\' because 'C:' is not an absolute path. if len(prefix) == 3 and prefix[1] == ':': pass else: prefix = prefix[:-1] return prefix def sanitize_dir_option_value(self, prefix, option, value): ''' If the option is an installation directory option and the value is an absolute path, check that it resides within prefix and return the value as a path relative to the prefix. This way everyone can do f.ex, get_option('libdir') and be sure to get the library directory relative to prefix. ''' if option.endswith('dir') and os.path.isabs(value) and \ option not in builtin_dir_noprefix_options: # Value must be a subdir of the prefix # commonpath will always return a path in the native format, so we # must use pathlib.PurePath to do the same conversion before # comparing. if commonpath([value, prefix]) != str(PurePath(prefix)): m = 'The value of the {!r} option is {!r} which must be a ' \ 'subdir of the prefix {!r}.\nNote that if you pass a ' \ 'relative path, it is assumed to be a subdir of prefix.' raise MesonException(m.format(option, value, prefix)) # Convert path to be relative to prefix skip = len(prefix) + 1 value = value[skip:] return value def init_builtins(self, options): self.builtins = {} # Sanitize prefix options.prefix = self.sanitize_prefix(options.prefix) # Initialize other builtin options for key in get_builtin_options(): if hasattr(options, key): value = getattr(options, key) value = self.sanitize_dir_option_value(options.prefix, key, value) setattr(options, key, value) else: value = get_builtin_option_default(key) args = [key] + builtin_options[key][1:-1] + [value] self.builtins[key] = builtin_options[key][0](*args) def get_builtin_option(self, optname): if optname in self.builtins: return self.builtins[optname].value raise RuntimeError('Tried to get unknown builtin option %s.' % optname) def set_builtin_option(self, optname, value): if optname == 'prefix': value = self.sanitize_prefix(value) elif optname in self.builtins: prefix = self.builtins['prefix'].value value = self.sanitize_dir_option_value(prefix, optname, value) else: raise RuntimeError('Tried to set unknown builtin option %s.' % optname) self.builtins[optname].set_value(value) def validate_option_value(self, option_name, override_value): for opts in (self.builtins, self.base_options, self.compiler_options, self.user_options): if option_name in opts: opt = opts[option_name] return opt.validate_value(override_value) raise MesonException('Tried to validate unknown option %s.' % option_name) def load(filename): load_fail_msg = 'Coredata file {!r} is corrupted. Try with a fresh build tree.'.format(filename) try: with open(filename, 'rb') as f: obj = pickle.load(f) except pickle.UnpicklingError: raise MesonException(load_fail_msg) if not isinstance(obj, CoreData): raise MesonException(load_fail_msg) if obj.version != version: raise MesonException('Build directory has been generated with Meson version %s, which is incompatible with current version %s.\nPlease delete this build directory AND create a new one.' % (obj.version, version)) return obj def save(obj, filename): if obj.version != version: raise MesonException('Fatal version mismatch corruption.') with open(filename, 'wb') as f: pickle.dump(obj, f) def get_builtin_options(): return list(builtin_options.keys()) def is_builtin_option(optname): return optname in get_builtin_options() def get_builtin_option_choices(optname): if is_builtin_option(optname): if builtin_options[optname][0] == UserStringOption: return None elif builtin_options[optname][0] == UserBooleanOption: return [True, False] else: return builtin_options[optname][2] else: raise RuntimeError('Tried to get the supported values for an unknown builtin option \'%s\'.' % optname) def get_builtin_option_description(optname): if is_builtin_option(optname): return builtin_options[optname][1] else: raise RuntimeError('Tried to get the description for an unknown builtin option \'%s\'.' % optname) def get_builtin_option_default(optname): if is_builtin_option(optname): o = builtin_options[optname] if o[0] == UserComboOption: return o[3] return o[2] else: raise RuntimeError('Tried to get the default value for an unknown builtin option \'%s\'.' % optname) builtin_options = { 'buildtype': [UserComboOption, 'Build type to use.', ['plain', 'debug', 'debugoptimized', 'release', 'minsize'], 'debug'], 'strip': [UserBooleanOption, 'Strip targets on install.', False], 'unity': [UserComboOption, 'Unity build.', ['on', 'off', 'subprojects'], 'off'], 'prefix': [UserStringOption, 'Installation prefix.', default_prefix()], 'libdir': [UserStringOption, 'Library directory.', default_libdir()], 'libexecdir': [UserStringOption, 'Library executable directory.', default_libexecdir()], 'bindir': [UserStringOption, 'Executable directory.', 'bin'], 'sbindir': [UserStringOption, 'System executable directory.', 'sbin'], 'includedir': [UserStringOption, 'Header file directory.', 'include'], 'datadir': [UserStringOption, 'Data file directory.', 'share'], 'mandir': [UserStringOption, 'Manual page directory.', 'share/man'], 'infodir': [UserStringOption, 'Info page directory.', 'share/info'], 'localedir': [UserStringOption, 'Locale data directory.', 'share/locale'], # sysconfdir, localstatedir and sharedstatedir are a bit special. These defaults to ${prefix}/etc, # ${prefix}/var and ${prefix}/com but nobody uses that. Instead they always set it # manually to /etc, /var and /var/lib. This default values is thus pointless and not really used # but we set it to this for consistency with other systems. # # Projects installing to sysconfdir, localstatedir or sharedstatedir probably want # to set the following in project(): # # default_options : ['sysconfdir=/etc', 'localstatedir=/var', 'sharedstatedir=/var/lib'] 'sysconfdir': [UserStringOption, 'Sysconf data directory.', 'etc'], 'localstatedir': [UserStringOption, 'Localstate data directory.', 'var'], 'sharedstatedir': [UserStringOption, 'Architecture-independent data directory.', 'com'], 'werror': [UserBooleanOption, 'Treat warnings as errors.', False], 'warning_level': [UserComboOption, 'Compiler warning level to use.', ['1', '2', '3'], '1'], 'layout': [UserComboOption, 'Build directory layout.', ['mirror', 'flat'], 'mirror'], 'default_library': [UserComboOption, 'Default library type.', ['shared', 'static'], 'shared'], 'backend': [UserComboOption, 'Backend to use.', backendlist, 'ninja'], 'stdsplit': [UserBooleanOption, 'Split stdout and stderr in test logs.', True], 'errorlogs': [UserBooleanOption, "Whether to print the logs from failing tests.", True], } # Installation directories that can reside in a path outside of the prefix builtin_dir_noprefix_options = {'sysconfdir', 'localstatedir', 'sharedstatedir'} forbidden_target_names = {'clean': None, 'clean-ctlist': None, 'clean-gcno': None, 'clean-gcda': None, 'coverage-text': None, 'coverage-xml': None, 'coverage-html': None, 'phony': None, 'PHONY': None, 'all': None, 'test': None, 'benchmark': None, 'install': None, 'uninstall': None, 'build.ninja': None, 'scan-build': None, 'reconfigure': None, } meson-0.40.1/graphics/0000755000175000017500000000000013100703042016075 5ustar jpakkanejpakkane00000000000000meson-0.40.1/graphics/meson_logo_big.png0000644000175000017500000010463012650745767021626 0ustar jpakkanejpakkane00000000000000‰PNG  IHDRl„8°q®sBIT|dˆ pHYs.#.#x„?vtEXtSoftwarewww.inkscape.org›ī< IDATxœģŻyų¦ē|÷ń÷93ÉL&#ĖdO$™,²H‚„$N‘„ČJ‚Č"„øÖ®ÕG©¶Ŗ<¤ŌÖŚ¢Øh«URMmW‹¢O5m“ŌZA"’ĢõüqßIf&³ü–ū¾æ×ņ~LJ¼Iųż~Ÿū<Æ+5Mƒ$MK.i°3°Ėų÷»Ū+Ēæoī·ōÆ% ֎-ęo~±ĮƟ/šŸūY]5?Č’$µH.i``ĒMü¾Xl½‘_›śē7öÆ5ĄÆ€›7ų}¾üKąGĄĒæ’hŻ\WĶ/'ü_‘$MLr°‘4¹¤•ŒĘ—Ū˜]6ųµį?·=£aehn~\7žõƒužx£’Ųo%I³’KŚŲŲŲ•Ńą²©fŻß—GōNэl0ālę’ųf]5?ŽI•446’n7cö’Ś_{rdz2,°’~Ī<FŸ Ž“*Ij›\Rbōõś¶!fsæß%(³n¾9žõüń·żś,il¤É%-a4¾¬;ʬ;ĪģW§h}ś7ׁē:ÆjIR7å’VūūŽķĆh|YwˆŁXÕØŪŻ |›ĶŒ:uÕÜ—'©+l¤žÉ%-ażafFßąõķ(³ęēWŒ®jż£oæ¶ĮÆÆ×Usc\ž$ S.i;īcÖżµfüū® óŠq_]üpÕæ®­«fmd˜¤öp°‘:,—“ øp/ąžćߏ`ō@^i!ą»ŒĘ›k¹ó óŻŗņ ‡$ĶW.ią@6=Źģ§6ł%p5wrž«®š["Ć$ĶžƒŌ¹¤= 2ėž:?mÓlż’;9’|¾®šė#Ć$©MĘŖœ<8‰Ń+~ĶÖBŻ |ųwÖr¾ZWĶM‘a’¦ĒĮFj™ńk°ęĪćĢĪ‘]Ņ4ĄŸ[ēחż&RŅP䒖÷c4ΜƒĻ“ŃōŻ \ĆCĪ—ĻÕUóõČ(I“į`#æ™é$ątąXąp`Eh”47’Ńxó)ącuÕü 6I’&'—tp.p p~żV{ü€õ?Dł\]5?ŠM’4_6R€\Ņ!Ąć_'ąƒ€5 £Ož®> |Ś8’ŗ&—“p>š(ąčąi>ž‹õGœ®«ęW±I’6ĒĮFš\ŅVŒ>}{£‘fæŲ"©ndtņę£ĄuÕüæąIŚØ\Ņ.ŒNŅ\Ļ¢Q?üø’Ń×įŌUsulޤ 9ŲHS’KJŒī²?8Ų)¶Hj½kĖ€÷ÖUó„čIƖKŚ8›ŃHó |śļ›ŒĘ›2ŗĘüćąišl¤ Ė%Żøx4£×tJšæ’ŽĖh¼łJtŒ¤į_[ž ą"`epŽe-šyFćĶ‡źŖł§ąil¤ Č%ķ<žŃiš#ƒs¤¾¹ŠŃɛ?÷ø¶¤iÉ% ü&£—xåIZß7øćģ?GĒHCį`#-B.épąŒ†?…“¦ļJąO€÷×UsKp‹¤ŽĖ%mĆčkųowĪ‘ŗāF§`/««ę_¢c¤>s°‘ę)—“8 x&£×qKš½ļoŽTWĶw¢c$uK.iOą©Ą“€ƒs¤.»š;®0_#õƒ4G¹¤€'OĆ·Qź¦\R~x¾@꺟3z8ńĖėŖłAtŒŌ6œ\Ņ#€WūD·H ÷9ą)uÕ|1:DŅÜå’ŽÜ/ŗEŅDż„Ń›_WWĶĶŃ1R4 F.iWąMĄĆ¢[$µŹ­ŒŽc?殚ŸFĒHŚ“ń۟žĻčMŽ[ēHšž«=wīļ¢C¤H6„\Ņ9Œ^%øst‹¤ÖśoąQuÕ|&:DŅå’Nž_ É匆›ÆF‡HlŌk¹¤€×F·Hź„[}z‰Æ—Śa|ŖęUĄ“¢[$…ø™Ń«Ą_äIX ƒz+—tšV`ÆčIóą±>ųPŠ•Kŗ'šąŠčIįžųŗjž<:DšõĪų PƞŻ"©Ó¾\XWĶ•Ń!ŅŠŒßõŒŽåŪ%­ė2ą©uÕü0:Dš6õJ.énĄ_GD·Hź…[/öõßŅlä’v pzpФöś.škuÕ|(:Dš&õF.élFßąmœ"©®Ī©«ę†č©ĻrIŽģŻ"©ŽĀč”Ä?‹‘¦ĮĮF—KZüą·£[$õŚ—€3źŖł~tˆŌ7¹¤åĄόn‘Ō9×U]5ŸŒ‘&ĶĮF–KŚųsąÄčIƒp pj]5_‹‘ś"—“š×Ą=¢[$uÖZąåĄļÕUsktŒ4)6ź¬\Ņż=tlčIƒņ=F'm¾"uŻųkłū£[$õĀߏō-ź‹%ŃŅBä’.>Žc¤ŁŪų‡\Ņ¢C¤.Ė%UŒ¾–;ÖHš”_Ģ%"M‚'lŌ9¹¤ē/Rt‹¤A» xt]5"uI.i šRą9Ń-’zė&ą™uÕ¼):DZ uF.i)šząIŃ-’4¶øØ®šwE‡H]KZ¼ xht‹¤Ax+š“ŗjnŠ‘ĀĮFKŚ–ŃĆ…ĻŒn‘¤ Ü <¤®š+¢C¤6Ė%ķü->\XŅl}xD]5’"Ķ—ƒZ/—“+šAąččIŚ„Ÿ'ÖUóÅč©rI÷eō&ØŻ¢[$ Ņ·ÓėŖłJtˆ4>tX­–KZŌ8ÖHj·UĄå¹¤ż£C¤¶É%\‰c¤8{ŸĢ%Ż/:DšµÖx¬¹š I]°š‘\Ņ.Ń!R[Œßõ`ypŠ$ķ|,—ä#Ō6j„\Ņ~Ą?ūF·HŅ<|hüÜ-iŠrIOŽ,n‘¤±m€÷ē’"Ķ…ƒZg|„ąJ`ŸąIZˆ£÷咖E‡HQrIĻ^¤čIŚĄ2ąķ¹¤gG‡H[ā`£VÉ%€c¤ī;ųĆč)B.éEĄĖ¢;$i3šņ\Ņ%Ń!Ņęų–(µĘ:cĶ]ƒS$iÖ§ŌUó‰čiVrIÆžŻ!IópI]5æ!mŒƒZ!—“7šYk$õĖw€{ŌUóĆčišrIK€7æŻ"I šĀŗjž :BڐW¢.—“#šak$õĻžĄ[£#¤i?ÆéRk$u× sIωސ6ä`£P¹¤Ąßwn‘¤)yX.é)ŃŅ4ä’šąĀčIZ¤KrIψސÖå`£0ććÓŻ"ISöŠ\ŅaŃҼxtt„$MČ«sIžTk8Ų(ŅēDGHŅ l¼g|ŖPź…\Ņó?–Ō' xC.é±Ń!8Ų(ČųŽØßäI’#€FGH“0¾ę÷¢čIš‚%ĄŪrI§D‡H¾%J3—Kŗx7£[’†ä&ąŠŗj®‘*—t>šüąORæżČuÕü{tˆ†Ė/“š©\Ņ!Ą[p¬‘4LˁK¢#¤…Ź% ¼懔ŌŪŹ%ķ¢įņ„f&—“ š9ąščI v\]5ŸŽę#—t,šq`ŪčIš”Ļ'ÕUsStˆ†ĒOG4KÆĮ±F’^9~²Ō ¹¤CįX#ixī¼-:BĆä`£™Č%]\Ż!I-q,pAt„4¹¤];E·HRGē’^”įńJ”¦.—tšĻĄŖčIj‘o×UóĖčiSrI[1ŗu|t‹$µĄuÕ¼7:BĆį MU.iš>k$iCūϊސ¶ąU8ÖHŅmŽ2~‰Š46š¶?ī!I-õ¼\ŅŽŃŅĘä’<-ŗC’Zd𹤕Ń!MM.éąIŃ’Ōbwž!m(—t š§Ń’ŌB‡”aš6šŠ\ŅŻ=·ę.Ń-’Ōr_¬«ęÖč —“£Æį{E·HR‹]\WĶ[£#Ōož°ŃÄ咖ļűF’ęb pVt„·?dų/q¬‘¤-ym.ÉG?hŖl4 ÆŽŒŽ¤yft€4öąøčIź€m=ĻĘ©556šØ\ŅyĄS£;$©c˜K:":BƖKŗxrt‡$uČŻ€7FGØæl41¹¤€·DwHRG=#:@ƕK:xmt‡$uŠ£rI‹ŽP?9Ųh’Žl!Iõ˜\Ņźč Ļų¹5¬ˆn‘¤Žz}.ɟƒ4q6šˆ\Ņ…xē]’cąāč Ņ €£¢#$©Ćö.‰ŽP’ųZo-Z.i[ą«ĄžŃ-’Ōq×ŌUs`t„†#—t_ąÓĄŅčIźø8±®šOE‡Ø?äŗjnQ·yĀF ’KZ¼:ŗC’z(gEGØ×ވc$MÓŃĄ3£#Ō}6Zا‡FGHROy-JS‘K:8'ŗC’ąsIk‚Ōq6š·\Ņ.Ą ¢;$©Ē4~ƒ41ćæ§^Ż!I±-£Ņ‚9Ųh!^ģ!I=¶8-:B½óūĄŽŃ’4 §ę’.ŠŽPw9Ųh^rIGOŒī¤šõޚ˜\ŅĮĄoEwHҽr|CAš7Ķ×kšļIš…DØW^ l!I“£Ÿ”¤yóoĶY.éŃĄqŃ’4ūę’VGGØūrIē§DwHŅ€]K:#:BŻć`£9?Øš¢;$i`ŽŒP·æ~æ2ŗC’ÄĖsIžü­yńoĶÕS½¢#$i`l“XĻī!Iā0ą1ŃźmQ.išĢčI £¢Ō]¹¤CšAƒŌ&Kņybš3ĶÅyųéœ$Eš„浥VŃ’¤Ū­ž”īp°Ń\<+:@’ź ń3H¤yÉ%=89ŗC’t'æē×vĶ•ƒ6+—tąččIØ%Ą=£#ŌI IŚØŻšqĶ‘ƒ¶Ä’3‘¤X^‹Ņ¼ä’NŽī$mҳsI«£#Ō~6ڤ\ŅžĄĆ£;$ią|š°ęėEŃ’¤ĶŚx^t„ŚĻĮF›óų÷ˆ$EóJ”ę,—t£;$I[ōō\Ņ^Ńj7×F咶žŻ!IāĄčuЧk$©V/ˆŽP»9ŲhS~ X!Ibū\ŅŽŃjæ\ŅC€c¢;$Isöų\ŅŻ¢#Ō^6ŗ“\Ņ2ąŃ’¤Ūķ Nxat€$i^–/ŽŽP{9ŲhcĪö‰Ž$Żn’čµ[.锥}¢;$Ióv^.É7Bj£l“1¾Ź[’ŚÅ6ŚŸƒ IŻ”€—FG؝l“ž\Ņż€c£;$Iėq°Ń&咎Ć׿KR—–K:1:Bķć`£ yŗF’ŚĒ+Qڜ§EH’ĶS6ŗŻ.—“8;¶B’“ž°ŃFå’vcōģ9IR·å\ŅéŃj­ėiĄŅčIŅģ›KJŃj„‹­£#$Ińœčµ‹ƒČ%­Ż!IŚØåĄ^Ńj—\ŅRąIŃ’¤‰y`.É7žév6ŗĶłĄNŃ’¤MņZ”6t°wt„$i¢Ėf€l&—“ščIŅ‚xĀfø¼%IĆvN.É[ć`3<æŽŻ%©«vĪ%-ŽPˆ³£$I”–āM‰Įń÷É%m\Ż!IZ”=¢āŃ’¤pOČ%­ˆŽŠģ8Ų ĖŁĄnŃ’¤Eń96“Kŗ;°Kt‡$)ÜNĄ#£#4;6Ćā:Iź>Ÿc3<ˆ$µĘS£4;6‘K:æį“¤>p°ž£$I­qŒÆų›įxrt€$i"¼5<6’¤uyŹf l —“x\t‡$i":BÓē`3 >lX’śĆ6Ćāu(IŅĘ<%—”¢#4]6=—K:øwt‡$ib.Č%m”Ér°éŸÓ€½£#$ISå ›žs°‘$ĶĒjąĢčM–ƒM’\ Iš:›Ė%%ą°čIRē<.:@“å`Ó#¹¤ķ€‡FwH’¦nõų‡zõÓ~ĄŖčIRēœ1~Ė zĀĮ¦_ζ‰Ž$MŻR`‡čMĶŻ£$I“šččMŽƒMæ<6:@’43^‹źÆ5Ń’¤Īņ=ā`Ó¹¤}€£;$I3㛢śkMt€$©³ŽŹ%”Ép°éĒ>Ļ@’†Ć6żµ&:@’Ōi>|ø'lśĆėP’4,6żµ&:@’Ōi꒖FGhńlz —tąčIŅLy%ŖæÖDH’:mąŌč-žƒM?ų`)IOŲōP.iŽq’¤ÅógÄp°éø\Ņ2ą‚čIŅĢłC}?ķ Iꅇ璶ŽŠā8ŲtßéĄ.Ń’¤™ó„M?­‰$õĀ ąüč-ŽƒM÷ł°aI&›~Z Iź ßÕq66>āöŠčIRÆDõӚčIRo—K: :B ē`Ómē1:ź&IOŲō“ϰ‘$M’ī0›nó:”$ ן\RŠŽŠÄķ Iź•‹ü~”»l:*—“8>¶B’hąŪśĒ«n’¤IZœ”…q°é® —RI6ÆEõƒ$iŅ|ųpG9Ųt—×”$I6ż³::@’Ō;ēę’VFGhžl:(—t ppt‡$)œ§1z$—“ XŻ!Iź»gGGhžlŗÉÓ5’$š„Mß8ĄI’¦ÅkQä`Ó1¹¤­€ ¢;$I­ą`Ó/6’¤iyP.iÆčĶƒM÷œß K’Füæ_üė)Iš–%xS£slŗĒ’‘I’nć€ß/6’¤iŗ(:@óć`Ó!¹¤€³¢;$I­įųżā_OIŅ4šK:::Bsē`Ó-ēįŪ#$Iwš„Mæ8ŲH’¦Ķ‡wˆƒM·xJ’“.›~q°‘$MŪ¹¤­£#476‘KŚøt‡$©Uüæ_üė)Iš¶€‡DGhnlŗć1@ŠŽ$µŹN¹$æ6ō‡ƒ$i¼Õ6Żįu(I҆–ŪGGhbl$I³šą\’×Ŗ;ĄĮ¦rIĒw‹ī$µ’?ä÷‡-%I³°šččm™ƒM7\ Ij-?!ėIҬx-ŖlZ.—“šČčIRk9Ųō@.Éėm’¤Y:*—tXt„6ĻĮ¦żŒŸøI’6ĶÆż°::@’48>'µålŚĻ’I’6ĒōūĮįM’4kŽäh9›Ė%ķœŻ!Ijµ£46’¤Y[“Kŗot„6ĶĮ¦ŻĪ–GGH’ZĶĮ¦l$I.ˆЦ9Ų“ŪyŃ’¤ÖŪ!:@į`#IŠp^.É] „ü ÓR¹¤€DwH’ZĻ6ż°]t€$iöŽŽŠĘ9Ų“×ƀeŃ’¤Ös°é‡m£$IƒåµØ–r°iÆs¢$Ią•Ø~X I¬ssIh!›Ź%mœŻ!IźOŲōƒƒ$)ŹĪĄƒ¢#tg6ķt°ut„$©ēFH’:Ē6Żē`#IŠöŠ\ŅŹčŻĮĮ¦ErIŪ0:a#IŅ|8ŲtŸW¢$IѶΌŽŠlŚå4ü†M’4^‰ź>OŲH’ŚĄkQ-ā`Ó.^‡’$-„'lŗĻl$ImpF.i»č8Ų“Äųj?“$-„ƒM÷yĀF’Ō+€‡GGhÄĮ¦=Nfō*5I’ęĖ+Q–KZ,‹ī$iģ‘Ńq°iÆCI’Ź6Żęu(IR›œ’KZ!›VČ%-Ż!Iź,›nó:”$©M¶ΉŽƒM[<pĮ”$-”W¢ŗĶ6’¤¶ńmQ-ą`Ó®—’¤Åš„M·yĀF’Ō6Č%ķ1t6ĮrIK€³£;$Ię ›nó„$©m–ēEG ƒM¼ć]£#$Ię ›nó„$©|[T0›x^‡’$-Öö曟&IRŻ/—“OtĐłĶ] \RŻ!Iź¼l”óJ”$©p~tĐ9ŲÄŗ/°Wt„$©¼Õ]ž°‘$µ•o‹ ä`ĖėP’¤Iq°é.IR[Ż;—t`tÄP9ŲÄr°‘$MŠoŠź®ķ£$IŚ OŁq° ’Kŗ7°&ŗC’Ōž°é.IR›ł¶Ø 6q<]#Iš$›īr°‘$µŁį¹¤Ć¢#†ČĮ&ιŃ’¤^ńJTw9ŲH’ŚĪkQl䒎īŻ!IźOŲt—ƒ$©ķl8ŲÄšt$iŅlŗĖĮF’ŌvŽŸĆŖr°‰įók$I“敨īr°‘$u§lfĢĮfĘrI>°I’4iž°é.IR<2—”¢#†ÄĮfö¼%IšOŲtP.i)°*ŗC’¤9Ų8>:bHlfĻėP’¤iš„M7m IŅ<\0$63”KŚ82ŗC’ŌK6Żäu(IR—œ—KŚ::b(lfėŃ’¤ŽZķ½ņNr°‘$uɎĄƒ£#†ĀĮf¶ĪŒ$õÖ2|ŽM9ŲH’ŗĘkQ3ā`3#¹¤€ć¢;$I½¶Kt€ęĶĮF’Ō5gę’üś56³s*£O?%Iš›īń^IR׬Ą—éĢ„ƒĶģxJ’4m6Żć`#Iź"ÆEĶ€ƒĶ 䒖§GwH’zĻĮ¦{l$I]ō€\Ņ^Ń}ē`3Ēą7ђ¤éókM÷8ŲH’ŗh šØčˆ¾s°™‡DH’ĮĮ¦{l$I]嵨)s°™ IŅ,8Ųtƒ$©«ī•Kŗ{tDŸ9ŲLY.iOąČčIŅ 8Ųtƒ$©Ėr°™.IҬ9Ų$h\O IDATtĒīŃ’$Mˆ×¢¦ĄĮfJrIDwH’ĒĮ¦;öˆ$iBĪņZöä9ŲL§k$IlŗĆĮF’ŌŪˆŽč›éq°‘$Eš!¶Żį`#Iź“ĒDōƒĶ䒶Žī$ ’'lŗĆĮF’Ō''å’üŚ6A6Óq ąkĶ$IlŗĆ‡K’śd pAtDŸ8ŲL‡×”$IQlŗĆO!%I}ćŪ¢&ČĮfĀrI xpt‡$i°lŗĆĮF’Ō7÷Ī%Ń6“w`·čIŅ`9Ųt@.i ^‰’$õ“§l&ÄĮfņ¼%IŠä`Ó {ćóī$Iżōč耾p°™<IR¤U¹¤ŃŚ¢ż£$Iš’żsI9:¢l&(—“pļčIŅąyʦżˆ$iŠŠ6“õ` EGH’ĻĮ¦żl$I}v~.iYtD×9ŲL–×”$Imą`Ó~6’¤>Ū8-:¢ėl&$—“pJt‡$I8Ųtƒ$©ļ¼µH6“s<°]t„$I8Ųt–$õŻCsI«¢#ŗĢĮfr¼%Ij ›Ė%­vˆī$iŹVgGGt™ƒĶäœ IҘƒM»yJ’4Ft™ƒĶä’Šī$iĢĮ¦Żl$ICqr.i·čˆ®r°™ ÆCI’ŚÄĮ¦Żl$IC±xTtDW9ŲL†ƒ$©MlŚķ°čI’fČ·E-ƒĶ"Ÿz}bt‡$Iėp°i·#£$Iš”{ē’Žč"›Å;Ų::B’¤uģKŚ*:Bw–KZ‰Ļ½“$ §lĄĮfńN$i#vŽŠFŻæ’’$ Ļ…¹¤Ń5~ưx'GH’“ŪFh£¼%I¢}ć£#ŗĘĮfrI{w‹ī$i#–Gh£l$ICõŲ耮q°YO×H’ŚjEt€6ŹĮF’4Tēę’ü@ilĒĮF’ŌV~CŌ2¹¤eĄįŃ’$Ł8+:¢KlēAŃ’$m‚ƒMū‚'Ÿ$IĆęŪ¢ęĮĮfrI‡»EwH’“ 6ķću(IŅŠ=8—“StDW8Ų,œ×”$Imę`Ó>6’¤”Ū 8?:¢+lĪėP’¤6óźMū IR ų¶Ø9r°Y€ńCOŒī$i3vŠrIŪā`#I@Ī%Ń6 s,p—čI’6cŸč­ēžŒŽK’$><'6 ću(IRŪ9Ų“ĖIŃ’$µˆƒĶ8Ų,Œ–$µƒM»8ŲH’t‡sI÷Žh;›yßA÷o,IRŪ9Ų“D.i{|C”$Iņ”Ķ8ŲĢß x]’Ō~»å’|µw;œ,Ž$©e™KņgėĶp°™?ÆCI’ŗ wŽŒ$©…vNŽh3›łs°‘$u…×¢ŚĮē×H’“qh3›yČ%ķ Ż!IŅŻ=:`črI;ć÷’$mŹYćg½i#lęē$FGĢ%Iź‚ūDˆą÷’$mŹ ąÜ舶r°™ÆCI’ŗÄĮ&ŽiŃ’$µœo‹Ś›łyPt€$Ióph.ietÄP咖gGwH’Ōr'ę’öŽŽh#›9Ź%¬‰ī$i–GFG ŲÉĄNŃ’$µ\.ŒŽh#›¹ó:”$©‹¼ēüčI’:ĀkQį`3w^‡’$u‘ƒM€\ŅÖxJ’¤¹:,—䩹 8ŲĢA.i £7DI’Ō561NvˆŽ$©CŠ66ss/¼ƒ.IꦃrI³÷ČčI’:ęQ¹¤„Ńmā`37^‡’$uÕF§=4#¹¤åĄĆ¢;$Iź˜Żńٱėq°™’¦‘$uŁŃs:°]t„$IäƇ×į`³ćOɎī$iNĻ%„čˆń:”$I sv.ietD[8ŲlY¶‰Ž$iöī1¹¤m€³¢;$IźØmT6sįu(IRx-j6ĪVEGH’ŌaēD“…ƒĶ–9ŲH’śĄĮf6ž IRĒ9~4Éą9ŲlF.i{ą>Ń’$M@]Ӕä’NŽŒī$©ć¶Ćƒ€ƒĶ–<š=š’¤>X†Æ÷ž6O×H’4^‹ĀĮfK\õ$I}rAt@_å’Ą‡ K’4)Ė%-‹Žˆę`³y6’¤>9+—“StDO=æÆ’$iRV3ŗń2h~c± ¹¤½€C¢;$I𠭁GGGōĶųŁ@Oˆī$©g-ŹĮfÓNА$i ŠC㫼%Iš“‡ē’½Y ś?üœ IŅ™KŗgtD_䒖ψī$©‡vŽ‹Žˆä`³i6’¤¾ņ”Ķäœ ģ!IRO śZ”ƒĶFä’vŠī$iJ.Ģ%mŃ’+:@’¤{Dt@$›;>:@’¤)Ś83:¢ėrIg÷ī$©ĒöĪ%ÅĮfćNŒ$iŹžŠećJ—DwH’4ƒ½å`³q>æF’Ōw'咎Žč°§w‹Ž$il4’KŚ8<ŗC’¤ų½č€.Æšæ£;$IˆsI÷ˆŽˆą`sgĒ):B’¤83—tDtDż>°::B’¤ä)›;ó:”$i(š¼čˆ.É%€Ļ’‘$iÖl8ŲH’†åü\ҁŃņ2`ėčI’ę°\ŅĮѳę`³Ž\Ņ*ąČčI’fh)šÜčˆ.Č%œŻ!IŅ@ ī”ƒĶśī,‹Ž$iĘ.Ź%Ż5:¢ĶrI xEt‡$Ię`3p^‡’$ Ń֌®śhÓųtI’ā•KZÜ0S6ės°‘$ Յ¹¤£#Ś(—“šščI’4¬S66c¹¤åĄ1Ń’$z].É«Įė_…*ĄNĮ)’$ 0K6w8X!IR ĆgDG“Ģ3S£#$I9—“gtĬ8ŲÜĮėP’$Į ĒW€/—t8pIt‡$Iŗ]ĪŽŽ˜›;8ŲH’Ū/Žˆ6¾*żn<}+IRŪ ę966Ąų¾žż¢;$Ij @ /ŽˆŽ$IwrB.i—čˆYp°9 Ų6:B’¤yk.i‡čˆ¹¤S€ßŒī$IµxXtÄ,8،xJ’¤õ¼cü–¤ĮČ%ķÄč­PƒśĻ-IRĒ āZ”ƒĶˆƒ$IwöPą¹Ń3öf`0oŸ$©£4„“Ą©išč†P¹¤%ĄuĄŽŃ-’$µŠ­Ą©uÕ|":dŚrIĻĘ.K³r#p-p šµńļßnaō”ņŅ ~ß 88hükĶų_“4\ÕUóĪčˆiZЇćX# Įæ¾Üülß׿ć›}#x$£ē[ Ü O$jø–ļÉ%UWĶ·£c¦a|ķė„ ļ4‘4Kæ>ü5šQą[uµšOŽsI[ūwNĪ`4āHŽG½lÄh¤łp]5?ŸęŸ,—tp:£ńęD`ł4’|’ĀŻģŌ·ļMÖå`SŅeĄyŃ’&ā_}zwšÉi}c8ž†š·Ē[OćĻ!µŌ[€__̧ām’Kŗ š—Ą)Ń-RĻüøx]]57Fä’Vž Ü+¢AŅLœPWͧ¢#¦ÅĮ¦¤ļ»EwHZ°µĄ_XWĶWfł'Ī%ķ üšd`»Yž¹„@oe4Ś,čÄZ[ä’v.gtrNŅdܼ xE]5?Ž¹M.éFĆĶĆń¹7Rß¼ø®šēGGLĖ ›\ŅAĄÕŃ’d-š^F’'}UdH.i;ąIĄļ«#[¤¹xB]5·F‡,Äųė’‡ż¢[¤žø™Ń#^ZWĶuŃ1›’KŚx~Š"õÉēźŖ96:bZ†>Ųüš¦čIór+šną%uÕ“jp#xŠŪ/Ņ:ŽĆčķ ·D‡ĢG.é¾Ąß;G·H=ń}ąÜŗj>2Wćv—0zv•Ϥ“ŗm-°K]5?Š™†”æõä„čIóņwĄ!uÕ\Ō¶± ®šoĒŻ"ĶĄ£½=j«č¹Ź%=ų8Ž5Ҥ|øO—Ę€ŗj¾WWĶć€ū_Œī‘“(K€EGL‹ƒ¤.øx6šŗjž+:fsźŖ¹¹®šg1zĶąõŃ=Ņ” ¼/—“mtČęä’vĢ%½™Ń›jVF÷H=q)p|]5ߊYØŗj> ĶčŠŌƒs$-Ü©ŃÓ2Ų+Q¹¤}ÆGwHŚ¢k źŖł\tČ|å’öŽÜ;ŗEš²k€ĒÕUó™č å’.^ ģŻ"õČoÕUóŖčˆIŹ%­f4B=$ŗEҼ}³®š}£#¦aČ'l<]#µßū€#»8ÖŌUs-p?F’9¤>;ųd.ée¹¤V¼ź>—t`.é ąĻp¬‘&éÅ}kĘĻæ8 x0ĢO“„īŚ'—tHtÄ48ŲHj£_O®«ęüŗj~³uÕü øųHt‹4eK€ē_Č%Ż3*"—“u.é÷NŽźzꯀ’1-uÕ4uÕ¼xŠéļ?¤źåµ(Imó ×UóĘčI©«ęfFĻ“łlt‹4GŸĖ%żn.iÅ,’Ť€/ĢōĻ- Ą—½®÷§OźŖł[F϶¹*ŗEҜõr°ä3lrI»ߋīt'?NŖ«ę+Ń!ӐKŚųF?ŠJCš#ąķĄ¦õĄšń×ōG1z=ļQÓųsHāūĄ1ć·!F.iš~<­'uĮρÕćÓķ½1ŌĮę<ą²čIėłFcĶæE‡LS.iąÓĄžŃ-Ņ 5ĄĄŸ¬«ęÖÅü›å’Vg4Ҝ,]t”¤MYĖčmPƒ<%:~ ŽG=“NR»=°®š+£#&iØƒĶ«gFwHŗŻ÷5ƒ8zœKڟŃh³Gt‹࿁÷2ŗjšĄÕć‡}nR.i`/F7>‡ŃĆUSī”4ņĪŗj.ŠŽˆ”KŚøøWpФĶ{i]5æ1ICl>Ü'ŗC0°±ę6¹¤#ZńF)ŲuŒĒą‡ĄžŒšŪ~m—& ŚĶĄ!uÕ|-:$Z.iąSĄĮŃ-’6éŸėŖéÕĻłƒlrIŪ0zźūVŃ-’ų£±ęߣC"ä’~xit‡$I›š†ŗjžŃ¹¤»2:!»ot‹¤j€]ėŖ¹.:dR†ų–ØūąX#µĮõ x¬ū#ą3Ń’$m茮ø¦±ŗj¾œĘčᦒŚ'ѳ‡„q°ńaR¼xĢĄĒźŖY \ü,ŗE’¤ ¼¾®šļDG“M]5WĻŽī“I½z½÷› ‰ŌUó”čˆ6?ąYŃ’$­ć§ĄĖ¢#ŚŖ®š7Ż!i£l:ĪĮFŠõąÅŃmRWĶ[€FwH’4ö’ŗj~ŃrO6ū†;I!öŹ%1)ƒlrI»FwHv5šŲŗŲÓĪēębFoŹ‘$)ҵĄ«£#Ś®®šļOŽī“Q½9e3ØĮO×H‘nĪ®«ę§Ń!mTWĶ÷ßŒī$ ŽsėŖ¹):¢ źŖyšīčIwā`ÓQ>pXŠŃśC†ēąŻĄ£#$Iƒõ™ń”¹{pKt„¤õœKZ1 Cl üct‡¤Ū%ą”čˆÅÄ`“KJ8ŲH³“–ŃUØ_E‡tÕų!†Æī$õŽļÕUóó舞xGt€¤õtžZŌ ą `ut„4 ÆŖ«ęŸ¢#ząeĄ/¢#$I½õ%&éŠčIėń„MGÜ/:@’žŃuÕüø4ŗC’Ō[æ_W¹Ÿŗj®¾Ż!év{ä’:ż¦č” 6^‡’f£žXWĶŃ!=ņj|UØ$iņ¾TWĶåŃ=ō±čIėéōµ(I“ti]5ŸŠŽč“ŗjžųpt‡$©w^ŠS6R»œ°½lrIŪwīąFFo6Ņä½*:@’Ō+WŃSŸĄ“±R›Ü?—“UtÄBõ~°Že’9„hÆØ«ę[Ń}TWĶĄæEwH’zć„uÕ8*LH.éē’ī[WĶ€/G7IŗŻ6Ą½¢#jC†×”¤éū>pItDĻżqt€$©®ŽŃ'uÕ\l \žK:ß¼%µMg_B4„Į¦³q¤yA]5?‹Žč¹?®‹Ž$uŽ%uÕÜŃCš#ąķĄ ”5’ÖÕŁM`YtĄ4咖0ŗ%iz®ŽŃwuÕü2—ō|N$iį¾…§?¦¢®šoß¾ķē’Ž<=®HŅ::;Ųōż„Ķ”ĄöŃRĻż¶ŸŌĶĢŪšA†’¤…ū£ŗj~1ÆÅÆŁR[Ü5—“wtÄBō}°éģ’&uÄĒźŖ¹<:b(źŖ¹ųLt‡$©“¾'bg¦®šÆŽīt»Nn}l|ą°4=kgGG Š;£$IōŹŗjnŒŽ˜×DHŗƒM 9ŲHÓóēuÕüKtÄ]Ü!Iź”ė?Ž WGGHlŚ%—“88ŗCź©xItÄÕUs=šĮčIR§¼µ®ßZ4cuÕ4Œže#)޽rI+£#ę«·ƒ p_ EGH=õWuÕ\1`^‹’$ĶÕZąO¢#ģĄO£#$± 8::b¾ś<ŲtņȓŌž®‰u9šĆčIR'\^WĶ×¢#†Ŗ®šŸ1zĖ£¤xŪś<Ųųüi:>XWĶ—¢#†¬®š›÷FwH’:Į+9ń^Ē褓¤X6mKZ Ż!õŌ‹£x-J’“eWWDG ]]5׊īDĪ%uź±)½l€#€UŃR}¬®šŠŽŌUóĄw¢;$I­öśńƒoĻW|KńvŠŽ˜¾6^‡’¦ć£“žĖ£$I­u£ŽŖźŖłą ¤xŗå`#i®>UWĶ'£#“IҦ\ZWo'jŸ'$Ås°iNżE:ĀgדĻĄÆ¢#$I­ōŗčŻÉ„ĄõŃŅĄ0½lrI;DwH=ó/uÕ|4:Bėæ*ōSŃ’¤ÖłX]5’”õÕUó ą-ŃŅĄšKZ1W½lšķPŅ4¼::@›ä['$IņźM{½_ń-EZĘč%EŠĒĮęčč©g~¼;:B›äsl$IėśšĮčm\]5_>Ż! ܑŃsÕĒĮĘ6Ņd½±®š›¢#“quÕ\ \Ż!IjKėŖńG»ł|!)–ƒM irnž$:B[ä)IŅm.Š}?l‘"9ŲDČ%ķģŻ!õČeuÕ|7:B[äsl$IŸ©«ęæ¢#“yuÕ4Ą›£;¤»G.iitÄ\ōj°ĮÓ5Ҥł°įnųąŃ’¤pļˆМ½ŃIfI³·8(:b.l$mJ]WĶē£#“euÕüųxt‡$)Ō/Ė¢#47uÕüš7ŃŅ€uāZ”ƒ¤MńtM·ųI¶æ©«ę'Ńš—7EHę`3Kć;hGEwH=ń-ą/£#4/6’4l^‡źž_‹ŽŹĮfĘgtMŅā½”®š[¢#4wuÕ|ųJt‡$)Ä÷€FGh~Ę~Kt‡4P63ęu(i2Öā§t]å)I¦?««ęÖč-ČŪ?$“fou.iŸčˆ-éÓ`stt€ŌŸØ«ę[ŃZ_ļ-IĆtit€¦®šļˆīŖõTéÓ`ć i2Jt€ģ³ĄõŃ’¤™śR]5’”EńįĆRŒÖ_‹źÅ`“KZÉč6’ē§Ąū£#“0ćēł IO×tßĄ×£#¤r°™‘£€„ŃR¼Æ®š_DGhQ®Œ$ĶLüEt„§®šµųša)‚ƒĶŒxJš 6Ü}Ÿ‰$ĶĢē}ī\o¼ >,ĶŚ]sI»DGlŽƒ¤Ū\SWͧ¢#“h_~!Iš Æ1÷D]5ß>Ż! н£6ĒĮFŅm¼ßćcÕut‡$i&ž*:@åƇ„Łs°™¦\ŅĪĄ~ŃRĒ58Ųō‰×¢$©’®Ŗ«ę«ŃšØßˆŽĘĮfŹ<]#-Ž?ŌUóõčMŒƒ$õŸ×”zf|Jö­ŃŅĄÜ':`sś0Ų õ@‰ŠDż>øP’śĪėPżōVąÖči@önóƒ‡ū0ŲxĀFZœŸć+A{eüjö/GwH’¦ęuÕ|1:B“WWĶw€EwHÓŚS66’ž¢®šŸGGhā¼%Iżõ×ŃšŖ7GHÓŚēŲtz°É%ķģŻ!uÜ;¢4ŸŽ$M×”śķĆĄ÷£#¤q°™O×H‹óuąŹąM‡'l$©Ÿ~€£|ÆÕUs šīči@¼5%6Ņā¼³®š&:B“WWĶwk£;$I÷7ć· ©ß.䮹¤]£#6ĘĮF6ÆCõ›§l$©|÷ŌUóeą_£;¤i嵨Ī6¹¤„ĄQŃR‡}ŗ®šk¢#4U6’Ō/7ŽŠĢxŹFšV^‹źģ`¬ŒŽ:¬Dhźl$©_>TWĶMŃš™w·FGHį › ó:”“p掔©ū7ąśčIŅÄxj@ĘĻ£ūXt‡46vtt€Ōaﯫę§Ńš®ńC)ėčIŅDÜ\”™óZ”4wĶ%ķ±”.6ž°‘Ī/žĆįµ(Iź‡+źŖłYt„fīżŒž]$iśZwʦ“ƒM.i%£gŲHšæŸˆŽŠĢ|6:@’4^‡ ŗjnÄkģҬ“īĮƝl½jit„ŌQØ«ę–čĶĢ€µŃ’¤E¹ų@t„Āx2Zš OŲLˆ×”¤…ūĖčĶN]57WGwH’åSuÕ\”0Ÿ¾! Ą‘Ńr°‘†å§ĄŃš¹ĻEH’ÅėPVWM¼3ŗC€½sI;DG¬ĖĮF–ÖUsSt„fīóŃ’¤Eq°‘ƒ4‡E¬«sƒM.i`æč©£¼5Lž°‘¤īśB]5’”XuÕ|ųĒčiŽˆXWēąģč©£~|8:B!žųUt„$iA<]£ŪųšaiśZõ6ź.6:źļźŖłEt„fÆ®š_1m$IŻsyt€Zć½ųŒ4mž°YØ\ŅĪĄńŃRGyjŲ|Ž$uĻ÷pp×X]5?>Ż!õœ'lį,`it„ŌA7įų”ó96’Ō=æ!Hŗ×¢¤éZKŚ#:ā6]l|~“0WŌUsCt„ByĀF’ŗĒgĻiC—×EGH=ךkQlrIŪ§DwHåu(żąh'IŻq+šŃčµK]57Ż!õ\k®Euf°NVDGHt ščÅŖ«f-šĻŃ’¤9ū\]5?ŽŽP+] õœ'lĄėPŅĀüżų!u’ϱ‘¤īų»čµÖg€ļDGH=ę ›’ĻŽĒŻv×õ”’¬“ ČCdF@j\¢ γUƶ½­Že-z-ÖŚZķÕ«µŠ­·j[-Zl]jµ*0ŒaLHp%LaB „) ĢgŻ?žēsNΰ‡µ÷oķµßļ×kæNĪyžgķ/ {ŸĻž~ku[—ä[Kē€ õāŅ ēŲlē×pH»S³ÖŻaužP·Õ(ŗ’Q„˜Įs’œV:l ½I^V:£aĀ`3\—äķ„C0j/*&ģ~IY:D²9…Ķß+6Ō…]Ó_[:ćŠ5żG“\S:GužŪysÖ¢`µF±5śĀ¦n«* X”qYvié•u(ŽČZ¬Ü(}a“äéIT:l >ÉKJ‡`tŽ[:G“7nēĶl¬EĮ꘰™‘»CĮb.难ć„C0:ļ)€#zG×ōוĮF°«cĀfFÖ”`1Ęd9… Ąø¹73±+õ˜ŗ­Ž/bŌ…MŻVOHņŲŅ9`CyēPž6ɝ„CpXĪÆaÖ¢`5ŽMņÅ„CŒŗ°‰u(XŌ»»¦’péŒO×ōw$¹¬té†$o-‚b- V§ųšˆĀ¦é„0jÖ¢Ęéu]Óß]:›ĆZ¬”Āępź¶:'Éß-6ŌĖK`Ō6ćäüa- Vć1„Œ¶°‰Ć†aQ×&y[錚[{ŒOŸä¼Ņ!ŲHÖ¢`5L؁u(XĢ+wĒcįpL،ϻŗ¦’TélkQ°2&l„n«Ó“<³tŲPίሺ¦’X’KēąīÅ2¬EĮšĪŖŪźŌ’FYŲ$łö$Ē”čŽ$Æ-‚`Ź`\œ_Ć2¬EĮj]‹kaćüXĢł]ÓßR:Į96ćqS’®t63r IDAT—µ(X™¢kQ£+lź¶:!É7”ĪŹŻ”˜• €ńx}×ōw•ĮƳĆ3asÆLrßŅ!`C9æ†Y)lĘĆł5 ĮZ OasÆ)6Ōūŗ¦’HélŒĖKą ^W:›ĻZ¬„•؃|mé°”L×0³®éoLņ™Ņ9Č»¦æŖt&ć„„ĄÄ˜°Ł§n«““<µtŲPĪÆa^W–@^_:“ra| C:„n«³J=łØ ›$ĻLrl鰁®Orqélœ—€Ā†įģ^ķL$V±)›±6Ö”`1ÆŚŻ[†y˜°(ko’7•Į䘺†a)lv9p慙E(lŹzĒī™b0¤W'¹»t˜b¦°©ŪźŒ$O*6ŠI^[:IaP–»C1øŻš¢Ņ9`BLŲ$yN’ŖtŲ@tMsél$… @YĪÆaUL_ĆpLŲÄł5°(·ófQWeēüÖļÖ$]:“„°į<ŗn«"Ć% Ų|^YH×ōw&¹ŗt€-ua×ō·—Į4uMy’ĖK瀉øo’sJ<ń( ›ŗ­ĪIņčŅ9`} kzk-,Ć’~ʰÅŖłP†Sd-j…MLץ¢¼³¬—°„6¬šµyN‘ƒ‡ĒRŲø7,Ę 1Ė2a°~×'yWéLŽEIÜ6†±Õ… ˜ß qX!ĖSجߺ¦ļK‡`Śŗ¦æ+ÉkJ瀉ŲĪ•Øŗ­—äĮ„sĄzu×ōw—ĮĘSŲ¬Ÿu(ÖÅś< ck'l¬CĮb¼3„O”°…6¬Ė«“ÜU:LĄ#ź¶:vŻO:†ĀĘ:Ģψ+C¹¦t€-ó”®é?R:Ū”kśĻdē,`9Ē&yÄŗŸ“haS·Õž$Ļ.™6Ō…]ÓßT:›Ækś;ā@B€u2]Ćŗ™Ź†a¬}-Ŗō„ĶS’< pŲD^xҧJŲ"Æ+€­ć}# cķ—.lœ_‹q;o†d- `=ö&ySél—®é?˜ä²Ņ9`¶nĀĘł50æĖv_xa(&lÖć]ÓßP:[ɔ ,o{&lź¶:.ÉW—z~Ų`¦kšĀ`=œ_C) XŽVMŲ<=ɉŸ6•\†f% `=6”ņ–øÉ,뜺­ī»Ī',YŲX‡‚łŻ˜\’ €Õ»-^Ć)¤kś»ćü$XV•äQė|Ā’…ĶW|nŲTÆéšž®Ņ!˜6«wa×ō·•ĮV{Cé0k]‹*RŲŌmU%yZ‰ē† ēüVĮ„ ĄźY‡¢“7–0żĀ&É撜Vč¹aSŻäÕ„C0I €ÕSŲPT×ō›ä„sĄ†[ė¢J6_Qčya“½„kz‡Å± ×%éK‡˜°O'¹“tˆµ(XÖVLŲ<½ŠóĀ&sw(Vb÷\¤ėK瘰7vMÆg ¬EĮr½Ī'3a›CaĆ*Y‹XėPŒ… XĪŁu[“®'[{aS·Õ‰Ižøīē… wE×ō—•Į¤¹SĄź¼®tH’®éÆNņĮŅ9`Ć­ķ›6OMrLē…Mfŗ†U3a°WvM’įŅ!`?Ö¢`9k[‹*QŲ8æę÷ŖŅ˜<6«aб±Ė™ō„ók`>{“\\:“gĀ`5^[:äMqwHXʤ'l60Ÿ÷wMKéLžĀ`xwń #Ó5żõIŽS:l°iNŲŌmõ°$gÆó9aL×°V¢†wq×ō7•‡`- 7Ł ēץü.)€­`Ā`xÆ)Ca‹[Ū­½×]ŲX‡‚ł™°aLŲ OaĆX½9;+{ĄbÖ2e£°q»9ÉJ‡`+\ŸäīŅ!&äŗ$ļ,e÷|Ä·–Īl-ēŲ¬­°©Ūźų$_¶®ēƒ‰x[×ō{K‡`śv’wvmér^×ōīÄƘY‹‚ÅMnĀęÉINXćóĮX‡b¬E ē¼Ņą(6°øiMŲÄ:,BaĆ:9x`}6ŒßÅIn-6”Āp‡(ÖJa0ŒwvM]ép$]Óߞä¢Ņ9`CMn%Jaó¹Ņ›=ÖĢJĄ0ÜŠMa- ³–[{Æ„°©ŪźĢ$\ĒsĮ„X‡bŻLŲ CaƦø tŲ`+Ÿ²YׄĶÓ×ō<0%Ö”X·—07Ň.lŽK“ÜQ:lؕŸc³®ĀĘ:ĢĻ›=Öķc„LĄŗ¦æ«t˜Åī96—–ĪŹ„ l©Ū“¼«t¶ŽĀ`yÖ”Ų4>$„Ålž„MŻV{’³²µØ•6u[Ÿäq«ŗ>L”;D1¦lfwa×ōŠn¦ąo“|¦tŲ@›WŲ$yB’ćVx}˜"Ÿl0 €ŁY‡bŗ¦ļ“¼µtŲ@+;Ēf•…u(˜ĻĶI>P:ÄĮĆóPŲ0%><„łm䄍Āęó¶®é÷–1a0«÷wMeé0 … ĢĻ„ l/Œ…Ā`6¦k˜ē)ĀüLŲĄšÉXX‰˜Ā†I难†$——ĪęA«ŗµ÷J ›ŗ­’äōU\&Ģ„ caĀąč®‰[˜&ĆüV2e³Ŗ Ó50Ÿ+»¦æ®tŲ„°8ŗWģŽU¦ę½„ĄśāU\Taćą:F£kśĻ$ł|é#gŠ©z_鰁¾dUŲĄ8X‡blLŁŽ­I^W:¬ČūK€ ō„U\Tać °al< pxÆļšžÖŅ!`E>šä–Ņ!`ĆlʄMŻV÷MņŲ”Æ v{’w•1apxÖ”˜¬Ż³™ž¦tŲ0®Ūźų”/ŗŠ ›/]ŃuaŖ.ķšžŽŅ!ą €C듼¼tX1ēŲĄ|ŽMņ˜”/ŗŠbÅ:ĢĒ:cd% ąŠ.难šŅ!`Ŝcó|-Jaå¹CcdĀąŠ^V:¬Āę7ųĮĆ (Ļ„ cteé#„°a(l`~QŲę7čĮĆC6ųz0eÖ”»ĖćNQIņ™$ē—ėŌ5ż§’ÜP:l˜qNŲģž†üČ”®[ĄĆŒš;E|Į+»¦æ³t(Ą” Ģē±u[;Ōņœ°yd’Į‚Įxké0oŌ¬C±½œcó9>É£‡ŗŲ…ók`v·%ł@é0… °ķnKņšŅ! ļ`~ƒ­E)l Œ÷vMļl67jĄ¶{}×ō·”…xó{ŅPRŲ@—–3ś›Ņ ³Å6ó>ę÷””.¤°2ŽY:Ģȝ¢€m¶7ɹ„C@)]Ó_›»¤³SŲĄ†3aĆFŲ½SŌå„sņ–®éÆ+ ó>ęó°ŗ­ī?ą)lvÜ9ĵ` ܝä=„CĄ܂ŲVÖ” ¹¬tŲ@ƒLŁ 5acŗf÷®éo+ępaé…(lĄ„ ,bT…ĶcŗlėPlš‹J(ą]]Ó_Y:Œ€ ˜ßßā"&l`ż8ĢF难Š$Ÿ*`Ķž¢t 60æQMŲ(l`v&lŲDo)`Ķž²t‰&éK‡€ óųŗ­NXö" XÆ>É»J‡€8ĒŲ&o·;ŗ¦’|’«Kē€ sl’'.{‘„ ›ŗ­ö$yׁ̲-qe×ō7• pŽ °M¬CĮ¬EĮü–^‹bĀęaI–õ-aŠMõ®$·”°}’•#ćąa˜ß( ėP0;³‘ŗ¦æ;ÉÅ„s¬Į%]Ó_U:ŒŒ ˜ßŅwŠRŲĄz™°a“9ĒŲÖ”ąŽLŲĄüžT·UµĢ6°^ 6™sl€©³‡fĀęwr’G-s… ¬Ļ'ŗ¦æ¦tXĀÅIī*`…ŽŅ5żĒK‡€ŗ*Éķ„CĄZj-jˆĀę±\¶é6Śīm=ĆL™u(8„®é÷&¹¢tŲ@K<¼TaS·Õ‰IŗĢ5`‹ų‹.S`- ˜Ŗ½I^\:Œ˜sl`~å ›˜®y˜°a Ü) ˜Ŗ7wM’©Ņ!`Ĝcó+ŗåü˜Ā†)xGé+b ŽĢ„ ĢļAu[°č+l`=nģšž#„CĄ²ŗ¦æ2ɍ„s ģī$’»t9… ,ę“EPaėaŗ†)q05oźšžŗŅ!`ä¬DĮbN]ō6°ž‚Ė”X‹¦Ę:E×ōŸNņéŅ9`›°qč0Ģʄ S¢°¦äĪ$/)6„)˜ßś ›ŗ­’ä¤E¶ĢūJ€™¦äe]ÓßP:lēŲĄüЬD™®ŁģO#˜–%¹©t€ü^é°A¼§…łY‰r~ Ģę#]ÓßV: „kś>ÉŪKēĄIŽX:l60?… ŒŲߖ+š¦Ņšū»%4060æ"+Q ˜Ā†)zCéKŗ#I[:l˜fgŻ˜ ±”+šö$7—°„—tM]é°Iŗ¦æ=ÉU„sĄ†YoaS·Õ I¾č“Ā–1aĆätMW’7—ΰ‡ Ćb¬EĮ|Ö¾õč%~¶Ā†©²lŖĖ»¦?ætŲP†ł¬}%Ź:Ģęś®éÆ/VDal*Ó5°860… Œ”é¦ģ}I®-`N·'ł£Ņ!`ƒ™°ł(l`¤8ĢdķŽ ÷„sĢéÅ]ÓŗtŲ`&l`>k?Ć걋>!l6LŻKJ˜“u(XĪÕIn-6ČÉu[³Čš°ÕRŲ0uÆLņłŅ!fō®é/,6Łī„ķKē€ ³Š”Ķ܅MŻVg$yĄ"O[ČJ“Ö5żē³SŚlÓ50 ēŲĄ|ÖSŲÄt Ģź¶$W•kš¢Ņfp[’?.&Ā960Ÿ…VŲĄź\Ö5żŽŅ!` ¬E›ąE]ÓßX:L„ ˜ĀFĘł5lkQĄ†xAé0! ˜Ļé‹üĀVGaĆ6±ŒŁk»¦[é0!V¢`>g.ņC‹6né ³qą0Ūä•In)ą0ž}é0%]Ó&ɵ„sĄ9k‘š«°©ŪjO’G.ņD°…LŲ°5v×¢ž¬t€CøØkś7—dŹf·śĀ&É9INXä‰`Ėģ1¶Ļļ–pæ\:L”sl`vkY‰zō"O[čŖ®éo-Ö©kśK“¼µt€ż¼£kśóJ‡€‰ņį$Ģn-6 ˜u(¶•)`Lœ]«cĀfgĀFāĆl«?Oņ™Ņ!’¼?ÉĖJ‡€ »²tŲ k™°yĢ"O[Ȅ [iwšKēHņó]Ó÷„CĄ„}“tŲ ØŪź˜yȄ ¬†Ā†mf- (ķ¢®é_Z:LY×ō7%¹¹tŲ{’œ¾Čͤn«*né ³ņ‰[«kś$y}éĄVūׄĄ–øŖtŲ sÆEĶ3aó$÷÷ ` ķMņ‰Ņ! 0·ŃJłĖ®é/)¶„)avs<ÉÅ„s[ćĘXĒ„u3a³³# °{˜²Öå—ŗ¦æ”tŲ2&l`v&l`®.Ę¢kśW%yGéĄä½-É J‡€-dĀf§°0aś„Ņ€I»3É?ķšžīŅA` }"É]„CĄ†XĶJTŻVNræ¹ćĄvRŲĄ~ŗ¦?7É„s“õ«]Óæ§tŲF]Óļ÷¾0«•Mؘ®Łyт{ū‰${K‡&ē²8+ J³³Yٔà ˜MŸäć„CĄŲtM’®$’£t`Rś$ĻķšžöŅA`Ė9xfs’ŗ­Ž›ē60¬k»¦æ£t©ŸKrséĄdün×ō–˜°9šä’)H¢°ya£°Ł)l`F]Ó’U’?.ŲĪ­qsš0Ģʄ ¤°łü‹ų’ pd/Šsk`ģLŲĄlLŲ@!×uM{é°Iŗ¦’L’*­ “|æsk`ō>Y:lˆSė¶:qÖovč0 Ē”, kś×&łķŅ9€Ńł@’ļōal7€ŁĶV¢`ŗ¦æ"É7dē/xĄęūd’ētMļœ*˜60»™Ö¢606°"]Óæ7É·$ł\é,ĄRŗ$·kśw— Na³›éąa… ć®®éo+¦¬kś‹“ü½ģR lžßMņģ®é?Y:°V¢`vKOŲ8ĆfgŗÖ kś×gg=ź3„³3»=É?ķšžG»¦æ£t`eLŲĄģLŲĄ)l`Mŗ¦æ(ɳ²s0nKņĢ®é’{é ĄŹ)l`v‹OŲŌmuZ’ӍÓęĄaX£®éߓäI®(8¬ ²s^Ķ[KÖĀJĢn© Ó506°f]Ó8ÉW%¹“tąw&ł„$_×5½æĄĮ–čšžę$Īt„Ł,u†Ā棰ŗ¦æ&ɳ³óI>PŽ„IžŚ5ż/tMWé0ĄŚY‹‚Ł,5aćĄa˜•((d÷½oLņĀŅY`‹Ż‘äē’<Ķ-»a«™ŖƒŁœU·ÕqGū¦cóē&l`>&l  ®éoOņĆu[]”äw’ÜÆp$Ų&oMņOŗ¦é @q&l`6U’³“\}¤o²Ć0a#Š5ż'yz’ĖKg-p[’ŸNņ•Ź`— ˜ŻQϱQŲĄ0LŲĄHtM’¾$_žäE„³Ą„½"ɓ»¦’µ®éļ. 60»£žcsÆ•Øŗ­NIrÖJāĄt)l`Dŗ¦’l’ļ«ŪźĒ“üz’£ī3¹$ÉOwM’ęŅA€Qŗ©tŲ MŲ¤€ƒ]“ä·“üN×ōחl… Ģn”3l¼y…łyq‚ ²{ūļĒ'ya’» ǁ1xo’Lņ°®éŸÆ¬ä=1Ģn”3lLŲĄü¼8Į†éšžŗ®é8;ÅĶ’JŅŽėÖ'yu’ÆļšžI]Ó·]Óß^:°ŃLĆģN©Ūź¤#}ƒĀ†įÅ 6T×ōWtM’&yJ’——Īkpk’ßĻĪAĀßŅ5żėK&Ƈ˜0Ÿ#®E9t†qkéĄrŗ¦O’ļØŪź+’ü‡$Ļ) †vevÖ’ĄŹ°" ˜Ļƒ“\vø/:t†qØi5`uMq’Æ©ŪźYIžy’ļĢ”_/aܙ䯲3Qóś®é­ž«¤°ł˜°5PŲĄÄtMA’ ź¶zH’IņÜ$g—M3Ū7Mó‡]Ó_S: °ŗ¦æµn«»“S: lˆ#ް’ן¶:.É#sč2ēˆć³ŒÖ-IŽ–)š‹“\bĶ ˜ … ĢēĮIŽwØ/˜°a˜°µ{ńĖvØŪźÄÜSŽ<&Nåœ%ņōI>żŹ™$ļ³āl… Ģē°Ä)l` `mŗ¦’\’KwØŪź„ģ¬Y“ä‹óė)k ;m}’'¹āPŻ’ž¶Āę3sac% s\éIŅ5żķŁ9åC‡ūžŗ­NĶį˜/ŹNįćßk;öfge탹w)se×ō·Ģ0F†ł˜°;¹t€YuMS’÷ī>īe÷0䳓œ™sNĻĪ{„Cżó¾ß? ›wHņŽģüÅāęŻĒĒrčRęŽb 6éB˜ X1… 0»‡!r÷1³ŻÉC•9ū~½ovŽ{ õø=÷”-‹(Մ ,FaĄ¼ĪŽ]Gæ—/6»ßp’µE‚iQŲ0Æc“œuØ/ģ?asZܚ„°`‡\‹Śæ q~ ,NaĄ"ŽZŲ8æ§°`&l`…6,Ā„ ¬Ā€E˜°RŲ°… ¬Ā€EX‰‚ŗél$6°BgÖmuLélœ³ź¶:öą?4aĆŲ“äĢŅ!Ų8{’<šPø XĪŁ„°‘īµe†ó ŅŲHG,lLŲĄrLŲ°ˆC6u[ķIrŚŚćĄ“(lXÄa'lZo˜… ‹8laćüXžĀ€EqĀXŽĀ€E¶°9uĶA`ŠÜ% €E(l`…LŲ°ˆ3ź¶:~’?ŲW؜R LĶÉu[ŻÆt(č¤Ņ`ƒ°µ”°a}QéPķ XÜkQV¢`X) 2 ‹{Čžæ1aĆRŲ°Ķ Ąā9a£°a(lŲf Xœ•(X!… ŪĢ0,Ī„ ¬Ā€mf÷Ąż£°aS·Õ}J‡€B6°ø3ö’•(V•äQ„C@!†`qµ}±É IDATgī’60¼Ē–…€ÅrĀFaĆqŽ [§n«’œP:l°ūÖmuæ}æŁS·Õž$' S£°`€å}aŹfO’“³sī0 … ŪČ:,ļ ēŲ쉒SĮŠ6l#·„å0acl †õąż÷`K(l`y X1·ö`Ūų»%,ĻJ¬Ų£K€5ówKXž X16l… ,Oa+fĀ€mćļ–°¼V¢ī[0L• ¶ XŽ6' SeĀ€m£°å)l`ÅĪ©ŪźųŅ!`¬DĮņ6°bĒ$yxé°F÷/&ąōŗ­ŖDa«ōŲŅ`Ī)&ą˜ģ–Ÿ XÆ.Öča„ĄDœ‘ģ6÷)¦źėJ€uØŪźŒ$÷+&āĢĄ ¬Ņߣ}ဩ3]Ć9=QŲĄ*UI¾¦tXƒ‡—rj¢°U³Ą60aĆ99QŲĄŖ}}é° Ī)‰ĀVķįu[=ŖtX1… ē 6ī«e- €©SŲĄpLŲĄšX‹`ź^:Lˆ3l`M¾¹n«SK‡€UØŪź”$§•ĪbĀÖä~I¾ætXėP0,6°F?\:¬ˆĀ†õ… ‡Ćź}iŻVué° – X³)Vąį„ĄÄ8ĆÖģūź¶ŗé0060,… ¬Ł}ćša¦GaĆ:©n«jOé°e¬E05 V•ä¤=Iī*¶Čź¶zfé0„ŗ­ī“䁄sĄ¼'ɝ„SĄ–łw„Ą@LץjœbĀÖļ9u[}cé0… ¬ĘÉ (ćWź¶ŖJ‡€%)l`5LŲ@!'É?(–ōˆŅ`¢LŲ@AĻÆŪźøŅ!` .&Ja=*ÉsK‡€%(l`5īć.QPÖĻ×mubé° … ¬Ęń&l ¬³“üDé0Æŗ­˜ääŅ9`¢60?S·Õ#K‡€9=¦t˜0… ŒĄ‰IžŠm¾Ų0O)&ģ… ŒĆ3“üxé0‡g–fĀFäWź¶zlé0£Æ.&La#rß$mŻV{J€#Łż ńģŅ9`ĀŽw[o—:ÉO–GaŗVĖ„ ŒŠóė¶zBép_W:LœĀFč„$T·Õ±„ƒĄĮź¶:1É·—Īē.Q0R_žä7J‡€CųŽ$'–gĀFģyu[żHépX:l… ŒÜ ź¶zvé$u[= É7•Ī[ąų=In)8¬ć’¼øn«G–Ł™®9®tŲĒļIņéŅ)€#:=ɹu[\:Ū«n«=Ižeé°%6°!¾$ɟķ¾H@ ߕäQ„CĄ–8Aa›ćŪ’üJél­Ÿ*¶ˆ Ų0?]·Õ’]:Ū„n«ÆNņōŅ9`‹(l`ż·ŗ­ž[:Ūaw-’×Jē€-£° T%ł½ŗ­~°t¶ĀOÄt ¬›Ā6T•äź¶śŅA˜®ŗ­•äł„sĄRŲĄŪ“äė¶śG„ƒ0=u[UI^˜ä~„³Ą:aO×ōw$¹„t`!{’üQŻV’°t&ē¹IžS:l©ć÷ģžƒ)Ų\Ē$ł“ŗ­¾Æt¦”n«‡ĘAĆPŅ1ū ›ė‹Ę–uL’?­ŪźŸ”Ą$ün’SJ‡€-v· ˜Žc“ü÷ŗ­ ĄĀvĻHüÖŅ9`ĖŻ„°éł¹ŗ­ž¤n«ćK`³ŌmõČ$æY:`¦ź'9Æn«ū—ĄfØŪź!I^ŸäōŅY60eĻNņ–ŗ­^4£W·Õ™Ł)kQ: Da“÷ų$×mõŌŅA§ŗ­NKņŚ$+ų+Q°˜äüŗ­¾»tĘ„n«“¼*ÉSJg`Ā¶Äż’üļŗ­~ĆaÄ$IŻV÷Irn’ŗtą^6°ežEvε±› °Åź¶:.ɋ’|Mé,Ą!Y‰‚-ōåI.­Ūź{J`żv˚?Iņm„³‡õ… ›O$Ł[2 °V§&yqŻV/ØŪź„ŅaXŗ­ĪIņę$ætąˆv ›®éoOņŃĀa€õū±$]·Õ£J`µź¶śĘ$—&łŠŅY€£śĀJT’|°X  ¤/KņĪŗ­žqé Æn«=u[żbvīuzé<ĄLīRŲIrJ’?©ŪźUu[}Qé0 £n«3“œ—äß&Łs”oĘć€Āęņb1€±ųę$ļÆŪźĒź¶ŖJ‡`qu[}evV ¾®t`nV¢€{9)É ’\X·ÕćJ‡`~u[żĖ$$yHé,ĄBī:væß(l€ż=#É»ź¶śå$’±kś;KąČź¶zz’’’¤.XŹ+QNrW©$Ą(äłIŽ^·ÕSK‡ąŠź¶zhŻV’3Ie LĮŻUß÷_ų]ŻV—'yL¹<ĄˆķMņGIžß®é?Y: IŻV'&łé$?•ä¾…ćĆ9÷ąĀę•I¾„\`|.ÉÆ&łõ®é?_: Ą6ڽAÄ÷'ł•$.ŽK¾­›;EGsb’_LryŻV?ąnRėU·ÕW%ykv¦Ÿ•50Mw\Ų8x˜ÕC²ó&įmu[=³t€)«ŪŖŖŪźź¶zU’ “|yéLĄJp—ØDaĢļļ&¹ n«—&ł7]Óū÷Ą@vĻØł$?žäq…ćės×ĮgŲ<,ÉGŠÅ6ŻŻIž<É蚾oJ‡ŲTu[="Éó’üP’Ó ĒÖļ.lö$ł|vnå °Ø>ÉK’üū®é/-`SŌmõœģLÓ|G’ƒ°¶ĒÆPŲ$IŻVļOņ„2y€ ze’_īšžāŅAĘØn«³“|O’Iņ„…ććšsŸa“ģÜ)Ja å[“|kŻVoČNqs~į<ÅÕmõ$ߝä{“<#¦i€}ęP…CUųŚ$_[·Õ%I~+É_vMGįLkS·Õ9Ł™¤łŽ$u’Ŗl"`Ä6ĄŚ=}÷ńŸė¶za’ßėšž£…3¬DŻVĻ=%ĶÓ¢¤fó™Caó¬$ē‰l£»“¼<Éo'yC×ō/%€ ²{ͳ’<{÷×Ē lŖÆ:Taóą$/“Ųr—%łoIžØkś›J‡8šŻ³hž•{JšĒ LÅļUŲ$IŻVŸJņĄõēH’ÜšäÜ$šä5]ÓßY8@ź¶Ŗ’<";‡ļ+hU20Y=\asn’o_€{łt’e§¼y‹•)`ź¶ŗO’/Iņ”żOJrJÉ\ĄÖ8ép…ĶĻ%yžśóŃUIžW’?ķšž}„ĆÓP·Õ™Ł)džœ{Ź™/Nr؛“¬Ś]]ÓwøĀę’œ·žL3{O’—%yE’·›¼§n«=I’õ„żÜżõžåŅÜĖõ]ӟyøĀę“$7Ä-ē€ĶpM’Wī>^Ū5ż-…ókT·Õ©IĪŽļń ģœ5³Æ˜yD’Š˜Ļ{ŗ¦ņ! ›$©Ūź²8įŲžU’›ė¶z]’W$yu×ō×Mpu[=#É÷'ł¾$÷/Žäņ}’0Kaó†`³’ä{v}ŻVoĻĪäĶ’ģšžCE“[­n«S“ÉO'9”pĀßģ’›=³üD×ō—g擊`Iē$łļIŽ[·••[`.u[=%ÉŪ³SŲ(k˜Šł ›]/8<>ÉKź¶ŗøn«g—Œ[ŻVĒķNē½5ɓ Ē€”-\؜;pŲēéIŽT·Õ«w?98@ŻVOĪNQó IŽ+Vį€Āf¦C‡“¤n«c’\›ä+ūōIž ÉOtM’łŅa€²ź¶:6ÉĻdgżIQĄ”=ØkśOķūĶĢ6»‡B¾z%‘ąU’ē&y{ŻVV`‹Õmur’W%ł„(k˜¶k÷/k’łV¢kQ¬Ļć“\R·Õ?+Xæŗ­˜äü$__8 ¬ĆE’Į¼…ĶyIī& Õ}’üvŻV/©Ūźž„ĆėQ·Õ£“üu’/+Öd¹Ā¦kś›’¼y°80›ļJņīŗ­¾Ŗt`µź¶śņģ”5,Öčƒ’`Ž ›ÄZeœ“äüŗ­žW:°u[}SvÖ Ī,Öé–$—ü‡‹6/_> ,ä˜$æU·Õ– «n«”÷™'–ĪkÖķŽčés6]Ó8Éū‰‹łķŗ­~Øt`u[=+I›äŲĀQ „{_“,6a“X‹ ¬*Éļ×mõż„ƒĖ©ŪźaI^e Ūė^ē×$‹6Ö¢(mO’?¬Ūź”,¦n«ū%yY’3Jg€BīLrÉ”¾°hasI’kŽĆ8&ɟŌmõŻ„ƒ łĆ$O) zG×ōŸ?Ō*lŗ¦ß›ä•KE€a›äĻė¶śŚŅA€ŁÕmõ³I¾Æt(ģėPÉā6‰µ(Ęćø$mŻV§–]ŻVß–äł„sĄœø/,SŲ¼6ÉķKü< é”IžK饑ÕmõØ$šåއĄܝĆÜ!*Yā…²kśĻ%yć¢?+šƒu[}K饿ē$§”#pi×ō7ī‹Ė~²a- €±yaŻV§•ÜŪīYSßQ:ŒÄGś¢Ā€©yp’ß,8PŻVĒÄŚ"ģļü#}q©Ā¦kś%¹t™kĄ üĄī”¦ĄxüÓ$_Z:ŒÄŽįQÉ0‡½;Ą5`hæ_·•s2`vļąę®PpwuMӑ¾aˆĀĘZcō $Mé@’äē“œY:ŒČĻÆI†)lŽ™ä\†ö£„Ą¶«ŪźŃIžyé02ēķ–.lŗ¦ļcŹ€qzÜī]i€r~5Éń„CĄˆõüšd˜ ›DaĄxż³Ņ`[ÕmuN’ļ,Fę=]Óßx“oŖ°yC’Ļt-ŅwÖmõŠŅ!`K5īż&LÅł³|Ó / ]Óߖä¼!®;&É—Ū¦n«*É–Ī#tŌ‡“a?ńųóÆCznŻVĒ•[ęk’<¢t™>ɛgłĘ! ›—'¹eĄėĄPĪNņŻ„CĄ–ł'„Ą½·kśfłĘĮ ›®éoMņ²”®ū®Ņ`[ŌmuZ”¤p(ošõ‡>ī |=ŹÓJ€-ņ’ܧt”™ļ²=taóŚ$×|MĀ#ź¶:½tŲÖ”ąŽnȌ'6]ÓߕäÅC^ōŌŅ`źź¶zJ’/+FčÜŻŽd&COŲ$ɟ­ąš0… ¬ž³kąŠ^:Ļ7Æ¢°¹(ÉÕ+ø.,Ka«÷U„Ą}.;ĒČĢlšĀ¦kś>ɟ}]€ƒ‡a…ź¶:6ÉÓKē€zu×ō·Ķ󫘰IÜ- €qz`ŻVē”öeIīW:ŒŠK꿁•6]Ó_šä²U\–d- Vē„ĄŻ‘ä•óžŠŖ&l‡0N_^:L˜ókąŽŽŠ5żĶóžŠ* kQŒŃ£J€ SŲĄ½Ķ½•¬°°éšžƒI޾ŖėĄ‚V:LQŻVIrVé02{“œ»Č®rĀ&1eĄų(l`5Lץ½]Ō5żµ‹üąŖ ›æČN›cńĄŗ­N(&Ha÷öŅEp„…M×ōOņęU>Ģ©JāÖŽ0<… ÜŪ8 ›]Ö¢kQ0 ŗ­Ž‰½ą`ļ蚾ŖEx…Ķ‹“ܹ†ē€Y)l`Xg'9¦t™æ\ę‡W^ŲtMC’óVż<0‡/*&ęĮ„ĄČܙ¤]ę똰I¬E0.&l`X)Fęe‹ŽjŸu6•äskz.8… Ė„ č÷—½ĄZ ›®é?—ä×ń\0+Q0,6p%yòYׄM’¼`ĻGrNŻVUé0! øĒļwMß/{‘µ6]Ó ÉėÖõ|pĒ'yPé0!V¢`Ē҇ ļ³Ī ›$łÆk~>8kQ06°ć„Ė6¼Ļŗ ›Weg— Jsš0 Ē„ ģXś°į}ÖZŲtMæ7Éo­ó9ą060€ŗ­ī—ä“Ņ9`®HņĘ”.¶ī ›$łIn)š¼°?… Ćt ģä°į}Ö^ŲtMs:€–ą Ę„Ąܑ»Ž6ÉĪZŌ`­,Ą„ ćųŅ`^Ś5żuC^°HaÓ5żeIĪ+ńܰKaĆ8®tßś‚„&l·ų ¬Sź¶:µt˜… ŪīƒIĪś¢% ›×$¹¼ąó€)XžĀ€m÷›C6¼O±Āf÷?Œ[|P’Ā–§°`›}<ɬāĀ%'l’”o.œ€ķåNQ°<… Ūģ’ėšžöU\øhaÓ5żgćߔcĀ–§°`[}<É WuńŅ6Iņ‚øÅ7e(l`y ¶Õʦk’6]Ó_‘äU„s°•Z:L€Ā€m“Ņéšd…Ķ®_+€­t’Ņ`n+ XétM2’¦kś ’œ[:[ē”Ņ`>[:¬ŁŹ§k’‘6»~*ɝ„C°UN-&@aĄ¶YłtM2¢Ā¦kśĖ“üNél•ė¶Ķk!l(… Ūd-Ó5Ɉ ›]æ˜äĘŅ!ŲU’“K‡€ wsé°Fk™®IFVŲtMC’_.€­b- –cĀ€m±¶éšdd…Ķ®ßJrEél Ćr6l‹µM×$#,lŗ¦æ#Éæ)€­aĀ–sKé°k®IFXŲ$I×ō/IņęŅ9Ų &l` ]Óߝäó„sĄŠżĢ:§k’‘6»~2I_:“§°å]S:¬Š›ŗ¦’“u?éh ›®éߞä–ĪĄäY‰‚å]U:¬ČI~“ď¶°Łõ³In-€I3aĖSŲ0U’±kśĖJ<ńØ ›®é?–ä×Kē`Ņ6°<… StE’’PźÉG]ŲģśÕ$Ÿ,€É²ĖSŲ0E’¬kśŪJ=łč ›®éoÉĪj椰`jž¼kś×• 0śĀ&Iŗ¦o“¼“t&és„Ą(l˜’›’üĖŅ!6¢°ŁõCI>Z:“sKé0W'éK‡€ül×ōŸ*bc ›®éoLņ“ÜU: “bĀ–Ō5żķqę ÓšÖ$æ[:D²A…M’tM’×I~”tų’Ū»óXĶŹś€ć߃"•ŗZ‘¦­šj 5•†ō(85Z0ÕŅő6HįėRŃJ憖`*‹ ©µcA”S—Ö%AY†Ķ²“O[”%`7†mFd˜żéē½ĢåĪpēŽ™÷½æ÷¼ēūINŽ÷ŽÜ/!™ūęwžó<’&Š+l¤įųat€$IŪh=šīœŹ†ččŲĄfą$ąŅčIŅÄp…4ߏ$i}6§ņƒčˆ)Ų &]Ė£[$IĮ6Ņp\ IŅ6X1]ē6ƒĶĮĶķ$IŪĪ6ŅpøĀF’ŌU끃s*cu#Ɠ€œŹÅĄ§£;$I7V昄®Ź©ÜÜŻ!IŅVųxNå?£#fźģĄfąhą¢#$Ię ix\e#IźšsOEGlN§69•µ“G}?Ż"Iź,WŲHĆć>6’¤.ł1phNe,·[éōĄ §ņą]Ń’¤Īr`# +l$I]± XœSy0:ä©t~`Sł&pFt‡$©“|$Jž ¬Ž$iޟS¹>:b61°ų0v›I’ĘŚŗœŹźčiRäT®Šī$i šœŹ™Ń[21›œŹ*ą`¬'d’¤±ņpt€4–FH’4‹€÷FGĢÅÄ lą‰»:onn‘$u‚æ/¤įs`#IWÓī[óxtČ\LŌĄ §²Ųø;ŗE’4ön‰&MNåą§Ń’$mĘa9•Ū¢#ęjā6šÄÉQūD·H’ĘŚ­ŃŅ„r•$iܜšS9;:b>&r`S¹ x šXt‹$il9°‘Fć‚čI’¦¹ųhtÄ|MģĄ §r5°—”$mži4.:±?€$iāż8 §².:d¾&z`S¹8 (Ń-’¤±²7–Fb°™ćyŃ’¤Ž»Ų/§ņ`tČ֘ų @NåkĄ‘Ń’¤±r{ļ“HņÅčIRÆŻ¼1§²":dkõb`Sł,š‰čIŅŲø::@šp’ü,:B’ŌKwoČ©tśōčŽ lr*Ē’Ż!I WDH“,§²8+ŗC’Ō;÷Ņk:Ó W›#€ÆGGH’Ā] õĄYĄ†čIRoÜOūŌmŃ!ĆŠ»ĶąnĻĮĄæF·H’ĀܑSY!MŗœŹĻi’$iŌ¢Ż`ųęča鯥 §²žöäØĻE·H’B\ õˆ›K’Fm%šĒ9•ė¢C†©—€œJÉ©¼ųdt‹$iĮ] õČw€åŃ’¤‰µ 8 §2qJōv`3%§r4šŃčIŅ‚ŗ<:@ź‹œŹąSŃ’¤‰“xkNå²čQ迥 §r š^ D·H’FŹ]ŃRĻ,ĮU6’¤įz80§rAtČØ8°Č©|8XŻ"I©ÆDH}“Sy WŁH’†ē`QNå;Ń!£äĄfšœŹW·«£[$I#±ųft„ŌS®²‘$ ĆõĄŽ9•k¢CFĶĶ ƒ ݟŠī2-Iš,Ks*DGH}ä*IŅœ ģ“SY²ŲlFNå»Ą~“ēøK’&‡CI±\e#IŚZŸnō‚›§08ģõĄŠčIŅP<,Žślš!ū¤čIR§¬Ī©SéÕAAlf‘S¹xąi"’Ō}_/,)Ö?7FGH’:į>ąõ9•ÆE‡Dp`³9•[}€;¢[$I[m pJt„$Č©¬Ž ōź.©$iŽn Ż\8G‡Dq`39•ŸÆ® N‘$m/ęTīŒŽŌ|ų>=ŗC’4¶Ī^›SłytH$6s”S¹X\Ż"Iš—5Ą‰Ń’6ń1ąŽčIŅŲłšē9•G£C¢U„_{öl³ŗ©¶Ī‰n‘$ĶɒœŹŃ’6U7Õ_’Ż!I ?Ž—Sńˆ6[©nŖ£¢;$I³Z ¼,§²,:DŅęÕMu°t‡$)ĢZąTą„>Ł=>µ•r*Žlˆn‘$=„3ÖHcļ]ĄżŃ’¤WÆĪ©å°fSl¶ANåsĄĄŖčIŅ&–ĒGGHšŻ`CɃń&˜$õÉ/wūęTnŠŽW>5uSķ œ˜SY2īŲ IŻTæ \ģŻ"IāĖ9•C£#$Ķ]ŻTŪK7E·H’F⿁äT®Œé 6CT7ÕnĄ…ĄžŃ-’Ōcw{ęTŠ‘4?uS½øųµčIŅŠüųxNåģ萮q›!Ź©Üģ \œ"I}U€w8¬‘ŗ)§r?°˜ö„7IR·Ż ¼ŲĆaĶÖq…ĶŌMµšeŚ ‰%I gINåˆčIŪ¦nŖƒi?KUŃ-’¤y{88-§²2:¦Ė،HŻTpščIź‰ļ‹<Rš uSż-°$ŗC’4gk€ÓOø”šp8°±ŗ©>D;]ō‘$ĪĄkr*Ė£C$ OŻT¦ż%I_g§ęTīŽŽ™$l@ŻTgψn‘¤ “‚vXs{tˆ¤į«›źą˜čIŅ&V’üsNåĮč˜IäĄfŌMUßv‹n‘¤ ²x}NåščI£S7ÕiĄ‘Ń’$~|ųRNåńč˜IęĄfÕMµ+š ąƒS$i¬ž4§rAtˆ¤Ńģ x:šĪčIź±€“oäTÖGĒō›V7ÕӁ“€F·HRĒžS9+:BŅĀ©›źxąøčIź‘õĄyĄēs*—DĒō› uS½ ųšģčI꘵Ą»ÖHżT7Õ_gāŽ€’4JwÓž]ū…œŹ²č˜¾r`ØnŖWgƈn‘¤ŽxxkNåņčIqź¦Z|x^t‹$M\ |87§².ø§÷Ų«›ź9@üEpŠ$»oĪ©Ü")^ŻTæ,^Ż"I÷KŚSOϩܣ،‰ŗ©>|xZt‹$”«i7žEtˆ¤ńQ7ÕĪ“+mö‰n‘¤ŽYI;ōž&°4§²*øG›įĄfŒŌMµ°Ų;ŗE’ĘČׁ”SY"iüŌMõ4ąhąąéĮ9’4Ī.`ćę±ąm›1S7ÕvĄß'ĻĪ‘¤Hk€ć“rņ—•¤ŁÕMµ7šUąåŃ-’4F.¤ҜŸSYÜ£yp`3¦K|OŖąIZh’K{l÷ĶŃ!’ŗ£nŖg§ļŠn‘¤@«h‡4ßĪĖ©<Ü£­äĄfĢÕMõŚĒ¤^Ż"I ąqąXą“œŹśčIŻT7Õ[€/»F·HŅY \D»’ę¼œŹ#Į=60x6ū}Ą ĄNĮ9’4*WļštIĆP7Õ.Ą?‡ć”’&ÓąbŚ!͹9•‡ƒ{4dl:¤nŖŸŠn‘¤!z8 Xā^5’†­nŖ=€OūG·HҬ¾K;¤9'§ņPpFȁMÕMõ{ĄGÅxĒHRw­ž 8&§ņ³čI“­nŖżi7{D·HŅ<¬®.\ßĖ©<›¤…āĄ¦Ćź¦zšaąP`‡ąIš«B{WčųœŹ­Ń1’ścš˜łį“™æ(8G’6§7Ńg.žĖU4żåĄfŌMõ«Ąßļžœ#I³ł6p\NåĘčIż58Mź0ąļšpIńnc㠚Ės*+‚{4&ŲLŗ©ž |Ų%8G’¦¬£ԜœS¹6:F’¦ŌMUoŽŽœ#©?–±q@sYNåĪą)6ØnŖi—ū~ųõŲI=vpš…œŹ=Ń1’4›ĮęÄGožœ#i²üøœĮcNžˆ©¹r`3ĮwŃ~šX <7¶HRO\ ,”=^r]tŒ$ĶGŻT; ųKą÷ck$uŠ:ąfŚ‚ƾÜčI˜Ślz¢nŖh—ü¾}šź&Œ†ep p>š­œŹ‚{$i(ź¦ś ąmĄĄ^Į9’ĘĻŚ ‚Æcć€ę†œŹźŠ*M 6=4Ųėf1ķšfPÅIź ‡Kh‡4ęT–÷HŅHÕMõ›l޼:8GŅĀ[ ÜČĘĮĢu“+gքVi¢9°é¹ŗ©^4ø^œ#i¼ŻN; 9ŸöˆÉµĮ=’bšłišŗĮõŠŲ"IC¶ ų!3×7ūŁG ́žP7ՋiOHxćązql‘¤`ė€+i4K}ŌI’6ÆnŖ]€}Ł8Ąy°]h”¤¹Ųü ų?ąGĄõ“ƙ[܇O楁žRŻTÆžˆvx³Ų)¶H҈­n”½“tpqNå”Ų$Iźžŗ©v^¼dpķ>ķżŌå~‚ҹv(3óŗĆżf4ĪŲhNź¦z:°7Wßü°}h”¤mq/ķRߦ½ŽźR_IZƒU9O5ŠŁŲ Ų1,PźžGŲüPę6o@©«Ųh« Nś]Śö¢Ż|oą‘]’61µję‡LŠäTV„VI’¶ØnŖ°é@g7``ēiÆ®‚Vl ])s°Œvo½'39•{Ū¤‘p`£”©›źĄž“ƛ©AĪžøäWµ•ĄŻÓ®ŸÓžbąŖIꁺ©¶§Ü̼vyŠļw4^„Ä̼īžöž^÷•Qß8°ŃH >@üķę{/qķ˜&uĮjąž<ŒŁär™Æ$i¾ź¦z›q~xķŠ-½>7VÖģ ššKąŲ™zæ#ķŠėgN»v˜ć{··x€vš2uĶåėr*"‚„IįĄFci°2g×ĮõĀiļg~żBŚå¾ž2Ÿ›õĄ*Ś_¼kim^;ćż¶~oź/•jŚæwsļēś½Qü­3’[ęó:żż*f br*!I’¶É`04s3õõv“æŪ·ō:—ŸõŸ©h?#m˜qĶüް~f’쵓C—•[ž?%iŲh"ŌMõ\ął“wp¦®gĪųz¶ļĻē{…vš±nš:óŚÜ÷ēó³ėi…Y5ø¦æŸķŚāĻłÜÆ$I’$uĆ’ĘK}8EģålIEND®B`‚meson-0.40.1/graphics/meson_logo.svg0000644000175000017500000004564012650745767021025 0ustar jpakkanejpakkane00000000000000 image/svg+xml meson-0.40.1/graphics/wrap_logo.svg0000644000175000017500000001056212650745767020650 0ustar jpakkanejpakkane00000000000000 image/svg+xml meson-0.40.1/setup.py0000644000175000017500000000737113043442071016027 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Copyright 2016 The Meson development team # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys from distutils.dir_util import mkpath from distutils.file_util import copy_file from mesonbuild.coredata import version if sys.version_info[0] < 3: print('Tried to install with Python 2, Meson only supports Python 3.') sys.exit(1) # We need to support Python installations that have nothing but the basic # Python installation. Use setuptools when possible and fall back to # plain distutils when setuptools is not available. try: from setuptools import setup from setuptools.command.install_scripts import install_scripts as orig except ImportError: from distutils.core import setup from distutils.command.install_scripts import install_scripts as orig class install_scripts(orig): def run(self): if sys.platform == 'win32': super().run() return self.outfiles = [] if not self.dry_run: mkpath(self.install_dir) # We want the files to be installed without a suffix on Unix for infile in self.get_inputs(): in_stripped = infile[:-3] if infile.endswith('.py') else infile outfile = os.path.join(self.install_dir, in_stripped) # NOTE: Mode is preserved by default copy_file(infile, outfile, dry_run=self.dry_run) self.outfiles.append(outfile) setup(name='meson', version=version, description='A high performance build system', author='Jussi Pakkanen', author_email='jpakkane@gmail.com', url='http://mesonbuild.com', license=' Apache License, Version 2.0', packages=['mesonbuild', 'mesonbuild.modules', 'mesonbuild.scripts', 'mesonbuild.backend', 'mesonbuild.wrap'], scripts=['meson.py', 'mesonconf.py', 'mesontest.py', 'mesonintrospect.py', 'wraptool.py'], cmdclass={'install_scripts': install_scripts}, data_files=[('share/man/man1', ['man/meson.1', 'man/mesonconf.1', 'man/mesonintrospect.1', 'man/mesontest.1', 'man/wraptool.1'])], classifiers=['Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Natural Language :: English', 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: BSD', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python :: 3 :: Only', 'Topic :: Software Development :: Build Tools', ], long_description='''Meson is a cross-platform build system designed to be both as fast and as user friendly as possible. It supports many languages and compilers, including GCC, Clang and Visual Studio. Its build definitions are written in a simple non-turing complete DSL.''') meson-0.40.1/test cases/0000755000175000017500000000000013100703042016333 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/0000755000175000017500000000000013100703042020025 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/10 vs module defs generated/0000755000175000017500000000000013100703045024750 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/10 vs module defs generated/meson.build0000644000175000017500000000030113074426732027123 0ustar jpakkanejpakkane00000000000000project('generated_dll_module_defs', 'c') if meson.get_compiler('c').get_id() == 'msvc' subdir('subdir') exe = executable('prog', 'prog.c', link_with : shlib) test('runtest', exe) endif meson-0.40.1/test cases/windows/10 vs module defs generated/subdir/0000755000175000017500000000000013100703045026240 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/10 vs module defs generated/subdir/somedll.def.in0000644000175000017500000000002313074426732030776 0ustar jpakkanejpakkane00000000000000EXPORTS @func@ meson-0.40.1/test cases/windows/10 vs module defs generated/subdir/meson.build0000644000175000017500000000036013074426732030420 0ustar jpakkanejpakkane00000000000000conf = configuration_data() conf.set('func', 'somedllfunc') def_file = configure_file( input: 'somedll.def.in', output: 'somedll.def', configuration : conf, ) shlib = shared_library('somedll', 'somedll.c', vs_module_defs : def_file) meson-0.40.1/test cases/windows/10 vs module defs generated/subdir/somedll.c0000644000175000017500000000007413074426732030063 0ustar jpakkanejpakkane00000000000000#ifdef _MSC_VER int somedllfunc() { return 42; } #endif meson-0.40.1/test cases/windows/10 vs module defs generated/prog.c0000644000175000017500000000014013074426732026075 0ustar jpakkanejpakkane00000000000000int somedllfunc(); int main(int argc, char **argv) { return somedllfunc() == 42 ? 0 : 1; } meson-0.40.1/test cases/windows/1 basic/0000755000175000017500000000000013100703045021232 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/1 basic/installed_files.txt0000644000175000017500000000004213057037357025151 0ustar jpakkanejpakkane00000000000000usr/bin/prog.exe usr/bin/prog.pdb meson-0.40.1/test cases/windows/1 basic/meson.build0000644000175000017500000000014313057037357023413 0ustar jpakkanejpakkane00000000000000project('wintest', 'c') prog = executable('prog', 'prog.c', install : true) test('wintest', prog) meson-0.40.1/test cases/windows/1 basic/prog.c0000644000175000017500000000011012650745767022367 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/windows/7 mingw dll versioning/0000755000175000017500000000000013100703045024200 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/7 mingw dll versioning/installed_files.txt0000644000175000017500000000046013074426732030121 0ustar jpakkanejpakkane00000000000000usr/bin/?libsome-0.dll usr/lib/libsome.dll.a usr/bin/?libnoversion.dll usr/lib/libnoversion.dll.a usr/bin/?libonlyversion-1.dll usr/lib/libonlyversion.dll.a usr/bin/?libonlysoversion-5.dll usr/lib/libonlysoversion.dll.a usr/libexec/?libcustomdir.dll usr/libexec/libcustomdir.dll.a usr/lib/?libmodule.dll meson-0.40.1/test cases/windows/7 mingw dll versioning/lib.c0000644000175000017500000000011312742140120025105 0ustar jpakkanejpakkane00000000000000#ifdef _WIN32 __declspec(dllexport) #endif int myFunc() { return 55; } meson-0.40.1/test cases/windows/7 mingw dll versioning/meson.build0000644000175000017500000000327213074426732026365 0ustar jpakkanejpakkane00000000000000project('mingw dll versioning', 'c') cc = meson.get_compiler('c') if cc.get_id() == 'msvc' error('MESON_SKIP_TEST: test is only for MinGW') endif # Test that MinGW/GCC creates correctly-named dll files and dll.a files, # and also installs them in the right place some = shared_library('some', 'lib.c', version : '1.2.3', soversion : '0', install : true) noversion = shared_library('noversion', 'lib.c', install : true) onlyversion = shared_library('onlyversion', 'lib.c', version : '1.4.5', install : true) onlysoversion = shared_library('onlysoversion', 'lib.c', # Also test that int soversion is acceptable soversion : 5, install : true) # Hack to make the executables below depend on the shared libraries above # without actually adding them as `link_with` dependencies since we want to try # linking to them with -lfoo linker arguments. out = custom_target('library-dependency-hack', input : 'exe.orig.c', output : 'exe.c', depends : [some, noversion, onlyversion, onlysoversion], command : ['cp', '@INPUT@', '@OUTPUT@']) # Manually test if the linker can find the above libraries # i.e., whether they were generated with the right naming scheme test('manually linked 1', executable('manuallink1', out, link_args : ['-L.', '-lsome'])) test('manually linked 2', executable('manuallink2', out, link_args : ['-L.', '-lnoversion'])) test('manually linked 3', executable('manuallink3', out, link_args : ['-L.', '-lonlyversion'])) test('manually linked 4', executable('manuallink4', out, link_args : ['-L.', '-lonlysoversion'])) shared_library('customdir', 'lib.c', install : true, install_dir : get_option('libexecdir')) shared_module('module', 'lib.c', install : true) meson-0.40.1/test cases/windows/7 mingw dll versioning/exe.orig.c0000644000175000017500000000015213057037357026103 0ustar jpakkanejpakkane00000000000000int myFunc (void); int main (int argc, char *argv[]) { if (myFunc() == 55) return 0; return 1; } meson-0.40.1/test cases/windows/2 winmain/0000755000175000017500000000000013100703045021614 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/2 winmain/meson.build0000644000175000017500000000014112650745767024004 0ustar jpakkanejpakkane00000000000000project('winmain', 'c') exe = executable('prog', 'prog.c', gui_app : true) test('winmain', exe) meson-0.40.1/test cases/windows/2 winmain/prog.c0000644000175000017500000000023412650745767022760 0ustar jpakkanejpakkane00000000000000#include int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { return 0; } meson-0.40.1/test cases/windows/4 winmaincpp/0000755000175000017500000000000013100703045022321 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/4 winmaincpp/meson.build0000644000175000017500000000015312650745767024514 0ustar jpakkanejpakkane00000000000000project('winmaincpp', 'cpp') exe = executable('prog', 'prog.cpp', gui_app : true) test('winmaincpp', exe) meson-0.40.1/test cases/windows/4 winmaincpp/prog.cpp0000644000175000017500000000025012650745767024023 0ustar jpakkanejpakkane00000000000000#include class Foo; int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { return 0; } meson-0.40.1/test cases/windows/3 cpp/0000755000175000017500000000000013100703045020735 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/3 cpp/meson.build0000644000175000017500000000012312650745767023125 0ustar jpakkanejpakkane00000000000000project('wincpp', 'cpp') exe = executable('prog', 'prog.cpp') test('wincpp', exe) meson-0.40.1/test cases/windows/3 cpp/prog.cpp0000644000175000017500000000012312650745767022436 0ustar jpakkanejpakkane00000000000000#include class Foo; int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/windows/8 msvc dll versioning/0000755000175000017500000000000013100703045024030 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/8 msvc dll versioning/installed_files.txt0000644000175000017500000000045013074426732027750 0ustar jpakkanejpakkane00000000000000usr/bin/some-0.dll usr/bin/some-0.pdb usr/lib/some.lib usr/bin/noversion.dll usr/bin/noversion.pdb usr/lib/noversion.lib usr/bin/onlyversion-1.dll usr/lib/onlyversion.lib usr/bin/onlysoversion-5.dll usr/lib/onlysoversion.lib usr/libexec/customdir.dll usr/libexec/customdir.lib usr/lib/module.dll meson-0.40.1/test cases/windows/8 msvc dll versioning/lib.c0000644000175000017500000000011312742140120024735 0ustar jpakkanejpakkane00000000000000#ifdef _WIN32 __declspec(dllexport) #endif int myFunc() { return 55; } meson-0.40.1/test cases/windows/8 msvc dll versioning/meson.build0000644000175000017500000000332113074426732026210 0ustar jpakkanejpakkane00000000000000project('msvc dll versioning', 'c') cc = meson.get_compiler('c') if cc.get_id() != 'msvc' error('MESON_SKIP_TEST: test is only for msvc') endif # Test that MSVC creates correctly-named dll files and .lib files, # and also installs them in the right place some = shared_library('some', 'lib.c', version : '1.2.3', soversion : '0', install : true) noversion = shared_library('noversion', 'lib.c', install : true) onlyversion = shared_library('onlyversion', 'lib.c', version : '1.4.5', install : true) onlysoversion = shared_library('onlysoversion', 'lib.c', # Also test that int soversion is acceptable soversion : 5, install : true) # Hack to make the executables below depend on the shared libraries above # without actually adding them as `link_with` dependencies since we want to try # linking to them with -lfoo linker arguments. cp = find_program('copyfile.py') out = custom_target('library-dependency-hack', input : 'exe.orig.c', output : 'exe.c', depends : [some, noversion, onlyversion, onlysoversion], command : [cp, '@INPUT@', '@OUTPUT@']) # Manually test if the linker can find the above libraries # i.e., whether they were generated with the right naming scheme test('manually linked 1', executable('manuallink1', out, link_args : ['-L.', '-lsome'])) test('manually linked 2', executable('manuallink2', out, link_args : ['-L.', '-lnoversion'])) test('manually linked 3', executable('manuallink3', out, link_args : ['-L.', '-lonlyversion'])) test('manually linked 4', executable('manuallink4', out, link_args : ['-L.', '-lonlysoversion'])) shared_library('customdir', 'lib.c', install : true, install_dir : get_option('libexecdir')) shared_module('module', 'lib.c', install : true) meson-0.40.1/test cases/windows/8 msvc dll versioning/copyfile.py0000644000175000017500000000013413065321007026216 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) meson-0.40.1/test cases/windows/8 msvc dll versioning/exe.orig.c0000644000175000017500000000015213057037357025733 0ustar jpakkanejpakkane00000000000000int myFunc (void); int main (int argc, char *argv[]) { if (myFunc() == 55) return 0; return 1; } meson-0.40.1/test cases/windows/6 vs module defs/0000755000175000017500000000000013100703045022756 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/6 vs module defs/meson.build0000644000175000017500000000026712700546566025147 0ustar jpakkanejpakkane00000000000000project('dll_module_defs', 'c') if meson.get_compiler('c').get_id() == 'msvc' subdir('subdir') exe = executable('prog', 'prog.c', link_with : shlib) test('runtest', exe) endif meson-0.40.1/test cases/windows/6 vs module defs/subdir/0000755000175000017500000000000013100703045024246 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/6 vs module defs/subdir/somedll.def0000644000175000017500000000002612700546566026405 0ustar jpakkanejpakkane00000000000000EXPORTS somedllfunc meson-0.40.1/test cases/windows/6 vs module defs/subdir/meson.build0000644000175000017500000000011712700546566026431 0ustar jpakkanejpakkane00000000000000shlib = shared_library('somedll', 'somedll.c', vs_module_defs : 'somedll.def') meson-0.40.1/test cases/windows/6 vs module defs/subdir/somedll.c0000644000175000017500000000007412700546566026074 0ustar jpakkanejpakkane00000000000000#ifdef _MSC_VER int somedllfunc() { return 42; } #endif meson-0.40.1/test cases/windows/6 vs module defs/prog.c0000644000175000017500000000014012700546566024106 0ustar jpakkanejpakkane00000000000000int somedllfunc(); int main(int argc, char **argv) { return somedllfunc() == 42 ? 0 : 1; } meson-0.40.1/test cases/windows/5 resources/0000755000175000017500000000000013100703045022167 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/5 resources/meson.build0000644000175000017500000000342013074426732024347 0ustar jpakkanejpakkane00000000000000project('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' 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 src_parts = meson.source_root().split('/') build_parts = meson.build_root().split('/') # Get the common path (which might just be '/' or 'C:/') common = [] done = false count = 0 if src_parts.length() > build_parts.length() parts = build_parts other = src_parts else parts = src_parts other = build_parts endif foreach part : parts if not done and part == other.get(count) common += [part] else done = true endif count += 1 endforeach # Create path components to go down from the build root to the common path count = 0 rel = build_parts foreach build : build_parts if count < build_parts.length() - common.length() rel += ['..'] endif count += 1 endforeach # Create path components to go up from the common path to the build root count = 0 foreach src : src_parts if count >= common.length() rel += [src] endif count += 1 endforeach build_to_src = '/'.join(rel) if build_to_src.contains(' ') message('build_to_src is: ' + build_to_src) error('MESON_SKIP_TEST build_to_src has spaces') endif # Welcome to the end of this conditional. # We hope you never have to implement something like this. endif subdir('inc') subdir('res') exe = executable('prog', 'prog.c', res, gui_app : true) test('winmain', exe) meson-0.40.1/test cases/windows/5 resources/res/0000755000175000017500000000000013100703045022760 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/5 resources/res/sample.ico0000644000175000017500000002267613070746245024771 0ustar jpakkanejpakkane0000000000000000 Ø%(0` ’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåóåóåóåóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåóåóåóåóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåóåóåóåóåóåó åó åóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåóåó åóåóåóåóåóåóåó åó åóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåó åóåó#åó+åó/åó1åó-åó%åóåóåóåó åóåó’’’’’’’’’’’’’’’’’’’’’åóåóåó åóåóåóåóåó"åó&åó(åó)åó&åó!åóåóåóåó åóåó’’’’’’’’’’’’’’’’’’åóåó åóåó*åó<åóIåóQåóQåóKåóCåó:åó.åó&åóåóåó åóåó’’’’’’’’’’’’åóåóåóåóåó&åó.åó0åó7åó<åóCåóFåóEåóBåó;åó3åó*åó!åóåóåóåó’’’’’’’’’’’’åóåóåóåó*åó@åóVåófåókåógåóaåóXåóOåóFåó<åó3åó(åóåóåóåó’’’’’’’’’åóåóåó#åó4åóDåóLåóQåóVåóXåó[åó^åó]åóZåóRåóMåóCåó8åó-åó åóåó åó’’’’’’’’’åóåóåó$åó<åóVåójåóxåóyåóvåómåóbåó\åóWåóQåóHåó?åó0åó"åóåóåó’’’’’’åóåó"åó9åóNåóbåójåólåójåóiåógåóhåógåódåóaåóZåóWåóMåóBåó4åó'åóåó åó’’’åóåóåóåó0åóIåóbåóuåó|åóxåóråóeåó^åó[åó[åó^åó^åóXåóKåó6åó#åóåó’’’’’’åóåó.åóKåóhåó{åó€åóåósåónåógåóeåódåóaåó_åócåóaåó_åóYåóJåó:åó(åóåó åóåóåó åóåó7åóUåójåóuåózåónåócåóWåóPåóPåóVåóbåójåójåó`åóMåó4åóåó åó’’’åóåó7åóYåówåó‰åóˆåó‚åóqåóaåóWåóUåóSåóTåóUåóZåó`åófåóeåó^åóPåó>åó*åóåóåóåóåó åó?åóXåójåóråómåó]åóJåó>åó8åó;åóJåó_åómåótåóqåó_åóCåó(åóåó’’’åóåó:åó_åó~åóŒåó‰åó~åófåóQåó?åó7åó7åó:åó?åóJåóVåóbåójåókåóbåóQåó8åó"åóåó åóåó"åó>åóVåógåólåócåóNåó7åó(åóåó(åó:åóRåóiåóyåóxåóiåóOåó1åóåó ’’’åóåó<åóaåózåó†åóƒåóqåóXåó;åó(åóåóåóåó'åó2åóCåóSåódåónåójåó]åóFåó,åóåó åó åóåó9åóQåódåófåó[åóGåó-åóåó åóåó(åóDåóaåóuåó|åóqåó[åó>åó"åó åóåóåó9åó]åóuåóåóyåófåóDåó+åóåó åó åó åóåó åó-åóDåóYåóhåókåócåóMåó5åóåó åó åóåó2åóJåó]åódåó]åóHåó+åóåóåó åóåó5åóTåómåóxåósåóaåóGåó)åóåóåóåó3åóSåólåóuåónåóWåó7åóåó åó’’’’’’åóåó åó åó1åóJåó]åógåódåóRåó9åóåó åó åóåó,åóEåó\åóeåócåóOåó7åóåó åóåóåó+åóDåó]åómåónåóbåóJåó.åóåó åóåó-åóHåó^åóhåó_åóHåó,åóåó’’’’’’’’’’’’åóåóåó%åó<åóTåóbåóbåóRåó;åó!åóåóåóåó$åóBåóYåóeåóhåóYåóCåó&åóåóåó åóåó5åóMåó_åódåó[åóFåó-åóåó åóåó#åó8åóJåóQåóKåó8åó$åóåó’’’’’’’’’’’’åóåóåó"åó:åóOåó^åó\åóPåó9åó åóåóåó åóåó;åóWåógåóoåófåóPåó3åóåóåóåóåó&åó8åóKåóRåóMåó=åó'åóåó åó åóåó'åó3åó7åó3åó'åóåó åó’’’’’’’’’åóåóåóåó(åó>åóRåó\åó\åóNåó8åó åóåóåóåóåó5åóRåójåóvåósåócåóGåó*åóåóåóåóåó'åó4åó;åó7åó-åóåóåóåóåó åóåóåó!åóåóåó åó’’’’’’’’’åóåó åóåó'åó8åóKåóYåó_åóYåóIåó2åóåó åóåóåóåó/åóPåólåó}åóåóuåó\åóAåó)åóåó åóåóåóåó"åó!åóåóåóåóåóåóåó åóåóåóåó åó’’’’’’’’’åóåóåóåó.åó?åóPåó\åódåócåóXåóEåó,åóåó åóåóåóåó(åóLåókåó‚åóŠåó„åótåóZåóAåó,åóåóåóåóåóåóåó åóåó’’’’’’’’’åóåóåóåóåó’’’’’’’’’åóåóåó%åó5åóHåóZåófåólåójåóaåóMåó;åó#åóåó’’’’’’åó åó#åó@åócåó€åóŽåó’åó†åóråó[åóDåó5åó#åóåó åóåóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåó åóåó+åó8åóNåócåónåótåósåóiåóVåóEåó/åóåó åó’’’’’’åóåóåó6åóYåówåóŠåóåóåó€åónåó`åóOåó;åó)åóåó åó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåó!åó-åóAåóTåógåóråó~åóyåónåó_åóJåó4åó"åóåóåó’’’’’’åóåóåó'åóFåódåó}åó…åó„åó€åóyåótåódåóUåó>åó*åóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåó%åó:åóJåóaåónåóyåó}åó{åóqåó`åóKåó6åó%åóåóåó’’’’’’’’’’’’åóåóåó3åóJåó`åólåósåóvåóxåówåóqåóeåóSåó:åó#åóåó’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó!åó9åóTåógåóxåó€åóåózåópåóaåóIåó6åó%åóåóåó’’’’’’’’’’’’’’’åóåó åóåó,åó>åóKåóSåó^åóhåósåótåópåó_åóHåó-åóåó’’’’’’’’’’’’’’’’’’’’’åóåó åóåó3åóMåókåó|åó‡åó†åóåóqåó^åóEåó1åó!åóåóåó’’’’’’’’’’’’’’’’’’’’’åóåóåóåó åó*åó3åóAåóRåóaåóoåósåójåóTåó8åóåó åó’’’’’’’’’’’’’’’’’’åóåóåó$åóBåó]åóvåóƒåó‡åóƒåóuåó_åóEåó-åóåó åó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó åóåóåó'åó7åóQåóeåóoåólåó]åóCåó'åóåó’’’’’’’’’’’’’’’åóåó åóåó2åóMåóeåóxåó‚åóåóråó_åóEåó.åóåó åó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåóåó)åóBåó]åónåópåófåóNåó/åóåó’’’’’’’’’’’’’’’åóåóåó åó8åóTåókåóuåóvåójåóWåóCåó/åóåó åó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó>åóYåóoåótåólåóUåó9åóåó ’’’’’’’’’’’’’’’åóåóåó$åó?åó[åójåóråóiåóXåó?åó,åóåó åó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó6åóYåóoåó{åótåó_åó:åó åó åó’’’’’’’’’’’’åóåóåó&åóCåó]åómåómåócåóJåó1åóåó åóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó9åó\åótåó~åóuåóaåóAåó!åó åó’’’’’’’’’’’’åóåóåó(åóHåó_åónåóoåóaåóFåó*åóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåó åóåó:åóZåósåó|åóråó\åó:åóåó åó’’’’’’’’’’’’åóåóåó%åóCåó`åópåópåófåóIåó*åóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåó åó"åó?åó\åóråóxåókåóRåó4åóåó’’’’’’’’’’’’’’’åóåó åó$åó>åó[åónåótåójåóRåó3åóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåó åó åó<åóXåómåólåó^åóEåó)åóåó’’’’’’’’’’’’’’’åóåó åóåó5åóWåókåótåómåóZåó<åóåó åó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåó åó"åó?åóVåógåóeåóVåó;åó#åó åó’’’’’’’’’’’’’’’’’’åóåóåó-åóIåófåóråópåó_åóEåó(åóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó#åó@åóUåódåóaåóNåó4åóåóåó’’’’’’’’’’’’’’’’’’åóåóåó$åó@åó]åópåóråóhåóQåó2åóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó*åóGåó[åófåó_åóMåó2åóåó’’’’’’’’’’’’’’’’’’’’’åóåó åóåó;åóZåómåóvåópåó^åóAåó(åóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåó åóåó2åóOåócåókåócåóNåó0åóåó’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó2åóQåókåóxåówåójåóPåó:åó&åóåó åóåóåó’’’’’’åóåóåóåóåóåóåóåó åóåóåóåóåó.åóBåó[åókåópåógåóQåó3åóåó’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó)åóGåócåóuåóyåópåó`åóNåó<åó-åó"åóåóåó åó åó åó åó åó åó åóåóåóåóåó"åó*åó/åó8åóBåóSåógåósåósåóhåóRåó/åóåóåó’’’’’’’’’’’’’’’’’’’’’åóåó åó åó:åóTåóiåóuåótåómåóaåóTåóHåó<åó2åó*åó%åó#åó$åó!åó"åó"åó!åó!åó'åó-åó6åó?åóDåóLåóOåóVåóaåónåósåóråóaåóIåó-åóåóåó’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó*åóBåóYåógåólåóoåójåóeåó\åóSåóMåóHåóFåóCåóAåóAåó@åó>åó>åó>åóBåóGåóPåóWåóZåó^åóaåóbåófåómåómåóeåóUåó>åó"åóåóåó’’’’’’’’’’’’’’’’’’’’’’’’åóåó åóåó,åó?åóOåó^åóeåóhåójåóiåógåódåóbåóeåóeåóeåóbåó]åóZåóVåóTåóUåóYåó^åócåóhåófåócåó`åóbåóaåó]åóSåóDåó.åóåó åó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåó åóåó*åó7åóCåóQåó\åócåófåókåónåóråótåówåóvåótåópåóiåócåóbåóaåó^åóaåóbåócåó_åóXåóSåóNåóMåóDåó;åó-åóåóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåó åóåó!åó+åó8åóDåóPåóXåóbåókåópåóxåó{åó|åóyåóråójåóaåó]åó[åóXåóVåóTåóRåóJåóCåó=åó7åó/åó*åó!åóåó åóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó åóåó åó*åó6åó@åóMåóWåó`åóhåónåónåóhåóaåóZåóQåóKåóGåóDåó@åó:åó5åó-åó)åó!åóåóåóåóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó åóåóåó%åó/åó:åóFåóNåóSåóTåóQåóIåó@åó:åó0åó,åó)åó&åó!åóåóåóåóåó åóåóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåó åóåóåó åó%åó*åó/åó0åó.åó(åó"åóåóåóåóåóåóåó åóåóåóåóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåó åóåóåóåóåóåóåóåó åó åóåóåóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’åóåóåóåóåóåóåóåóåóåó’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ü’ž’šą?ą?€Ą€€<<8pąĮĄ`’`ü`ųšųššųšüą’ą?’ąą’ąą’ąą’’Ąą’’Ąą’’Ąą’’Ąš’’Ąš’’Ąš?žųųųüüž’’€?’ą’ų’’ž’’’Ą’’meson-0.40.1/test cases/windows/5 resources/res/meson.build0000644000175000017500000000013613070746245025141 0ustar jpakkanejpakkane00000000000000win = import('windows') res = win.compile_resources('myres.rc', include_directories : inc) meson-0.40.1/test cases/windows/5 resources/res/myres.rc0000644000175000017500000000010413070746245024457 0ustar jpakkanejpakkane00000000000000#include #include"resource.h" ICON_ID ICON "sample.ico" meson-0.40.1/test cases/windows/5 resources/prog.c0000644000175000017500000000037112650745767023335 0ustar jpakkanejpakkane00000000000000#include #define MY_ICON 1 int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HICON hIcon; hIcon = LoadIcon(NULL, IDI_APPLICATION); return hIcon ? 0 : 1; } meson-0.40.1/test cases/windows/5 resources/inc/0000755000175000017500000000000013100703045022740 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/5 resources/inc/meson.build0000644000175000017500000000004613070746245025121 0ustar jpakkanejpakkane00000000000000inc = include_directories('resource') meson-0.40.1/test cases/windows/5 resources/inc/resource/0000755000175000017500000000000013100703045024567 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/5 resources/inc/resource/resource.h0000644000175000017500000000002213070746245026600 0ustar jpakkanejpakkane00000000000000#define ICON_ID 1 meson-0.40.1/test cases/windows/9 find program/0000755000175000017500000000000013100703045022531 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/windows/9 find program/meson.build0000644000175000017500000000054513055371450024711 0ustar jpakkanejpakkane00000000000000project('find program', 'c') # Test that we can find native windows executables find_program('cmd') find_program('cmd.exe') # Test that a script file with an extension can be found ext = find_program('test-script-ext.py') test('ext', ext) # Test that a script file without an extension can be found prog = find_program('test-script') test('script', prog) meson-0.40.1/test cases/windows/9 find program/test-script-ext.py0000644000175000017500000000005313055371450026172 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 print('ext/noext') meson-0.40.1/test cases/windows/9 find program/test-script0000644000175000017500000000004212747162664024757 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python print('1') meson-0.40.1/test cases/failing build/0000755000175000017500000000000013100703042021024 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing build/1 vala c werror/0000755000175000017500000000000013100703044023576 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing build/1 vala c werror/meson.build0000644000175000017500000000060513003456157025755 0ustar jpakkanejpakkane00000000000000project('valatest', 'c', default_options : 'werror=true') if find_program('valac', required : false).found() add_languages('vala') valadeps = [dependency('glib-2.0'), dependency('gobject-2.0')] # Must fail due to -Werror and unused variable in C file executable('valaprog', 'prog.vala', 'unused-var.c', dependencies : valadeps) else executable('failprog', 'unused-var.c') endif meson-0.40.1/test cases/failing build/1 vala c werror/unused-var.c0000644000175000017500000000011313033265323026036 0ustar jpakkanejpakkane00000000000000#warning "something" int somelib(void) { int unused_var; return 33; } meson-0.40.1/test cases/failing build/1 vala c werror/prog.vala0000644000175000017500000000022313003456157025423 0ustar jpakkanejpakkane00000000000000class MainProg : GLib.Object { public static int main(string[] args) { stdout.printf("Vala is working.\n"); return 0; } } meson-0.40.1/test cases/common/0000755000175000017500000000000013100703042017623 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/61 custom target source output/0000755000175000017500000000000013100703043025416 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/61 custom target source output/main.c0000644000175000017500000000011212650745767026534 0ustar jpakkanejpakkane00000000000000#include"mylib.h" int main(int argc, char **argv) { return func(); } meson-0.40.1/test cases/common/61 custom target source output/meson.build0000644000175000017500000000031713100702315027562 0ustar jpakkanejpakkane00000000000000project('source generation', 'c') ct = custom_target('gen', output : ['mylib.h', 'mylib.c'], command : [find_program('generator.py'), '@OUTDIR@'], ) e = executable('prog', 'main.c', ct) test('gentest', e) meson-0.40.1/test cases/common/61 custom target source output/generator.py0000755000175000017500000000046113057037314027776 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys, os if len(sys.argv) != 2: print(sys.argv[0], '') odir = sys.argv[1] with open(os.path.join(odir, 'mylib.h'), 'w') as f: f.write('int func();\n') with open(os.path.join(odir, 'mylib.c'), 'w') as f: f.write('''int func() { return 0; } ''') meson-0.40.1/test cases/common/74 modules/0000755000175000017500000000000013100703043021507 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/74 modules/meson.build0000644000175000017500000000011713100702323023650 0ustar jpakkanejpakkane00000000000000project('module test', 'c') modtest = import('modtest') modtest.print_hello() meson-0.40.1/test cases/common/6 linkshared/0000755000175000017500000000000013100703043022076 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/6 linkshared/main.c0000644000175000017500000000030512650745767023220 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_IMPORT __declspec(dllimport) #else #define DLL_IMPORT #endif int DLL_IMPORT func(); int main(int argc, char **arg) { return func(); } meson-0.40.1/test cases/common/6 linkshared/cpplib.cpp0000644000175000017500000000027212650745767024110 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 #define DLL_PUBLIC __declspec(dllexport) #else #define DLL_PUBLIC __attribute__ ((visibility ("default"))) #endif int DLL_PUBLIC cppfunc() { return 42; } meson-0.40.1/test cases/common/6 linkshared/installed_files.txt0000644000175000017500000000002112742140120025773 0ustar jpakkanejpakkane00000000000000usr/bin/prog?exe meson-0.40.1/test cases/common/6 linkshared/meson.build0000644000175000017500000000075113100702260024243 0ustar jpakkanejpakkane00000000000000project('shared library linking test', 'c', 'cpp') lib = shared_library('mylib', 'libfile.c' # Split to different lines before and after the comma to test parser. , install : false) # Don't install libraries in common tests; the path is platform-specific exe = executable('prog', 'main.c', link_with : lib, install : true) test('runtest', exe) cpplib = shared_library('mycpplib', 'cpplib.cpp') cppexe = executable('cppprog', 'cppmain.cpp', link_with : cpplib) test('cpptest', cppexe) meson-0.40.1/test cases/common/6 linkshared/libfile.c0000644000175000017500000000051512650745767023705 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int DLL_PUBLIC func() { return 0; } meson-0.40.1/test cases/common/6 linkshared/cppmain.cpp0000644000175000017500000000012012650745767024256 0ustar jpakkanejpakkane00000000000000int cppfunc(); int main(int argc, char **argv) { return cppfunc() != 42; } meson-0.40.1/test cases/common/111 has header symbol/0000755000175000017500000000000013100703042023360 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/111 has header symbol/meson.build0000644000175000017500000000365513100702356025542 0ustar jpakkanejpakkane00000000000000project('has header symbol', 'c', 'cpp') cc = meson.get_compiler('c') cpp = meson.get_compiler('cpp') 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') # Cross compilation and boost do not mix. if not meson.is_cross_build() 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 endif meson-0.40.1/test cases/common/128 extract all shared library/0000755000175000017500000000000013100703042025175 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/128 extract all shared library/extractor.h0000644000175000017500000000010213024065327027366 0ustar jpakkanejpakkane00000000000000#pragma once int func1(); int func2(); int func3(); int func4(); meson-0.40.1/test cases/common/128 extract all shared library/func1234.def0000644000175000017500000000004413024065327027134 0ustar jpakkanejpakkane00000000000000EXPORTS func1 func2 func3 func4 meson-0.40.1/test cases/common/128 extract all shared library/meson.build0000644000175000017500000000047413100702365027353 0ustar jpakkanejpakkane00000000000000project('extract all', 'c', 'cpp') a = static_library('a', 'one.c', 'two.c') b = static_library('b', 'three.c', 'four.c') c = shared_library('c', objects : [a.extract_all_objects(), b.extract_all_objects()], vs_module_defs : 'func1234.def') e = executable('proggie', 'prog.c', link_with : c) test('extall', e) meson-0.40.1/test cases/common/128 extract all shared library/one.c0000644000175000017500000000006513024065327026137 0ustar jpakkanejpakkane00000000000000#include"extractor.h" int func1() { return 1; } meson-0.40.1/test cases/common/128 extract all shared library/four.c0000644000175000017500000000006513024065327026331 0ustar jpakkanejpakkane00000000000000#include"extractor.h" int func4() { return 4; } meson-0.40.1/test cases/common/128 extract all shared library/two.c0000644000175000017500000000006513024065327026167 0ustar jpakkanejpakkane00000000000000#include"extractor.h" int func2() { return 2; } meson-0.40.1/test cases/common/128 extract all shared library/prog.c0000644000175000017500000000033313024065327026323 0ustar jpakkanejpakkane00000000000000#include"extractor.h" #include int main(int argc, char **argv) { if((1+2+3+4) != (func1() + func2() + func3() + func4())) { printf("Arithmetic is fail.\n"); return 1; } return 0; } meson-0.40.1/test cases/common/128 extract all shared library/three.c0000644000175000017500000000006513024065327026465 0ustar jpakkanejpakkane00000000000000#include"extractor.h" int func3() { return 3; } meson-0.40.1/test cases/common/107 postconf/0000755000175000017500000000000013100703042021746 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/107 postconf/postconf.py0000644000175000017500000000055413057037314024174 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import os template = '''#pragma once #define THE_NUMBER {} ''' input_file = os.path.join(os.environ['MESON_SOURCE_ROOT'], 'raw.dat') output_file = os.path.join(os.environ['MESON_BUILD_ROOT'], 'generated.h') with open(input_file) as f: data = f.readline().strip() with open(output_file, 'w') as f: f.write(template.format(data)) meson-0.40.1/test cases/common/107 postconf/meson.build0000644000175000017500000000016613100702347024122 0ustar jpakkanejpakkane00000000000000project('postconf script', 'c') meson.add_postconf_script('postconf.py') test('post', executable('prog', 'prog.c')) meson-0.40.1/test cases/common/107 postconf/prog.c0000644000175000017500000000012712665647635023117 0ustar jpakkanejpakkane00000000000000#include"generated.h" int main(int argc, char **argv) { return THE_NUMBER != 9; } meson-0.40.1/test cases/common/107 postconf/raw.dat0000644000175000017500000000000212665647635023257 0ustar jpakkanejpakkane000000000000009 meson-0.40.1/test cases/common/81 file object/0000755000175000017500000000000013100703044022204 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/81 file object/lib.c0000644000175000017500000000003512650745767023147 0ustar jpakkanejpakkane00000000000000int func() { return 0; } meson-0.40.1/test cases/common/81 file object/meson.build0000644000175000017500000000023713100702330024345 0ustar jpakkanejpakkane00000000000000project('file object', 'c') prog0 = files('prog.c') lib0 = files('lib.c') test('fobj', executable('fobj', prog0, lib0)) subdir('subdir1') subdir('subdir2') meson-0.40.1/test cases/common/81 file object/subdir1/0000755000175000017500000000000013100703044023555 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/81 file object/subdir1/lib.c0000644000175000017500000000003512650745767024520 0ustar jpakkanejpakkane00000000000000int func() { return 1; } meson-0.40.1/test cases/common/81 file object/subdir1/meson.build0000644000175000017500000000036312650745767025754 0ustar jpakkanejpakkane00000000000000prog1 = files('prog.c') lib1 = files('lib.c') test('subdir0', executable('subdir0', prog0, lib1), should_fail : true) test('subdir1', executable('subdir1', prog1, lib0), should_fail : true) test('subdir2', executable('subdir2', prog1, lib1))meson-0.40.1/test cases/common/81 file object/subdir1/prog.c0000644000175000017500000000031412650745767024721 0ustar jpakkanejpakkane00000000000000#include int func(); int main(int argc, char **argv) { if(func() == 1) { printf("Iz success.\n"); } else { printf("Iz fail.\n"); return 1; } return 0; } meson-0.40.1/test cases/common/81 file object/prog.c0000644000175000017500000000040612650745767023352 0ustar jpakkanejpakkane00000000000000#include int func(); /* Files in different subdirs return different values. */ int main(int argc, char **argv) { if(func() == 0) { printf("Iz success.\n"); } else { printf("Iz fail.\n"); return 1; } return 0; } meson-0.40.1/test cases/common/81 file object/subdir2/0000755000175000017500000000000013100703044023556 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/81 file object/subdir2/lib.c0000644000175000017500000000003512650745767024521 0ustar jpakkanejpakkane00000000000000int func() { return 2; } meson-0.40.1/test cases/common/81 file object/subdir2/meson.build0000644000175000017500000000036312650745767025755 0ustar jpakkanejpakkane00000000000000prog2 = files('prog.c') lib2 = files('lib.c') test('subdir3', executable('subdir3', prog1, lib2), should_fail : true) test('subdir4', executable('subdir4', prog2, lib1), should_fail : true) test('subdir4', executable('subdir5', prog2, lib2))meson-0.40.1/test cases/common/81 file object/subdir2/prog.c0000644000175000017500000000031412650745767024722 0ustar jpakkanejpakkane00000000000000#include int func(); int main(int argc, char **argv) { if(func() == 2) { printf("Iz success.\n"); } else { printf("Iz fail.\n"); return 1; } return 0; } meson-0.40.1/test cases/common/92 skip subdir/0000755000175000017500000000000013100703044022257 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/92 skip subdir/meson.build0000644000175000017500000000005713100702336024426 0ustar jpakkanejpakkane00000000000000project('foo', 'c') subdir('subdir1/subdir2') meson-0.40.1/test cases/common/92 skip subdir/subdir1/0000755000175000017500000000000013100703044023630 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/92 skip subdir/subdir1/meson.build0000644000175000017500000000004412650745767026023 0ustar jpakkanejpakkane00000000000000error('This should not be called.') meson-0.40.1/test cases/common/92 skip subdir/subdir1/subdir2/0000755000175000017500000000000013100703044025202 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/92 skip subdir/subdir1/subdir2/meson.build0000644000175000017500000000004212650745767027373 0ustar jpakkanejpakkane00000000000000message('I\'m in subdir subdir.') meson-0.40.1/test cases/common/21 includedir/0000755000175000017500000000000013100703043022151 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/21 includedir/meson.build0000644000175000017500000000012513100702270024312 0ustar jpakkanejpakkane00000000000000project('include dir test', 'c') inc = include_directories('include') subdir('src') meson-0.40.1/test cases/common/21 includedir/include/0000755000175000017500000000000013100703043023574 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/21 includedir/include/func.h0000644000175000017500000000006712650745767024737 0ustar jpakkanejpakkane00000000000000#ifndef FUNC_H__ #define FUNC_H__ int func(); #endif meson-0.40.1/test cases/common/21 includedir/src/0000755000175000017500000000000013100703043022740 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/21 includedir/src/func.c0000644000175000017500000000006012650745767024067 0ustar jpakkanejpakkane00000000000000#include "func.h" int func() { return 0; } meson-0.40.1/test cases/common/21 includedir/src/meson.build0000644000175000017500000000013612650745767025136 0ustar jpakkanejpakkane00000000000000exe = executable('prog', 'prog.c', 'func.c', include_directories : inc) test('inc test', exe) meson-0.40.1/test cases/common/21 includedir/src/prog.c0000644000175000017500000000011212650745767024101 0ustar jpakkanejpakkane00000000000000#include "func.h" int main(int argc, char **argv) { return func(); } meson-0.40.1/test cases/common/28 config subdir/0000755000175000017500000000000013100703043022554 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/28 config subdir/meson.build0000644000175000017500000000014413100702273024721 0ustar jpakkanejpakkane00000000000000project('subdirconfig', 'c') inc = include_directories('include') subdir('include') subdir('src') meson-0.40.1/test cases/common/28 config subdir/include/0000755000175000017500000000000013100703043024177 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/28 config subdir/include/config.h.in0000644000175000017500000000011312650745767026251 0ustar jpakkanejpakkane00000000000000#ifndef CONFIG_H_ #define CONFIG_H_ #define RETURN_VALUE @number@ #endif meson-0.40.1/test cases/common/28 config subdir/include/meson.build0000644000175000017500000000021712650745767026375 0ustar jpakkanejpakkane00000000000000conf_data = configuration_data() conf_data.set('number', '0') configure_file(input:'config.h.in', output:'config.h', configuration:conf_data) meson-0.40.1/test cases/common/28 config subdir/src/0000755000175000017500000000000013100703043023343 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/28 config subdir/src/meson.build0000644000175000017500000000013112650745767025534 0ustar jpakkanejpakkane00000000000000exe = executable('prog', 'prog.c', include_directories : inc) test('subdir config', exe) meson-0.40.1/test cases/common/28 config subdir/src/prog.c0000644000175000017500000000012212650745767024505 0ustar jpakkanejpakkane00000000000000#include "config.h" int main(int argc, char **argv) { return RETURN_VALUE; } meson-0.40.1/test cases/common/71 arithmetic bidmas/0000755000175000017500000000000013100703043023405 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/71 arithmetic bidmas/meson.build0000644000175000017500000000057513100702321025554 0ustar jpakkanejpakkane00000000000000project('arithmetic bidmas', 'c') if 5 * 3 - 6 / 2 + 1 != 13 error('Arithemtic bidmas broken') endif if 5 * (3 - 6 / 2) + 1 != 1 error('Arithmetic bidmas with brackets broken') endif if 5 * 12 / 2 * 3 != 90 error('Sequential multiplication and division broken') endif if 5 * (12 / (2 * 3)) != 10 error('Sequential multiplication and division with brackets broken') endif meson-0.40.1/test cases/common/113 generatorcustom/0000755000175000017500000000000013100703042023331 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/113 generatorcustom/gen.py0000755000175000017500000000036513057037314024500 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys ifile = sys.argv[1] ofile = sys.argv[2] with open(ifile, 'r') as f: resname = f.readline().strip() templ = 'const char %s[] = "%s";\n' with open(ofile, 'w') as f: f.write(templ % (resname, resname)) meson-0.40.1/test cases/common/113 generatorcustom/main.c0000644000175000017500000000013612732535546024447 0ustar jpakkanejpakkane00000000000000#include #include"alltogether.h" int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/113 generatorcustom/catter.py0000755000175000017500000000045113057037314025205 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys output = sys.argv[-1] inputs = sys.argv[1:-1] with open(output, 'w') as ofile: ofile.write('#pragma once\n') for i in inputs: with open(i, 'r') as ifile: content = ifile.read() ofile.write(content) ofile.write('\n') meson-0.40.1/test cases/common/113 generatorcustom/meson.build0000644000175000017500000000063413100702353025502 0ustar jpakkanejpakkane00000000000000project('generatorcustom', 'c') creator = find_program('gen.py') catter = find_program('catter.py') gen = generator(creator, output: '@BASENAME@.h', arguments : ['@INPUT@', '@OUTPUT@']) hs = gen.process('res1.txt', 'res2.txt') allinone = custom_target('alltogether', input : hs, output : 'alltogether.h', command : [catter, '@INPUT@', '@OUTPUT@']) executable('proggie', 'main.c', allinone) meson-0.40.1/test cases/common/113 generatorcustom/res2.txt0000644000175000017500000000000512732535546024766 0ustar jpakkanejpakkane00000000000000res2 meson-0.40.1/test cases/common/113 generatorcustom/res1.txt0000644000175000017500000000000512732535546024765 0ustar jpakkanejpakkane00000000000000res1 meson-0.40.1/test cases/common/145 whole archive/0000755000175000017500000000000013100703043022636 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/145 whole archive/mylib.h0000644000175000017500000000073313076164167024152 0ustar jpakkanejpakkane00000000000000#pragma once /* Both funcs here for simplicity. */ #if defined _WIN32 || defined __CYGWIN__ #if defined BUILDING_DLL #define DLL_PUBLIC __declspec(dllexport) #else #define DLL_PUBLIC __declspec(dllimport) #endif #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int DLL_PUBLIC func1(); int DLL_PUBLIC func2(); meson-0.40.1/test cases/common/145 whole archive/meson.build0000644000175000017500000000077513100702400025005 0ustar jpakkanejpakkane00000000000000project('whole archive', 'c') cc = meson.get_compiler('c') if cc.get_id() == 'msvc' if cc.version().version_compare('<19') error('MESON_SKIP_TEST link_whole only works on VS2015 or newer.') endif endif stlib = static_library('allofme', 'libfile.c') # Nothing in dylib.c uses func1, so the linker would throw it # away and thus linking the exe would fail. dylib = shared_library('shlib', 'dylib.c', link_whole : stlib) exe = executable('prog', 'prog.c', link_with : dylib) test('prog', exe) meson-0.40.1/test cases/common/145 whole archive/libfile.c0000644000175000017500000000011013076164167024424 0ustar jpakkanejpakkane00000000000000#define BUILDING_DLL #include int func1() { return 42; } meson-0.40.1/test cases/common/145 whole archive/dylib.c0000644000175000017500000000011013076164167024121 0ustar jpakkanejpakkane00000000000000#define BUILDING_DLL #include int func2() { return 42; } meson-0.40.1/test cases/common/145 whole archive/prog.c0000644000175000017500000000012513076164167023773 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { return func1() - func2(); } meson-0.40.1/test cases/common/137 build by default/0000755000175000017500000000000013100703043023216 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/137 build by default/mygen.py0000644000175000017500000000017013043224360024713 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys ifile = open(sys.argv[1]) ofile = open(sys.argv[2], 'w') ofile.write(ifile.read()) meson-0.40.1/test cases/common/137 build by default/foo.c0000644000175000017500000000014613043224360024154 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("Existentialism.\n"); return 0; } meson-0.40.1/test cases/common/137 build by default/meson.build0000644000175000017500000000135113100702372025364 0ustar jpakkanejpakkane00000000000000project('build on all', 'c') py3_mod = import('python3') py3 = py3_mod.find_python() executable('fooprog', 'foo.c', build_by_default : false) comp = files('mygen.py') mytarget = custom_target('gendat', output : 'generated.dat', input : 'source.txt', command : [py3] + comp + ['@INPUT@', '@OUTPUT@'], build_by_default : true, ) ct_output = join_paths(meson.build_root(), 'generated.dat') exe_output = join_paths(meson.build_root(), 'fooprog') if host_machine.system() == 'windows' exe_output += '.exe' endif ct_exists_exe_nexists = 'import os.path, sys; sys.exit(not os.path.exists(sys.argv[1]) and os.path.exists(sys.argv[2]))' test('check-build-by-default', py3, args : ['-c', ct_exists_exe_nexists, ct_output, exe_output]) meson-0.40.1/test cases/common/137 build by default/source.txt0000644000175000017500000000002613043224360025263 0ustar jpakkanejpakkane00000000000000I am a bunch of text. meson-0.40.1/test cases/common/46 library chain/0000755000175000017500000000000013100703043022545 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/46 library chain/main.c0000644000175000017500000000006112650745767023666 0ustar jpakkanejpakkane00000000000000int libfun(); int main() { return libfun(); } meson-0.40.1/test cases/common/46 library chain/installed_files.txt0000644000175000017500000000002112742140120026442 0ustar jpakkanejpakkane00000000000000usr/bin/prog?exe meson-0.40.1/test cases/common/46 library chain/meson.build0000644000175000017500000000017513100702306024713 0ustar jpakkanejpakkane00000000000000project('libchain', 'c') subdir('subdir') e = executable('prog', 'main.c', link_with : lib1, install : true) test('tst', e) meson-0.40.1/test cases/common/46 library chain/subdir/0000755000175000017500000000000013100703043024035 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/46 library chain/subdir/subdir3/0000755000175000017500000000000013100703043025410 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/46 library chain/subdir/subdir3/lib3.c0000644000175000017500000000051712650745767026444 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int DLL_PUBLIC lib3fun() { return 0; } meson-0.40.1/test cases/common/46 library chain/subdir/subdir3/meson.build0000644000175000017500000000007112742140120027552 0ustar jpakkanejpakkane00000000000000lib3 = shared_library('lib3', 'lib3.c', install : false) meson-0.40.1/test cases/common/46 library chain/subdir/meson.build0000644000175000017500000000017012742140120026177 0ustar jpakkanejpakkane00000000000000subdir('subdir2') subdir('subdir3') lib1 = shared_library('lib1', 'lib1.c', install : false, link_with : [lib2, lib3]) meson-0.40.1/test cases/common/46 library chain/subdir/lib1.c0000644000175000017500000000060012650745767025060 0ustar jpakkanejpakkane00000000000000int lib2fun(); int lib3fun(); #if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int DLL_PUBLIC libfun() { return lib2fun() + lib3fun(); } meson-0.40.1/test cases/common/46 library chain/subdir/subdir2/0000755000175000017500000000000013100703043025407 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/46 library chain/subdir/subdir2/meson.build0000644000175000017500000000007112742140120027551 0ustar jpakkanejpakkane00000000000000lib2 = shared_library('lib2', 'lib2.c', install : false) meson-0.40.1/test cases/common/46 library chain/subdir/subdir2/lib2.c0000644000175000017500000000051612650745767026441 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int DLL_PUBLIC lib2fun() { return 0; } meson-0.40.1/test cases/common/69 string arithmetic/0000755000175000017500000000000013100703043023463 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/69 string arithmetic/meson.build0000644000175000017500000000046113100702321025624 0ustar jpakkanejpakkane00000000000000project('string arithmetic', 'c') if 'foo' + 'bar' != 'foobar' error('String concatenation is broken') endif if 'foo' + 'bar' + 'baz' != 'foobarbaz' error('Many-string concatenation is broken') endif a = 'a' b = 'b' if a + b + 'c' != 'abc' error('String concat with variables is broken.') endif meson-0.40.1/test cases/common/129 object only target/0000755000175000017500000000000013100703043023577 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/129 object only target/installed_files.txt0000644000175000017500000000002113024065327027505 0ustar jpakkanejpakkane00000000000000usr/bin/prog?exe meson-0.40.1/test cases/common/129 object only target/source2.c0000644000175000017500000000004513024065327025337 0ustar jpakkanejpakkane00000000000000int func2_in_obj() { return 0; } meson-0.40.1/test cases/common/129 object only target/source.c0000644000175000017500000000004513024065327025255 0ustar jpakkanejpakkane00000000000000int func1_in_obj() { return 0; } meson-0.40.1/test cases/common/129 object only target/meson.build0000644000175000017500000000232713100702366025754 0ustar jpakkanejpakkane00000000000000project('object generator', 'c') # FIXME: Note that this will not add a dependency to the compiler executable. # Code will not be rebuilt if it changes. comp = find_program('obj_generator.py') if host_machine.system() == 'windows' ext = '.obj' else ext = '.o' endif cc = meson.get_compiler('c').cmd_array().get(-1) # Generate an object file with configure_file to mimic prebuilt objects # provided by the source tree source1 = configure_file(input : 'source.c', output : 'source' + ext, command : [comp, cc, files('source.c'), join_paths(meson.current_build_dir(), 'source' + ext)]) obj = static_library('obj', objects : source1) # Generate an object file manually. gen = generator(comp, output : '@BASENAME@' + ext, arguments : [cc, '@INPUT@', '@OUTPUT@']) generated = gen.process(['source2.c']) shr = shared_library('shr', generated, vs_module_defs : 'source2.def') # Generate an object file with indexed OUTPUT replacement. gen2 = generator(comp, output : '@BASENAME@' + ext, arguments : [cc, '@INPUT@', '@OUTPUT0@']) generated2 = gen2.process(['source3.c']) stc = static_library('stc', generated2) e = executable('prog', 'prog.c', link_with : [obj, shr, stc], install : true) test('objgen', e) meson-0.40.1/test cases/common/129 object only target/source2.def0000644000175000017500000000003513024065327025652 0ustar jpakkanejpakkane00000000000000EXPORTS func2_in_obj meson-0.40.1/test cases/common/129 object only target/prog.c0000644000175000017500000000023613024065327024726 0ustar jpakkanejpakkane00000000000000int func1_in_obj(); int func2_in_obj(); int func3_in_obj(); int main(int argc, char **argv) { return func1_in_obj() + func2_in_obj() + func3_in_obj(); } meson-0.40.1/test cases/common/129 object only target/obj_generator.py0000755000175000017500000000101313057037314027003 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Mimic a binary that generates an object file (e.g. windres). import sys, subprocess if __name__ == '__main__': if len(sys.argv) != 4: print(sys.argv[0], 'compiler input_file output_file') sys.exit(1) compiler = sys.argv[1] ifile = sys.argv[2] ofile = sys.argv[3] if compiler.endswith('cl'): cmd = [compiler, '/nologo', '/MDd', '/Fo' + ofile, '/c', ifile] else: cmd = [compiler, '-c', ifile, '-o', ofile] sys.exit(subprocess.call(cmd)) meson-0.40.1/test cases/common/129 object only target/source3.c0000644000175000017500000000004513024065327025340 0ustar jpakkanejpakkane00000000000000int func3_in_obj() { return 0; } meson-0.40.1/test cases/common/58 run target/0000755000175000017500000000000013100703043022114 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/58 run target/meson.build0000644000175000017500000000257613100702313024267 0ustar jpakkanejpakkane00000000000000project('run target', 'c') # deprecated format, fix once we remove support for it. run_target('mycommand','scripts/script.sh') # Make it possible to run built programs. # In cross builds exe_wrapper should be added if it exists. exe = executable('helloprinter', 'helloprinter.c') run_target('runhello', command : [exe, 'argument']) converter = find_program('converter.py') hex = custom_target('exe.hex', input : exe, output : 'exe.hex', command : [converter, '@INPUT@', '@OUTPUT@', ], ) fakeburner = find_program('fakeburner.py') # These emulates the Arduino flasher application. It sandwiches the filename inside # a packed argument. Thus we need to declare it manually. run_target('upload', command : [fakeburner, 'x:@0@:y'.format(exe.full_path())], depends : exe, ) run_target('upload2', command : [fakeburner, 'x:@0@:y'.format(hex.full_path())], depends : hex, ) python3 = find_program('python3', required : false) if not python3.found() python3 = find_program('python') endif run_target('py3hi', command : [python3, '-c', 'print("I am Python3.")']) run_target('check_exists', command : [find_program('check_exists.py'), files('helloprinter.c')]) # What if the output of a custom_target is the command to # execute. Obviously this will not work as hex is not an # executable but test that the output is generated correctly. run_target('donotrunme', command : hex) meson-0.40.1/test cases/common/58 run target/scripts/0000755000175000017500000000000013100703043023603 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/58 run target/scripts/script.sh0000755000175000017500000000015512650745767025503 0ustar jpakkanejpakkane00000000000000#!/bin/sh cd "$MESON_SOURCE_ROOT" echo My current directory is `pwd` echo Build dir is at $MESON_BUILD_ROOT meson-0.40.1/test cases/common/58 run target/converter.py0000644000175000017500000000021313057037314024505 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys with open(sys.argv[1], 'rb') as ifile, open(sys.argv[2], 'wb') as ofile: ofile.write(ifile.read()) meson-0.40.1/test cases/common/58 run target/check_exists.py0000755000175000017500000000022013057037314025153 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import os import sys if not os.path.isfile(sys.argv[1]): raise Exception("Couldn't find {!r}".format(sys.argv[1])) meson-0.40.1/test cases/common/58 run target/helloprinter.c0000644000175000017500000000034012650745767025020 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { if(argc != 2) { printf("I can not haz argument.\n"); return 1; } else { printf("I can haz argument: %s\n", argv[1]); } return 0; } meson-0.40.1/test cases/common/58 run target/fakeburner.py0000755000175000017500000000061213057037314024630 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 from __future__ import print_function import sys plain_arg = sys.argv[1] _, filename, _ = plain_arg.split(':') try: with open(filename, 'rb') as f: content = f.read() except FileNotFoundError: print('Could not open file. Missing dependency?') sys.exit(1) print('File opened, pretending to send it somewhere.') print(len(content), 'bytes uploaded') meson-0.40.1/test cases/common/114 multiple dir configure file/0000755000175000017500000000000013100703042025345 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/114 multiple dir configure file/meson.build0000644000175000017500000000025613100702354027517 0ustar jpakkanejpakkane00000000000000project('multiple dir configure file', 'c') subdir('subdir') configure_file(input : 'subdir/someinput.in', output : 'outputhere', configuration : configuration_data()) meson-0.40.1/test cases/common/114 multiple dir configure file/subdir/0000755000175000017500000000000013100703042026635 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/114 multiple dir configure file/subdir/meson.build0000644000175000017500000000017512746700520031017 0ustar jpakkanejpakkane00000000000000configure_file(input : 'someinput.in', output : 'outputsubdir', install : false, configuration : configuration_data()) meson-0.40.1/test cases/common/114 multiple dir configure file/subdir/someinput.in0000644000175000017500000000000012746700520031213 0ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/143 custom target object output/0000755000175000017500000000000013100703043025445 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/143 custom target object output/meson.build0000644000175000017500000000045613100702377027625 0ustar jpakkanejpakkane00000000000000project('custom target object output', 'c') comp = find_program('obj_generator.py') if host_machine.system() == 'windows' outputname = '@BASENAME@.obj' else outputname = '@BASENAME@.o' endif cc = meson.get_compiler('c').cmd_array().get(-1) subdir('objdir') subdir('progdir') test('objgen', e) meson-0.40.1/test cases/common/143 custom target object output/progdir/0000755000175000017500000000000013100703043027113 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/143 custom target object output/progdir/meson.build0000644000175000017500000000005113074426732031272 0ustar jpakkanejpakkane00000000000000e = executable('prog', 'prog.c', object) meson-0.40.1/test cases/common/143 custom target object output/progdir/prog.c0000644000175000017500000000012413074426732030244 0ustar jpakkanejpakkane00000000000000int func1_in_obj(); int main(int argc, char **argv) { return func1_in_obj(); } meson-0.40.1/test cases/common/143 custom target object output/obj_generator.py0000644000175000017500000000101313074426732030653 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Mimic a binary that generates an object file (e.g. windres). import sys, subprocess if __name__ == '__main__': if len(sys.argv) != 4: print(sys.argv[0], 'compiler input_file output_file') sys.exit(1) compiler = sys.argv[1] ifile = sys.argv[2] ofile = sys.argv[3] if compiler.endswith('cl'): cmd = [compiler, '/nologo', '/MDd', '/Fo' + ofile, '/c', ifile] else: cmd = [compiler, '-c', ifile, '-o', ofile] sys.exit(subprocess.call(cmd)) meson-0.40.1/test cases/common/143 custom target object output/objdir/0000755000175000017500000000000013100703043026716 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/143 custom target object output/objdir/source.c0000644000175000017500000000004513074426732030402 0ustar jpakkanejpakkane00000000000000int func1_in_obj() { return 0; } meson-0.40.1/test cases/common/143 custom target object output/objdir/meson.build0000644000175000017500000000024113074426732031076 0ustar jpakkanejpakkane00000000000000# Generate an object file manually. object = custom_target('object', input : 'source.c', output : outputname, command : [comp, cc, '@INPUT@', '@OUTPUT@']) meson-0.40.1/test cases/common/133 configure file in generator/0000755000175000017500000000000013100703043025332 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/133 configure file in generator/meson.build0000644000175000017500000000010413100702370027471 0ustar jpakkanejpakkane00000000000000project('conf file in generator', 'c') subdir('inc') subdir('src') meson-0.40.1/test cases/common/133 configure file in generator/src/0000755000175000017500000000000013100703043026121 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/133 configure file in generator/src/gen.py0000755000175000017500000000035013057037314027261 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys ifile = sys.argv[1] ofile = sys.argv[2] with open(ifile, 'r') as f: resval = f.readline().strip() templ = '#define RESULT (%s)\n' with open(ofile, 'w') as f: f.write(templ % (resval, )) meson-0.40.1/test cases/common/133 configure file in generator/src/main.c0000644000175000017500000000042113037214503027215 0ustar jpakkanejpakkane00000000000000#include #include"confdata.h" #if RESULT != 42 #error Configuration RESULT is not defined correctly #endif #undef RESULT #include"source.h" #if RESULT != 23 #error Source RESULT is not defined correctly #endif int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/133 configure file in generator/src/meson.build0000644000175000017500000000031313037214503030267 0ustar jpakkanejpakkane00000000000000compiler = find_program('gen.py') gen = generator(compiler, output: '@BASENAME@.h', arguments : ['@INPUT@', '@OUTPUT@']) hs = gen.process(cfile, files('source')) executable('proggie', 'main.c', hs) meson-0.40.1/test cases/common/133 configure file in generator/src/source0000644000175000017500000000000313037214503027344 0ustar jpakkanejpakkane0000000000000023 meson-0.40.1/test cases/common/133 configure file in generator/inc/0000755000175000017500000000000013100703043026103 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/133 configure file in generator/inc/confdata.in0000644000175000017500000000001013037214503030210 0ustar jpakkanejpakkane00000000000000@VALUE@ meson-0.40.1/test cases/common/133 configure file in generator/inc/meson.build0000644000175000017500000000022113037214503030247 0ustar jpakkanejpakkane00000000000000cdata = configuration_data() cdata.set('VALUE', '42') cfile = configure_file(input : 'confdata.in', output : 'confdata', configuration : cdata) meson-0.40.1/test cases/common/126 llvm ir and assembly/0000755000175000017500000000000013100703042024004 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/126 llvm ir and assembly/main.c0000644000175000017500000000034713024065327025114 0ustar jpakkanejpakkane00000000000000#include unsigned square_unsigned (unsigned a); int main (int argc, char * argv[]) { unsigned int ret = square_unsigned (2); if (ret != 4) { printf("Got %u instead of 4\n", ret); return 1; } return 0; } meson-0.40.1/test cases/common/126 llvm ir and assembly/symbol-underscore.h0000644000175000017500000000017313024065327027646 0ustar jpakkanejpakkane00000000000000#if defined(MESON_TEST__UNDERSCORE_SYMBOL) # define SYMBOL_NAME(name) _##name #else # define SYMBOL_NAME(name) name #endif meson-0.40.1/test cases/common/126 llvm ir and assembly/main.cpp0000644000175000017500000000037013024065327025450 0ustar jpakkanejpakkane00000000000000#include extern "C" { unsigned square_unsigned (unsigned a); } int main (int argc, char * argv[]) { unsigned int ret = square_unsigned (2); if (ret != 4) { printf("Got %u instead of 4\n", ret); return 1; } return 0; } meson-0.40.1/test cases/common/126 llvm ir and assembly/meson.build0000644000175000017500000000443613100702362026161 0ustar jpakkanejpakkane00000000000000project('llvm-ir', 'c', 'cpp') cpu = host_machine.cpu_family() supported_cpus = ['arm', 'x86', 'x86_64'] foreach lang : ['c', 'cpp'] cc = meson.get_compiler(lang) cc_id = cc.get_id() ## Build a trivial executale with mixed LLVM IR source if cc_id == 'clang' e = executable('square_ir_' + lang, 'square.ll', 'main.' + lang) test('test IR square' + lang, e) endif ## Build a trivial executable with mixed assembly source # This also helps test whether cc.symbols_have_underscore_prefix() is working # properly. This is done by assembling some assembly into an object that will # provide the unsigned_squared() symbol to main.c/cpp. This requires the # C symbol mangling to be known in advance. if cc.symbols_have_underscore_prefix() uscore_args = ['-DMESON_TEST__UNDERSCORE_SYMBOL'] message('underscore is prefixed') else uscore_args = [] message('underscore is NOT prefixed') endif square_base = 'square-' + cpu square_impl = square_base + '.S' # MSVC cannot directly compile assembly files, so we pass it through the # cl.exe pre-processor first and then assemble it with the ml.exe assembler. # Then we can link it into the executable. if cc_id == 'msvc' cl = find_program('cl') if cpu == 'x86' ml = find_program('ml') elif cpu == 'x86_64' ml = find_program('ml64') else error('Unsupported cpu family: "' + cpu + '"') endif # Preprocess file (ml doesn't support pre-processing) preproc_name = lang + square_base + '.i' square_preproc = custom_target(lang + square_impl + 'preproc', input : square_impl, output : preproc_name, command : [cl, '/EP', '/P', '/Fi' + preproc_name, '@INPUT@'] + uscore_args) # Use assembled object file instead of the original .S assembly source square_impl = custom_target(lang + square_impl, input : square_preproc, output : lang + square_base + '.obj', command : [ml, '/Fo', '@OUTPUT@', '/c', '@INPUT@']) endif if supported_cpus.contains(cpu) e = executable('square_asm_' + lang, square_impl, 'main.' + lang, c_args : uscore_args, cpp_args : uscore_args) test('test ASM square' + lang, e) elif cc_id != 'clang' error('MESON_SKIP_TEST: Unsupported cpu: "' + cpu + '", and LLVM not found') endif endforeach meson-0.40.1/test cases/common/126 llvm ir and assembly/square-arm.S0000644000175000017500000000022113024065327026214 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" .text .globl SYMBOL_NAME(square_unsigned) SYMBOL_NAME(square_unsigned): mul r1, r0, r0 mov r0, r1 mov pc, lr meson-0.40.1/test cases/common/126 llvm ir and assembly/square-x86.S0000644000175000017500000000100313024065327026061 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" /* This sadly doesn't test the symbol underscore stuff. I can't figure out how * to not use an automatic stdcall mechanism and do everything manually. */ #ifdef _MSC_VER .386 .MODEL FLAT, C PUBLIC square_unsigned _TEXT SEGMENT square_unsigned PROC var1:DWORD mov eax, var1 imul eax, eax ret square_unsigned ENDP _TEXT ENDS END #else .text .globl SYMBOL_NAME(square_unsigned) SYMBOL_NAME(square_unsigned): movl 4(%esp), %eax imull %eax, %eax retl #endif meson-0.40.1/test cases/common/126 llvm ir and assembly/square.ll0000644000175000017500000000011313024065327025644 0ustar jpakkanejpakkane00000000000000define i32 @square_unsigned(i32 %a) { %1 = mul i32 %a, %a ret i32 %1 } meson-0.40.1/test cases/common/126 llvm ir and assembly/square-x86_64.S0000644000175000017500000000103513074426732026405 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" #ifdef _MSC_VER /* MSVC on Windows */ PUBLIC SYMBOL_NAME(square_unsigned) _TEXT SEGMENT SYMBOL_NAME(square_unsigned) PROC mov eax, ecx imul eax, eax ret SYMBOL_NAME(square_unsigned) ENDP _TEXT ENDS END #else .text .globl SYMBOL_NAME(square_unsigned) # if defined(_WIN32) || defined(__CYGWIN__) /* msabi */ SYMBOL_NAME(square_unsigned): imull %ecx, %ecx movl %ecx, %eax retq # else /* sysvabi */ SYMBOL_NAME(square_unsigned): imull %edi, %edi movl %edi, %eax retq # endif #endif meson-0.40.1/test cases/common/17 if/0000755000175000017500000000000013100703043020432 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/17 if/meson.build0000644000175000017500000000074313100702266022606 0ustar jpakkanejpakkane00000000000000project('if test', 'c') var1 = true set_variable('var2', false) if var1 exe = executable('prog', 'prog.c') endif if var2 exe = executable('breakbreakbreak', 'crashing.c') endif test('iftest', exe) if not is_variable('var1') error('Is_variable fail.') endif if is_variable('nonexisting') error('Is_variable fail 2.') endif if not get_variable('var1', false) error('Get_variable fail.') endif if get_variable('nonexisting', false) error('Get_variable fail.') endif meson-0.40.1/test cases/common/17 if/prog.c0000644000175000017500000000005612650745767021602 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/117 custom target capture/0000755000175000017500000000000013100703042024321 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/117 custom target capture/installed_files.txt0000644000175000017500000000002412763077471030247 0ustar jpakkanejpakkane00000000000000usr/subdir/data.dat meson-0.40.1/test cases/common/117 custom target capture/meson.build0000644000175000017500000000125713100702357026500 0ustar jpakkanejpakkane00000000000000project('custom target', 'c') python3 = import('python3').find_python() # Note that this will not add a dependency to the compiler executable. # Code will not be rebuilt if it changes. comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py') mytarget = custom_target('bindat', output : 'data.dat', input : 'data_source.txt', capture : true, command : [python3, comp, '@INPUT@'], install : true, install_dir : 'subdir' ) ct_output_exists = '''import os, sys if not os.path.exists(sys.argv[1]): print("could not find {!r} in {!r}".format(sys.argv[1], os.getcwd())) sys.exit(1) ''' test('capture-wrote', python3, args : ['-c', ct_output_exists, mytarget]) meson-0.40.1/test cases/common/117 custom target capture/data_source.txt0000644000175000017500000000004012763077471027375 0ustar jpakkanejpakkane00000000000000This is a text only input file. meson-0.40.1/test cases/common/117 custom target capture/my_compiler.py0000755000175000017500000000054612763077471027252 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys if __name__ == '__main__': if len(sys.argv) != 2: print(sys.argv[0], 'input_file') sys.exit(1) with open(sys.argv[1]) as f: ifile = f.read() if ifile != 'This is a text only input file.\n': print('Malformed input') sys.exit(1) print('This is a binary output file.') meson-0.40.1/test cases/common/48 test args/0000755000175000017500000000000013100703043021734 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/48 test args/tester.py0000755000175000017500000000016613057037314023636 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys with open(sys.argv[1]) as f: if f.read() != 'contents\n': sys.exit(1) meson-0.40.1/test cases/common/48 test args/env2vars.c0000644000175000017500000000121313012152443023647 0ustar jpakkanejpakkane00000000000000#include #include #include int main(int argc, char **argv) { if(strcmp(getenv("first"), "something-else") != 0) { fprintf(stderr, "First envvar is wrong. %s\n", getenv("first")); return 1; } if(strcmp(getenv("second"), "val2") != 0) { fprintf(stderr, "Second envvar is wrong.\n"); return 1; } if(strcmp(getenv("third"), "val3:and_more") != 0) { fprintf(stderr, "Third envvar is wrong.\n"); return 1; } if(strstr(getenv("PATH"), "fakepath:") != NULL) { fprintf(stderr, "Third envvar is wrong.\n"); return 1; } return 0; } meson-0.40.1/test cases/common/48 test args/meson.build0000644000175000017500000000134713100702306024104 0ustar jpakkanejpakkane00000000000000project('test features', 'c') e1 = executable('cmd_args', 'cmd_args.c') e2 = executable('envvars', 'envvars.c') e3 = executable('env2vars', 'env2vars.c') env = environment() env.set('first', 'val1') env.set('second', 'val2') env.set('third', 'val3', 'and_more', separator: ':') env.append('PATH', 'fakepath', separator: ':') # Make sure environment objects are copied on assignment and we can # change the copy without affecting the original environment object. env2 = env env2.set('first', 'something-else') test('command line arguments', e1, args : ['first', 'second']) test('environment variables', e2, env : env) test('environment variables 2', e3, env : env2) test('file arg', find_program('tester.py'), args : files('testfile.txt')) meson-0.40.1/test cases/common/48 test args/envvars.c0000644000175000017500000000120112767063125023600 0ustar jpakkanejpakkane00000000000000#include #include #include int main(int argc, char **argv) { if(strcmp(getenv("first"), "val1") != 0) { fprintf(stderr, "First envvar is wrong. %s\n", getenv("first")); return 1; } if(strcmp(getenv("second"), "val2") != 0) { fprintf(stderr, "Second envvar is wrong.\n"); return 1; } if(strcmp(getenv("third"), "val3:and_more") != 0) { fprintf(stderr, "Third envvar is wrong.\n"); return 1; } if(strstr(getenv("PATH"), "fakepath:") != NULL) { fprintf(stderr, "Third envvar is wrong.\n"); return 1; } return 0; } meson-0.40.1/test cases/common/48 test args/cmd_args.c0000644000175000017500000000066112650745767023716 0ustar jpakkanejpakkane00000000000000#include #include int main(int argc, char **argv) { if(argc != 3) { fprintf(stderr, "Incorrect number of arguments.\n"); return 1; } if(strcmp(argv[1], "first") != 0) { fprintf(stderr, "First argument is wrong.\n"); return 1; } if(strcmp(argv[2], "second") != 0) { fprintf(stderr, "Second argument is wrong.\n"); return 1; } return 0; } meson-0.40.1/test cases/common/48 test args/testfile.txt0000644000175000017500000000001112650745767024340 0ustar jpakkanejpakkane00000000000000contents meson-0.40.1/test cases/common/9 header install/0000755000175000017500000000000013100703044022635 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/9 header install/subdir.h0000644000175000017500000000011212650745767024323 0ustar jpakkanejpakkane00000000000000/* This file goes to subdirectory of include root. */ int subdir_func(); meson-0.40.1/test cases/common/9 header install/vanishing_subdir/0000755000175000017500000000000013100703044026173 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/9 header install/vanishing_subdir/meson.build0000644000175000017500000000003612650745767030367 0ustar jpakkanejpakkane00000000000000install_headers('vanished.h') meson-0.40.1/test cases/common/9 header install/vanishing_subdir/vanished.h0000644000175000017500000000022112650745767030173 0ustar jpakkanejpakkane00000000000000#pragma once /* This is a header in a subdirectory. Make sure it installs into * /prefix/include and not /prefix/include/vanishing_subdir. */ meson-0.40.1/test cases/common/9 header install/rootdir.h0000644000175000017500000000007612650745767024526 0ustar jpakkanejpakkane00000000000000/* This header goes to include dir root. */ int root_func(); meson-0.40.1/test cases/common/9 header install/installed_files.txt0000644000175000017500000000014213016624375026553 0ustar jpakkanejpakkane00000000000000usr/include/rootdir.h usr/include/subdir/subdir.h usr/include/vanished.h usr/include/fileheader.h meson-0.40.1/test cases/common/9 header install/meson.build0000644000175000017500000000032313100702261024775 0ustar jpakkanejpakkane00000000000000project('header install') as_array = ['subdir.h'] subdir('vanishing_subdir') subdir('sub') h1 = install_headers('rootdir.h') h2 = install_headers(as_array, subdir : 'subdir') h3 = install_headers(subheader) meson-0.40.1/test cases/common/9 header install/sub/0000755000175000017500000000000013100703044023426 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/9 header install/sub/meson.build0000644000175000017500000000004313016624375025604 0ustar jpakkanejpakkane00000000000000subheader = files('fileheader.h') meson-0.40.1/test cases/common/9 header install/sub/fileheader.h0000644000175000017500000000007113016624375025704 0ustar jpakkanejpakkane00000000000000#pragma once #define LIFE "Is life! Na naa, naa-na na." meson-0.40.1/test cases/common/139 custom target multiple outputs/0000755000175000017500000000000013100703043026222 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/139 custom target multiple outputs/installed_files.txt0000644000175000017500000000014013074426732032140 0ustar jpakkanejpakkane00000000000000usr/include/diff.h usr/include/first.h usr/bin/diff.sh usr/bin/second.sh opt/same.h opt/same.sh meson-0.40.1/test cases/common/139 custom target multiple outputs/meson.build0000644000175000017500000000165613100702373030401 0ustar jpakkanejpakkane00000000000000project('multiple outputs install', 'c') gen = find_program('generator.py') custom_target('different-install-dirs', output : ['diff.h', 'diff.sh'], command : [gen, 'diff', '@OUTDIR@'], install : true, install_dir : [join_paths(get_option('prefix'), get_option('includedir')), join_paths(get_option('prefix'), get_option('bindir'))]) custom_target('same-install-dir', output : ['same.h', 'same.sh'], command : [gen, 'same', '@OUTDIR@'], install : true, install_dir : '/opt') custom_target('only-install-first', output : ['first.h', 'first.sh'], command : [gen, 'first', '@OUTDIR@'], install : true, install_dir : [join_paths(get_option('prefix'), get_option('includedir')), false]) custom_target('only-install-second', output : ['second.h', 'second.sh'], command : [gen, 'second', '@OUTDIR@'], install : true, install_dir : [false, join_paths(get_option('prefix'), get_option('bindir'))]) meson-0.40.1/test cases/common/139 custom target multiple outputs/generator.py0000755000175000017500000000050213074426732030603 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys, os if len(sys.argv) != 3: print(sys.argv[0], '', '') name = sys.argv[1] odir = sys.argv[2] with open(os.path.join(odir, name + '.h'), 'w') as f: f.write('int func();\n') with open(os.path.join(odir, name + '.sh'), 'w') as f: f.write('#!/bin/bash') meson-0.40.1/test cases/common/146 C and CPP link/0000755000175000017500000000000013100703043022345 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/146 C and CPP link/foobar.h0000644000175000017500000000116013076637146024012 0ustar jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ void mynumbers(int nums[]); meson-0.40.1/test cases/common/146 C and CPP link/foo.c0000644000175000017500000000121413076637146023320 0ustar jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "foo.h" int forty_two(void) { return 42; } meson-0.40.1/test cases/common/146 C and CPP link/foo.cpp0000644000175000017500000000156513076637146023671 0ustar jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include const int cnums[] = {0, 61}; template std::vector makeVector(const T (&data)[N]) { return std::vector(data, data+N); } namespace { std::vector numbers = makeVector(cnums); } extern "C" int six_one(void) { return numbers[1]; } meson-0.40.1/test cases/common/146 C and CPP link/meson.build0000644000175000017500000000343513100702401024511 0ustar jpakkanejpakkane00000000000000# Copyright Ā© 2017 Dylan Baker # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. project('C and C++ static link test', ['c', 'cpp']) libc = static_library('cfoo', ['foo.c', 'foo.h']) # Test that linking C libs to external static C++ libs uses the C++ linker # Since we can't depend on the test system to provide this, we create one # ourselves at configure time and then 'find' it with cxx.find_library(). cxx = meson.get_compiler('cpp') if cxx.get_id() == 'msvc' compile_cmd = ['/c', '@INPUT@', '/Fo@OUTPUT@'] stlib_cmd = ['lib', '/OUT:@OUTPUT@', '@INPUT@'] else compile_cmd = ['-c', '-fPIC', '@INPUT@', '-o', '@OUTPUT@'] stlib_cmd = ['ar', 'csr', '@OUTPUT@', '@INPUT@'] endif foo_cpp_o = configure_file( input : 'foo.cpp', output : 'foo.cpp.o', command : cxx.cmd_array() + compile_cmd) configure_file( input : foo_cpp_o, output : 'libstcppext.a', command : stlib_cmd) libstcppext = cxx.find_library('stcppext', dirs : meson.current_build_dir()) libfooext = shared_library( 'fooext', ['foobar.c', 'foobar.h'], link_with : libc, dependencies : libstcppext, ) # Test that linking C libs to internal static C++ libs uses the C++ linker libcpp = static_library('cppfoo', ['foo.cpp', 'foo.hpp']) libfoo = shared_library( 'foo', ['foobar.c', 'foobar.h'], link_with : [libc, libcpp], ) meson-0.40.1/test cases/common/146 C and CPP link/foo.h0000644000175000017500000000115113076637146023325 0ustar jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ int forty_two(void); meson-0.40.1/test cases/common/146 C and CPP link/foo.hpp0000644000175000017500000000125413076637146023671 0ustar jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef __cplusplus extern "C" { #endif int six_one(void); #ifdef __cplusplus } #endif meson-0.40.1/test cases/common/146 C and CPP link/foobar.c0000644000175000017500000000134013076637146024005 0ustar jpakkanejpakkane00000000000000/* Copyright Ā© 2017 Dylan Baker * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "foo.h" #include "foo.hpp" #include "foobar.h" void mynumbers(int nums[]) { nums[0] = forty_two(); nums[1] = six_one(); } meson-0.40.1/test cases/common/95 dep fallback/0000755000175000017500000000000013100703044022333 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/95 dep fallback/subprojects/0000755000175000017500000000000013100703042024674 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/95 dep fallback/subprojects/dummylib/0000755000175000017500000000000013100703044026520 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/95 dep fallback/subprojects/dummylib/meson.build0000644000175000017500000000014713012152443030667 0ustar jpakkanejpakkane00000000000000project('dummylib', 'c') dummy_dep = declare_dependency() error('this subproject fails to configure') meson-0.40.1/test cases/common/95 dep fallback/subprojects/boblib/0000755000175000017500000000000013100703044026127 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/95 dep fallback/subprojects/boblib/meson.build0000644000175000017500000000066712774524535030330 0ustar jpakkanejpakkane00000000000000project('bob', 'c') gensrc_py = find_program('genbob.py') genbob_h = custom_target('genbob.h', output : 'genbob.h', command : [gensrc_py, '@OUTPUT@']) genbob_c = custom_target('genbob.c', output : 'genbob.c', command : [gensrc_py, '@OUTPUT@']) boblib = library('bob', ['bob.c', genbob_c]) bobinc = include_directories('.') bob_dep = declare_dependency(link_with : boblib, sources : [genbob_h], include_directories : bobinc) meson-0.40.1/test cases/common/95 dep fallback/subprojects/boblib/genbob.py0000644000175000017500000000012613057037314027747 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys with open(sys.argv[1], 'w') as f: f.write('') meson-0.40.1/test cases/common/95 dep fallback/subprojects/boblib/bob.h0000644000175000017500000000012212774524535027063 0ustar jpakkanejpakkane00000000000000#pragma once #ifdef _MSC_VER __declspec(dllimport) #endif const char* get_bob(); meson-0.40.1/test cases/common/95 dep fallback/subprojects/boblib/bob.c0000644000175000017500000000015212774524535027061 0ustar jpakkanejpakkane00000000000000#include"bob.h" #ifdef _MSC_VER __declspec(dllexport) #endif const char* get_bob() { return "bob"; } meson-0.40.1/test cases/common/95 dep fallback/meson.build0000644000175000017500000000152113100702340024472 0ustar jpakkanejpakkane00000000000000project('dep fallback', 'c') bob = dependency('boblib', fallback : ['boblib', 'bob_dep'], required: false, default_options : 'warning_level=1') if not bob.found() error('Bob is actually needed') endif # boblib subproject exists, but sita_dep doesn't exist sita = dependency('sitalib', fallback : ['boblib', 'sita_dep'], required: false) # jimmylib subproject doesn't exist jimmy = dependency('jimmylib', fallback : ['jimmylib', 'jimmy_dep'], required: false) # dummylib subproject fails to configure dummy = dependency('dummylib', fallback : ['dummylib', 'dummy_dep'], required: false) gensrc_py = find_program('gensrc.py') gensrc = custom_target('gensrc.c', input : 'tester.c', output : 'gensrc.c', command : [gensrc_py, '@INPUT@', '@OUTPUT@']) exe = executable('bobtester', [gensrc], dependencies : bob) test('bobtester', exe) meson-0.40.1/test cases/common/95 dep fallback/gensrc.py0000644000175000017500000000013413057037314024177 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) meson-0.40.1/test cases/common/95 dep fallback/tester.c0000644000175000017500000000043412774524535024034 0ustar jpakkanejpakkane00000000000000#include"bob.h" #include"genbob.h" #include #include int main(int argc, char **argv) { if(strcmp("bob", get_bob()) == 0) { printf("Bob is indeed bob.\n"); } else { printf("ERROR: bob is not bob.\n"); return 1; } return 0; } meson-0.40.1/test cases/common/110 extract same name/0000755000175000017500000000000013100703042023366 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/110 extract same name/main.c0000644000175000017500000000015512677267452024513 0ustar jpakkanejpakkane00000000000000int func1(); int func2(); int main(int argc, char **argv) { return !(func1() == 23 && func2() == 42); } meson-0.40.1/test cases/common/110 extract same name/lib.c0000644000175000017500000000003712677267452024334 0ustar jpakkanejpakkane00000000000000int func1() { return 23; } meson-0.40.1/test cases/common/110 extract same name/meson.build0000644000175000017500000000042013100702351025526 0ustar jpakkanejpakkane00000000000000project('object extraction', 'c') lib = shared_library('somelib', ['lib.c', 'src/lib.c']) # Also tests that the object list is flattened properly obj = lib.extract_objects(['lib.c', ['src/lib.c']]) exe = executable('main', 'main.c', objects: obj) test('extraction', exe) meson-0.40.1/test cases/common/110 extract same name/src/0000755000175000017500000000000013100703042024155 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/110 extract same name/src/lib.c0000644000175000017500000000003712677267452025123 0ustar jpakkanejpakkane00000000000000int func2() { return 42; } meson-0.40.1/test cases/common/2 cpp/0000755000175000017500000000000013100703043020530 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/2 cpp/something.txt0000644000175000017500000000010612650745767023317 0ustar jpakkanejpakkane00000000000000This file is only here so it shows up in IDEs as part of this target. meson-0.40.1/test cases/common/2 cpp/trivial.cc0000644000175000017500000000017412650745767022547 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { std::cout << "C++ seems to be working." << std::endl; return 0; } meson-0.40.1/test cases/common/2 cpp/meson.build0000644000175000017500000000045213100702256022700 0ustar jpakkanejpakkane00000000000000project('c++ test', 'cpp') if meson.get_compiler('cpp').get_id() == 'intel' # Error out if the -std=xxx option is incorrect add_project_arguments('-diag-error', '10159', language : 'cpp') endif exe = executable('trivialprog', 'trivial.cc', extra_files : 'something.txt') test('runtest', exe) meson-0.40.1/test cases/common/30 pipeline/0000755000175000017500000000000013100703043021634 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/30 pipeline/meson.build0000644000175000017500000000020013100702274023773 0ustar jpakkanejpakkane00000000000000project('pipeline test', 'c') # This is in a subdirectory to make sure # we write proper subdir paths to output. subdir('src') meson-0.40.1/test cases/common/30 pipeline/src/0000755000175000017500000000000013100703043022423 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/30 pipeline/src/meson.build0000644000175000017500000000045612650745767024626 0ustar jpakkanejpakkane00000000000000e1 = executable('srcgen', 'srcgen.c', native : true) # Generate a header file that needs to be included. gen = generator(e1, output : '@BASENAME@.h', arguments : ['@INPUT@', '@OUTPUT@']) generated = gen.process('input_src.dat') e2 = executable('prog', 'prog.c', generated) test('pipelined', e2) meson-0.40.1/test cases/common/30 pipeline/src/srcgen.c0000644000175000017500000000160512650745767024106 0ustar jpakkanejpakkane00000000000000#include #include #define ARRSIZE 80 int main(int argc, char **argv) { char arr[ARRSIZE]; char *ifilename; char *ofilename; FILE *ifile; FILE *ofile; size_t bytes; if(argc != 3) { fprintf(stderr, "%s \n", argv[0]); return 1; } ifilename = argv[1]; ofilename = argv[2]; printf("%s\n", ifilename); ifile = fopen(ifilename, "r"); if(!ifile) { fprintf(stderr, "Could not open source file %s.\n", ifilename); return 1; } ofile = fopen(ofilename, "w"); if(!ofile) { fprintf(stderr, "Could not open target file %s\n", ofilename); fclose(ifile); return 1; } bytes = fread(arr, 1, ARRSIZE, ifile); assert(bytes < 80); assert(bytes > 0); fwrite(arr, 1, bytes, ofile); fclose(ifile); fclose(ofile); return 0; } meson-0.40.1/test cases/common/30 pipeline/src/input_src.dat0000644000175000017500000000002212650745767025151 0ustar jpakkanejpakkane00000000000000#include meson-0.40.1/test cases/common/30 pipeline/src/prog.c0000644000175000017500000000020712650745767023571 0ustar jpakkanejpakkane00000000000000#include"input_src.h" int main(int argc, char **argv) { void *foo = printf; if(foo) { return 0; } return 1; } meson-0.40.1/test cases/common/4 shared/0000755000175000017500000000000013100703043021216 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/4 shared/meson.build0000644000175000017500000000011713100702256023364 0ustar jpakkanejpakkane00000000000000project('shared library test', 'c') lib = shared_library('mylib', 'libfile.c') meson-0.40.1/test cases/common/4 shared/libfile.c0000644000175000017500000000052012650745767023021 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int DLL_PUBLIC libfunc() { return 3; } meson-0.40.1/test cases/common/139 override options/0000755000175000017500000000000013100703043023414 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/139 override options/meson.build0000644000175000017500000000027313100702374025566 0ustar jpakkanejpakkane00000000000000project('option override', 'c', default_options : 'unity=on') executable('mustunity', 'one.c', 'two.c') executable('notunity', 'three.c', 'four.c', override_options : ['unity=off']) meson-0.40.1/test cases/common/139 override options/one.c0000644000175000017500000000005313070746245024360 0ustar jpakkanejpakkane00000000000000static int hidden_func() { return 0; } meson-0.40.1/test cases/common/139 override options/four.c0000644000175000017500000000020713070746245024553 0ustar jpakkanejpakkane00000000000000int func(); static int duplicate_func() { return -4; } int main(int argc, char **argv) { return duplicate_func() + func(); } meson-0.40.1/test cases/common/139 override options/two.c0000644000175000017500000000021013070746245024403 0ustar jpakkanejpakkane00000000000000/* * Requires a Unity build. Otherwise hidden_func is not specified. */ int main(int argc, char **argv) { return hidden_func(); } meson-0.40.1/test cases/common/139 override options/three.c0000644000175000017500000000013313070746245024705 0ustar jpakkanejpakkane00000000000000static int duplicate_func() { return 4; } int func() { return duplicate_func(); } meson-0.40.1/test cases/common/141 mesonintrospect from scripts/0000755000175000017500000000000013100703043025742 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/141 mesonintrospect from scripts/meson.build0000644000175000017500000000051613100702376030116 0ustar jpakkanejpakkane00000000000000project('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') meson-0.40.1/test cases/common/141 mesonintrospect from scripts/check_env.py0000644000175000017500000000064513074426732030267 0ustar jpakkanejpakkane00000000000000#!/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='') meson-0.40.1/test cases/common/16 configure file/0000755000175000017500000000000013100703043022714 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/16 configure file/config.h.in0000644000175000017500000000017012650745767024771 0ustar jpakkanejpakkane00000000000000#define MESSAGE "@var@" #define OTHER "@other@" "@second@" "@empty@" #mesondefine BE_TRUE #mesondefine SHOULD_BE_UNDEF meson-0.40.1/test cases/common/16 configure file/prog2.c0000644000175000017500000000012113012152443024107 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { return ZERO_RESULT; } meson-0.40.1/test cases/common/16 configure file/installed_files.txt0000644000175000017500000000016513070746245026641 0ustar jpakkanejpakkane00000000000000usr/share/appdir/config2.h usr/share/appdir/config2b.h usr/share/appdireh/config2-1.h usr/share/appdirok/config2-2.h meson-0.40.1/test cases/common/16 configure file/meson.build0000644000175000017500000000535013100702266025067 0ustar jpakkanejpakkane00000000000000project('configure file test', 'c') conf = configuration_data() conf.set('var', 'mystring') conf.set('other', 'string 2') conf.set('second', ' bonus') conf.set('BE_TRUE', true) assert(conf.get('var') == 'mystring', 'Get function is not working.') assert(conf.get('var', 'default') == 'mystring', 'Get function is not working.') assert(conf.get('notthere', 'default') == 'default', 'Default value getting is not working.') cfile = configure_file(input : 'config.h.in', output : 'config.h', configuration : conf) e = executable('inctest', 'prog.c', # Note that you should NOT do this. Don't add generated headers here # This tests that we do the right thing even if people add in conf files # to their sources. 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()) ifile = '@0@/dummy.dat'.format(meson.current_source_dir()) ofile = '@0@/config2.h'.format(meson.current_build_dir()) check_file = find_program('check_file.py') # Configure in source root with command and absolute paths configure_file(input : 'dummy.dat', output : 'config2.h', command : [genprog, scriptfile, ifile, ofile], install_dir : 'share/appdir') run_command(check_file, join_paths(meson.current_build_dir(), 'config2.h')) # Same again as before, but an input file should not be required in # this case where we use a command/script to generate the output file. genscript2b = '@0@/generator-without-input-file.py'.format(meson.current_source_dir()) ofile2b = '@0@/config2b.h'.format(meson.current_build_dir()) configure_file( output : 'config2b.h', command : [genprog, genscript2b, ofile2b], install_dir : 'share/appdir') run_command(check_file, join_paths(meson.current_build_dir(), 'config2b.h')) found_script = find_program('generator.py') # More configure_file tests in here subdir('subdir') test('inctest2', executable('prog2', 'prog2.c')) # Generate a conf file without an input file. dump = configuration_data() dump.set_quoted('SHOULD_BE_STRING', 'string', description : 'A string') dump.set_quoted('SHOULD_BE_STRING2', 'A "B" C') dump.set_quoted('SHOULD_BE_STRING3', 'A "" C') dump.set_quoted('SHOULD_BE_STRING4', 'A " C') dump.set('SHOULD_BE_RETURN', 'return') dump.set('SHOULD_BE_DEFINED', true) dump.set('SHOULD_BE_UNDEFINED', false) dump.set('SHOULD_BE_ONE', 1) dump.set('SHOULD_BE_ZERO', 0, description : 'Absolutely zero') dump.set('SHOULD_BE_QUOTED_ONE', '"1"') configure_file(output : 'config3.h', configuration : dump) test('Configless.', executable('dumpprog', 'dumpprog.c')) meson-0.40.1/test cases/common/16 configure file/subdir/0000755000175000017500000000000013100703043024204 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/16 configure file/subdir/meson.build0000644000175000017500000000157413055371477026402 0ustar jpakkanejpakkane00000000000000# Configure in subdir with absolute paths for input and relative for output configure_file(input : '../dummy.dat', output : 'config2-1.h', command : [genprog, scriptfile, ifile, 'config2-1.h'], install_dir : 'share/appdireh') run_command(check_file, join_paths(meson.current_build_dir(), 'config2-1.h')) # Configure in subdir with files() for input and relative for output configure_file(input : '../dummy.dat', output : 'config2-2.h', command : [genprog, scriptfile, files('../dummy.dat'), 'config2-2.h'], install_dir : 'share/appdirok') run_command(check_file, join_paths(meson.current_build_dir(), 'config2-2.h')) # Configure in subdir with string templates for input and output configure_file(input : '../dummy.dat', output : 'config2-3.h', command : [found_script, '@INPUT@', '@OUTPUT@']) run_command(check_file, join_paths(meson.current_build_dir(), 'config2-3.h')) meson-0.40.1/test cases/common/16 configure file/dummy.dat0000644000175000017500000000000012650745767024563 0ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/16 configure file/generator-without-input-file.py0000755000175000017500000000050613070746245031054 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys, os from pathlib import Path if len(sys.argv) != 2: print("Wrong amount of parameters.") build_dir = Path(os.environ['MESON_BUILD_ROOT']) subdir = Path(os.environ['MESON_SUBDIR']) outputf = Path(sys.argv[1]) with outputf.open('w') as ofile: ofile.write("#define ZERO_RESULT 0\n") meson-0.40.1/test cases/common/16 configure file/dumpprog.c0000644000175000017500000000214212767063125024736 0ustar jpakkanejpakkane00000000000000#define SHOULD_BE_UNDEFINED 1 #include"config3.h" #include #include #ifdef SHOULD_BE_UNDEFINED #error Token did not get undefined. #endif #ifndef SHOULD_BE_DEFINED #error Token did not get defined #endif int main(int argc, char **argv) { if(strcmp(SHOULD_BE_STRING, "string") != 0) { printf("String token defined wrong.\n"); return 1; } if(strcmp(SHOULD_BE_STRING2, "A \"B\" C") != 0) { printf("String token 2 defined wrong.\n"); return 1; } if(strcmp(SHOULD_BE_STRING3, "A \"\" C") != 0) { printf("String token 3 defined wrong.\n"); return 1; } if(strcmp(SHOULD_BE_STRING4, "A \" C") != 0) { printf("String token 4 defined wrong.\n"); return 1; } if(SHOULD_BE_ONE != 1) { printf("One defined incorrectly.\n"); return 1; } if(SHOULD_BE_ZERO != 0) { printf("Zero defined incorrectly.\n"); return 1; } if(strcmp(SHOULD_BE_QUOTED_ONE, "1") != 0) { printf("Quoted number defined incorrectly.\n"); return 1; } SHOULD_BE_RETURN 0; } meson-0.40.1/test cases/common/16 configure file/prog.c0000644000175000017500000000045413012152443024036 0ustar jpakkanejpakkane00000000000000#include /* config.h must not be in quotes: * https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html */ #include #ifdef SHOULD_BE_UNDEF #error "FAIL!" #endif int main(int argc, char **argv) { #ifndef BE_TRUE return 1; #else return strcmp(MESSAGE, "mystring"); #endif } meson-0.40.1/test cases/common/16 configure file/check_file.py0000644000175000017500000000012213055371477025362 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import os import sys assert(os.path.exists(sys.argv[1])) meson-0.40.1/test cases/common/16 configure file/config.h0000644000175000017500000000014313012152443024334 0ustar jpakkanejpakkane00000000000000#error "This file should not be included. Build dir must become before source dir in search order" meson-0.40.1/test cases/common/16 configure file/generator.py0000755000175000017500000000057213055371477025310 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys, os from pathlib import Path if len(sys.argv) != 3: print("Wrong amount of parameters.") build_dir = Path(os.environ['MESON_BUILD_ROOT']) subdir = Path(os.environ['MESON_SUBDIR']) inputf = Path(sys.argv[1]) outputf = Path(sys.argv[2]) assert(inputf.exists()) with outputf.open('w') as ofile: ofile.write("#define ZERO_RESULT 0\n") meson-0.40.1/test cases/common/40 logic ops/0000755000175000017500000000000013100703043021707 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/40 logic ops/meson.build0000644000175000017500000000207413100702301024050 0ustar jpakkanejpakkane00000000000000project('logicopts', 'c') t = true f = false if (true) message('Ok.') else error('Not ok.') endif if (false) error('Not ok.') else message('Ok.') endif if (f) error('Not ok.') else message('Ok.') endif if (t) message('Ok.') else error('Not ok.') endif if true and t message('Ok.') else error('Not ok.') endif if t and false error('Not ok.') else message('Ok.') endif if f and t error('Not ok.') else message('Ok.') endif if f or false error('Not ok.') else message('Ok.') endif if true or f message('Ok.') else error('Not ok.') endif if t or true message('Ok.') else error('Not ok.') endif if not true error('Negation failed.') else message('Ok.') endif if not f message('Ok.') else error('Negation failed.') endif if f or f or f or f or f or f or f or f or t message('Ok.') else error('Chain of ors failed.') endif if t and t and t and t and t and t and t and t and f error('Chain of ands failed.') else message('Ok.') endif if t and t or t message('Ok.') else error('Combination of and-or failed.') endif meson-0.40.1/test cases/common/33 try compile/0000755000175000017500000000000013100703043022261 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/33 try compile/invalid.c0000644000175000017500000000010613001212425024047 0ustar jpakkanejpakkane00000000000000#include void func() { printf("This won't work.\n"); } meson-0.40.1/test cases/common/33 try compile/meson.build0000644000175000017500000000151613100702276024435 0ustar jpakkanejpakkane00000000000000project('try compile', 'c', 'cpp') code = '''#include void func() { printf("Something.\n"); } ''' breakcode = '''#include void func() { printf("This won't work.\n"); } ''' 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 ' + compiler.get_id() + ' is fail.') 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 ' + compiler.get_id() + ' returned true on broken code.') endif endforeach meson-0.40.1/test cases/common/33 try compile/valid.c0000644000175000017500000000007213001212425023522 0ustar jpakkanejpakkane00000000000000#include void func() { printf("Something.\n"); } meson-0.40.1/test cases/common/54 same file name/0000755000175000017500000000000013100703043022563 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/54 same file name/meson.build0000644000175000017500000000014013100702311024715 0ustar jpakkanejpakkane00000000000000project('samefile', 'c') test('basic', executable('prog', 'prog.c', 'd1/file.c', 'd2/file.c')) meson-0.40.1/test cases/common/54 same file name/prog.c0000644000175000017500000000013512650745767023731 0ustar jpakkanejpakkane00000000000000int func1(); int func2(); int main(int argc, char **argv) { return func1() - func2(); } meson-0.40.1/test cases/common/54 same file name/d1/0000755000175000017500000000000013100703043023067 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/54 same file name/d1/file.c0000644000175000017500000000003312650745767024202 0ustar jpakkanejpakkane00000000000000int func1() { return 42; } meson-0.40.1/test cases/common/54 same file name/d2/0000755000175000017500000000000013100703043023070 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/54 same file name/d2/file.c0000644000175000017500000000003312650745767024203 0ustar jpakkanejpakkane00000000000000int func2() { return 42; } meson-0.40.1/test cases/common/50 subproject options/0000755000175000017500000000000013100703043023665 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/50 subproject options/subprojects/0000755000175000017500000000000013100703042026227 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/50 subproject options/subprojects/subproject/0000755000175000017500000000000013100703043030410 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/50 subproject options/subprojects/subproject/meson.build0000644000175000017500000000014612666130376032576 0ustar jpakkanejpakkane00000000000000project('subproject', 'c') if get_option('opt') error('option set when it should be unset.') endif meson-0.40.1/test cases/common/50 subproject options/subprojects/subproject/meson_options.txt0000644000175000017500000000012212650745767034074 0ustar jpakkanejpakkane00000000000000option('opt', type : 'boolean', value : false, description : 'subproject option') meson-0.40.1/test cases/common/50 subproject options/meson.build0000644000175000017500000000020313100702307026024 0ustar jpakkanejpakkane00000000000000project('suboptions', 'c') subproject('subproject') if not get_option('opt') error('option unset when it should be set') endif meson-0.40.1/test cases/common/50 subproject options/meson_options.txt0000644000175000017500000000012312650745767027352 0ustar jpakkanejpakkane00000000000000option('opt', type : 'boolean', value : true, description : 'main project option') meson-0.40.1/test cases/common/32 multiline string/0000755000175000017500000000000013100703043023322 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/32 multiline string/meson.build0000644000175000017500000000057013100702275025474 0ustar jpakkanejpakkane00000000000000project('multiline string', 'c') x = '''hello again''' y = '''hello again''' if x == y error('Things are wrong.') endif multieol = ''' ''' singleeol = '\n' if multieol != singleeol error('Newline quoting is broken.') endif # And one more for good measure. quote1 = ''' ' '''.strip() quote2 = '\'' if quote1 != quote2 error('Single quote quoting is broken.') endif meson-0.40.1/test cases/common/80 shared subproject 2/0000755000175000017500000000000013100703043023565 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/80 shared subproject 2/subprojects/0000755000175000017500000000000013100703042026127 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/80 shared subproject 2/subprojects/B/0000755000175000017500000000000013100703043026311 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/80 shared subproject 2/subprojects/B/meson.build0000644000175000017500000000015412650745767030507 0ustar jpakkanejpakkane00000000000000project('B', 'c') C = subproject('C') c = C.get_variable('c') b = shared_library('b', 'b.c', link_with : c) meson-0.40.1/test cases/common/80 shared subproject 2/subprojects/B/b.c0000644000175000017500000000064412650745767026736 0ustar jpakkanejpakkane00000000000000#include char func_c(); #if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif char DLL_PUBLIC func_b() { if(func_c() != 'c') { exit(3); } return 'b'; } meson-0.40.1/test cases/common/80 shared subproject 2/subprojects/C/0000755000175000017500000000000013100703043026312 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/80 shared subproject 2/subprojects/C/c.c0000644000175000017500000000052012650745767026731 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif char DLL_PUBLIC func_c() { return 'c'; } meson-0.40.1/test cases/common/80 shared subproject 2/subprojects/C/meson.build0000644000175000017500000000006112650745767030505 0ustar jpakkanejpakkane00000000000000project('C', 'c') c = shared_library('c', 'c.c') meson-0.40.1/test cases/common/80 shared subproject 2/meson.build0000644000175000017500000000036413100702327025736 0ustar jpakkanejpakkane00000000000000project('A', 'c') # Same as the previous test but use C and B in # the opposite order. C = subproject('C') c = C.get_variable('c') B = subproject('B') b = B.get_variable('b') a = executable('a', 'a.c', link_with : [b, c]) test('a test', a) meson-0.40.1/test cases/common/80 shared subproject 2/a.c0000644000175000017500000000031012650745767024177 0ustar jpakkanejpakkane00000000000000#include char func_b(); char func_c(); int main(int argc, char **argv) { if(func_b() != 'b') { return 1; } if(func_c() != 'c') { return 2; } return 0; } meson-0.40.1/test cases/common/123 subproject project arguments/0000755000175000017500000000000013100703042025706 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/123 subproject project arguments/subprojects/0000755000175000017500000000000013100703042030251 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/123 subproject project arguments/subprojects/subexe/0000755000175000017500000000000013100703042031544 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/123 subproject project arguments/subprojects/subexe/subexe.c0000644000175000017500000000043213074426732033224 0ustar jpakkanejpakkane00000000000000#ifdef PROJECT_OPTION #error #endif #ifdef PROJECT_OPTION_1 #error #endif #ifdef PROJECT_OPTION_C_CPP #error #endif #ifndef GLOBAL_ARGUMENT #error #endif #ifndef SUBPROJECT_OPTION #error #endif #ifdef OPTION_CPP #error #endif int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/123 subproject project arguments/subprojects/subexe/meson.build0000644000175000017500000000061413016624375033730 0ustar jpakkanejpakkane00000000000000project('subproject', 'c', version : '1.0.0', license : ['sublicense1', 'sublicense2']) if not meson.is_subproject() error('Claimed to be master project even though we are a subproject.') endif assert(meson.project_name() == 'subproject', 'Incorrect subproject name') add_project_arguments('-DSUBPROJECT_OPTION', language: 'c') e = executable('subexe', 'subexe.c') test('subexetest', e) meson-0.40.1/test cases/common/123 subproject project arguments/meson.build0000644000175000017500000000105613100702361030055 0ustar jpakkanejpakkane00000000000000project('project options tester', 'c', 'cpp', version : '2.3.4', license : 'mylicense') add_global_arguments('-DGLOBAL_ARGUMENT', language: 'c') add_project_arguments('-DPROJECT_OPTION', 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) test('execpptest', e) meson-0.40.1/test cases/common/123 subproject project arguments/exe.cpp0000644000175000017500000000044313074426732027216 0ustar jpakkanejpakkane00000000000000#ifdef PROJECT_OPTION #error #endif #ifdef PROJECT_OPTION_1 #error #endif #ifdef GLOBAL_ARGUMENT #error #endif #ifdef SUBPROJECT_OPTION #error #endif #ifndef PROJECT_OPTION_CPP #error #endif #ifndef PROJECT_OPTION_C_CPP #error #endif int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/123 subproject project arguments/exe.c0000644000175000017500000000043413074426732026656 0ustar jpakkanejpakkane00000000000000#ifndef PROJECT_OPTION #error #endif #ifndef PROJECT_OPTION_1 #error #endif #ifndef GLOBAL_ARGUMENT #error #endif #ifdef SUBPROJECT_OPTION #error #endif #ifdef OPTION_CPP #error #endif #ifndef PROJECT_OPTION_C_CPP #error #endif int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/72 build always/0000755000175000017500000000000013100703043022415 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/72 build always/main.c0000644000175000017500000000021112650745767023533 0ustar jpakkanejpakkane00000000000000#include #include"version.h" int main(int argc, char **argv) { printf("Version is %s.\n", version_string); return 0; } meson-0.40.1/test cases/common/72 build always/version.c.in0000644000175000017500000000007712650745767024713 0ustar jpakkanejpakkane00000000000000#include"version.h" const char *version_string = "@VERSION@"; meson-0.40.1/test cases/common/72 build always/meson.build0000644000175000017500000000046013100702322024556 0ustar jpakkanejpakkane00000000000000project('run always', 'c') version = '1.0.0' vgen = find_program('version_gen.py') version_src = custom_target('Version string', input : 'version.c.in', output : 'version.c', command : [vgen, '@INPUT@', '@OUTPUT@', version], build_always : true, ) executable('versionprinter', 'main.c', version_src) meson-0.40.1/test cases/common/72 build always/version.h0000644000175000017500000000005212650745767024304 0ustar jpakkanejpakkane00000000000000#pragma once const char *version_string; meson-0.40.1/test cases/common/72 build always/version_gen.py0000755000175000017500000000157413057037314025333 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys, os, subprocess def generate(infile, outfile, fallback): workdir = os.path.split(infile)[0] if workdir == '': workdir = '.' version = fallback try: p = subprocess.Popen(['git', 'describe'], cwd=workdir, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdo, _) = p.communicate() if p.returncode == 0: version = stdo.decode().strip() except: pass with open(infile) as f: newdata = f.read().replace('@VERSION@', version) try: with open(outfile) as f: olddata = f.read() if olddata == newdata: return except: pass with open(outfile, 'w') as f: f.write(newdata) if __name__ == '__main__': infile = sys.argv[1] outfile = sys.argv[2] fallback = sys.argv[3] generate(infile, outfile, fallback) meson-0.40.1/test cases/common/131 custom target directory install/0000755000175000017500000000000013100703043026306 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/131 custom target directory install/installed_files.txt0000644000175000017500000000016213025554726032231 0ustar jpakkanejpakkane00000000000000usr/share/doc/testpkgname/html/a.html usr/share/doc/testpkgname/html/b.html usr/share/doc/testpkgname/html/c.html meson-0.40.1/test cases/common/131 custom target directory install/meson.build0000644000175000017500000000036413100702367030463 0ustar jpakkanejpakkane00000000000000project('custom-target-dir-install', 'c') docgen = find_program('docgen.py') custom_target('docgen', output : 'html', command : [docgen, '@OUTPUT@'], install : true, install_dir : join_paths(get_option('datadir'), 'doc/testpkgname')) meson-0.40.1/test cases/common/131 custom target directory install/docgen.py0000644000175000017500000000027713057037314030141 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import os import sys out = sys.argv[1] os.mkdir(out) for name in ('a', 'b', 'c'): with open(os.path.join(out, name + '.html'), 'w') as f: f.write(name) meson-0.40.1/test cases/common/79 shared subproject/0000755000175000017500000000000013100703043023453 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/79 shared subproject/subprojects/0000755000175000017500000000000013100703042026015 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/79 shared subproject/subprojects/B/0000755000175000017500000000000013100703043026177 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/79 shared subproject/subprojects/B/meson.build0000644000175000017500000000015412650745767030375 0ustar jpakkanejpakkane00000000000000project('B', 'c') C = subproject('C') c = C.get_variable('c') b = shared_library('b', 'b.c', link_with : c) meson-0.40.1/test cases/common/79 shared subproject/subprojects/B/b.c0000644000175000017500000000064512650745767026625 0ustar jpakkanejpakkane00000000000000#include #if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif char func_c(); char DLL_PUBLIC func_b() { if(func_c() != 'c') { exit(3); } return 'b'; } meson-0.40.1/test cases/common/79 shared subproject/subprojects/C/0000755000175000017500000000000013100703043026200 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/79 shared subproject/subprojects/C/c.c0000644000175000017500000000052012650745767026617 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif char DLL_PUBLIC func_c() { return 'c'; } meson-0.40.1/test cases/common/79 shared subproject/subprojects/C/meson.build0000644000175000017500000000006112650745767030373 0ustar jpakkanejpakkane00000000000000project('C', 'c') c = shared_library('c', 'c.c') meson-0.40.1/test cases/common/79 shared subproject/meson.build0000644000175000017500000000025613100702326025623 0ustar jpakkanejpakkane00000000000000project('A', 'c') B = subproject('B') b = B.get_variable('b') C = subproject('C') c = C.get_variable('c') a = executable('a', 'a.c', link_with : [b, c]) test('a test', a) meson-0.40.1/test cases/common/79 shared subproject/a.c0000644000175000017500000000031012650745767024065 0ustar jpakkanejpakkane00000000000000#include char func_b(); char func_c(); int main(int argc, char **argv) { if(func_b() != 'b') { return 1; } if(func_c() != 'c') { return 2; } return 0; } meson-0.40.1/test cases/common/130 no buildincdir/0000755000175000017500000000000013100703043022775 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/130 no buildincdir/meson.build0000644000175000017500000000054213100702366025147 0ustar jpakkanejpakkane00000000000000project('nobuilddir', 'c', default_options : 'werror=true') cc = meson.get_compiler('c') incwarg = '-Wmissing-include-dirs' if cc.has_argument(incwarg) executable('prog', 'prog.c', c_args : incwarg, include_directories : include_directories('include')) else error('MESON_SKIP_TEST compiler does not support bad inc dir argument.') endif meson-0.40.1/test cases/common/130 no buildincdir/include/0000755000175000017500000000000013100703043024420 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/130 no buildincdir/include/header.h0000644000175000017500000000003413024065327026031 0ustar jpakkanejpakkane00000000000000#pragma once int foobar(); meson-0.40.1/test cases/common/130 no buildincdir/prog.c0000644000175000017500000000010613024065327024120 0ustar jpakkanejpakkane00000000000000#include"header.h" int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/121 interpreter copy mutable var on assignment/0000755000175000017500000000000013100703042030316 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/121 interpreter copy mutable var on assignment/meson.build0000644000175000017500000000105213100702360032460 0ustar jpakkanejpakkane00000000000000project('foo', 'c') a = configuration_data() a.set('HELLO', 1) b = a assert(a.has('HELLO'), 'Original config data should be set on a') assert(b.has('HELLO'), 'Original config data should be set on copy') configure_file(output : 'b.h', configuration : b) # This should still work, as we didn't use the original above but a copy! a.set('WORLD', 1) assert(a.has('WORLD'), 'New config data should have been set') assert(not b.has('WORLD'), 'New config data set should not affect var copied earlier') configure_file(output : 'a.h', configuration : a) meson-0.40.1/test cases/common/82 custom subproject dir/0000755000175000017500000000000013100703044024251 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/82 custom subproject dir/meson.build0000644000175000017500000000032613100702331026412 0ustar jpakkanejpakkane00000000000000project('A', 'c', subproject_dir:'custom_subproject_dir') B = subproject('B') b = B.get_variable('b') C = subproject('C') c = C.get_variable('c') a = executable('a', 'a.c', link_with : [b, c]) test('a test', a) meson-0.40.1/test cases/common/82 custom subproject dir/a.c0000644000175000017500000000031012650745767024662 0ustar jpakkanejpakkane00000000000000#include char func_b(); char func_c(); int main(int argc, char **argv) { if(func_b() != 'b') { return 1; } if(func_c() != 'c') { return 2; } return 0; } meson-0.40.1/test cases/common/82 custom subproject dir/custom_subproject_dir/0000755000175000017500000000000013100703042030657 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/82 custom subproject dir/custom_subproject_dir/B/0000755000175000017500000000000013100703044031042 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/82 custom subproject dir/custom_subproject_dir/B/meson.build0000644000175000017500000000015412650745767033237 0ustar jpakkanejpakkane00000000000000project('B', 'c') C = subproject('C') c = C.get_variable('c') b = shared_library('b', 'b.c', link_with : c) meson-0.40.1/test cases/common/82 custom subproject dir/custom_subproject_dir/B/b.c0000644000175000017500000000064412650745767031466 0ustar jpakkanejpakkane00000000000000#include char func_c(); #if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif char DLL_PUBLIC func_b() { if(func_c() != 'c') { exit(3); } return 'b'; } meson-0.40.1/test cases/common/82 custom subproject dir/custom_subproject_dir/C/0000755000175000017500000000000013100703044031043 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/82 custom subproject dir/custom_subproject_dir/C/c.c0000644000175000017500000000052012650745767031461 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif char DLL_PUBLIC func_c() { return 'c'; } meson-0.40.1/test cases/common/82 custom subproject dir/custom_subproject_dir/C/meson.build0000644000175000017500000000006112650745767033235 0ustar jpakkanejpakkane00000000000000project('C', 'c') c = shared_library('c', 'c.c') meson-0.40.1/test cases/common/51 pkgconfig-gen/0000755000175000017500000000000013100703043022550 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/51 pkgconfig-gen/installed_files.txt0000644000175000017500000000011513001212425026446 0ustar jpakkanejpakkane00000000000000usr/include/simple.h usr/lib/pkgconfig/simple.pc usr/lib/pkgconfig/libfoo.pc meson-0.40.1/test cases/common/51 pkgconfig-gen/simple.c0000644000175000017500000000007512650745767024243 0ustar jpakkanejpakkane00000000000000#include"simple.h" int simple_function() { return 42; } meson-0.40.1/test cases/common/51 pkgconfig-gen/meson.build0000644000175000017500000000232513100702307024716 0ustar jpakkanejpakkane00000000000000project('pkgconfig-gen', 'c') pkgg = import('pkgconfig') lib = shared_library('simple', 'simple.c') libver = '1.0' h = install_headers('simple.h') pkgg.generate( libraries : [lib, '-lz'], subdirs : '.', version : libver, name : 'libsimple', filebase : 'simple', description : 'A simple demo library.', requires : 'glib-2.0', # Not really, but only here to test that this works. requires_private : ['gio-2.0', 'gobject-2.0'], libraries_private : [lib, '-lz'], ) pkgconfig = find_program('pkg-config', required: false) if pkgconfig.found() v = run_command(pkgconfig, '--version').stdout().strip() if v.version_compare('>=0.29') test('pkgconfig-validation', pkgconfig, args: ['--validate', 'simple'], env: ['PKG_CONFIG_PATH=' + meson.current_build_dir() + '/meson-private' ]) else message('pkg-config version \'' + v + '\' too old, skipping validate test') endif else message('pkg-config not found, skipping validate test') endif # Test that name_prefix='' and name='libfoo' results in '-lfoo' lib2 = shared_library('libfoo', 'simple.c', name_prefix : '', version : libver) pkgg.generate( libraries : lib2, name : 'libfoo', version : libver, description : 'A foo library.') meson-0.40.1/test cases/common/51 pkgconfig-gen/simple.h0000644000175000017500000000010412650745767024241 0ustar jpakkanejpakkane00000000000000#ifndef SIMPLE_H_ #define SIMPLE_H_ int simple_function(); #endif meson-0.40.1/test cases/common/57 custom target chain/0000755000175000017500000000000013100703043023664 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/57 custom target chain/installed_files.txt0000644000175000017500000000005212763077471027612 0ustar jpakkanejpakkane00000000000000usr/subdir/data2.dat usr/subdir/data3.dat meson-0.40.1/test cases/common/57 custom target chain/meson.build0000644000175000017500000000156313100702313026032 0ustar jpakkanejpakkane00000000000000project('custom target', 'c') python = find_program('python3', required : false) if not python.found() python = find_program('python') endif # files() is the correct way to do this, but some people # do this so test that it works. comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py') comp2 = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler2.py') infile = files('data_source.txt')[0] mytarget = custom_target('bindat', output : 'data.dat', command : [python, comp, infile, '@OUTPUT@'], ) mytarget2 = custom_target('bindat2', output : 'data2.dat', command : [python, comp2, mytarget, '@OUTPUT@'], install : true, install_dir : 'subdir' ) mytarget3 = custom_target('bindat3', output : 'data3.dat', input : [mytarget], command : [python, comp2, '@INPUT@', '@OUTPUT@'], install : true, install_dir : 'subdir' ) subdir('usetarget') meson-0.40.1/test cases/common/57 custom target chain/usetarget/0000755000175000017500000000000013100703043025667 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/57 custom target chain/usetarget/myexe.c0000644000175000017500000000014212665637120027200 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("I am myexe.\n"); return 0; } meson-0.40.1/test cases/common/57 custom target chain/usetarget/meson.build0000644000175000017500000000026612665637120030056 0ustar jpakkanejpakkane00000000000000e = executable('myexe', 'myexe.c') subexe = find_program('subcomp.py') custom_target('use_exe', input : e, output : 'subout.res', command : [subexe, '@INPUT@', '@OUTPUT@'], ) meson-0.40.1/test cases/common/57 custom target chain/usetarget/subcomp.py0000755000175000017500000000023413043224360027721 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python import sys with open(sys.argv[1], 'rb') as ifile: with open(sys.argv[2], 'w') as ofile: ofile.write('Everything ok.\n') meson-0.40.1/test cases/common/57 custom target chain/my_compiler2.py0000755000175000017500000000065713043224360026660 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python import sys if __name__ == '__main__': if len(sys.argv) != 3: print(sys.argv[0], 'input_file output_file') sys.exit(1) with open(sys.argv[1]) as f: ifile = f.read() if ifile != 'This is a binary output file.\n': print('Malformed input') sys.exit(1) with open(sys.argv[2], 'w') as ofile: ofile.write('This is a different binary output file.\n') meson-0.40.1/test cases/common/57 custom target chain/data_source.txt0000644000175000017500000000004012650745767026744 0ustar jpakkanejpakkane00000000000000This is a text only input file. meson-0.40.1/test cases/common/57 custom target chain/my_compiler.py0000755000175000017500000000064713043224360026575 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python import sys if __name__ == '__main__': if len(sys.argv) != 3: print(sys.argv[0], 'input_file output_file') sys.exit(1) with open(sys.argv[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: ofile.write('This is a binary output file.\n') meson-0.40.1/test cases/common/27 library versions/0000755000175000017500000000000013100703043023332 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/27 library versions/installed_files.txt0000644000175000017500000000003512742140120027234 0ustar jpakkanejpakkane00000000000000usr/lib/prefixsomelib.suffix meson-0.40.1/test cases/common/27 library versions/lib.c0000644000175000017500000000004012650745767024272 0ustar jpakkanejpakkane00000000000000int myFunc() { return 55; } meson-0.40.1/test cases/common/27 library versions/meson.build0000644000175000017500000000026413100702273025502 0ustar jpakkanejpakkane00000000000000project('library versions', 'c') shared_library('somelib', 'lib.c', name_prefix : 'prefix', name_suffix : 'suffix', install_dir : 'lib', install : true) subdir('subdir') meson-0.40.1/test cases/common/27 library versions/subdir/0000755000175000017500000000000013100703043024622 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/27 library versions/subdir/meson.build0000644000175000017500000000054212742140120026767 0ustar jpakkanejpakkane00000000000000# Test that using files generated with configure_file as sources works. # We do this inside a subdir so that the path isn't accidentally correct # because there is no structure in the build dir. genlib = configure_file(input : '../lib.c', output : 'genlib.c', configuration : configuration_data()) shared_library('genlib', genlib, install : false) meson-0.40.1/test cases/common/98 gen extra/0000755000175000017500000000000013100703044021723 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/98 gen extra/srcgen.py0000755000175000017500000000124213057037314023573 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys import argparse parser = argparse.ArgumentParser() parser.add_argument('--input', dest='input', help='the input file') parser.add_argument('--output', dest='output', help='the output file') parser.add_argument('--upper', dest='upper', action='store_true', default=False, help='Convert to upper case.') c_templ = '''int %s() { return 0; } ''' options = parser.parse_args(sys.argv[1:]) with open(options.input) as f: funcname = f.readline().strip() if options.upper: funcname = funcname.upper() with open(options.output, 'w') as f: f.write(c_templ % funcname) meson-0.40.1/test cases/common/98 gen extra/upper.c0000644000175000017500000000011612650745767023253 0ustar jpakkanejpakkane00000000000000int BOB_MCBOB(); int main(int argc, char **argv) { return BOB_MCBOB(); } meson-0.40.1/test cases/common/98 gen extra/meson.build0000644000175000017500000000056513100702342024073 0ustar jpakkanejpakkane00000000000000project('extra args in gen', 'c') prog = find_program('srcgen.py') gen = generator(prog, output : '@BASENAME@.c', arguments : ['--input=@INPUT@', '--output=@OUTPUT@', '@EXTRA_ARGS@']) g1 = gen.process('name.dat') g2 = gen.process('name.dat', extra_args: '--upper') test('basic', executable('basic', 'plain.c', g1)) test('upper', executable('upper', 'upper.c', g2)) meson-0.40.1/test cases/common/98 gen extra/plain.c0000644000175000017500000000011612650745767023223 0ustar jpakkanejpakkane00000000000000int bob_mcbob(); int main(int argc, char **argv) { return bob_mcbob(); } meson-0.40.1/test cases/common/98 gen extra/name.dat0000644000175000017500000000001212650745767023361 0ustar jpakkanejpakkane00000000000000bob_mcbob meson-0.40.1/test cases/common/41 elif/0000755000175000017500000000000013100703043020750 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/41 elif/meson.build0000644000175000017500000000042613100702301023110 0ustar jpakkanejpakkane00000000000000project('elseif', 'c') t = true f = false if true message('Ok.') elif true error('Error') else error('Error') endif if f error('Error.') elif t message('Ok') else error('Error') endif if f error('Error.') elif false error('Error') else message('Ok') endif meson-0.40.1/test cases/common/83 has type/0000755000175000017500000000000013100703044021555 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/83 has type/meson.build0000644000175000017500000000054113100702331023715 0ustar jpakkanejpakkane00000000000000project('has type', 'c', 'cpp') compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] foreach cc : compilers if not cc.has_type('time_t', prefix : '#include') error('Did not detect type that exists.') endif if cc.has_type('no_time_t', prefix : '#include') error('Not existing type found.') endif endforeach meson-0.40.1/test cases/common/89 add language/0000755000175000017500000000000013100703044022342 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/89 add language/meson.build0000644000175000017500000000044113100702335024505 0ustar jpakkanejpakkane00000000000000project('add language', 'c') test('C', executable('cprog', 'prog.c')) assert(add_languages('cpp'), 'Add_languages returned false on success') assert(not add_languages('klingon', required : false), 'Add_languages returned true on failure.') test('C++', executable('cppprog', 'prog.cc')) meson-0.40.1/test cases/common/89 add language/prog.cc0000644000175000017500000000013412650745767023651 0ustar jpakkanejpakkane00000000000000#include int main(int, char**) { std::cout << "I am C++.\n"; return 0; } meson-0.40.1/test cases/common/89 add language/prog.c0000644000175000017500000000014412650745767023507 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("I am plain C.\n"); return 0; } meson-0.40.1/test cases/common/70 array arithmetic/0000755000175000017500000000000013100703043023263 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/70 array arithmetic/meson.build0000644000175000017500000000062613100702321025427 0ustar jpakkanejpakkane00000000000000project('array arithmetic', 'c') array1 = ['foo', 'bar'] array2 = ['qux', 'baz'] if array1 + array2 != ['foo', 'bar', 'qux', 'baz'] error('Array concatenation is broken') endif if array2 + array1 != ['qux', 'baz', 'foo', 'bar'] error('Array concatenation is broken') endif if array1 + array1 + array1 != ['foo', 'bar', 'foo', 'bar', 'foo', 'bar'] error('Many-array concatenation is broken') endif meson-0.40.1/test cases/common/64 custom header generator/0000755000175000017500000000000013100703043024530 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/64 custom header generator/meson.build0000644000175000017500000000056113100702316026676 0ustar jpakkanejpakkane00000000000000project('custom header generator', 'c') gen = find_program('makeheader.py') generated_h = custom_target('makeheader.py', output : 'myheader.lh', # Suffix not .h to ensure this works with custom suffixes, too. input : 'input.def', command : [gen, '@INPUT0@', '@OUTPUT0@', files('somefile.txt')]) prog = executable('prog', 'prog.c', generated_h) test('gentest', prog) meson-0.40.1/test cases/common/64 custom header generator/somefile.txt0000644000175000017500000000000013100702043027061 0ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/64 custom header generator/prog.c0000644000175000017500000000011712650745767025676 0ustar jpakkanejpakkane00000000000000#include"myheader.lh" int main(int argc, char **argv) { return RET_VAL; } meson-0.40.1/test cases/common/64 custom header generator/makeheader.py0000644000175000017500000000050213100702042027163 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # NOTE: this file does not have the executable bit set. This tests that # Meson can automatically parse shebang lines. import sys template = '#define RET_VAL %s\n' with open(sys.argv[1]) as f: output = template % (f.readline().strip(), ) with open(sys.argv[2], 'w') as f: f.write(output) meson-0.40.1/test cases/common/64 custom header generator/input.def0000644000175000017500000000000213100702040026333 0ustar jpakkanejpakkane000000000000000 meson-0.40.1/test cases/common/78 ctarget dependency/0000755000175000017500000000000013100703043023573 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/78 ctarget dependency/gen1.py0000755000175000017500000000035513057037314025021 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import time, sys # Make sure other script runs first if dependency # is missing. time.sleep(0.5) with open(sys.argv[1], 'r') as f: contents = f.read() with open(sys.argv[2], 'w') as f: f.write(contents) meson-0.40.1/test cases/common/78 ctarget dependency/meson.build0000644000175000017500000000105613100702325025741 0ustar jpakkanejpakkane00000000000000project('custom target dependency', 'c') # Sometimes custom targets do not take input files # but instead do globbing or some similar wackiness. # In this case we need to be able to specify a # manual dependency between two custom targets, # if one needs to be run before the other. g1 = find_program('gen1.py') g2 = find_program('gen2.py') c1 = custom_target('medput', input : 'input.dat', output : 'medput.tmp', command : [g1, '@INPUT@', '@OUTPUT@']) custom_target('output', output : 'output.dat', command : [g2, '@OUTDIR@', '@OUTPUT@'], depends : c1) meson-0.40.1/test cases/common/78 ctarget dependency/gen2.py0000755000175000017500000000035213057037314025017 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys, os from glob import glob files = glob(os.path.join(sys.argv[1], '*.tmp')) assert(len(files) == 1) with open(files[0], 'r') as ifile, open(sys.argv[2], 'w') as ofile: ofile.write(ifile.read()) meson-0.40.1/test cases/common/78 ctarget dependency/input.dat0000644000175000017500000000003112650745767025452 0ustar jpakkanejpakkane00000000000000This is a piece of text. meson-0.40.1/test cases/common/88 extract all/0000755000175000017500000000000013100703044022250 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/88 extract all/extractor.h0000644000175000017500000000010212650745767024460 0ustar jpakkanejpakkane00000000000000#pragma once int func1(); int func2(); int func3(); int func4(); meson-0.40.1/test cases/common/88 extract all/meson.build0000644000175000017500000000042313100702334024412 0ustar jpakkanejpakkane00000000000000project('extract all', 'c') a = static_library('a', 'one.c', 'two.c') b = static_library('b', 'three.c', 'four.c') c = static_library('c', objects : [a.extract_all_objects(), b.extract_all_objects()]) e = executable('proggie', 'prog.c', link_with : c) test('extall', e) meson-0.40.1/test cases/common/88 extract all/one.c0000644000175000017500000000006512650745767023231 0ustar jpakkanejpakkane00000000000000#include"extractor.h" int func1() { return 1; } meson-0.40.1/test cases/common/88 extract all/four.c0000644000175000017500000000006512650745767023423 0ustar jpakkanejpakkane00000000000000#include"extractor.h" int func4() { return 4; } meson-0.40.1/test cases/common/88 extract all/two.c0000644000175000017500000000006512650745767023261 0ustar jpakkanejpakkane00000000000000#include"extractor.h" int func2() { return 2; } meson-0.40.1/test cases/common/88 extract all/prog.c0000644000175000017500000000033312650745767023415 0ustar jpakkanejpakkane00000000000000#include"extractor.h" #include int main(int argc, char **argv) { if((1+2+3+4) != (func1() + func2() + func3() + func4())) { printf("Arithmetic is fail.\n"); return 1; } return 0; } meson-0.40.1/test cases/common/88 extract all/three.c0000644000175000017500000000006512650745767023557 0ustar jpakkanejpakkane00000000000000#include"extractor.h" int func3() { return 3; } meson-0.40.1/test cases/common/29 pipeline/0000755000175000017500000000000013100703043021644 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/29 pipeline/meson.build0000644000175000017500000000104013100702274024006 0ustar jpakkanejpakkane00000000000000project('pipeline test', 'c') # We need to run this executable locally so build it with # the host compiler. e1 = executable('srcgen', 'srcgen.c', native : true) # Generate a source file that needs to be included in the build. gen = generator(e1, \ depfile : '@BASENAME@.d', output : '@BASENAME@.c', # Line continuation inside arguments should work without needing a "\". arguments : ['@INPUT@', '@OUTPUT@', '@DEPFILE@']) generated = gen.process(['input_src.dat']) e2 = executable('prog', 'prog.c', generated) test('pipelined', e2) meson-0.40.1/test cases/common/29 pipeline/srcgen.c0000644000175000017500000000317412763077471023325 0ustar jpakkanejpakkane00000000000000#include #include #include #define ARRSIZE 80 int main(int argc, char **argv) { char arr[ARRSIZE]; char *ofilename; char *ifilename; char *dfilename; FILE *ifile; FILE *ofile; FILE *depfile; size_t bytes; int i; if(argc != 4) { fprintf(stderr, "%s \n", argv[0]); return 1; } ifilename = argv[1]; ofilename = argv[2]; dfilename = argv[3]; ifile = fopen(argv[1], "r"); if(!ifile) { fprintf(stderr, "Could not open source file %s.\n", argv[1]); return 1; } ofile = fopen(ofilename, "w"); if(!ofile) { fprintf(stderr, "Could not open target file %s\n", ofilename); fclose(ifile); return 1; } bytes = fread(arr, 1, ARRSIZE, ifile); assert(bytes < 80); assert(bytes > 0); fwrite(arr, 1, bytes, ofile); depfile = fopen(dfilename, "w"); if(!depfile) { fprintf(stderr, "Could not open depfile %s\n", ofilename); fclose(ifile); fclose(ofile); return 1; } for(i=0; i #include int main(int argc, char **argv) { if(INTSIZE != sizeof(int)) { fprintf(stderr, "Mismatch: detected int size %d, actual size %d.\n", INTSIZE, (int)sizeof(int)); return 1; } if(WCHARSIZE != sizeof(wchar_t)) { fprintf(stderr, "Mismatch: detected wchar size %d, actual size %d.\n", WCHARSIZE, (int)sizeof(wchar_t)); return 1; } return 0; } meson-0.40.1/test cases/common/35 sizeof/meson.build0000644000175000017500000000172613100702277023513 0ustar jpakkanejpakkane00000000000000project('sizeof', 'c', 'cpp') # Test with C cc = meson.get_compiler('c') intsize = cc.sizeof('int') wcharsize = cc.sizeof('wchar_t', prefix : '#include') 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', s) test('sizeof test', e) # Test with C++ cpp = meson.get_compiler('cpp') intsize = cpp.sizeof('int') wcharsize = cpp.sizeof('wchar_t', prefix : '#include') 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) meson-0.40.1/test cases/common/15 mixed pch/0000755000175000017500000000000013100703043021673 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/15 mixed pch/pch/0000755000175000017500000000000013100703043022445 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/15 mixed pch/pch/func_pch.c0000644000175000017500000000002112650745767024423 0ustar jpakkanejpakkane00000000000000#include"func.h" meson-0.40.1/test cases/common/15 mixed pch/pch/main_pch.cc0000644000175000017500000000002112650745767024557 0ustar jpakkanejpakkane00000000000000#include"main.h" meson-0.40.1/test cases/common/15 mixed pch/pch/main.h0000644000175000017500000000002312650745767023571 0ustar jpakkanejpakkane00000000000000#include meson-0.40.1/test cases/common/15 mixed pch/pch/func.h0000644000175000017500000000002212650745767023577 0ustar jpakkanejpakkane00000000000000#include meson-0.40.1/test cases/common/15 mixed pch/func.c0000644000175000017500000000020612650745767023024 0ustar jpakkanejpakkane00000000000000void tmp_func() { fprintf(stdout, "This is a function that fails if stdio is not #included.\n"); } int cfunc() { return 0; } meson-0.40.1/test cases/common/15 mixed pch/meson.build0000644000175000017500000000026713100702265024047 0ustar jpakkanejpakkane00000000000000project('mixed C and C++ pch test', 'cpp', 'c') exe = executable('prog', 'main.cc', 'func.c', c_pch : ['pch/func.h', 'pch/func_pch.c'], cpp_pch : ['pch/main_pch.cc', 'pch/main.h']) meson-0.40.1/test cases/common/15 mixed pch/main.cc0000644000175000017500000000032712650745767023164 0ustar jpakkanejpakkane00000000000000extern "C" int cfunc(); void func() { std::cout << "This is a function that fails to compile if iostream is not included." << std::endl; } int main(int argc, char **argv) { return cfunc(); } meson-0.40.1/test cases/common/22 header in file list/0000755000175000017500000000000013100703043023503 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/22 header in file list/meson.build0000644000175000017500000000014713100702270025650 0ustar jpakkanejpakkane00000000000000project('header in file list', 'c') exe = executable('prog', 'prog.c', 'header.h') test('basic', exe) meson-0.40.1/test cases/common/22 header in file list/prog.c0000644000175000017500000000010313074426732024631 0ustar jpakkanejpakkane00000000000000#include "header.h" int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/22 header in file list/header.h0000644000175000017500000000002213100702050025073 0ustar jpakkanejpakkane00000000000000#include meson-0.40.1/test cases/common/115 spaces backslash/0000755000175000017500000000000013100703042023304 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/115 spaces backslash/comparer-end.c0000644000175000017500000000061112747162664026053 0ustar jpakkanejpakkane00000000000000#include "comparer.h" #ifndef COMPARER_INCLUDED #error "comparer.h not included" #endif #define COMPARE_WITH "foo\\bar\\" /* This is `foo\bar\` */ int main (int argc, char **argv) { if (strcmp (DEF_WITH_BACKSLASH, COMPARE_WITH)) { printf ("Arg string is quoted incorrectly: %s vs %s\n", DEF_WITH_BACKSLASH, COMPARE_WITH); return 1; } return 0; } meson-0.40.1/test cases/common/115 spaces backslash/asm output/0000755000175000017500000000000013100703042025405 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/115 spaces backslash/asm output/meson.build0000644000175000017500000000011412747162664027574 0ustar jpakkanejpakkane00000000000000configure_file(output : 'blank.txt', configuration : configuration_data()) meson-0.40.1/test cases/common/115 spaces backslash/meson.build0000644000175000017500000000246513100702355025463 0ustar jpakkanejpakkane00000000000000project('comparer', 'c') # Added manually as a c_arg to test handling of include paths with backslashes # and spaces. This is especially useful on Windows in vcxproj files since it # stores include directories in a separate element that has its own # context-specific escaping/quoting. include_dir = meson.current_source_dir() + '/include' default_c_args = ['-I' + include_dir] if meson.get_compiler('c').get_id() == 'msvc' default_c_args += ['/Faasm output\\'] # Hack to create the 'asm output' directory in the builddir subdir('asm output') endif # Path can contain \. Here we're sending `"foo\bar"`. test('backslash quoting', executable('comparer', 'comparer.c', c_args : default_c_args + ['-DDEF_WITH_BACKSLASH="foo\\bar"'])) # Path can end in \ without any special quoting. Here we send `"foo\bar\"`. test('backslash end quoting', executable('comparer-end', 'comparer-end.c', c_args : default_c_args + ['-DDEF_WITH_BACKSLASH="foo\\bar\\"'])) # Path can (really) end in \ if we're not passing a string literal without any # special quoting. Here we're sending `foo\bar\`. test('backslash end quoting when not a string literal', executable('comparer-end-notstring', 'comparer-end-notstring.c', c_args : default_c_args + ['-DDEF_WITH_BACKSLASH=foo\\bar\\'])) meson-0.40.1/test cases/common/115 spaces backslash/comparer.c0000644000175000017500000000063212747162664025312 0ustar jpakkanejpakkane00000000000000#include "comparer.h" #ifndef COMPARER_INCLUDED #error "comparer.h not included" #endif #define COMPARE_WITH "foo\\bar" /* This is the literal `foo\bar` */ int main (int argc, char **argv) { if (strcmp (DEF_WITH_BACKSLASH, COMPARE_WITH)) { printf ("Arg string is quoted incorrectly: %s instead of %s\n", DEF_WITH_BACKSLASH, COMPARE_WITH); return 1; } return 0; } meson-0.40.1/test cases/common/115 spaces backslash/include/0000755000175000017500000000000013100703042024727 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/115 spaces backslash/include/comparer.h0000644000175000017500000000010212747162664026732 0ustar jpakkanejpakkane00000000000000#include #include #define COMPARER_INCLUDED meson-0.40.1/test cases/common/115 spaces backslash/comparer-end-notstring.c0000644000175000017500000000102112747162664030074 0ustar jpakkanejpakkane00000000000000#include "comparer.h" #ifndef COMPARER_INCLUDED #error "comparer.h not included" #endif /* This converts foo\\\\bar\\\\ to "foo\\bar\\" (string literal) */ #define Q(x) #x #define QUOTE(x) Q(x) #define COMPARE_WITH "foo\\bar\\" /* This is the literal `foo\bar\` */ int main(int argc, char **argv) { if(strcmp(QUOTE(DEF_WITH_BACKSLASH), COMPARE_WITH)) { printf("Arg string is quoted incorrectly: %s instead of %s\n", QUOTE(DEF_WITH_BACKSLASH), COMPARE_WITH); return 1; } return 0; } meson-0.40.1/test cases/common/5 linkstatic/0000755000175000017500000000000013100703043022116 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/5 linkstatic/main.c0000644000175000017500000000010312650745767023234 0ustar jpakkanejpakkane00000000000000int func(); int main(int argc, char **arg) { return func(); } meson-0.40.1/test cases/common/5 linkstatic/libfile4.c0000644000175000017500000000003613012152443023757 0ustar jpakkanejpakkane00000000000000int func4() { return 4; } meson-0.40.1/test cases/common/5 linkstatic/meson.build0000644000175000017500000000035213100702257024266 0ustar jpakkanejpakkane00000000000000project('static library linking test', 'c') lib = build_target('mylib', 'libfile.c', 'libfile2.c', 'libfile3.c', 'libfile4.c', target_type : 'static_library') exe = executable('prog', 'main.c', link_with : lib) test('runtest', exe) meson-0.40.1/test cases/common/5 linkstatic/libfile.c0000644000175000017500000000003512650745767023722 0ustar jpakkanejpakkane00000000000000int func() { return 0; } meson-0.40.1/test cases/common/5 linkstatic/libfile3.c0000644000175000017500000000003613012152443023756 0ustar jpakkanejpakkane00000000000000int func3() { return 3; } meson-0.40.1/test cases/common/5 linkstatic/libfile2.c0000644000175000017500000000003613012152443023755 0ustar jpakkanejpakkane00000000000000int func2() { return 2; } meson-0.40.1/test cases/common/31 find program/0000755000175000017500000000000013100703043022400 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/31 find program/source.in0000644000175000017500000000006012650745767024260 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/31 find program/meson.build0000644000175000017500000000112413100702275024546 0ustar jpakkanejpakkane00000000000000project('find program', 'c') if build_machine.system() == 'windows' # Things Windows does not provide: # - an executable to copy files without prompting # - working command line quoting # - anything that you might actually need # Because of these reasons we only check that # the program can be found. cp = find_program('xcopy') else cp = find_program('donotfindme', 'cp') gen = generator(cp, \ output : '@BASENAME@.c', \ arguments : ['@INPUT@', '@OUTPUT@']) generated = gen.process('source.in') e = executable('prog', generated) test('external exe', e) endif meson-0.40.1/test cases/common/108 postconf with args/0000755000175000017500000000000013100703042023620 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/108 postconf with args/postconf.py0000644000175000017500000000066313057037314026047 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys, os template = '''#pragma once #define THE_NUMBER {} #define THE_ARG1 {} #define THE_ARG2 {} ''' input_file = os.path.join(os.environ['MESON_SOURCE_ROOT'], 'raw.dat') output_file = os.path.join(os.environ['MESON_BUILD_ROOT'], 'generated.h') with open(input_file) as f: data = f.readline().strip() with open(output_file, 'w') as f: f.write(template.format(data, sys.argv[1], sys.argv[2])) meson-0.40.1/test cases/common/108 postconf with args/meson.build0000644000175000017500000000020113100702350025754 0ustar jpakkanejpakkane00000000000000project('postconf script', 'c') meson.add_postconf_script('postconf.py', '5', '33') test('post', executable('prog', 'prog.c')) meson-0.40.1/test cases/common/108 postconf with args/prog.c0000644000175000017500000000017212665647635024771 0ustar jpakkanejpakkane00000000000000#include"generated.h" int main(int argc, char **argv) { return THE_NUMBER != 9 || THE_ARG1 != 5 || THE_ARG2 != 33; } meson-0.40.1/test cases/common/108 postconf with args/raw.dat0000644000175000017500000000000212665647635025131 0ustar jpakkanejpakkane000000000000009 meson-0.40.1/test cases/common/42 string operations/0000755000175000017500000000000013100703043023504 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/42 string operations/meson.build0000644000175000017500000000515013100702302025644 0ustar jpakkanejpakkane00000000000000project('string formatting', 'c') templ = '@0@bar@1@' assert(templ.format('foo', 'baz') == 'foobarbaz', 'Basic string formatting is broken.') assert('@0@'.format(1) == '1', 'String number formatting is broken.') assert('@0@'.format(true) == 'true', 'String boolean formatting is broken.') templ2 = '@0@' subs2 = '42' assert(templ2.format(subs2) == '42', 'String formatting with variables is broken.') long = 'abcde' prefix = 'abc' suffix = 'cde' assert(long.startswith(prefix), 'Prefix.') assert(not long.startswith(suffix), 'Not prefix.') assert(long.endswith(suffix), 'Suffix.') assert(not long.endswith(prefix), 'Not suffix.') assert(long.contains(prefix), 'Does not contain prefix') assert(long.contains(suffix), 'Does not contain suffix') assert(long.contains('bcd'), 'Does not contain middle part') assert(not long.contains('dc'), 'Broken contains') assert(long.to_upper() == 'ABCDE', 'Broken to_upper') assert(long.to_upper().to_lower() == long, 'Broken to_lower') assert('struct stat.st_foo'.underscorify() == 'struct_stat_st_foo', 'Broken underscorify') assert('#include '.underscorify() == '_include__foo_bar_h_', 'Broken underscorify') # case should not change, space should be replaced, numbers are ok too assert('Do SomeThing 09'.underscorify() == 'Do_SomeThing_09', 'Broken underscorify') assert('3'.to_int() == 3, 'String int conversion does not work.') assert(true.to_string() == 'true', 'bool string conversion failed') assert(false.to_string() == 'false', 'bool string conversion failed') assert(true.to_string('yes', 'no') == 'yes', 'bool string conversion with args failed') assert(false.to_string('yes', 'no') == 'no', 'bool string conversion with args failed') assert('@0@'.format(true) == 'true', 'bool string formatting failed') assert(' '.join(['a', 'b', 'c']) == 'a b c', 'join() array broken') assert(''.join(['a', 'b', 'c']) == 'abc', 'empty join() broken') assert(' '.join(['a']) == 'a', 'single join broken') version_number = '1.2.8' assert(version_number.version_compare('>=1.2.8'), 'Version_compare gt broken') assert(not version_number.version_compare('>1.2.8'), 'Version_compare greater broken') assert(not version_number.version_compare('<1.2.8'), 'Version_compare less broken') assert(version_number.version_compare('<=1.2.8'), 'Version_compare le broken') assert(version_number.version_compare('==1.2.8'), 'Version_compare eq broken') assert(not version_number.version_compare('!=1.2.8'), 'Version_compare neq broken') assert(version_number.version_compare('<2.0'), 'Version_compare major less broken') assert(version_number.version_compare('>0.9'), 'Version_compare major greater broken') meson-0.40.1/test cases/common/8 install/0000755000175000017500000000000013100703043021422 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/8 install/installed_files.txt0000644000175000017500000000004712747162664025355 0ustar jpakkanejpakkane00000000000000usr/bin/prog?exe usr/libtest/libstat.a meson-0.40.1/test cases/common/8 install/meson.build0000644000175000017500000000026013100702261023563 0ustar jpakkanejpakkane00000000000000project('install test', 'c', default_options : ['libdir=libtest']) stlib = static_library('stat', 'stat.c', install : true) exe = executable('prog', 'prog.c', install : true) meson-0.40.1/test cases/common/8 install/stat.c0000644000175000017500000000003312650745767022571 0ustar jpakkanejpakkane00000000000000int func() { return 933; } meson-0.40.1/test cases/common/8 install/prog.c0000644000175000017500000000006212650745767022567 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/96 default library/0000755000175000017500000000000013100703044023115 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/96 default library/ef.h0000644000175000017500000000062612650745767023717 0ustar jpakkanejpakkane00000000000000#pragma once #if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif class Ef { private: int x; public: DLL_PUBLIC Ef(); int DLL_PUBLIC get_x() const; }; meson-0.40.1/test cases/common/96 default library/meson.build0000644000175000017500000000022113100702340025250 0ustar jpakkanejpakkane00000000000000project('default library', 'cpp') flib = library('ef', 'ef.cpp') exe = executable('eftest', 'eftest.cpp', link_with : flib) test('eftest', exe) meson-0.40.1/test cases/common/96 default library/ef.cpp0000644000175000017500000000014412650745767024245 0ustar jpakkanejpakkane00000000000000#include"ef.h" DLL_PUBLIC Ef::Ef() : x(99) { } int DLL_PUBLIC Ef::get_x() const { return x; } meson-0.40.1/test cases/common/96 default library/eftest.cpp0000644000175000017500000000036512650745767025152 0ustar jpakkanejpakkane00000000000000#include"ef.h" #include int main(int, char **) { Ef var; if(var.get_x() == 99) { std::cout << "All is fine.\n"; return 0; } else { std::cout << "Something went wrong.\n"; return 1; } } meson-0.40.1/test cases/common/20 array/0000755000175000017500000000000013100703043021144 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/20 array/func.c0000644000175000017500000000003112650745767022271 0ustar jpakkanejpakkane00000000000000int func() { return 0; } meson-0.40.1/test cases/common/20 array/meson.build0000644000175000017500000000017313100702267023316 0ustar jpakkanejpakkane00000000000000project('array test', 'c') arr = [ 'func.c', 'prog.c'] exe = executable('prog', sources : arr) test('arr test', exe) meson-0.40.1/test cases/common/20 array/prog.c0000644000175000017500000000010712650745767022311 0ustar jpakkanejpakkane00000000000000extern int func(); int main(int argc, char **argv) { return func(); } meson-0.40.1/test cases/common/109 testframework options/0000755000175000017500000000000013100703042024466 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/109 testframework options/test_args.txt0000644000175000017500000000035112672617123027242 0ustar jpakkanejpakkane00000000000000# This file is not read by meson itself, but by the test framework. # It is not possible to pass arguments to meson from a file. ['--werror', '-D', 'testoption=A string with spaces', '-D', 'other_one=true', \ '-D', 'combo_opt=one'] meson-0.40.1/test cases/common/109 testframework options/meson.build0000644000175000017500000000044113100702350026630 0ustar jpakkanejpakkane00000000000000project('options', 'c') assert(get_option('testoption') == 'A string with spaces', 'Incorrect value for testoption option.') assert(get_option('other_one') == true, 'Incorrect value for other_one option.') assert(get_option('combo_opt') == 'one', 'Incorrect value for combo_opt option.') meson-0.40.1/test cases/common/109 testframework options/meson_options.txt0000644000175000017500000000036012672617123030143 0ustar jpakkanejpakkane00000000000000option('testoption', type : 'string', value : 'optval', description : 'An option to do something') option('other_one', type : 'boolean', value : false) option('combo_opt', type : 'combo', choices : ['one', 'two', 'combo'], value : 'combo') meson-0.40.1/test cases/common/77 external test program/0000755000175000017500000000000013100703043024254 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/77 external test program/meson.build0000644000175000017500000000014213100702325026415 0ustar jpakkanejpakkane00000000000000project('test is external', 'c') test('external', find_program('mytest.py'), args : ['correct']) meson-0.40.1/test cases/common/77 external test program/mytest.py0000755000175000017500000000032313057037314026170 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 from __future__ import print_function import sys if sys.argv[1] == 'correct': print('Argument is correct.') sys.exit(0) print('Argument is incorrect:', sys.argv[1]) sys.exit(1) meson-0.40.1/test cases/common/24 target arg/0000755000175000017500000000000013100703043022052 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/24 target arg/func.c0000644000175000017500000000021212650745767023200 0ustar jpakkanejpakkane00000000000000#ifndef CTHING #error "Local argument not set" #endif #ifdef CPPTHING #error "Wrong local argument set" #endif int func() { return 0; } meson-0.40.1/test cases/common/24 target arg/prog2.cc0000644000175000017500000000033312672617123023431 0ustar jpakkanejpakkane00000000000000#ifdef CTHING #error "Local C argument set in wrong target" #endif #ifdef CPPTHING #error "Local CPP argument set in wrong target" #endif extern "C" int func(); int main(int argc, char **argv) { return func(); } meson-0.40.1/test cases/common/24 target arg/meson.build0000644000175000017500000000034513100702271024220 0ustar jpakkanejpakkane00000000000000project('local arg test', 'cpp', 'c') exe1 = executable('prog', 'prog.cc', 'func.c', \ c_args : '-DCTHING', \ cpp_args : '-DCPPTHING') exe2 = executable('prog2', 'prog2.cc', 'func2.c') test('prog1', exe1) test('prog2', exe2) meson-0.40.1/test cases/common/24 target arg/prog.cc0000644000175000017500000000030012650745767023355 0ustar jpakkanejpakkane00000000000000#ifdef CTHING #error "Wrong local argument set" #endif #ifndef CPPTHING #error "Local argument not set" #endif extern "C" int func(); int main(int argc, char **argv) { return func(); } meson-0.40.1/test cases/common/24 target arg/func2.c0000644000175000017500000000024512672617123023254 0ustar jpakkanejpakkane00000000000000#ifdef CTHING #error "Local C argument set in wrong target" #endif #ifdef CPPTHING #error "Local CPP argument set in wrong target" #endif int func() { return 0; } meson-0.40.1/test cases/common/25 object extraction/0000755000175000017500000000000013100703043023442 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/25 object extraction/main.c0000644000175000017500000000012212650745767024561 0ustar jpakkanejpakkane00000000000000int func(); int main(int argc, char **argv) { return func() == 42 ? 0 : 1; } meson-0.40.1/test cases/common/25 object extraction/lib.c0000644000175000017500000000003612650745767024407 0ustar jpakkanejpakkane00000000000000int func() { return 42; } meson-0.40.1/test cases/common/25 object extraction/meson.build0000644000175000017500000000075713100702272025620 0ustar jpakkanejpakkane00000000000000project('object extraction', 'c') if meson.is_unity() message('Skipping extraction test because this is a Unity build.') else lib1 = shared_library('somelib', 'src/lib.c') lib2 = shared_library('somelib2', 'lib.c', 'lib2.c') obj1 = lib1.extract_objects('src/lib.c') obj2 = lib2.extract_objects(['lib.c']) e1 = executable('main1', 'main.c', objects : obj1) e2 = executable('main2', 'main.c', objects : obj2) test('extraction test 1', e1) test('extraction test 2', e2) endif meson-0.40.1/test cases/common/25 object extraction/lib2.c0000644000175000017500000000003613016624375024455 0ustar jpakkanejpakkane00000000000000int retval() { return 43; } meson-0.40.1/test cases/common/25 object extraction/src/0000755000175000017500000000000013100703043024231 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/25 object extraction/src/lib.c0000644000175000017500000000003612650745767025176 0ustar jpakkanejpakkane00000000000000int func() { return 42; } meson-0.40.1/test cases/common/104 stringdef/0000755000175000017500000000000013100703042022075 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/104 stringdef/stringdef.c0000644000175000017500000000027412650745767024266 0ustar jpakkanejpakkane00000000000000#include #include int main(int argc, char **argv) { if(strcmp(FOO, "bar")) { printf("FOO is misquoted: %s\n", FOO); return 1; } return 0; } meson-0.40.1/test cases/common/104 stringdef/meson.build0000644000175000017500000000015513100702346024246 0ustar jpakkanejpakkane00000000000000project('stringdef', 'c') test('stringdef', executable('stringdef', 'stringdef.c', c_args : '-DFOO="bar"')) meson-0.40.1/test cases/common/52 custom install dirs/0000755000175000017500000000000013100703043023716 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/52 custom install dirs/prog.10000644000175000017500000000001512650745767024777 0ustar jpakkanejpakkane00000000000000Man up, you. meson-0.40.1/test cases/common/52 custom install dirs/installed_files.txt0000644000175000017500000000036212763077471027650 0ustar jpakkanejpakkane00000000000000usr/dib/dab/dub/prog?exe usr/dib/dab/dub2/prog2?exe usr/some/dir/sample.h usr/some/dir2/sample.h usr/woman/prog.1.gz usr/woman2/prog.1.gz usr/meow/datafile.cat usr/meow2/datafile.cat usr/woof/subdir/datafile.dog usr/woof2/subdir/datafile.dog meson-0.40.1/test cases/common/52 custom install dirs/meson.build0000644000175000017500000000130013100702310026046 0ustar jpakkanejpakkane00000000000000project('custom install dirs', 'c') executable('prog', 'prog.c', install : true, install_dir : 'dib/dab/dub') executable('prog2', 'prog.c', install : true, install_dir : get_option('prefix') + '/dib/dab/dub2') install_headers('sample.h', install_dir : 'some/dir') install_headers('sample.h', install_dir : get_option('prefix') + '/some/dir2') install_man('prog.1', install_dir : 'woman') install_man('prog.1', install_dir : get_option('prefix') + '/woman2') install_data('datafile.cat', install_dir : 'meow') install_data('datafile.cat', install_dir : get_option('prefix') + '/meow2') install_subdir('subdir', install_dir : 'woof') install_subdir('subdir', install_dir : get_option('prefix') + '/woof2') meson-0.40.1/test cases/common/52 custom install dirs/subdir/0000755000175000017500000000000013100703043025206 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/52 custom install dirs/subdir/datafile.dog0000644000175000017500000000003412763077471027476 0ustar jpakkanejpakkane00000000000000Installed dog is installed. meson-0.40.1/test cases/common/52 custom install dirs/datafile.cat0000644000175000017500000000003412650745767026211 0ustar jpakkanejpakkane00000000000000Installed cat is installed. meson-0.40.1/test cases/common/52 custom install dirs/prog.c0000644000175000017500000000006112650745767025062 0ustar jpakkanejpakkane00000000000000int main(int argc, char **arv) { return 0; } meson-0.40.1/test cases/common/52 custom install dirs/sample.h0000644000175000017500000000007412650745767025405 0ustar jpakkanejpakkane00000000000000#ifndef SAMPLE_H #define SAMPLE_H int wackiness(); #endif meson-0.40.1/test cases/common/118 allgenerate/0000755000175000017500000000000013100703042022400 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/118 allgenerate/meson.build0000644000175000017500000000072113100702357024552 0ustar jpakkanejpakkane00000000000000# Must have two languages here to exercise linker language # selection bug project('all sources generated', 'c', 'cpp') comp = find_program('converter.py') g = generator(comp, output : '@BASENAME@', arguments : ['@INPUT@', '@OUTPUT@']) c = g.process('foobar.cpp.in') prog = executable('genexe', c) c2 = custom_target('c2gen', output : '@BASENAME@', input : 'foobar.cpp.in', command : [comp, '@INPUT@', '@OUTPUT@']) prog2 = executable('genexe2', c2) meson-0.40.1/test cases/common/118 allgenerate/converter.py0000755000175000017500000000017013057037314024777 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys ifile = sys.argv[1] ofile = sys.argv[2] open(ofile, 'w').write(open(ifile).read()) meson-0.40.1/test cases/common/118 allgenerate/foobar.cpp.in0000644000175000017500000000014212772547213025002 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("I am a program.\n"); return 0; } meson-0.40.1/test cases/common/87 declare dep/0000755000175000017500000000000013100703044022174 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/87 declare dep/main.c0000644000175000017500000000053312665647612023314 0ustar jpakkanejpakkane00000000000000#include #include #ifndef USING_ENT #error "Entity use flag not used for compilation." #endif int main(int argc, char **argv) { if(entity_func1() != 5) { printf("Error in func1.\n"); return 1; } if(entity_func2() != 9) { printf("Error in func2.\n"); return 2; } return 0; } meson-0.40.1/test cases/common/87 declare dep/meson.build0000644000175000017500000000130113100702333024331 0ustar jpakkanejpakkane00000000000000project('declare dependency', 'c') subdir('entity') exe = executable('dep_user', 'main.c', dependencies : entity_dep) test('dep', exe) # just to make sure [] works as a no-op dep here executable('dummy', 'main.c', dependencies : [entity_dep, []]) # simple case declare_dependency(dependencies : entity_dep) # nested deps should be flattened declare_dependency(dependencies : [entity_dep]) declare_dependency(dependencies : [[entity_dep]]) # check that [] properly works as a no-op dep in declare_dependency() too declare_dependency(dependencies : []) declare_dependency(dependencies : [[]]) declare_dependency(dependencies : [entity_dep, []]) declare_dependency(dependencies : [[], entity_dep]) meson-0.40.1/test cases/common/87 declare dep/entity/0000755000175000017500000000000013100703044023510 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/87 declare dep/entity/meson.build0000644000175000017500000000062412723634706025676 0ustar jpakkanejpakkane00000000000000entity_lib = static_library('entity', 'entity1.c') entity_dep = declare_dependency(link_with : entity_lib, include_directories : include_directories('.'), sources : 'entity2.c', compile_args : ['-DUSING_ENT=1'], version : '1.2.3', link_args : []) # No simple way of testing linker flags :(. assert(entity_dep.version().version_compare('==1.2.3'), 'Declare_dep has incorrect version string.') meson-0.40.1/test cases/common/87 declare dep/entity/entity1.c0000644000175000017500000000021312665647612025274 0ustar jpakkanejpakkane00000000000000#include"entity.h" #ifdef USING_ENT #error "Entity use flag leaked into entity compilation." #endif int entity_func1() { return 5; } meson-0.40.1/test cases/common/87 declare dep/entity/entity2.c0000644000175000017500000000007112650745767025303 0ustar jpakkanejpakkane00000000000000#include int entity_func2() { return 9; } meson-0.40.1/test cases/common/87 declare dep/entity/entity.h0000644000175000017500000000006612650745767025232 0ustar jpakkanejpakkane00000000000000#pragma once int entity_func1(); int entity_func2(); meson-0.40.1/test cases/common/85 internal dependency/0000755000175000017500000000000013100703044023755 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/85 internal dependency/proj1/0000755000175000017500000000000013100703044025010 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/85 internal dependency/proj1/proj1f3.c0000644000175000017500000000013512650745767026472 0ustar jpakkanejpakkane00000000000000#include #include void proj1_func3() { printf("In proj1_func3.\n"); } meson-0.40.1/test cases/common/85 internal dependency/proj1/meson.build0000644000175000017500000000043712650745767027211 0ustar jpakkanejpakkane00000000000000incdirs = include_directories('include') p1lib = static_library('proj1', 'proj1f1.c', include_directories : incdirs ) indirect_source = files('proj1f2.c') proj1_dep = declare_dependency(include_directories : incdirs, link_with : p1lib, sources : ['proj1f3.c', indirect_source]) meson-0.40.1/test cases/common/85 internal dependency/proj1/include/0000755000175000017500000000000013100703044026433 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/85 internal dependency/proj1/include/proj1.h0000644000175000017500000000011212650745767027664 0ustar jpakkanejpakkane00000000000000#pragma once void proj1_func1(); void proj1_func2(); void proj1_func3(); meson-0.40.1/test cases/common/85 internal dependency/proj1/proj1f2.c0000644000175000017500000000013512650745767026471 0ustar jpakkanejpakkane00000000000000#include #include void proj1_func2() { printf("In proj1_func2.\n"); } meson-0.40.1/test cases/common/85 internal dependency/proj1/proj1f1.c0000644000175000017500000000013512650745767026470 0ustar jpakkanejpakkane00000000000000#include #include void proj1_func1() { printf("In proj1_func1.\n"); } meson-0.40.1/test cases/common/85 internal dependency/meson.build0000644000175000017500000000010313100702332026110 0ustar jpakkanejpakkane00000000000000project('internal dependency', 'c') subdir('proj1') subdir('src') meson-0.40.1/test cases/common/85 internal dependency/src/0000755000175000017500000000000013100703044024544 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/85 internal dependency/src/main.c0000644000175000017500000000027312650745767025671 0ustar jpakkanejpakkane00000000000000#include #include int main(int argc, char **argv) { printf("Now calling into library.\n"); proj1_func1(); proj1_func2(); proj1_func3(); return 0; } meson-0.40.1/test cases/common/85 internal dependency/src/meson.build0000644000175000017500000000012712650745767026741 0ustar jpakkanejpakkane00000000000000exe = executable('projtest', 'main.c', dependencies : proj1_dep) test('projtest', exe) meson-0.40.1/test cases/common/68 number arithmetic/0000755000175000017500000000000013100703043023444 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/68 number arithmetic/meson.build0000644000175000017500000000272313100702320025607 0ustar jpakkanejpakkane00000000000000project('number arithmetic', 'c') if 6 + 4 != 10 error('Number addition is broken') endif if 6 - 4 != 2 error('Number subtraction is broken') endif if 6 * 4 != 24 error('Number multiplication is broken') endif if 16 / 4 != 4 error('Number division is broken') endif #if (1 / 3) * 3 != 1 # error('Float interconversion broken') #endif if (5 / 3) * 3 != 3 error('Integer division is broken') endif assert((5 % 2) == 1, 'Integer modulo (odd) is broken') assert((4 % 2) == 0, 'Integer modulo (even) is broken') if 2 * 1 % 2 != 0 error('Modulo precendence with multiplication is broken') endif if 2 + 1 % 2 != 3 error('Modulo precendence with addition is broken') endif if 9 / 9 % 2 != 1 error('Modulo precendence with division is broken') endif if 9 - 9 % 2 != 8 error('Modulo precendence with subtraction is broken') endif assert(2.is_even(), 'int is_even() broken for even value') assert(not(2.is_odd()), 'int is_odd() broken for even value') assert(not(3.is_even()), 'int is_even() broken for odd value') assert(3.is_odd(), 'int is_odd() broken for odd value') assert(3 < 4, 'Lt broken') assert(not(4 < 3), 'Lt broken') assert(3 <= 4, 'Lte broken') assert(not(4 <= 3), 'Lte broken') assert(3 <= 3, 'Lte broken') assert(4 > 3, 'Gt broken') assert(not(3 > 4), 'Gt broken') assert(4 >= 3, 'Gte broken') assert(not(3 >= 4), 'Gte broken') assert(3 >= 3, 'Gte broken') assert(true.to_int() == 1,'bool to_int() broken') assert(false.to_int() == 0,'bool to_int() broken') meson-0.40.1/test cases/common/1 trivial/0000755000175000017500000000000013100703042021416 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/1 trivial/meson.build0000644000175000017500000000070713100702255023571 0ustar jpakkanejpakkane00000000000000# Comment on the first line project('trivial test', # Comment inside a function call + array for language list ['c'], meson_version : '>=0.27.0') #this is a comment sources = 'trivial.c' if meson.get_compiler('c').get_id() == 'intel' # Error out if the -std=xxx option is incorrect add_project_arguments('-diag-error', '10159', language : 'c') endif exe = executable('trivialprog', sources : sources) test('runtest', exe) # This is a comment meson-0.40.1/test cases/common/1 trivial/trivial.c0000644000175000017500000000015712650745767023274 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("Trivial test is working.\n"); return 0; } meson-0.40.1/test cases/common/53 subproject subproject/0000755000175000017500000000000013100703043024355 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/53 subproject subproject/subprojects/0000755000175000017500000000000013100703042026717 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/53 subproject subproject/subprojects/a/0000755000175000017500000000000013100703043027140 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/53 subproject subproject/subprojects/a/meson.build0000644000175000017500000000015012650745767031332 0ustar jpakkanejpakkane00000000000000project('a', 'c') b = subproject('b') l = shared_library('a', 'a.c', link_with : b.get_variable('lb')) meson-0.40.1/test cases/common/53 subproject subproject/subprojects/a/a.c0000644000175000017500000000053612650745767027564 0ustar jpakkanejpakkane00000000000000int func2(); #if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int DLL_PUBLIC func() { return func2(); } meson-0.40.1/test cases/common/53 subproject subproject/subprojects/b/0000755000175000017500000000000013100703043027141 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/53 subproject subproject/subprojects/b/meson.build0000644000175000017500000000006312650745767031336 0ustar jpakkanejpakkane00000000000000project('b', 'c') lb = shared_library('b', 'b.c') meson-0.40.1/test cases/common/53 subproject subproject/subprojects/b/b.c0000644000175000017500000000051712650745767027565 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int DLL_PUBLIC func2() { return 42; } meson-0.40.1/test cases/common/53 subproject subproject/meson.build0000644000175000017500000000021613100702311026513 0ustar jpakkanejpakkane00000000000000project('sub sub', 'c') a = subproject('a') lib = a.get_variable('l') exe = executable('prog', 'prog.c', link_with : lib) test('basic', exe)meson-0.40.1/test cases/common/53 subproject subproject/prog.c0000644000175000017500000000012212650745767025517 0ustar jpakkanejpakkane00000000000000int func(); int main(int argc, char **argv) { return func() == 42 ? 0 : 1; } meson-0.40.1/test cases/common/36 define10/0000755000175000017500000000000013100703043021430 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/36 define10/config.h.in0000644000175000017500000000004312650745767023504 0ustar jpakkanejpakkane00000000000000#mesondefine ONE #mesondefine ZERO meson-0.40.1/test cases/common/36 define10/meson.build0000644000175000017500000000036613100702277023607 0ustar jpakkanejpakkane00000000000000project('set10test', 'c') conf = configuration_data() conf.set10('ONE', true) conf.set10('ZERO', false) configure_file(input : 'config.h.in', output : 'config.h', configuration : conf) exe = executable('prog', 'prog.c') test('10test', exe) meson-0.40.1/test cases/common/36 define10/prog.c0000644000175000017500000000036612650745767022604 0ustar jpakkanejpakkane00000000000000#include #include"config.h" int main(int argc, char **argv) { if(ONE != 1) { fprintf(stderr, "ONE is not 1.\n"); return 1; } if(ZERO != 0) { fprintf(stderr, "ZERO is not 0.\n"); } return 0; } meson-0.40.1/test cases/common/141 c cpp and asm/0000755000175000017500000000000013100703043022363 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/141 c cpp and asm/main.c0000644000175000017500000000021413070746245023471 0ustar jpakkanejpakkane00000000000000#include int get_retval(void); int main(int argc, char **argv) { printf("C seems to be working.\n"); return get_retval(); } meson-0.40.1/test cases/common/141 c cpp and asm/symbol-underscore.h0000644000175000017500000000017313070746245026232 0ustar jpakkanejpakkane00000000000000#if defined(MESON_TEST__UNDERSCORE_SYMBOL) # define SYMBOL_NAME(name) _##name #else # define SYMBOL_NAME(name) name #endif meson-0.40.1/test cases/common/141 c cpp and asm/main.cpp0000644000175000017500000000030613070746245024033 0ustar jpakkanejpakkane00000000000000#include extern "C" { int get_retval(void); int get_cval(void); } int main(int argc, char **argv) { std::cout << "C++ seems to be working." << std::endl; return get_retval(); } meson-0.40.1/test cases/common/141 c cpp and asm/meson.build0000644000175000017500000000146513100702376024543 0ustar jpakkanejpakkane00000000000000project('c cpp and asm', 'c', 'cpp') cpu = host_machine.cpu_family() cc = meson.get_compiler('c') supported_cpus = ['arm', 'x86', 'x86_64'] if not supported_cpus.contains(cpu) error('MESON_SKIP_TEST unsupported cpu:' + cpu) endif if meson.get_compiler('c').get_id() == 'msvc' error('MESON_SKIP_TEST MSVC can\'t compile assembly') endif if cc.symbols_have_underscore_prefix() add_project_arguments('-DMESON_TEST__UNDERSCORE_SYMBOL', language: 'c') endif test('test-c-asm', executable('c-asm', ['main.c', 'retval-' + cpu + '.S'])) test('test-cpp-asm', executable('cpp-asm', ['main.cpp', 'retval-' + cpu + '.S'])) test('test-c-cpp-asm', executable('c-cpp-asm', ['somelib.c', 'main.cpp', 'retval-' + cpu + '.S'])) test('test-cpp-c-asm', executable('cpp-c-asm', ['main.cpp', 'somelib.c', 'retval-' + cpu + '.S'])) meson-0.40.1/test cases/common/141 c cpp and asm/retval-x86_64.S0000644000175000017500000000016613070746245024764 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" .text .globl SYMBOL_NAME(get_retval) SYMBOL_NAME(get_retval): xorl %eax, %eax retq meson-0.40.1/test cases/common/141 c cpp and asm/retval-arm.S0000644000175000017500000000016713070746245024606 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" .text .globl SYMBOL_NAME(get_retval) SYMBOL_NAME(get_retval): mov r0, #0 mov pc, lr meson-0.40.1/test cases/common/141 c cpp and asm/retval-x86.S0000644000175000017500000000016613070746245024453 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" .text .globl SYMBOL_NAME(get_retval) SYMBOL_NAME(get_retval): xorl %eax, %eax retl meson-0.40.1/test cases/common/141 c cpp and asm/somelib.c0000644000175000017500000000004413070746245024200 0ustar jpakkanejpakkane00000000000000int get_cval (void) { return 0; } meson-0.40.1/test cases/common/62 exe static shared/0000755000175000017500000000000013100703043023314 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/62 exe static shared/stat2.c0000644000175000017500000000004613001212425024514 0ustar jpakkanejpakkane00000000000000int statlibfunc2() { return 18; } meson-0.40.1/test cases/common/62 exe static shared/meson.build0000644000175000017500000000100513100702316025454 0ustar jpakkanejpakkane00000000000000project('statchain', 'c') subdir('subdir') # Test that -fPIC in c_args is also accepted statlib2 = static_library('stat2', 'stat2.c', c_args : '-fPIC', pic : false) # Test that pic is needed for both direct and indirect static library # dependencies of shared libraries (on Linux and BSD) statlib = static_library('stat', 'stat.c', link_with : [shlib, statlib2], pic : true) shlib2 = shared_library('shr2', 'shlib2.c', link_with : statlib) exe = executable('prog', 'prog.c', link_with : shlib2) test('runtest', exe) meson-0.40.1/test cases/common/62 exe static shared/subdir/0000755000175000017500000000000013100703043024604 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/62 exe static shared/subdir/exports.h0000644000175000017500000000046213001212425026462 0ustar jpakkanejpakkane00000000000000#pragma once #if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif meson-0.40.1/test cases/common/62 exe static shared/subdir/meson.build0000644000175000017500000000005212650745767026777 0ustar jpakkanejpakkane00000000000000shlib = shared_library('shar', 'shlib.c') meson-0.40.1/test cases/common/62 exe static shared/subdir/shlib.c0000644000175000017500000000010413001212425026043 0ustar jpakkanejpakkane00000000000000#include "exports.h" int DLL_PUBLIC shlibfunc() { return 42; } meson-0.40.1/test cases/common/62 exe static shared/stat.c0000644000175000017500000000015013012152443024433 0ustar jpakkanejpakkane00000000000000#include "subdir/exports.h" int shlibfunc(); int DLL_PUBLIC statlibfunc() { return shlibfunc(); } meson-0.40.1/test cases/common/62 exe static shared/prog.c0000644000175000017500000000026513001212425024431 0ustar jpakkanejpakkane00000000000000int shlibfunc2(); int statlibfunc(); int main(int argc, char **argv) { if (statlibfunc() != 42) return 1; if (shlibfunc2() != 24) return 1; return 0; } meson-0.40.1/test cases/common/62 exe static shared/shlib2.c0000644000175000017500000000023413001212425024641 0ustar jpakkanejpakkane00000000000000#include "subdir/exports.h" int statlibfunc(void); int statlibfunc2(void); int DLL_PUBLIC shlibfunc2(void) { return statlibfunc() - statlibfunc2(); } meson-0.40.1/test cases/common/49 subproject/0000755000175000017500000000000013100703043022221 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/49 subproject/subprojects/0000755000175000017500000000000013100703042024563 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/49 subproject/subprojects/sublib/0000755000175000017500000000000013100703043026044 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/49 subproject/subprojects/sublib/simpletest.c0000644000175000017500000000013512650745767030434 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { return subfunc() == 42 ? 0 : 1; } meson-0.40.1/test cases/common/49 subproject/subprojects/sublib/meson.build0000644000175000017500000000116012742140120030206 0ustar jpakkanejpakkane00000000000000project('subproject', 'c', version : '1.0.0', license : ['sublicense1', 'sublicense2']) if not meson.is_subproject() error('Claimed to be master project even though we are a subproject.') endif assert(meson.project_name() == 'subproject', 'Incorrect subproject name') if meson.project_version() != '1.0.0' error('Incorrect version string in subproject.') endif i = include_directories('include') l = shared_library('sublib', 'sublib.c', include_directories : i, install : false, c_args : '-DBUILDING_SUB=2') t = executable('simpletest', 'simpletest.c', include_directories : i, link_with : l) test('plain', t) meson-0.40.1/test cases/common/49 subproject/subprojects/sublib/sublib.c0000644000175000017500000000010112650745767027514 0ustar jpakkanejpakkane00000000000000#include int DLL_PUBLIC subfunc() { return 42; } meson-0.40.1/test cases/common/49 subproject/subprojects/sublib/include/0000755000175000017500000000000013100703043027467 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/49 subproject/subprojects/sublib/include/subdefs.h0000644000175000017500000000067712650745767031341 0ustar jpakkanejpakkane00000000000000#ifndef SUBDEFS_H_ #define SUBDEFS_H_ #if defined _WIN32 || defined __CYGWIN__ #if defined BUILDING_SUB #define DLL_PUBLIC __declspec(dllexport) #else #define DLL_PUBLIC __declspec(dllimport) #endif #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int DLL_PUBLIC subfunc(); #endif meson-0.40.1/test cases/common/49 subproject/installed_files.txt0000644000175000017500000000005712742140120026127 0ustar jpakkanejpakkane00000000000000usr/bin/user?exe usr/share/sublib/sublib.depmf meson-0.40.1/test cases/common/49 subproject/meson.build0000644000175000017500000000123213100702307024363 0ustar jpakkanejpakkane00000000000000project('subproj user', 'c', version : '2.3.4', license : 'mylicense') assert(meson.project_name() == 'subproj user', 'Incorrect project name') sub = subproject('sublib', version : '1.0.0') if meson.project_version() != '2.3.4' error('Incorrect master project version string:' + meson.project_version()) endif if meson.is_subproject() error('Claimed to be a subproject even though we are the master project.') endif inc = sub.get_variable('i') lib = sub.get_variable('l') e = executable('user', 'user.c', include_directories : inc, link_with : lib, install : true) test('subdirtest', e) meson.install_dependency_manifest('share/sublib/sublib.depmf') meson-0.40.1/test cases/common/49 subproject/user.c0000644000175000017500000000046712650745767023406 0ustar jpakkanejpakkane00000000000000#include #include int main(int argc, char **argv) { int res; printf("Calling into sublib now.\n"); res = subfunc(); if(res == 42) { printf("Everything is fine.\n"); return 0; } else { printf("Something went wrong.\n"); return 1; } } meson-0.40.1/test cases/common/138 include order/0000755000175000017500000000000013100703043022637 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/138 include order/meson.build0000644000175000017500000000214713100702373025012 0ustar jpakkanejpakkane00000000000000project('include order', 'c') # Test that the order of priority of include paths (from first to last) is: # # 1. Target's current build directory # 2. Target's current source directory # 3. Include paths added with the `c_args:` kwarg # 4. Include paths added with the `include_directories`: kwarg # Within this, the build dir takes precedence over the source dir # 5. Include paths added via `include_directories:` of internal deps # Within this, the build dir takes precedence over the source dir # Defines an internal dep subdir('sub1') # Defines a per-target include path subdir('sub2') # Directory for `c_args:` include path subdir('sub3') # The directory where the target resides subdir('sub4') # Test that the order in which internal dependencies are specified is # preserved. This is needed especially when subprojects get involved and # multiple build-root config.h files exist, and we must be sure that the # correct one is found: https://github.com/mesonbuild/meson/issues/1495 f = executable('somefxe', 'sub4/main.c', dependencies : [correctinc, dep, wronginc]) test('eh', e) test('oh', f) meson-0.40.1/test cases/common/138 include order/sub3/0000755000175000017500000000000013100703043023513 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/138 include order/sub3/meson.build0000644000175000017500000000004213043224360025657 0ustar jpakkanejpakkane00000000000000sub3 = meson.current_source_dir() meson-0.40.1/test cases/common/138 include order/sub3/main.h0000644000175000017500000000003613043224360024615 0ustar jpakkanejpakkane00000000000000#error "sub3/main.h included" meson-0.40.1/test cases/common/138 include order/sub4/0000755000175000017500000000000013100703043023514 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/138 include order/sub4/main.c0000644000175000017500000000027013043224360024611 0ustar jpakkanejpakkane00000000000000/* Use the <> include notation to force searching in include directories */ #include int main(int argc, char *argv[]) { if (somefunc() == 1984) return 0; return 1; } meson-0.40.1/test cases/common/138 include order/sub4/meson.build0000644000175000017500000000034713066536047025705 0ustar jpakkanejpakkane00000000000000e = executable('someexe', 'main.c', c_args : ['-I' + sub3], include_directories : j, dependencies : dep) correctinc = declare_dependency(include_directories : include_directories('.')) meson-0.40.1/test cases/common/138 include order/sub4/main.h0000644000175000017500000000004013043224360024611 0ustar jpakkanejpakkane00000000000000#pragma once #include "some.h" meson-0.40.1/test cases/common/138 include order/sub2/0000755000175000017500000000000013100703043023512 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/138 include order/sub2/meson.build0000644000175000017500000000012413066536047025674 0ustar jpakkanejpakkane00000000000000j = include_directories('.') wronginc = declare_dependency(include_directories : j) meson-0.40.1/test cases/common/138 include order/sub2/main.h0000644000175000017500000000003613043224360024614 0ustar jpakkanejpakkane00000000000000#error "sub2/main.h included" meson-0.40.1/test cases/common/138 include order/sub1/0000755000175000017500000000000013100703043023511 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/138 include order/sub1/some.h0000644000175000017500000000024413043224360024633 0ustar jpakkanejpakkane00000000000000#pragma once #if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllimport) #else #define DLL_PUBLIC #endif DLL_PUBLIC int somefunc(void); meson-0.40.1/test cases/common/138 include order/sub1/meson.build0000644000175000017500000000023713043224360025663 0ustar jpakkanejpakkane00000000000000i = include_directories('.') l = shared_library('somelib', 'some.c') dep = declare_dependency(link_with : l, include_directories : i) meson-0.40.1/test cases/common/138 include order/sub1/main.h0000644000175000017500000000003613043224360024613 0ustar jpakkanejpakkane00000000000000#error "sub1/main.h included" meson-0.40.1/test cases/common/138 include order/sub1/some.c0000644000175000017500000000015613043224360024630 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ __declspec(dllexport) #endif int somefunc(void) { return 1984; } meson-0.40.1/test cases/common/7 mixed/0000755000175000017500000000000013100703043021061 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/7 mixed/func.c0000644000175000017500000000006412650745767022214 0ustar jpakkanejpakkane00000000000000int func() { int class = 0; return class; } meson-0.40.1/test cases/common/7 mixed/meson.build0000644000175000017500000000015213100702260023221 0ustar jpakkanejpakkane00000000000000project('mixed C and C++', 'c', 'cpp') exe = executable('prog', 'main.cc', 'func.c') test('mixtest', exe) meson-0.40.1/test cases/common/7 mixed/main.cc0000644000175000017500000000015312650745767022347 0ustar jpakkanejpakkane00000000000000extern "C" int func(); class BreakPlainCCompiler; int main(int argc, char **argv) { return func(); } meson-0.40.1/test cases/common/132 dependency file generation/0000755000175000017500000000000013100703043025244 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/132 dependency file generation/meson.build0000644000175000017500000000070213100702367027415 0ustar jpakkanejpakkane00000000000000project('dep file gen', 'c') cc_id = meson.get_compiler('c').get_id() if cc_id == 'intel' # ICC does not escape spaces in paths in the dependency file, so Ninja # (correctly) thinks that the rule has multiple outputs and errors out: # 'depfile has multiple output paths' error('MESON_SKIP_TEST: Skipping test with Intel compiler because it generates broken dependency files') endif e = executable('main file', 'main .c') test('test it', e) meson-0.40.1/test cases/common/132 dependency file generation/main .c0000644000175000017500000000006113033265323026402 0ustar jpakkanejpakkane00000000000000int main(int argc, char *argv[]) { return 0; } meson-0.40.1/test cases/common/76 configure file in custom target/0000755000175000017500000000000013100703043026053 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/76 configure file in custom target/meson.build0000644000175000017500000000011013100702324030206 0ustar jpakkanejpakkane00000000000000project('conf file in custom target', 'c') subdir('inc') subdir('src') meson-0.40.1/test cases/common/76 configure file in custom target/src/0000755000175000017500000000000013100703043026642 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/76 configure file in custom target/src/mycompiler.py0000644000175000017500000000032213057037314031405 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys with open(sys.argv[1]) as ifile: if ifile.readline().strip() != '42': print('Incorrect input') with open(sys.argv[2], 'w') as ofile: ofile.write('Success\n') meson-0.40.1/test cases/common/76 configure file in custom target/src/meson.build0000644000175000017500000000105712742140120031011 0ustar jpakkanejpakkane00000000000000custom_target('thing', output : 'final.dat', input : cfile, command : [find_program('mycompiler.py'), '@INPUT@', '@OUTPUT@']) # Test usage of a `configure_file` as part of the command list py3 = find_program('python3', required : false) if not py3.found() # Maybe 'python' is Python 3 py3 = find_program('python') endif compiler = configure_file(input : 'mycompiler.py', output : 'mycompiler2.py', configuration : configuration_data()) custom_target('thing2', output : 'final2.dat', input : cfile, command : [py3, compiler, '@INPUT@', '@OUTPUT@']) meson-0.40.1/test cases/common/76 configure file in custom target/inc/0000755000175000017500000000000013100703043026624 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/76 configure file in custom target/inc/confdata.in0000644000175000017500000000001012650745767030756 0ustar jpakkanejpakkane00000000000000@VALUE@ meson-0.40.1/test cases/common/76 configure file in custom target/inc/meson.build0000644000175000017500000000022112650745767031015 0ustar jpakkanejpakkane00000000000000cdata = configuration_data() cdata.set('VALUE', '42') cfile = configure_file(input : 'confdata.in', output : 'confdata', configuration : cdata) meson-0.40.1/test cases/common/26 endian/0000755000175000017500000000000013100703043021272 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/26 endian/meson.build0000644000175000017500000000025213100702272023436 0ustar jpakkanejpakkane00000000000000project('endian check', 'c') if host_machine.endian() == 'big' add_global_arguments('-DIS_BE', language : 'c') endif test('endiantest', executable('prog', 'prog.c')) meson-0.40.1/test cases/common/26 endian/prog.c0000644000175000017500000000061012650745767022436 0ustar jpakkanejpakkane00000000000000#include int is_big_endian(void) { uint32_t one = 1; if(*((uint8_t*) &one) == 1) return 0; return 1; } int main(int argc, char **argv) { int is_be_check = is_big_endian(); int is_be; #ifdef IS_BE is_be = 1; #else is_be = 0; #endif if(is_be_check && is_be) return 0; if(!is_be_check && !is_be) return 0; return 1; } meson-0.40.1/test cases/common/59 object generator/0000755000175000017500000000000013100703043023257 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/59 object generator/source2.c0000644000175000017500000000004512650745767025040 0ustar jpakkanejpakkane00000000000000int func2_in_obj() { return 0; } meson-0.40.1/test cases/common/59 object generator/source.c0000644000175000017500000000004512650745767024756 0ustar jpakkanejpakkane00000000000000int func1_in_obj() { return 0; } meson-0.40.1/test cases/common/59 object generator/meson.build0000644000175000017500000000166513100702314025431 0ustar jpakkanejpakkane00000000000000project('object generator', 'c') python = find_program('python3', required : false) if not python.found() python = find_program('python') endif # Note that this will not add a dependency to the compiler executable. # Code will not be rebuilt if it changes. comp = '@0@/@1@'.format(meson.current_source_dir(), 'obj_generator.py') if host_machine.system() == 'windows' outputname = '@BASENAME@.obj' else outputname = '@BASENAME@.o' endif cc = meson.get_compiler('c').cmd_array().get(-1) # Generate an object file manually. gen = generator(python, output : outputname, arguments : [comp, cc, '@INPUT@', '@OUTPUT@']) generated = gen.process(['source.c', 'source2.c']) # Generate an object file with indexed OUTPUT replacement. gen2 = generator(python, output : outputname, arguments : [comp, cc, '@INPUT@', '@OUTPUT0@']) generated2 = gen2.process(['source3.c']) e = executable('prog', 'prog.c', generated, generated2) test('objgen', e)meson-0.40.1/test cases/common/59 object generator/prog.c0000644000175000017500000000023612723634706024416 0ustar jpakkanejpakkane00000000000000int func1_in_obj(); int func2_in_obj(); int func3_in_obj(); int main(int argc, char **argv) { return func1_in_obj() + func2_in_obj() + func3_in_obj(); } meson-0.40.1/test cases/common/59 object generator/obj_generator.py0000755000175000017500000000101313032764405026464 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 # Mimic a binary that generates an object file (e.g. windres). import sys, subprocess if __name__ == '__main__': if len(sys.argv) != 4: print(sys.argv[0], 'compiler input_file output_file') sys.exit(1) compiler = sys.argv[1] ifile = sys.argv[2] ofile = sys.argv[3] if compiler.endswith('cl'): cmd = [compiler, '/nologo', '/MDd', '/Fo' + ofile, '/c', ifile] else: cmd = [compiler, '-c', ifile, '-o', ofile] sys.exit(subprocess.call(cmd)) meson-0.40.1/test cases/common/59 object generator/source3.c0000644000175000017500000000004512723634706025030 0ustar jpakkanejpakkane00000000000000int func3_in_obj() { return 0; } meson-0.40.1/test cases/common/34 compiler id/0000755000175000017500000000000013100703043022222 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/34 compiler id/meson.build0000644000175000017500000000017313100702276024374 0ustar jpakkanejpakkane00000000000000project('compiler id', 'c') comp = meson.get_compiler('c') str = comp.get_id() message('Compiler name is:') message(str) meson-0.40.1/test cases/common/105 find program path/0000755000175000017500000000000013100703042023376 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/105 find program path/meson.build0000644000175000017500000000156613100702346025556 0ustar jpakkanejpakkane00000000000000project('find program', 'c') python = find_program('python3', required : false) if not python.found() python = find_program('python') endif # Source file via string prog = find_program('program.py') # Source file via files() progf = files('program.py') # Built file py = configure_file(input : 'program.py', output : 'builtprogram.py', configuration : configuration_data()) foreach f : [prog, find_program(py), find_program(progf)] ret = run_command(python, f.path()) assert(ret.returncode() == 0, 'can\'t manually run @0@'.format(prog.path())) assert(ret.stdout().strip() == 'Found', 'wrong output from manually-run @0@'.format(prog.path())) ret = run_command(f) assert(ret.returncode() == 0, 'can\'t run @0@'.format(prog.path())) assert(ret.stdout().strip() == 'Found', 'wrong output from @0@'.format(prog.path())) endforeach meson-0.40.1/test cases/common/105 find program path/program.py0000644000175000017500000000004713057037314025435 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 print("Found") meson-0.40.1/test cases/common/39 tryrun/0000755000175000017500000000000013100703043021403 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/39 tryrun/ok.c0000644000175000017500000000020313001212425022152 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("%s\n", "stdout"); fprintf(stderr, "%s\n", "stderr"); return 0; } meson-0.40.1/test cases/common/39 tryrun/meson.build0000644000175000017500000000356713100702301023554 0ustar jpakkanejpakkane00000000000000project('tryrun', 'c', 'cpp') # Complex to exercise all code paths. if meson.is_cross_build() if meson.has_exe_wrapper() compilers = [meson.get_compiler('c', native : false), meson.get_compiler('cpp', native : false)] else compilers = [meson.get_compiler('c', native : true), meson.get_compiler('cpp', native : true)] endif else compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] endif ok_code = '''#include int main(int argc, char **argv) { printf("%s\n", "stdout"); fprintf(stderr, "%s\n", "stderr"); return 0; } ''' error_code = '''int main(int argc, char **argv) { return 1; } ''' no_compile_code = '''int main(int argc, char **argv) { ''' INPUTS = [ ['String', ok_code, error_code, no_compile_code], ['File', files('ok.c'), files('error.c'), files('no_compile.c')], ] 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 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 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.stderr().strip() == 'stderr' message(type + ' stderr ok.') else message(type + ' bad stderr.') endif endforeach endforeach meson-0.40.1/test cases/common/39 tryrun/no_compile.c0000644000175000017500000000004213001212425023666 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { meson-0.40.1/test cases/common/39 tryrun/error.c0000644000175000017500000000006013001212425022673 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 1; } meson-0.40.1/test cases/common/106 subproject subdir/0000755000175000017500000000000013100703042023543 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/106 subproject subdir/subprojects/0000755000175000017500000000000013100703042026106 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/106 subproject subdir/subprojects/sub/0000755000175000017500000000000013100703042026677 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/106 subproject subdir/subprojects/sub/meson.build0000644000175000017500000000004212664266514031063 0ustar jpakkanejpakkane00000000000000project('sub', 'c') subdir('lib') meson-0.40.1/test cases/common/106 subproject subdir/subprojects/sub/lib/0000755000175000017500000000000013100703042027445 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/106 subproject subdir/subprojects/sub/lib/sub.c0000644000175000017500000000005312664266514030426 0ustar jpakkanejpakkane00000000000000#include "sub.h" int sub() { return 0; } meson-0.40.1/test cases/common/106 subproject subdir/subprojects/sub/lib/meson.build0000644000175000017500000000020012664266514031625 0ustar jpakkanejpakkane00000000000000lib = static_library('sub', 'sub.c') libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib) meson-0.40.1/test cases/common/106 subproject subdir/subprojects/sub/lib/sub.h0000644000175000017500000000006012664266514030431 0ustar jpakkanejpakkane00000000000000#ifndef SUB_H #define SUB_H int sub(); #endif meson-0.40.1/test cases/common/106 subproject subdir/meson.build0000644000175000017500000000027013100702347025713 0ustar jpakkanejpakkane00000000000000project('proj', 'c') subproject('sub') libSub = dependency('sub', fallback: ['sub', 'libSub']) exe = executable('prog', 'prog.c', dependencies: libSub) test('subproject subdir', exe) meson-0.40.1/test cases/common/106 subproject subdir/prog.c0000644000175000017500000000006012664266514024700 0ustar jpakkanejpakkane00000000000000#include int main() { return sub(); } meson-0.40.1/test cases/common/142 compute int/0000755000175000017500000000000013100703043022342 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/142 compute int/foobar.h0000644000175000017500000000014513074426732024004 0ustar jpakkanejpakkane00000000000000#ifndef __FOOBAR_H__ #define __FOOBAR_H__ #define FOOBAR_IN_FOOBAR_H 10 #endif /*__FOOBAR_H__*/ meson-0.40.1/test cases/common/142 compute int/config.h.in0000644000175000017500000000007613074426732024411 0ustar jpakkanejpakkane00000000000000#define INTSIZE @INTSIZE@ #define FOOBAR_IN_CONFIG_H @FOOBAR@ meson-0.40.1/test cases/common/142 compute int/prog.c.in0000644000175000017500000000073513074426732024110 0ustar jpakkanejpakkane00000000000000#include "@CONFIG@" #include #include #include "foobar.h" int main(int argc, char **argv) { if(INTSIZE != sizeof(int)) { fprintf(stderr, "Mismatch: computed int size %d, actual size %d.\n", INTSIZE, (int)sizeof(int)); return 1; } if(FOOBAR_IN_CONFIG_H != FOOBAR_IN_FOOBAR_H) { fprintf(stderr, "Mismatch: computed int %d, should be %d.\n", FOOBAR_IN_CONFIG_H, FOOBAR_IN_FOOBAR_H); return 1; } return 0; } meson-0.40.1/test cases/common/142 compute int/meson.build0000644000175000017500000000220613100702377024515 0ustar jpakkanejpakkane00000000000000project('compute int', 'c', 'cpp') inc = include_directories('.') # Test with C cc = meson.get_compiler('c') intsize = cc.compute_int('sizeof(int)', low : 1, high : 16, guess : 4) foobar = cc.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc) cd = configuration_data() cd.set('INTSIZE', intsize) cd.set('FOOBAR', foobar) 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', s) test('compute int test', e) # Test with C++ cpp = meson.get_compiler('cpp') intsize = cpp.compute_int('sizeof(int)') foobar = cpp.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', include_directories : inc) cdpp = configuration_data() cdpp.set('INTSIZE', intsize) cdpp.set('FOOBAR', foobar) 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('compute int test c++', epp) meson-0.40.1/test cases/common/13 pch/0000755000175000017500000000000013100703043020602 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/13 pch/pch/0000755000175000017500000000000013100703043021354 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/13 pch/pch/prog.h0000644000175000017500000000002212650745767022522 0ustar jpakkanejpakkane00000000000000#include meson-0.40.1/test cases/common/13 pch/pch/prog_pch.c0000644000175000017500000000013712650745767023356 0ustar jpakkanejpakkane00000000000000#if !defined(_MSC_VER) #error "This file is only for use with MSVC." #endif #include "prog.h" meson-0.40.1/test cases/common/13 pch/meson.build0000644000175000017500000000014713100702263022751 0ustar jpakkanejpakkane00000000000000project('pch test', 'c') exe = executable('prog', 'prog.c', c_pch : ['pch/prog_pch.c', 'pch/prog.h']) meson-0.40.1/test cases/common/13 pch/prog.c0000644000175000017500000000031412650745767021747 0ustar jpakkanejpakkane00000000000000// No includes here, they need to come from the PCH void func() { fprintf(stdout, "This is a function that fails if stdio is not #included.\n"); } int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/112 has arg/0000755000175000017500000000000013100703042021414 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/112 has arg/meson.build0000644000175000017500000000326013100702352023562 0ustar jpakkanejpakkane00000000000000project('has arg', 'c', 'cpp') cc = meson.get_compiler('c') cpp = meson.get_compiler('cpp') if cc.get_id() == 'msvc' is_arg = '/O2' useless = '/DFOO' else is_arg = '-O2' useless = '-DFOO' endif isnt_arg = '-fiambroken' assert(cc.has_argument(is_arg), 'Arg that should have worked does not work.') assert(not cc.has_argument(isnt_arg), 'Arg that should be broken is not.') assert(cpp.has_argument(is_arg), 'Arg that should have worked does not work.') assert(not cpp.has_argument(isnt_arg), 'Arg that should be broken is not.') # Have useless at the end to ensure that the search goes from front to back. l1 = cc.first_supported_argument([isnt_arg, is_arg, isnt_arg, useless]) l2 = cc.first_supported_argument(isnt_arg, isnt_arg, isnt_arg) assert(l1.length() == 1, 'First supported returned wrong result.') assert(l1.get(0) == is_arg, 'First supported returned wrong argument.') assert(l2.length() == 0, 'First supported did not return empty array.') l1 = cpp.first_supported_argument([isnt_arg, is_arg, isnt_arg, useless]) l2 = cpp.first_supported_argument(isnt_arg, isnt_arg, isnt_arg) assert(l1.length() == 1, 'First supported returned wrong result.') assert(l1.get(0) == is_arg, 'First supported returned wrong argument.') assert(l2.length() == 0, 'First supported did not return empty array.') if cc.get_id() == 'gcc' pre_arg = '-Wformat' anti_pre_arg = '-Wno-format' arg = '-Werror=format-security' assert(not cc.has_multi_arguments([anti_pre_arg, arg]), 'Arg that should be broken is not.') assert(cc.has_multi_arguments(pre_arg), 'Arg that should have worked does not work.') assert(cc.has_multi_arguments([pre_arg, arg]), 'Arg that should have worked does not work.') endif meson-0.40.1/test cases/common/67 foreach/0000755000175000017500000000000013100703043021450 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/67 foreach/prog2.c0000644000175000017500000000014712650745767022703 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("This is test #2.\n"); return 0; } meson-0.40.1/test cases/common/67 foreach/installed_files.txt0000644000175000017500000000006612742140120025356 0ustar jpakkanejpakkane00000000000000usr/bin/prog1?exe usr/bin/prog2?exe usr/bin/prog3?exe meson-0.40.1/test cases/common/67 foreach/meson.build0000644000175000017500000000133213100702320023606 0ustar jpakkanejpakkane00000000000000project('foreach', 'c') tests = [['test1', 'prog1', 'prog1.c'], ['test2', 'prog2', 'prog2.c', 'fallback'], ['test3', 'prog3', 'prog3.c', 'urgh']] assert(tests[0].get(3, 'fallbck') == 'fallbck', 'array #1 fallback did not match') assert(tests[1].get(3, 'failbk') == 'fallback', 'array #2 value did not match') assert(tests[2].get(3, 'urgh') == 'urgh', 'array #3 value did not match') foreach i : tests test(i.get(0), executable(i.get(1), i.get(2), install : true)) # Ensure that changing the tests variable does not # affect ongoing iteration in the foreach loop. # # Being able to do that would make Meson Turing complete and # we definitely don't want that. tests = ['test4', 'prog4', 'prog4.c'] endforeach meson-0.40.1/test cases/common/67 foreach/prog3.c0000644000175000017500000000014712650745767022704 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("This is test #3.\n"); return 0; } meson-0.40.1/test cases/common/67 foreach/prog1.c0000644000175000017500000000014712650745767022702 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("This is test #1.\n"); return 0; } meson-0.40.1/test cases/common/119 pathjoin/0000755000175000017500000000000013100703042021732 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/119 pathjoin/meson.build0000644000175000017500000000204313100702360024075 0ustar jpakkanejpakkane00000000000000project('pathjoin', 'c') # Test string-args form since that is the canonical way assert(join_paths('foo') == 'foo', 'Single argument join is broken') assert(join_paths('foo', 'bar') == 'foo/bar', 'Path joining is broken') assert(join_paths('foo', 'bar', 'baz') == 'foo/bar/baz', 'Path joining is broken') assert(join_paths('/foo', 'bar') == '/foo/bar', 'Path joining is broken') assert(join_paths('foo', '/bar') == '/bar', 'Absolute path joining is broken') assert(join_paths('/foo', '/bar') == '/bar', 'Absolute path joining is broken') # Test array form since people are using that too assert(join_paths(['foo']) == 'foo', 'Single argument join is broken') assert(join_paths(['foo', 'bar']) == 'foo/bar', 'Path joining is broken') assert(join_paths(['foo', 'bar', 'baz']) == 'foo/bar/baz', 'Path joining is broken') assert(join_paths(['/foo', 'bar']) == '/foo/bar', 'Path joining is broken') assert(join_paths(['foo', '/bar']) == '/bar', 'Absolute path joining is broken') assert(join_paths(['/foo', '/bar']) == '/bar', 'Absolute path joining is broken') meson-0.40.1/test cases/common/99 benchmark/0000755000175000017500000000000013100703044022001 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/99 benchmark/delayer.c0000644000175000017500000000060112650745767023622 0ustar jpakkanejpakkane00000000000000/* Simple prog that sleeps for a random time. */ #include #include #if defined(_WIN32) #include #endif int main(int argc, char **argv) { srand(time(NULL)); #if !defined(_WIN32) struct timespec t; t.tv_sec = 0; t.tv_nsec = 199999999.0*rand()/RAND_MAX; nanosleep(&t, NULL); #else Sleep(50.0*rand()/RAND_MAX); #endif return 0; } meson-0.40.1/test cases/common/99 benchmark/meson.build0000644000175000017500000000020013100702343024134 0ustar jpakkanejpakkane00000000000000project('benchmark', 'c') delayer = executable('delayer', 'delayer.c', c_args : '-D_GNU_SOURCE') benchmark('delayer', delayer) meson-0.40.1/test cases/common/60 install script/0000755000175000017500000000000013100703043022765 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/60 install script/installed_files.txt0000644000175000017500000000016113026303756026703 0ustar jpakkanejpakkane00000000000000usr/bin/prog?exe usr/diiba/daaba/file.dat usr/this/should/also-work.dat usr/this/does/something-different.dat.in meson-0.40.1/test cases/common/60 install script/meson.build0000644000175000017500000000036013100702314025126 0ustar jpakkanejpakkane00000000000000project('custom install script', 'c') executable('prog', 'prog.c', install : true) meson.add_install_script('myinstall.py', 'diiba/daaba', 'file.dat') meson.add_install_script('myinstall.py', 'this/should', 'also-work.dat') subdir('src') meson-0.40.1/test cases/common/60 install script/myinstall.py0000644000175000017500000000035613057037314025373 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import os import sys prefix = os.environ['MESON_INSTALL_DESTDIR_PREFIX'] dirname = os.path.join(prefix, sys.argv[1]) os.makedirs(dirname) with open(os.path.join(dirname, sys.argv[2]), 'w') as f: f.write('') meson-0.40.1/test cases/common/60 install script/prog.c0000644000175000017500000000014412650745767024133 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("This is text.\n"); return 0; } meson-0.40.1/test cases/common/60 install script/src/0000755000175000017500000000000013100703043023554 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/60 install script/src/meson.build0000644000175000017500000000012113026303756025726 0ustar jpakkanejpakkane00000000000000meson.add_install_script('myinstall.py', 'this/does', 'something-different.dat') meson-0.40.1/test cases/common/60 install script/src/myinstall.py0000644000175000017500000000036613057037314026163 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import os import sys prefix = os.environ['MESON_INSTALL_DESTDIR_PREFIX'] dirname = os.path.join(prefix, sys.argv[1]) os.makedirs(dirname) with open(os.path.join(dirname, sys.argv[2] + '.in'), 'w') as f: f.write('') meson-0.40.1/test cases/common/60 install script/no-installed-files0000644000175000017500000000000012742140120026371 0ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/102 threads/0000755000175000017500000000000013100703042021540 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/102 threads/meson.build0000644000175000017500000000046713100702345023716 0ustar jpakkanejpakkane00000000000000project('threads', 'cpp', 'c', default_options : ['cpp_std=c++11']) threaddep = dependency('threads') test('cppthreadtest', executable('cppthreadprog', 'threadprog.cpp', dependencies : threaddep ) ) test('cthreadtest', executable('cthreadprog', 'threadprog.c', dependencies : threaddep ) ) meson-0.40.1/test cases/common/102 threads/threadprog.cpp0000644000175000017500000000157212650745767024445 0ustar jpakkanejpakkane00000000000000/* On Windows not all versions of VS support C++11 and * some (most?) versions of mingw don't support std::thread, * even though they do support c++11. Since we only care about * threads working, do the test with raw win threads. */ #if defined _WIN32 #include #include DWORD WINAPI thread_func(LPVOID) { printf("Printing from a thread.\n"); return 0; } int main(int, char**) { printf("Starting thread.\n"); HANDLE th; DWORD id; th = CreateThread(NULL, 0, thread_func, NULL, 0, &id); WaitForSingleObject(th, INFINITE); printf("Stopped thread.\n"); return 0; } #else #include #include void main_func() { printf("Printing from a thread.\n"); } int main(int, char**) { printf("Starting thread.\n"); std::thread th(main_func); th.join(); printf("Stopped thread.\n"); return 0; } #endif meson-0.40.1/test cases/common/102 threads/threadprog.c0000644000175000017500000000143612650745767024104 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 #include #include DWORD WINAPI thread_func(LPVOID ignored) { printf("Printing from a thread.\n"); return 0; } int main(int argc, char **argv) { DWORD id; HANDLE th; printf("Starting thread.\n"); th = CreateThread(NULL, 0, thread_func, NULL, 0, &id); WaitForSingleObject(th, INFINITE); printf("Stopped thread.\n"); return 0; } #else #include #include void* main_func(void* ignored) { printf("Printing from a thread.\n"); return NULL; } int main(int argc, char** argv) { pthread_t thread; int rc; printf("Starting thread.\n"); rc = pthread_create(&thread, NULL, main_func, NULL); rc = pthread_join(thread, NULL); printf("Stopped thread.\n"); return rc; } #endif meson-0.40.1/test cases/common/140 get define/0000755000175000017500000000000013100703043022103 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/140 get define/meson.build0000644000175000017500000000343313100702374024256 0ustar jpakkanejpakkane00000000000000project('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)) run_1665_test = false if meson.is_cross_build() # Can't use an empty array as a fallback here because of # https://github.com/mesonbuild/meson/issues/1481 lang_args = meson.get_cross_property(lang + '_args', false) if lang_args != false foreach lang_arg : lang_args if lang_arg.contains('MESON_TEST_ISSUE_1665') run_1665_test = true endif endforeach endif endif if run_1665_test have = cc.get_define('MESON_TEST_ISSUE_1665') assert(have == '1', 'MESON_TEST_ISSUE_1665 value is "@0@" instead of "1"'.format(have)) endif endforeach meson-0.40.1/test cases/common/140 get define/meson_options.txt0000644000175000017500000000010113074426732025551 0ustar jpakkanejpakkane00000000000000option('MESON_TEST_DEFINE_VALUE', type : 'string', default : '') meson-0.40.1/test cases/common/125 shared module/0000755000175000017500000000000013100703042022627 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/125 shared module/runtime.c0000644000175000017500000000070313024065327024472 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif /* * This file pretends to be a language runtime that supports extension * modules. */ int DLL_PUBLIC func_from_language_runtime(void) { return 86; } meson-0.40.1/test cases/common/125 shared module/meson.build0000644000175000017500000000104213100702362024772 0ustar jpakkanejpakkane00000000000000project('shared module', 'c') dl = meson.get_compiler('c').find_library('dl', required : false) 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. 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) meson-0.40.1/test cases/common/125 shared module/prog.c0000644000175000017500000000402413024065327023756 0ustar jpakkanejpakkane00000000000000 #include int func_from_language_runtime(void); typedef int (*fptr) (void); #ifdef _WIN32 #include wchar_t* win32_get_last_error (void) { wchar_t *msg = NULL; FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), 0, (LPWSTR) &msg, 0, NULL); return msg; } int main (int argc, char **argv) { HINSTANCE handle; fptr importedfunc; int expected, actual; int ret = 1; handle = LoadLibraryA (argv[1]); if (!handle) { wchar_t *msg = win32_get_last_error (); printf ("Could not open %s: %S\n", argv[1], msg); goto nohandle; } importedfunc = (fptr) GetProcAddress (handle, "func"); if (importedfunc == NULL) { wchar_t *msg = win32_get_last_error (); printf ("Could not find 'func': %S\n", msg); goto out; } actual = importedfunc (); expected = func_from_language_runtime (); if (actual != expected) { printf ("Got %i instead of %i\n", actual, expected); goto out; } ret = 0; out: FreeLibrary (handle); nohandle: return ret; } #else #include #include int main(int argc, char **argv) { void *dl; fptr importedfunc; int expected, actual; char *error; int ret = 1; dlerror(); dl = dlopen(argv[1], RTLD_LAZY); error = dlerror(); if(error) { printf("Could not open %s: %s\n", argv[1], error); goto nodl; } importedfunc = (fptr) dlsym(dl, "func"); if (importedfunc == NULL) { printf ("Could not find 'func'\n"); goto out; } assert(importedfunc != func_from_language_runtime); actual = (*importedfunc)(); expected = func_from_language_runtime (); if (actual != expected) { printf ("Got %i instead of %i\n", actual, expected); goto out; } ret = 0; out: dlclose(dl); nodl: return ret; } #endif meson-0.40.1/test cases/common/125 shared module/module.c0000644000175000017500000000372513074426732024311 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif #if defined(_WIN32) || defined(__CYGWIN__) #include typedef int (*fptr) (void); #ifdef __CYGWIN__ #include fptr find_any_f (const char *name) { return (fptr) dlsym(RTLD_DEFAULT, name); } #else /* _WIN32 */ #include #include /* 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 * modules is taken from gmodule.c in glib */ fptr find_any_f (const char *name) { fptr f; HANDLE snapshot; MODULEENTRY32 me32; snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); if (snapshot == (HANDLE) -1) { printf("Could not get snapshot\n"); return 0; } me32.dwSize = sizeof (me32); f = NULL; if (Module32First (snapshot, &me32)) { do { if ((f = (fptr) GetProcAddress (me32.hModule, name)) != NULL) break; } while (Module32Next (snapshot, &me32)); } CloseHandle (snapshot); return f; } #endif int DLL_PUBLIC func() { fptr f; f = find_any_f ("func_from_language_runtime"); if (f != NULL) return f(); printf ("Could not find function\n"); return 1; } #else /* * Shared modules often have references to symbols that are not defined * at link time, but which will be provided from deps of the executable that * dlopens it. We need to make sure that this works, i.e. that we do * not pass -Wl,--no-undefined when linking modules. */ int func_from_language_runtime(); int DLL_PUBLIC func(void) { return func_from_language_runtime(); } #endif meson-0.40.1/test cases/common/116 ternary/0000755000175000017500000000000013100703042021577 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/116 ternary/meson.build0000644000175000017500000000043513100702356023752 0ustar jpakkanejpakkane00000000000000project('ternary operator', 'c') one = true ? 1 : error('False branch should not be evaluated') two = false ? error('True branch should not be evaluated.') : 2 assert(one == 1, 'Return value from ternary true is wrong.') assert(two == 2, 'Return value from ternary false is wrong.') meson-0.40.1/test cases/common/44 has member/0000755000175000017500000000000013100703043022037 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/44 has member/meson.build0000644000175000017500000000140113100702303024173 0ustar jpakkanejpakkane00000000000000project('has member', 'c', 'cpp') compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] foreach cc : compilers if not cc.has_member('struct tm', 'tm_sec', prefix : '#include') error('Did not detect member of "struct tm" that exists: "tm_sec"') endif if cc.has_member('struct tm', 'tm_nonexistent', prefix : '#include') error('Not existing member "tm_nonexistent" found.') endif if not cc.has_members('struct tm', 'tm_sec', 'tm_min', prefix : '#include') 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') error('Not existing member "tm_nonexistent2" found.') endif endforeach meson-0.40.1/test cases/common/37 has header/0000755000175000017500000000000013100703043022022 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/37 has header/meson.build0000644000175000017500000000417113100702300024162 0ustar jpakkanejpakkane00000000000000project('has header', 'c', 'cpp') host_system = host_machine.system() non_existant_header = 'ouagadougou.h' # Copy it into the builddir to ensure that it isn't found even if it's there configure_file(input : non_existant_header, output : non_existant_header, configuration : configuration_data()) # Test that the fallback to __has_include also works on all compilers if host_system != 'darwin' fallbacks = ['', '\n#undef __has_include'] else # On Darwin's clang you can't redefine builtin macros so the above doesn't work fallbacks = [''] endif foreach fallback : fallbacks foreach comp : [meson.get_compiler('c'), meson.get_compiler('cpp')] 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 ' + fallback), 'Stdio missing.') # XInput.h should not require type definitions from windows.h, but it does # require macro definitions. Specifically, it requires an arch setting for # VS2015 at least. # 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 ' + fallback), 'XInput.h should not be missing on Windows') assert(comp.has_header('XInput.h', prefix : '#define _X86_' + fallback), 'XInput.h should not need windows.h') endif # Test that the following GCC bug doesn't happen: # 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', prefix : fallback), 'Could not find ') 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, prefix : fallback), 'Found non-existant header.') endforeach endforeach meson-0.40.1/test cases/common/37 has header/ouagadougou.h0000644000175000017500000000004313062323030024510 0ustar jpakkanejpakkane00000000000000#define OMG_THIS_SHOULDNT_BE_FOUND meson-0.40.1/test cases/common/135 generated assembly/0000755000175000017500000000000013100703043023653 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/135 generated assembly/main.c0000644000175000017500000000046013074426732024764 0ustar jpakkanejpakkane00000000000000#include #if defined(_WIN32) || defined(__CYGWIN__) __declspec(dllimport) #endif unsigned square_unsigned (unsigned a); int main (int argc, char * argv[]) { unsigned int ret = square_unsigned (2); if (ret != 4) { printf("Got %u instead of 4\n", ret); return 1; } return 0; } meson-0.40.1/test cases/common/135 generated assembly/symbol-underscore.h0000644000175000017500000000017313043224360027507 0ustar jpakkanejpakkane00000000000000#if defined(MESON_TEST__UNDERSCORE_SYMBOL) # define SYMBOL_NAME(name) _##name #else # define SYMBOL_NAME(name) name #endif meson-0.40.1/test cases/common/135 generated assembly/square-x86.S.in0000644000175000017500000000071213070746245026350 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" #ifdef _MSC_VER .386 .MODEL FLAT, C PUBLIC square_unsigned _TEXT SEGMENT square_unsigned PROC var1:DWORD mov eax, var1 imul eax, eax ret square_unsigned ENDP _TEXT ENDS END #else .text .globl SYMBOL_NAME(square_unsigned) /* Only supported on Linux with GAS */ # ifdef __linux__ .type square_unsigned,@function # endif SYMBOL_NAME(square_unsigned): movl 4(%esp), %eax imull %eax, %eax retl #endif meson-0.40.1/test cases/common/135 generated assembly/meson.build0000644000175000017500000000201013100702371026011 0ustar jpakkanejpakkane00000000000000project('generated assembly', 'c') cc = meson.get_compiler('c') if cc.get_id() == 'msvc' error('MESON_SKIP_TEST: assembly files cannot be compiled directly by MSVC') endif cpu = host_machine.cpu_family() supported_cpus = ['arm', 'x86', 'x86_64'] if not supported_cpus.contains(cpu) error('MESON_SKIP_TEST: unsupported cpu family: ' + cpu) endif if cc.symbols_have_underscore_prefix() add_project_arguments('-DMESON_TEST__UNDERSCORE_SYMBOL', language : 'c') endif copy = find_program('copyfile.py') output = 'square-@0@.S'.format(cpu) input = output + '.in' copygen = generator(copy, arguments : ['@INPUT@', '@OUTPUT@'], output : '@BASENAME@') l = shared_library('square-gen', copygen.process(input)) test('square-gen-test', executable('square-gen-test', 'main.c', link_with : l)) copyct = custom_target('square', input : input, output : output, command : [copy, '@INPUT@', '@OUTPUT@']) l = shared_library('square-ct', copyct) test('square-ct-test', executable('square-ct-test', 'main.c', link_with : l)) meson-0.40.1/test cases/common/135 generated assembly/copyfile.py0000644000175000017500000000013413057037314026051 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) meson-0.40.1/test cases/common/135 generated assembly/square-arm.S.in0000644000175000017500000000036113070746245026502 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" .text .globl SYMBOL_NAME(square_unsigned) /* Only supported on Linux with GAS */ # ifdef __linux__ .type square_unsigned,%function #endif SYMBOL_NAME(square_unsigned): mul r1, r0, r0 mov r0, r1 mov pc, lr meson-0.40.1/test cases/common/135 generated assembly/square-x86_64.S.in0000644000175000017500000000117713074426732026667 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" #ifdef _MSC_VER /* MSVC on Windows */ PUBLIC SYMBOL_NAME(square_unsigned) _TEXT SEGMENT SYMBOL_NAME(square_unsigned) PROC mov eax, ecx imul eax, eax ret SYMBOL_NAME(square_unsigned) ENDP _TEXT ENDS END #else .text .globl SYMBOL_NAME(square_unsigned) /* Only supported on Linux with GAS */ # ifdef __linux__ .type square_unsigned,@function # endif # if defined(_WIN32) || defined(__CYGWIN__) /* msabi */ SYMBOL_NAME(square_unsigned): imull %ecx, %ecx movl %ecx, %eax retq # else /* sysvabi */ SYMBOL_NAME(square_unsigned): imull %edi, %edi movl %edi, %eax retq # endif #endif meson-0.40.1/test cases/common/90 identical target name in subproject/0000755000175000017500000000000013100703044026672 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/90 identical target name in subproject/subprojects/0000755000175000017500000000000013100703042031233 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/90 identical target name in subproject/subprojects/foo/0000755000175000017500000000000013100703044032020 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/90 identical target name in subproject/subprojects/foo/meson.build0000644000175000017500000000006312650745767034214 0ustar jpakkanejpakkane00000000000000project('subfoo', 'c') executable('bar', 'bar.c') meson-0.40.1/test cases/common/90 identical target name in subproject/subprojects/foo/bar.c0000644000175000017500000000015412650745767032763 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("I'm a subproject bar.\n"); return 0; } meson-0.40.1/test cases/common/90 identical target name in subproject/meson.build0000644000175000017500000000011413100702335031032 0ustar jpakkanejpakkane00000000000000project('toplevel bar', 'c') subproject('foo') executable('bar', 'bar.c') meson-0.40.1/test cases/common/90 identical target name in subproject/bar.c0000644000175000017500000000015612650745767027637 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("I'm a main project bar.\n"); return 0; } meson-0.40.1/test cases/common/86 same basename/0000755000175000017500000000000013100703044022524 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/86 same basename/exe2.c0000644000175000017500000000012112650745767023560 0ustar jpakkanejpakkane00000000000000int func(); int main(int argc, char **argv) { return func() == 1 ? 0 : 1; } meson-0.40.1/test cases/common/86 same basename/lib.c0000644000175000017500000000067412650745767023500 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif #if defined SHAR int DLL_PUBLIC func() { return 1; } #elif defined STAT int func() { return 0; } #else #error "Missing type definition." #endif meson-0.40.1/test cases/common/86 same basename/meson.build0000644000175000017500000000060513100702333024667 0ustar jpakkanejpakkane00000000000000project('same basename', 'c') subdir('sharedsub') subdir('staticsub') # Use the same source file to check that each top level target # has its own unique working directory. If they don't # then the .o files will clobber each other. exe1 = executable('name', 'exe1.c', link_with : stlib) exe2 = executable('name2', 'exe2.c', link_with : shlib) test('static', exe1) test('shared', exe2) meson-0.40.1/test cases/common/86 same basename/exe1.c0000644000175000017500000000010412650745767023560 0ustar jpakkanejpakkane00000000000000int func(); int main(int argc, char **argv) { return func(); } meson-0.40.1/test cases/common/86 same basename/sharedsub/0000755000175000017500000000000013100703044024504 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/86 same basename/sharedsub/meson.build0000644000175000017500000000007612765341571026674 0ustar jpakkanejpakkane00000000000000shlib = shared_library('name', '../lib.c', c_args : '-DSHAR') meson-0.40.1/test cases/common/86 same basename/staticsub/0000755000175000017500000000000013100703044024525 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/86 same basename/staticsub/meson.build0000644000175000017500000000025612765341571026715 0ustar jpakkanejpakkane00000000000000# On Windows a static lib is now libfoo.a, so it does not conflict with foo.lib # from the shared library above stlib = static_library('name', '../lib.c', c_args : '-DSTAT') meson-0.40.1/test cases/common/38 run program/0000755000175000017500000000000013100703043022273 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/38 run program/meson.build0000644000175000017500000000203213100702300024425 0ustar jpakkanejpakkane00000000000000project('run command', 'c') if build_machine.system() == 'windows' c = run_command('cmd', '/c', 'echo', 'hello') else c = run_command('echo', 'hello') endif correct = 'hello' if c.returncode() != 0 error('Executing echo failed.') endif result = c.stdout().strip() if result != correct error('Getting stdout failed.') endif if c.stderr() != '' error('Extra text in stderr.') endif # Now the same with a script. if build_machine.system() == 'windows' cs = run_command('scripts/hello.bat') else cs = run_command('scripts/hello.sh') endif if cs.returncode() != 0 error('Executing script failed.') endif if cs.stdout().strip() != correct error('Getting stdout failed (script).') endif if cs.stderr() != '' error('Extra text in stderr (script).') endif # We should be able to have files() in argument f = files('meson.build') if build_machine.system() == 'windows' c = run_command('cmd', '/c', 'echo', f) else c = run_command('echo', f) endif if c.returncode() != 0 error('Using files() in argument failed.') endif meson-0.40.1/test cases/common/38 run program/scripts/0000755000175000017500000000000013100703043023762 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/38 run program/scripts/hello.bat0000644000175000017500000000002512650745767025606 0ustar jpakkanejpakkane00000000000000@ECHO OFF ECHO hello meson-0.40.1/test cases/common/38 run program/scripts/hello.sh0000755000175000017500000000002612650745767025456 0ustar jpakkanejpakkane00000000000000#!/bin/sh echo hello meson-0.40.1/test cases/common/134 generated llvm ir/0000755000175000017500000000000013100703043023400 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/134 generated llvm ir/main.c0000644000175000017500000000034713043224360024502 0ustar jpakkanejpakkane00000000000000#include unsigned square_unsigned (unsigned a); int main (int argc, char * argv[]) { unsigned int ret = square_unsigned (2); if (ret != 4) { printf("Got %u instead of 4\n", ret); return 1; } return 0; } meson-0.40.1/test cases/common/134 generated llvm ir/meson.build0000644000175000017500000000125113046167604025561 0ustar jpakkanejpakkane00000000000000project('generated llvm ir', 'c') if meson.get_compiler('c').get_id() != 'clang' error('MESON_SKIP_TEST: LLVM IR files can only be built with clang') endif copy = find_program('copyfile.py') copygen = generator(copy, arguments : ['@INPUT@', '@OUTPUT@'], output : '@BASENAME@') l = shared_library('square-gen', copygen.process('square.ll.in')) test('square-gen-test', executable('square-gen-test', 'main.c', link_with : l)) copyct = custom_target('square', input : 'square.ll.in', output : 'square.ll', command : [copy, '@INPUT@', '@OUTPUT@']) l = shared_library('square-ct', copyct) test('square-ct-test', executable('square-ct-test', 'main.c', link_with : l)) meson-0.40.1/test cases/common/134 generated llvm ir/copyfile.py0000644000175000017500000000013413057037314025576 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys import shutil shutil.copyfile(sys.argv[1], sys.argv[2]) meson-0.40.1/test cases/common/134 generated llvm ir/square.ll.in0000644000175000017500000000011313043224360025637 0ustar jpakkanejpakkane00000000000000define i32 @square_unsigned(i32 %a) { %1 = mul i32 %a, %a ret i32 %1 } meson-0.40.1/test cases/common/103 manygen/0000755000175000017500000000000013100703042021545 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/103 manygen/depuser.c0000644000175000017500000000037412650745767023421 0ustar jpakkanejpakkane00000000000000#include"gen_func.h" int main(int argc, char **argv) { unsigned int i = (unsigned int) gen_func_in_lib(); unsigned int j = (unsigned int) gen_func_in_obj(); unsigned int k = (unsigned int) gen_func_in_src(); return (int)(i + j + k); } meson-0.40.1/test cases/common/103 manygen/meson.build0000644000175000017500000000046013100702345023714 0ustar jpakkanejpakkane00000000000000project('manygen', 'c') if meson.is_cross_build() # FIXME error out with skip message once cross test runner # recognizes it. message('Not running this test during cross build.') else subdir('subdir') exe = executable('depuser', 'depuser.c', generated) test('depuser test', exe) endif meson-0.40.1/test cases/common/103 manygen/subdir/0000755000175000017500000000000013100703042023035 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/103 manygen/subdir/funcinfo.def0000644000175000017500000000001112650745767025351 0ustar jpakkanejpakkane00000000000000gen_func meson-0.40.1/test cases/common/103 manygen/subdir/meson.build0000644000175000017500000000153213043224360025207 0ustar jpakkanejpakkane00000000000000gen = files('manygen.py') py3_bin = import('python3').find_python() 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'] endif generated = custom_target('manygen', output : outfiles, input : ['funcinfo.def'], command : [py3_bin, gen[0], '@INPUT@', '@OUTDIR@', buildtype_args], ) meson-0.40.1/test cases/common/103 manygen/subdir/manygen.py0000755000175000017500000000412113043224360025055 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python from __future__ import print_function # Generates a static library, object file, source # file and a header file. import sys, os 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.') sys.exit(1) # Emulate the environment.detect_c_compiler() logic compiler = os.environ.get('CC', None) if not compiler: compiler = shutil.which('cl') or \ shutil.which('gcc') or \ shutil.which('clang') or \ shutil.which('cc') compbase = os.path.basename(compiler) if 'cl' in compbase and 'clang' not in compbase: libsuffix = '.lib' is_vs = True compiler = 'cl' linker = 'lib' else: libsuffix = '.a' is_vs = False linker = 'ar' if compiler is None: print('No known compilers found.') sys.exit(1) objsuffix = '.o' outo = os.path.join(outdir, funcname + objsuffix) outa = os.path.join(outdir, funcname + libsuffix) outh = os.path.join(outdir, funcname + '.h') outc = os.path.join(outdir, funcname + '.c') tmpc = 'diibadaaba.c' tmpo = 'diibadaaba' + objsuffix with open(outc, 'w') as f: f.write('''#include"%s.h" int %s_in_src() { return 0; } ''' % (funcname, funcname)) with open(outh, 'w') as f: f.write('''#pragma once int %s_in_lib(); int %s_in_obj(); int %s_in_src(); ''' % (funcname, funcname, funcname)) with open(tmpc, 'w') as f: f.write('''int %s_in_obj() { return 0; } ''' % funcname) if is_vs: subprocess.check_call([compiler, '/nologo', '/c', buildtype_args, '/Fo' + outo, tmpc]) else: subprocess.check_call([compiler, '-c', '-o', outo, tmpc]) with open(tmpc, 'w') as f: f.write('''int %s_in_lib() { return 0; } ''' % funcname) if is_vs: subprocess.check_call([compiler, '/nologo', '/c', '/Fo' + tmpo, tmpc]) subprocess.check_call([linker, '/NOLOGO', '/OUT:' + outa, tmpo]) else: subprocess.check_call([compiler, '-c', '-o', tmpo, tmpc]) subprocess.check_call([linker, 'csr', outa, tmpo]) os.unlink(tmpo) os.unlink(tmpc) meson-0.40.1/test cases/common/3 static/0000755000175000017500000000000013100703043021236 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/3 static/meson.build0000644000175000017500000000025313100702256023405 0ustar jpakkanejpakkane00000000000000project('static library test', 'c') lib = static_library('mylib', get_option('source'), link_args : '-THISMUSTNOBEUSED') # Static linker needs to ignore all link args. meson-0.40.1/test cases/common/3 static/libfile.c0000644000175000017500000000004012650745767023036 0ustar jpakkanejpakkane00000000000000int libfunc() { return 3; } meson-0.40.1/test cases/common/3 static/meson_options.txt0000644000175000017500000000013513055371450024706 0ustar jpakkanejpakkane00000000000000option('source', type : 'combo', choices : ['libfile.c', 'libfile2.c'], value : 'libfile.c') meson-0.40.1/test cases/common/3 static/libfile2.c0000644000175000017500000000004113055371450023101 0ustar jpakkanejpakkane00000000000000int libfunc2() { return 4; } meson-0.40.1/test cases/common/14 cpp pch/0000755000175000017500000000000013100703043021346 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/14 cpp pch/pch/0000755000175000017500000000000013100703043022120 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/14 cpp pch/pch/prog.hh0000644000175000017500000000002312650745767023437 0ustar jpakkanejpakkane00000000000000#include meson-0.40.1/test cases/common/14 cpp pch/pch/prog_pch.cc0000644000175000017500000000014012650745767024257 0ustar jpakkanejpakkane00000000000000#if !defined(_MSC_VER) #error "This file is only for use with MSVC." #endif #include "prog.hh" meson-0.40.1/test cases/common/14 cpp pch/meson.build0000644000175000017500000000016113100702265023513 0ustar jpakkanejpakkane00000000000000project('c++ pch test', 'cpp') exe = executable('prog', 'prog.cc', cpp_pch : ['pch/prog.hh', 'pch/prog_pch.cc']) meson-0.40.1/test cases/common/14 cpp pch/prog.cc0000644000175000017500000000027012650745767022657 0ustar jpakkanejpakkane00000000000000void func() { std::cout << "This is a function that fails to compile if iostream is not included." << std::endl; } int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/124 test skip/0000755000175000017500000000000013100703042022020 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/124 test skip/test_skip.c0000644000175000017500000000006113020525005024170 0ustar jpakkanejpakkane00000000000000int main(int argc, char *argv[]) { return 77; } meson-0.40.1/test cases/common/124 test skip/meson.build0000644000175000017500000000016313100702361024165 0ustar jpakkanejpakkane00000000000000project('test skip', 'c') exe_test_skip = executable('test_skip', 'test_skip.c') test('test_skip', exe_test_skip) meson-0.40.1/test cases/common/84 extract from nested subdir/0000755000175000017500000000000013100703044025153 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/84 extract from nested subdir/meson.build0000644000175000017500000000024313100702332027313 0ustar jpakkanejpakkane00000000000000project('Extract objects from subdirs.', 'c') if meson.is_unity() message('Unity build: skipping incompatible test') else subdir('src') subdir('tst') endif meson-0.40.1/test cases/common/84 extract from nested subdir/tst/0000755000175000017500000000000013100703044025765 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/84 extract from nested subdir/tst/first/0000755000175000017500000000000013100703044027114 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/84 extract from nested subdir/tst/first/meson.build0000644000175000017500000000021012650745767031302 0ustar jpakkanejpakkane00000000000000first_exe = executable('first_exe', 'exe_first.c', objects : first_lib.extract_objects('lib_first.c')) test('first_test', first_exe) meson-0.40.1/test cases/common/84 extract from nested subdir/tst/first/exe_first.c0000644000175000017500000000007112650745767031301 0ustar jpakkanejpakkane00000000000000int first(void); int main() { return first() - 1001; } meson-0.40.1/test cases/common/84 extract from nested subdir/tst/meson.build0000644000175000017500000000002012650745767030152 0ustar jpakkanejpakkane00000000000000subdir('first') meson-0.40.1/test cases/common/84 extract from nested subdir/src/0000755000175000017500000000000013100703044025742 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/84 extract from nested subdir/src/first/0000755000175000017500000000000013100703044027071 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/84 extract from nested subdir/src/first/meson.build0000644000175000017500000000006712650745767031271 0ustar jpakkanejpakkane00000000000000first_lib = shared_library('first_lib', 'lib_first.c') meson-0.40.1/test cases/common/84 extract from nested subdir/src/first/lib_first.c0000644000175000017500000000003612650745767031244 0ustar jpakkanejpakkane00000000000000int first() { return 1001; } meson-0.40.1/test cases/common/84 extract from nested subdir/src/meson.build0000644000175000017500000000002012650745767030127 0ustar jpakkanejpakkane00000000000000subdir('first') meson-0.40.1/test cases/common/94 default options/0000755000175000017500000000000013100703044023142 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/94 default options/meson.build0000644000175000017500000000241613100702337025313 0ustar jpakkanejpakkane00000000000000project('default options', 'cpp', 'c', default_options : [ 'prefix=/absoluteprefix', 'buildtype=debugoptimized', 'cpp_std=c++11', 'cpp_eh=none', 'warning_level=3', ]) cpp_id = meson.get_compiler('cpp').get_id() assert(get_option('buildtype') == 'debugoptimized', 'Build type default value wrong.') if cpp_id == 'msvc' cpp_eh = get_option('cpp_eh') assert(cpp_eh == 'none', 'MSVC eh value is "' + cpp_eh + '" instead of "none"') else cpp_std = get_option('cpp_std') assert(cpp_std == 'c++11', 'C++ std value is "' + cpp_std + '" instead of c++11.') endif w_level = get_option('warning_level') assert(w_level == '3', 'warning level "' + w_level + '" instead of "3"') # FIXME. Since we no longer accept invalid options to c_std etc, # there is no simple way to test this. Gcc does not seem to expose # the C std used in a preprocessor token so we can't check for it. # Think of a way to fix this. # # # Verify that project args are not used when told not to. # # MSVC plain C does not have a simple arg to test so skip it. # if cpp.get_id() != 'msvc' # cc = meson.get_compiler('c') # assert(not cc.compiles('int foobar;'), 'Default arg not used in test.') # assert(cc.compiles('int foobar;', no_builtin_args : true), 'No_builtin did not disable builtins.') # endif meson-0.40.1/test cases/common/100 test workdir/0000755000175000017500000000000013100703042022525 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/100 test workdir/meson.build0000644000175000017500000000024413100702343024672 0ustar jpakkanejpakkane00000000000000project('test workdir', 'c') exe = executable('opener', 'opener.c') test('basic', exe, workdir : meson.source_root()) test('shouldfail', exe, should_fail : true) meson-0.40.1/test cases/common/100 test workdir/opener.c0000644000175000017500000000033412650745767024216 0ustar jpakkanejpakkane00000000000000// This test only succeeds if run in the source root dir. #include int main(int arg, char **argv) { FILE *f = fopen("opener.c", "r"); if(f) { fclose(f); return 0; } return 1; } meson-0.40.1/test cases/common/47 options/0000755000175000017500000000000013100703043021532 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/47 options/meson.build0000644000175000017500000000060113100702305023671 0ustar jpakkanejpakkane00000000000000project('options', 'c') if get_option('testoption') != 'optval' error('Incorrect value to test option') endif if get_option('other_one') != false error('Incorrect value to boolean option.') endif if get_option('combo_opt') != 'combo' error('Incorrect value to combo option.') endif if get_option('includedir') != 'include' error('Incorrect value in builtin option.') endif meson-0.40.1/test cases/common/47 options/meson_options.txt0000644000175000017500000000036012650745767025222 0ustar jpakkanejpakkane00000000000000option('testoption', type : 'string', value : 'optval', description : 'An option to do something') option('other_one', type : 'boolean', value : false) option('combo_opt', type : 'combo', choices : ['one', 'two', 'combo'], value : 'combo') meson-0.40.1/test cases/common/120 subdir subproject/0000755000175000017500000000000013100703042023537 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/120 subdir subproject/subprojects/0000755000175000017500000000000013100703042026102 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/120 subdir subproject/subprojects/sub/0000755000175000017500000000000013100703042026673 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/120 subdir subproject/subprojects/sub/sub.c0000644000175000017500000000005313012152443027633 0ustar jpakkanejpakkane00000000000000#include "sub.h" int sub() { return 0; } meson-0.40.1/test cases/common/120 subdir subproject/subprojects/sub/meson.build0000644000175000017500000000022413012152443031040 0ustar jpakkanejpakkane00000000000000project('sub', 'c') lib = static_library('sub', 'sub.c') libSub = declare_dependency(include_directories: include_directories('.'), link_with: lib) meson-0.40.1/test cases/common/120 subdir subproject/subprojects/sub/sub.h0000644000175000017500000000006013012152443027636 0ustar jpakkanejpakkane00000000000000#ifndef SUB_H #define SUB_H int sub(); #endif meson-0.40.1/test cases/common/120 subdir subproject/meson.build0000644000175000017500000000004413100702360025701 0ustar jpakkanejpakkane00000000000000project('proj', 'c') subdir('prog') meson-0.40.1/test cases/common/120 subdir subproject/prog/0000755000175000017500000000000013100703042024506 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/120 subdir subproject/prog/meson.build0000644000175000017500000000024313012152443026654 0ustar jpakkanejpakkane00000000000000subproject('sub') libSub = dependency('sub', fallback: ['sub', 'libSub']) exe = executable('prog', 'prog.c', dependencies: libSub) test('subdir subproject', exe) meson-0.40.1/test cases/common/120 subdir subproject/prog/prog.c0000644000175000017500000000006013012152443025622 0ustar jpakkanejpakkane00000000000000#include int main() { return sub(); } meson-0.40.1/test cases/common/127 cpp and asm/0000755000175000017500000000000013100703042022163 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/127 cpp and asm/symbol-underscore.h0000644000175000017500000000017313070746245026033 0ustar jpakkanejpakkane00000000000000#if defined(MESON_TEST__UNDERSCORE_SYMBOL) # define SYMBOL_NAME(name) _##name #else # define SYMBOL_NAME(name) name #endif meson-0.40.1/test cases/common/127 cpp and asm/trivial.cc0000644000175000017500000000043413024065327024161 0ustar jpakkanejpakkane00000000000000#include extern "C" { int get_retval(void); } int main(int argc, char **argv) { std::cout << "C++ seems to be working." << std::endl; #if defined(USE_ASM) return get_retval(); #elif defined(NO_USE_ASM) return 0; #else #error "Forgot to pass asm define" #endif } meson-0.40.1/test cases/common/127 cpp and asm/meson.build0000644000175000017500000000130613100702365024334 0ustar jpakkanejpakkane00000000000000project('c++ and assembly test', 'cpp') cpp = meson.get_compiler('cpp') cpu = host_machine.cpu_family() supported_cpus = ['arm', 'x86', 'x86_64'] if not supported_cpus.contains(cpu) error('MESON_SKIP_TEST unsupported cpu:' + cpu) endif if cpp.symbols_have_underscore_prefix() add_project_arguments('-DMESON_TEST__UNDERSCORE_SYMBOL', language : 'cpp') endif sources = ['trivial.cc'] # If the compiler cannot compile assembly, don't use it if meson.get_compiler('cpp').get_id() != 'msvc' sources += ['retval-' + cpu + '.S'] cpp_args = ['-DUSE_ASM'] message('Using ASM') else cpp_args = ['-DNO_USE_ASM'] endif exe = executable('trivialprog', sources, cpp_args : cpp_args) test('runtest', exe) meson-0.40.1/test cases/common/127 cpp and asm/retval-x86_64.S0000644000175000017500000000016613024065327024557 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" .text .globl SYMBOL_NAME(get_retval) SYMBOL_NAME(get_retval): xorl %eax, %eax retq meson-0.40.1/test cases/common/127 cpp and asm/retval-arm.S0000644000175000017500000000016713024065327024401 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" .text .globl SYMBOL_NAME(get_retval) SYMBOL_NAME(get_retval): mov r0, #0 mov pc, lr meson-0.40.1/test cases/common/127 cpp and asm/retval-x86.S0000644000175000017500000000016613024065327024246 0ustar jpakkanejpakkane00000000000000#include "symbol-underscore.h" .text .globl SYMBOL_NAME(get_retval) SYMBOL_NAME(get_retval): xorl %eax, %eax retl meson-0.40.1/test cases/common/19 comparison/0000755000175000017500000000000013100703043022210 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/19 comparison/meson.build0000644000175000017500000000111713100702267024361 0ustar jpakkanejpakkane00000000000000project('comparison', 'c') var1 = 'foo' var2 = 'bar' if var1 == var2 exe1 = executable('broken', 'broken.c') else exe1 = executable('prog1', 'prog.c') endif if var1 == var1 exe2 = executable('prog2', 'prog.c') else exe2 = executable('broken', 'broken.c') endif if var1 != var2 exe3 = executable('prog3', 'prog.c') else exe3 = executable('broken', 'broken.c') endif if var1 != var1 exe4 = executable('broken', 'broken.c') else exe4 = executable('prog4', 'prog.c') endif test('equalfalse', exe1) test('equaltrue', exe2) test('nequaltrue', exe3) test('nequalfalse', exe4) meson-0.40.1/test cases/common/19 comparison/prog.c0000644000175000017500000000005612650745767023360 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/66 install subdir/0000755000175000017500000000000013100703043022757 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/66 install subdir/installed_files.txt0000644000175000017500000000015212723634706026702 0ustar jpakkanejpakkane00000000000000usr/share/sub1/data1.dat usr/share/sub1/second.dat usr/share/sub1/third.dat usr/share/sub1/sub2/data2.dat meson-0.40.1/test cases/common/66 install subdir/meson.build0000644000175000017500000000043013100702317025121 0ustar jpakkanejpakkane00000000000000project('install a whole subdir', 'c') subdir('subdir') # A subdir with write perms only for the owner # and read-list perms for owner and group install_subdir('sub1', install_dir : 'share', install_mode : ['rwxr-x--t', 'root']) install_subdir('sub/sub1', install_dir : 'share') meson-0.40.1/test cases/common/66 install subdir/subdir/0000755000175000017500000000000013100703043024247 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/66 install subdir/subdir/meson.build0000644000175000017500000000023013043224360026412 0ustar jpakkanejpakkane00000000000000install_subdir('sub1', install_dir : 'share', # This mode will be overriden by the mode set in the outer install_subdir install_mode : 'rwxr-x---') meson-0.40.1/test cases/common/66 install subdir/subdir/sub1/0000755000175000017500000000000013100703043025121 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/66 install subdir/subdir/sub1/data1.dat0000644000175000017500000000004112650745767026634 0ustar jpakkanejpakkane00000000000000This is a data file in a subdir. meson-0.40.1/test cases/common/66 install subdir/subdir/sub1/sub2/0000755000175000017500000000000013100703043025774 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/66 install subdir/subdir/sub1/sub2/data2.dat0000644000175000017500000000005012650745767027510 0ustar jpakkanejpakkane00000000000000This is a data file in a deeper subdir. meson-0.40.1/test cases/common/66 install subdir/sub/0000755000175000017500000000000013100703042023547 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/66 install subdir/sub/sub1/0000755000175000017500000000000013100703043024422 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/66 install subdir/sub/sub1/third.dat0000644000175000017500000000005012723634706026244 0ustar jpakkanejpakkane00000000000000This is a third data file for sub1 dir. meson-0.40.1/test cases/common/66 install subdir/sub1/0000755000175000017500000000000013100703043023631 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/66 install subdir/sub1/second.dat0000644000175000017500000000006612723634706025623 0ustar jpakkanejpakkane00000000000000Test that multiple install_subdirs meld their results.meson-0.40.1/test cases/common/73 vcstag/0000755000175000017500000000000013100703043021325 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/73 vcstag/vcstag.c.in0000644000175000017500000000004312650745767023416 0ustar jpakkanejpakkane00000000000000const char *vcstag = "@VCS_TAG@"; meson-0.40.1/test cases/common/73 vcstag/meson.build0000644000175000017500000000057513100702323023476 0ustar jpakkanejpakkane00000000000000project('vcstag', 'c') version_src = vcs_tag(input : 'vcstag.c.in', output : 'vcstag.c', fallback : '1.0.0') version_src_custom = vcs_tag(input : 'vcstag.c.in', output : 'vcstag-custom.c', command : ['git', 'show-ref', '-s', 'refs/heads/master'], fallback : '1.0.0') executable('tagprog', 'tagprog.c', version_src) executable('tagprog-custom', 'tagprog.c', version_src_custom) meson-0.40.1/test cases/common/73 vcstag/tagprog.c0000644000175000017500000000020212650745767023162 0ustar jpakkanejpakkane00000000000000#include const char *vcstag; int main(int argc, char **argv) { printf("Version is %s\n", vcstag); return 0; } meson-0.40.1/test cases/common/101 suites/0000755000175000017500000000000013100703042021421 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/101 suites/subprojects/0000755000175000017500000000000013100703042023764 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/101 suites/subprojects/sub/0000755000175000017500000000000013100703042024555 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/101 suites/subprojects/sub/sub1.c0000644000175000017500000000014612650745767025631 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("I am test sub1.\n"); return 0; } meson-0.40.1/test cases/common/101 suites/subprojects/sub/meson.build0000644000175000017500000000025112650745767026752 0ustar jpakkanejpakkane00000000000000project('subproject test suites', 'c') sub1 = executable('sub1', 'sub1.c') sub2 = executable('sub2', 'sub2.c') test('sub1', sub1) test('sub2', sub2, suite : 'suite2') meson-0.40.1/test cases/common/101 suites/subprojects/sub/sub2.c0000644000175000017500000000014612650745767025632 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("I am test sub2.\n"); return 0; } meson-0.40.1/test cases/common/101 suites/exe2.c0000644000175000017500000000014612650745767022466 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("I am test exe2.\n"); return 0; } meson-0.40.1/test cases/common/101 suites/meson.build0000644000175000017500000000031513100702344023566 0ustar jpakkanejpakkane00000000000000project('multiple test suites', 'c') subproject('sub') exe1 = executable('exe1', 'exe1.c') exe2 = executable('exe2', 'exe2.c') test('exe1', exe1) test('exe2', exe2, suite : ['suite2', 'super-special']) meson-0.40.1/test cases/common/101 suites/exe1.c0000644000175000017500000000014612650745767022465 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("I am test exe1.\n"); return 0; } meson-0.40.1/test cases/common/63 array methods/0000755000175000017500000000000013100703043022577 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/63 array methods/meson.build0000644000175000017500000000151013100702316024740 0ustar jpakkanejpakkane00000000000000project('array methods', 'c') empty = [] one = ['abc'] two = ['def', 'ghi'] combined = [empty, one, two] if empty.contains('abc') error('Empty is not empty.') endif if one.contains('a') error('One claims to contain a') endif if not one.contains('abc') error('One claims to not contain abc.') endif if one.contains('abcd') error('One claims to contain abcd.') endif if two.contains('abc') error('Two claims to contain abc.') endif if not two.contains('def') error('Two claims not to contain def.') endif if not two.contains('ghi') error('Two claims not to contain ghi.') endif if two.contains('defg') error('Two claims to contain defg.') endif if not combined.contains('abc') error('Combined claims not to contain abc.') endif if not combined.contains('ghi') error('Combined claims not to contain ghi.') endif meson-0.40.1/test cases/common/11 subdir/0000755000175000017500000000000013100703042021315 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/11 subdir/meson.build0000644000175000017500000000005513100702262023462 0ustar jpakkanejpakkane00000000000000project('subdir test', 'c') subdir('subdir') meson-0.40.1/test cases/common/11 subdir/subdir/0000755000175000017500000000000013100703042022605 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/11 subdir/subdir/meson.build0000644000175000017500000000003512650745767025002 0ustar jpakkanejpakkane00000000000000executable('prog', 'prog.c') meson-0.40.1/test cases/common/11 subdir/subdir/prog.c0000644000175000017500000000005612650745767023756 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/12 data/0000755000175000017500000000000013100703042020737 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/12 data/installed_files.txt0000644000175000017500000000026313043224360024651 0ustar jpakkanejpakkane00000000000000usr/share/progname/datafile.dat usr/share/progname/fileobject_datafile.dat usr/share/progname/vanishing.dat usr/share/progname/vanishing2.dat etc/etcfile.dat usr/bin/runscript.sh meson-0.40.1/test cases/common/12 data/vanishing/0000755000175000017500000000000013100703042022725 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/12 data/vanishing/meson.build0000644000175000017500000000011012650745767025114 0ustar jpakkanejpakkane00000000000000install_data(sources : 'vanishing.dat', install_dir : 'share/progname') meson-0.40.1/test cases/common/12 data/vanishing/vanishing.dat0000644000175000017500000000006712650745767025445 0ustar jpakkanejpakkane00000000000000This is a data file to be installed in a subdirectory. meson-0.40.1/test cases/common/12 data/vanishing/vanishing2.dat0000644000175000017500000000023612703007422025477 0ustar jpakkanejpakkane00000000000000This is a data file to be installed in a subdirectory. It is installed from a different subdir to test that the installer strips the source tree dir prefix. meson-0.40.1/test cases/common/12 data/meson.build0000644000175000017500000000122613100702263023106 0ustar jpakkanejpakkane00000000000000project('data install test', 'c') install_data(sources : 'datafile.dat', install_dir : 'share/progname') # Some file in /etc that is only read-write by root; add a sticky bit for testing install_data(sources : 'etcfile.dat', install_dir : '/etc', install_mode : 'rw------T') # Some script that needs to be executable by the group install_data('runscript.sh', install_dir : get_option('bindir'), install_mode : ['rwxr-sr-x', 'root', 0]) install_data(files('fileobject_datafile.dat'), install_dir : 'share/progname', install_mode : [false, false, 0]) subdir('vanishing') install_data(sources : 'vanishing/vanishing2.dat', install_dir : 'share/progname') meson-0.40.1/test cases/common/12 data/fileobject_datafile.dat0000644000175000017500000000007113016624375025407 0ustar jpakkanejpakkane00000000000000This is a data file that is installed via a File object. meson-0.40.1/test cases/common/12 data/etcfile.dat0000644000175000017500000000004012650745767023073 0ustar jpakkanejpakkane00000000000000This goes into /etc/etcfile.dat meson-0.40.1/test cases/common/12 data/datafile.dat0000644000175000017500000000002412650745767023233 0ustar jpakkanejpakkane00000000000000this is a data file meson-0.40.1/test cases/common/12 data/runscript.sh0000644000175000017500000000003413043224360023330 0ustar jpakkanejpakkane00000000000000#!/bin/sh echo "Runscript" meson-0.40.1/test cases/common/75 should fail/0000755000175000017500000000000013100703043022232 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/75 should fail/meson.build0000644000175000017500000000015413100702324024375 0ustar jpakkanejpakkane00000000000000project('should fail', 'c') exe = executable('prog', 'failing.c') test('failing', exe, should_fail : true) meson-0.40.1/test cases/common/75 should fail/failing.c0000644000175000017500000000006212650745767024041 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 1; } meson-0.40.1/test cases/common/136 build by default targets in tests/0000755000175000017500000000000013100703043026361 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/136 build by default targets in tests/main.c0000644000175000017500000000006213043224360027455 0ustar jpakkanejpakkane00000000000000int main (int argc, char *argv[]) { return 0; } meson-0.40.1/test cases/common/136 build by default targets in tests/meson.build0000644000175000017500000000164413100702371030533 0ustar jpakkanejpakkane00000000000000project('unit-test', 'c', version : '1.0') write_file = find_program('write_file.py') # A test that consumes and verifies the output generated by a custom target. # Should work even if target is not built by default. Makes sure that foo.out # is actually created before the test command that uses foo_out is run. foo_out = custom_target('foo.out', output : 'foo.out', command : [write_file, '@OUTPUT@']) # Also verify that a build_by_default : false BuildTarget added to a test is # built before the test is run. exe_out = executable('out', 'main.c', build_by_default : false) py_file_exists = '''import os, sys if not os.path.exists(sys.argv[1]) or not os.path.exists(sys.argv[2]): print("could not find {!r} or {!r} in {!r}" "".format(sys.argv[1], sys.argv[2], os.getcwd())) sys.exit(1)''' python = import('python3').find_python() test('output-check', python, args : ['-c', py_file_exists, foo_out, exe_out]) meson-0.40.1/test cases/common/136 build by default targets in tests/write_file.py0000644000175000017500000000013213043224360031066 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys with open(sys.argv[1], 'w') as f: f.write('Test') meson-0.40.1/test cases/common/56 custom target/0000755000175000017500000000000013100703043022620 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/56 custom target/installed_files.txt0000644000175000017500000000002412650745767026552 0ustar jpakkanejpakkane00000000000000usr/subdir/data.dat meson-0.40.1/test cases/common/56 custom target/meson.build0000644000175000017500000000122013100702312024753 0ustar jpakkanejpakkane00000000000000project('custom target', 'c') python = find_program('python3', required : false) if not python.found() python = find_program('python') endif # Note that this will not add a dependency to the compiler executable. # Code will not be rebuilt if it changes. comp = '@0@/@1@'.format(meson.current_source_dir(), 'my_compiler.py') # Test that files() in command: works. The compiler just discards it. useless = files('installed_files.txt') mytarget = custom_target('bindat', output : 'data.dat', input : 'data_source.txt', command : [python, comp, '--input=@INPUT@', '--output=@OUTPUT@', useless], install : true, install_dir : 'subdir' ) subdir('depfile') meson-0.40.1/test cases/common/56 custom target/data_source.txt0000644000175000017500000000004012650745767025700 0ustar jpakkanejpakkane00000000000000This is a text only input file. meson-0.40.1/test cases/common/56 custom target/depfile/0000755000175000017500000000000013100703043024230 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/56 custom target/depfile/meson.build0000644000175000017500000000026212763077471026421 0ustar jpakkanejpakkane00000000000000 mytarget = custom_target('depfile', output : 'dep.dat', depfile : 'dep.dat.d', command : [find_program('dep.py'), meson.current_source_dir(), '@DEPFILE@', '@OUTPUT@'], ) meson-0.40.1/test cases/common/56 custom target/depfile/dep.py0000755000175000017500000000056113043224360025365 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python import sys, os from glob import glob _, srcdir, depfile, output = sys.argv depfiles = glob(os.path.join(srcdir, '*')) quoted_depfiles = [x.replace(' ', '\ ') for x in depfiles] with open(output, 'w') as f: f.write('I am the result of globbing.') with open(depfile, 'w') as f: f.write('%s: %s\n' % (output, ' '.join(quoted_depfiles))) meson-0.40.1/test cases/common/56 custom target/my_compiler.py0000755000175000017500000000113613055371450025531 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import os import sys assert(os.path.exists(sys.argv[3])) args = sys.argv[:-1] if __name__ == '__main__': if len(args) != 3 or not args[1].startswith('--input') or \ not args[2].startswith('--output'): print(args[0], '--input=input_file --output=output_file') sys.exit(1) with open(args[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(args[2].split('=')[1], 'w') as ofile: ofile.write('This is a binary output file.\n') meson-0.40.1/test cases/common/55 file grabber/0000755000175000017500000000000013100703043022342 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/55 file grabber/grabber2.bat0000644000175000017500000000007512650745767024556 0ustar jpakkanejpakkane00000000000000@ECHO OFF echo suba.c echo subb.c echo subc.c echo subprog.c meson-0.40.1/test cases/common/55 file grabber/grabber.sh0000755000175000017500000000005312650745767024337 0ustar jpakkanejpakkane00000000000000#!/bin/sh for i in *.c; do echo $i done meson-0.40.1/test cases/common/55 file grabber/c.c0000644000175000017500000000003212650745767022757 0ustar jpakkanejpakkane00000000000000int funcc() { return 0; } meson-0.40.1/test cases/common/55 file grabber/meson.build0000644000175000017500000000167513100702312024513 0ustar jpakkanejpakkane00000000000000project('grabber', 'c') # What this script does is NOT reliable. Simply adding a file in this directory # will NOT make it automatically appear in the build. You have to manually # re-invoke Meson (not just Ninja) for that to happen. The simplest way # is to touch meson-private/coredata.dat. # This is not the recommended way to do things, but if the tradeoffs are # acceptable to you, then we're certainly not going to stop you. Just don't # file bugs when it fails. :) if build_machine.system() == 'windows' c = run_command('grabber.bat') grabber = find_program('grabber2.bat') else c = run_command('grabber.sh') grabber = find_program('grabber.sh') endif # First test running command explicitly. if c.returncode() != 0 error('Executing script failed.') endif newline = ''' ''' sources = c.stdout().strip().split(newline) e = executable('prog', sources) test('grabtest', e) # Then test using program with find_program subdir('subdir') meson-0.40.1/test cases/common/55 file grabber/b.c0000644000175000017500000000003212650745767022756 0ustar jpakkanejpakkane00000000000000int funcb() { return 0; } meson-0.40.1/test cases/common/55 file grabber/subdir/0000755000175000017500000000000013100703043023632 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/55 file grabber/subdir/meson.build0000644000175000017500000000021212650745767026023 0ustar jpakkanejpakkane00000000000000sc = run_command(grabber) subsources = sc.stdout().strip().split(newline) se = executable('subprog', subsources) test('subgrabtest', se) meson-0.40.1/test cases/common/55 file grabber/subdir/subc.c0000644000175000017500000000003212650745767024761 0ustar jpakkanejpakkane00000000000000int funcc() { return 0; } meson-0.40.1/test cases/common/55 file grabber/subdir/subb.c0000644000175000017500000000003212650745767024760 0ustar jpakkanejpakkane00000000000000int funcb() { return 0; } meson-0.40.1/test cases/common/55 file grabber/subdir/subprog.c0000644000175000017500000000016412650745767025514 0ustar jpakkanejpakkane00000000000000int funca(); int funcb(); int funcc(); int main(int argc, char **argv) { return funca() + funcb() + funcc(); } meson-0.40.1/test cases/common/55 file grabber/subdir/suba.c0000644000175000017500000000003212650745767024757 0ustar jpakkanejpakkane00000000000000int funca() { return 0; } meson-0.40.1/test cases/common/55 file grabber/grabber.bat0000644000175000017500000000006112650745767024467 0ustar jpakkanejpakkane00000000000000@ECHO OFF echo a.c echo b.c echo c.c echo prog.c meson-0.40.1/test cases/common/55 file grabber/prog.c0000644000175000017500000000016412650745767023512 0ustar jpakkanejpakkane00000000000000int funca(); int funcb(); int funcc(); int main(int argc, char **argv) { return funca() + funcb() + funcc(); } meson-0.40.1/test cases/common/55 file grabber/a.c0000644000175000017500000000003212650745767022755 0ustar jpakkanejpakkane00000000000000int funca() { return 0; } meson-0.40.1/test cases/common/45 alignment/0000755000175000017500000000000013100703043022013 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/45 alignment/meson.build0000644000175000017500000000154413100702304024160 0ustar jpakkanejpakkane00000000000000project('alignment', 'c', 'cpp') compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] 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') # 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 dbl_alignment == 8 or dbl_alignment == 4 message('Alignment of double ok.') else error('Alignment of double misdetected.') endif endforeach meson-0.40.1/test cases/common/10 man install/0000755000175000017500000000000013100703042022226 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/10 man install/installed_files.txt0000644000175000017500000000017412723634706026156 0ustar jpakkanejpakkane00000000000000usr/share/man/man1/foo.1.gz usr/share/man/man2/bar.2.gz usr/share/man/man1/vanishing.1.gz usr/share/man/man2/vanishing.2.gz meson-0.40.1/test cases/common/10 man install/vanishing/0000755000175000017500000000000013100703042024214 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/10 man install/vanishing/meson.build0000644000175000017500000000003312650745767026407 0ustar jpakkanejpakkane00000000000000install_man('vanishing.1') meson-0.40.1/test cases/common/10 man install/vanishing/vanishing.20000644000175000017500000000007112723634706026307 0ustar jpakkanejpakkane00000000000000This is a second man page of the vanishing subdirectory. meson-0.40.1/test cases/common/10 man install/vanishing/vanishing.10000644000175000017500000000006212650745767026317 0ustar jpakkanejpakkane00000000000000This is a man page of the vanishing subdirectory. meson-0.40.1/test cases/common/10 man install/meson.build0000644000175000017500000000021113100702262024365 0ustar jpakkanejpakkane00000000000000project('man install', 'c') m1 = install_man('foo.1') m2 = install_man('bar.2') install_man('vanishing/vanishing.2') subdir('vanishing') meson-0.40.1/test cases/common/10 man install/bar.20000644000175000017500000000007012650745767023107 0ustar jpakkanejpakkane00000000000000this is a man page of bar.2, its contents are irrelevantmeson-0.40.1/test cases/common/10 man install/foo.10000644000175000017500000000007012650745767023125 0ustar jpakkanejpakkane00000000000000this is a man page of foo.1 its contents are irrelevant meson-0.40.1/test cases/common/93 private include/0000755000175000017500000000000013100703044023117 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/93 private include/stlib/0000755000175000017500000000000013100703044024234 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/93 private include/stlib/meson.build0000644000175000017500000000045212650745767026432 0ustar jpakkanejpakkane00000000000000genbin = find_program('compiler.py') gen = generator(genbin, output : ['@BASENAME@.h', '@BASENAME@.c'], arguments : ['@INPUT@', '@BUILD_DIR@'] ) defs = ['foo1.def', 'foo2.def'] generated = gen.process(defs) stlib = static_library('st', generated) st_priv_inc = stlib.private_dir_include() meson-0.40.1/test cases/common/93 private include/stlib/foo2.def0000644000175000017500000000000012650745767025602 0ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/93 private include/stlib/compiler.py0000755000175000017500000000101013057037314026426 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys, os assert(len(sys.argv) == 3) h_templ = '''#pragma once unsigned int %s(); ''' c_templ = '''#include"%s.h" unsigned int %s() { return 0; } ''' ifile = sys.argv[1] outdir = sys.argv[2] base = os.path.splitext(os.path.split(ifile)[-1])[0] cfile = os.path.join(outdir, base + '.c') hfile = os.path.join(outdir, base + '.h') c_code = c_templ % (base, base) h_code = h_templ % base with open(cfile, 'w') as f: f.write(c_code) with open(hfile, 'w') as f: f.write(h_code) meson-0.40.1/test cases/common/93 private include/stlib/foo1.def0000644000175000017500000000000012650745767025601 0ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/93 private include/meson.build0000644000175000017500000000007713100702337025271 0ustar jpakkanejpakkane00000000000000project('access private', 'c') subdir('stlib') subdir('user') meson-0.40.1/test cases/common/93 private include/user/0000755000175000017500000000000013100703044024075 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/93 private include/user/meson.build0000644000175000017500000000017112650745767026271 0ustar jpakkanejpakkane00000000000000exe = executable('libuser', 'libuser.c', link_with : stlib, include_directories : st_priv_inc) test('libuser', exe) meson-0.40.1/test cases/common/93 private include/user/libuser.c0000644000175000017500000000014312650745767025737 0ustar jpakkanejpakkane00000000000000#include"foo1.h" #include"foo2.h" int main(int argc, char **argv) { return foo1() + foo2(); } meson-0.40.1/test cases/common/97 selfbuilt custom/0000755000175000017500000000000013100703044023331 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/97 selfbuilt custom/meson.build0000644000175000017500000000057613100702342025503 0ustar jpakkanejpakkane00000000000000project('selfbuilt custom', 'cpp') # Build an exe and use it in a custom target # whose output is used to build a different exe. tool = executable('tool', 'tool.cpp', native : true) hfile = custom_target('datah', output : 'data.h', input : 'data.dat', command : [tool, '@INPUT@', '@OUTPUT@'], ) main = executable('mainprog', 'mainprog.cpp', hfile) test('maintest', main) meson-0.40.1/test cases/common/97 selfbuilt custom/tool.cpp0000644000175000017500000000133712650745767025051 0ustar jpakkanejpakkane00000000000000#include #include #include using namespace std; const char prefix[] = "int "; const char suffix[] = " () {\n return 52;}\n"; int main(int argc, char **argv) { if(argc != 3) { cout << "You is fail.\n"; return 1; } ifstream is(argv[1], ifstream::binary); if(!is) { cout << "Opening input file failed.\n"; return 1; } string funcname; is >> funcname; ofstream os(argv[2], ofstream::binary); if(!os) { cout << "Opening output file failed.\n"; return 1; } os << prefix << funcname << suffix; os.close(); if(!os.good()) { cout << "Writing data out failed.\n"; return 1; } return 0; } meson-0.40.1/test cases/common/97 selfbuilt custom/mainprog.cpp0000644000175000017500000000012412650745767025701 0ustar jpakkanejpakkane00000000000000#include"data.h" int main(int, char **) { return generated_function() != 52; } meson-0.40.1/test cases/common/97 selfbuilt custom/data.dat0000644000175000017500000000002312650745767024762 0ustar jpakkanejpakkane00000000000000generated_function meson-0.40.1/test cases/common/18 else/0000755000175000017500000000000013100703043020765 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/18 else/meson.build0000644000175000017500000000023513100702267023136 0ustar jpakkanejpakkane00000000000000project('else test', 'c') var = false if var exe = executable('break', 'break.c') else exe = executable('prog', 'prog.c') endif test('elsetest', exe) meson-0.40.1/test cases/common/18 else/prog.c0000644000175000017500000000005612650745767022135 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/43 has function/0000755000175000017500000000000013100703043022414 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/43 has function/meson.build0000644000175000017500000001001513100702304024552 0ustar jpakkanejpakkane00000000000000project('has function', 'c', 'cpp') host_system = host_machine.system() # This is used in the `test_compiler_check_flags_order` unit test unit_test_args = '-I/tmp' defines_has_builtin = '''#ifndef __has_builtin #error "no __has_builtin" #endif ''' compilers = [meson.get_compiler('c'), meson.get_compiler('cpp')] foreach cc : compilers if not cc.has_function('printf', prefix : '#include', args : unit_test_args) 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', args : unit_test_args), '"fprintf" function not found without include (on !msvc).') else assert(cc.has_function('fprintf', prefix : '#include ', args : unit_test_args), '"fprintf" function not found with include (on msvc).') # Compiler intrinsics assert(cc.has_function('strcmp'), 'strcmp intrinsic should have been found on MSVC') assert(cc.has_function('strcmp', prefix : '#include '), 'strcmp intrinsic should have been found with #include on MSVC') endif if cc.has_function('hfkerhisadf', prefix : '#include', args : unit_test_args) error('Found non-existent function "hfkerhisadf".') endif if cc.has_function('hfkerhisadf', args : unit_test_args) 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_system == 'linux' or host_system == 'darwin' assert (cc.has_function('poll', prefix : '#include ', args : unit_test_args), 'couldn\'t detect "poll" when defined by a header') lchmod_prefix = '#include \n#include ' if host_system == 'linux' assert (not cc.has_function('lchmod', prefix : lchmod_prefix, args : unit_test_args), '"lchmod" check should have failed') else # macOS and *BSD have lchmod assert (cc.has_function('lchmod', prefix : lchmod_prefix, args : unit_test_args), '"lchmod" check should have succeeded') endif # Check that built-ins are found properly both with and without headers assert(cc.has_function('alloca', args : unit_test_args), 'built-in alloca must be found on ' + host_system) assert(cc.has_function('alloca', prefix : '#include ', args : unit_test_args), 'built-in alloca must be found with #include') if not cc.compiles(defines_has_builtin, args : unit_test_args) assert(not cc.has_function('alloca', prefix : '#include \n#undef alloca', args : unit_test_args), 'built-in alloca must not be found with #include and #undef') endif 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', args : unit_test_args) # We assume that if recvmmsg exists sendmmsg does too assert (cc.has_function('sendmmsg', args : unit_test_args), 'Failed to detect function "sendmmsg" (should always exist).') endif endforeach meson-0.40.1/test cases/common/144 empty build file/0000755000175000017500000000000013100703043023233 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/144 empty build file/meson.build0000644000175000017500000000010413100702400025364 0ustar jpakkanejpakkane00000000000000project('subdir with empty meson.build test', 'c') subdir('subdir') meson-0.40.1/test cases/common/144 empty build file/subdir/0000755000175000017500000000000013100703043024523 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/144 empty build file/subdir/meson.build0000644000175000017500000000000013074426732026674 0ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/23 global arg/0000755000175000017500000000000013100703043022023 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/23 global arg/meson.build0000644000175000017500000000051013100702271024163 0ustar jpakkanejpakkane00000000000000project('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') test('prog1', exe1) test('prog2', exe2) meson-0.40.1/test cases/common/23 global arg/prog.cc0000644000175000017500000000035013074426732023320 0ustar jpakkanejpakkane00000000000000#ifdef MYTHING #error "Wrong global argument set" #endif #ifndef MYCPPTHING #error "Global argument not set" #endif #ifndef MYCANDCPPTHING #error "Global argument not set" #endif int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/23 global arg/prog.c0000644000175000017500000000035013074426732023155 0ustar jpakkanejpakkane00000000000000#ifndef MYTHING #error "Global argument not set" #endif #ifdef MYCPPTHING #error "Wrong global argument set" #endif #ifndef MYCANDCPPTHING #error "Global argument not set" #endif int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/common/122 skip/0000755000175000017500000000000013100703042021056 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/common/122 skip/meson.build0000644000175000017500000000011513016624375023236 0ustar jpakkanejpakkane00000000000000project('skip', 'c') error('MESON_SKIP_TEST this test is always skipped.') meson-0.40.1/test cases/rust/0000755000175000017500000000000013100703042017330 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/rust/1 basic/0000755000175000017500000000000013100703045020535 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/rust/1 basic/installed_files.txt0000644000175000017500000000005113070746245024452 0ustar jpakkanejpakkane00000000000000usr/bin/program?exe usr/bin/program2?exe meson-0.40.1/test cases/rust/1 basic/meson.build0000644000175000017500000000017013100702532022675 0ustar jpakkanejpakkane00000000000000project('rustprog', 'rust') e = executable('program', 'prog.rs', install : true) test('rusttest', e) subdir('subdir') meson-0.40.1/test cases/rust/1 basic/subdir/0000755000175000017500000000000013100703045022025 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/rust/1 basic/subdir/meson.build0000644000175000017500000000011313070746245024201 0ustar jpakkanejpakkane00000000000000e = executable('program2', 'prog.rs', install : true) test('rusttest2', e) meson-0.40.1/test cases/rust/1 basic/subdir/prog.rs0000644000175000017500000000007013070746245023356 0ustar jpakkanejpakkane00000000000000fn main() { println!("rust compiler is working"); } meson-0.40.1/test cases/rust/1 basic/prog.rs0000644000175000017500000000007012650745767022101 0ustar jpakkanejpakkane00000000000000fn main() { println!("rust compiler is working"); } meson-0.40.1/test cases/rust/3 staticlib/0000755000175000017500000000000013100703045021434 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/rust/3 staticlib/installed_files.txt0000644000175000017500000000004712742140120025337 0ustar jpakkanejpakkane00000000000000usr/bin/prog?exe usr/lib/libstuff.rlib meson-0.40.1/test cases/rust/3 staticlib/stuff.rs0000644000175000017500000000011712650745767023162 0ustar jpakkanejpakkane00000000000000#![crate_name = "stuff"] pub fn explore() -> &'static str { "librarystring" } meson-0.40.1/test cases/rust/3 staticlib/meson.build0000644000175000017500000000026513100702534023603 0ustar jpakkanejpakkane00000000000000project('rust static library', 'rust') l = static_library('stuff', 'stuff.rs', install : true) e = executable('prog', 'prog.rs', link_with : l, install : true) test('linktest', e) meson-0.40.1/test cases/rust/3 staticlib/prog.rs0000644000175000017500000000011712650745767023002 0ustar jpakkanejpakkane00000000000000extern crate stuff; fn main() { println!("printing: {}", stuff::explore()); } meson-0.40.1/test cases/rust/2 sharedlib/0000755000175000017500000000000013100703045021412 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/rust/2 sharedlib/installed_files.txt0000644000175000017500000000004712742140120025315 0ustar jpakkanejpakkane00000000000000usr/bin/prog?exe usr/lib/libstuff.rlib meson-0.40.1/test cases/rust/2 sharedlib/stuff.rs0000644000175000017500000000011712650745767023140 0ustar jpakkanejpakkane00000000000000#![crate_name = "stuff"] pub fn explore() -> &'static str { "librarystring" } meson-0.40.1/test cases/rust/2 sharedlib/meson.build0000644000175000017500000000026513100702532023557 0ustar jpakkanejpakkane00000000000000project('rust shared library', 'rust') l = shared_library('stuff', 'stuff.rs', install : true) e = executable('prog', 'prog.rs', link_with : l, install : true) test('linktest', e) meson-0.40.1/test cases/rust/2 sharedlib/prog.rs0000644000175000017500000000011712650745767022760 0ustar jpakkanejpakkane00000000000000extern crate stuff; fn main() { println!("printing: {}", stuff::explore()); } meson-0.40.1/test cases/java/0000755000175000017500000000000013100703042017254 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/1 basic/0000755000175000017500000000000013100703044020460 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/1 basic/installed_files.txt0000644000175000017500000000002313046167604024374 0ustar jpakkanejpakkane00000000000000usr/bin/myprog.jar meson-0.40.1/test cases/java/1 basic/meson.build0000644000175000017500000000031713100702477022634 0ustar jpakkanejpakkane00000000000000project('simplejava', 'java') javaprog = jar('myprog', 'com/mesonbuild/Simple.java', main_class : 'com.mesonbuild.Simple', install : true, install_dir : get_option('bindir')) test('mytest', javaprog) meson-0.40.1/test cases/java/1 basic/com/0000755000175000017500000000000013100703042021234 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/1 basic/com/mesonbuild/0000755000175000017500000000000013100703044023377 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/1 basic/com/mesonbuild/Simple.java0000644000175000017500000000022012650745767025520 0ustar jpakkanejpakkane00000000000000package com.mesonbuild; class Simple { public static void main(String [] args) { System.out.println("Java is working.\n"); } } meson-0.40.1/test cases/java/2 subdir/0000755000175000017500000000000013100703044020670 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/2 subdir/meson.build0000644000175000017500000000005513100702477023043 0ustar jpakkanejpakkane00000000000000project('subdirjava', 'java') subdir('sub') meson-0.40.1/test cases/java/2 subdir/sub/0000755000175000017500000000000013100703044021461 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/2 subdir/sub/meson.build0000644000175000017500000000032312650745767023654 0ustar jpakkanejpakkane00000000000000javaprog = jar('myprog', 'com/mesonbuild/Simple.java', 'com/mesonbuild/TextPrinter.java', main_class : 'com.mesonbuild.Simple', include_directories : include_directories('.')) test('subdirtest', javaprog) meson-0.40.1/test cases/java/2 subdir/sub/com/0000755000175000017500000000000013100703042022235 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/2 subdir/sub/com/mesonbuild/0000755000175000017500000000000013100703044024400 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/2 subdir/sub/com/mesonbuild/Simple.java0000644000175000017500000000026112650745767026526 0ustar jpakkanejpakkane00000000000000package com.mesonbuild; class Simple { public static void main(String [] args) { TextPrinter t = new TextPrinter("Printing from Java."); t.print(); } } meson-0.40.1/test cases/java/2 subdir/sub/com/mesonbuild/TextPrinter.java0000644000175000017500000000030612650745767027565 0ustar jpakkanejpakkane00000000000000package com.mesonbuild; class TextPrinter { private String msg; TextPrinter(String s) { msg = s; } public void print() { System.out.println(msg); } } meson-0.40.1/test cases/java/3 args/0000755000175000017500000000000013100703044020335 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/3 args/meson.build0000644000175000017500000000036613100702503022503 0ustar jpakkanejpakkane00000000000000project('simplejava', 'java') add_project_arguments('-target', '1.6', language : 'java') javaprog = jar('myprog', 'com/mesonbuild/Simple.java', main_class : 'com.mesonbuild.Simple', java_args : ['-source', '1.6']) test('mytest', javaprog) meson-0.40.1/test cases/java/3 args/com/0000755000175000017500000000000013100703042021111 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/3 args/com/mesonbuild/0000755000175000017500000000000013100703044023254 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/3 args/com/mesonbuild/Simple.java0000644000175000017500000000022013016624375025361 0ustar jpakkanejpakkane00000000000000package com.mesonbuild; class Simple { public static void main(String [] args) { System.out.println("Java is working.\n"); } } meson-0.40.1/test cases/java/4 inner class/0000755000175000017500000000000013100703044021603 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/4 inner class/meson.build0000644000175000017500000000022713100702503023745 0ustar jpakkanejpakkane00000000000000project('simplejava', 'java') javaprog = jar('myprog', 'com/mesonbuild/Simple.java', main_class : 'com.mesonbuild.Simple') test('mytest', javaprog) meson-0.40.1/test cases/java/4 inner class/com/0000755000175000017500000000000013100703042022357 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/4 inner class/com/mesonbuild/0000755000175000017500000000000013100703044024522 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/java/4 inner class/com/mesonbuild/Simple.java0000644000175000017500000000051313024065327026627 0ustar jpakkanejpakkane00000000000000package com.mesonbuild; class Simple { class Inner { public String getString() { return "Inner class is working.\n"; } } public static void main(String [] args) { Simple s = new Simple(); Simple.Inner ic = s.new Inner(); System.out.println(ic.getString()); } } meson-0.40.1/test cases/failing/0000755000175000017500000000000013100703042017744 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/30 nested ternary/0000755000175000017500000000000013100703044023100 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/30 nested ternary/meson.build0000644000175000017500000000007712752712447025271 0ustar jpakkanejpakkane00000000000000project('nested ternary', 'c') x = true ? (false ? 1 : 0) : 2 meson-0.40.1/test cases/failing/1 project not first/0000755000175000017500000000000013100703044023426 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/1 project not first/meson.build0000644000175000017500000000016112650745767025621 0ustar jpakkanejpakkane00000000000000var = 'assignment before project() call' project('no worky', 'c') test('not run', executable('prog', 'prog.c')) meson-0.40.1/test cases/failing/1 project not first/prog.c0000644000175000017500000000005612650745767024575 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/failing/21 subver/0000755000175000017500000000000013100703044021457 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/21 subver/subprojects/0000755000175000017500000000000013100703042024020 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/21 subver/subprojects/foo/0000755000175000017500000000000013100703044024605 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/21 subver/subprojects/foo/meson.build0000644000175000017500000000004712650745767027003 0ustar jpakkanejpakkane00000000000000project('foo', 'c', version : '1.0.0') meson-0.40.1/test cases/failing/21 subver/meson.build0000644000175000017500000000010212650745767023645 0ustar jpakkanejpakkane00000000000000project('master', 'c') x = subproject('foo', version : '>1.0.0') meson-0.40.1/test cases/failing/3 missing subdir/0000755000175000017500000000000013100703044023013 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/3 missing subdir/meson.build0000644000175000017500000000005212650745767025205 0ustar jpakkanejpakkane00000000000000project('subdir', 'c') subdir('missing') meson-0.40.1/test cases/failing/38 has function external dependency/0000755000175000017500000000000013100703044026444 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/38 has function external dependency/meson.build0000644000175000017500000000040013024065327030612 0ustar jpakkanejpakkane00000000000000project('has function ext dep', 'c') cc = meson.get_compiler('c') mylib = shared_library('mylib', 'mylib.c') mylib_dep = declare_dependency(link_with : mylib) # Only external dependencies can work here cc.has_function('malloc', dependencies : mylib_dep) meson-0.40.1/test cases/failing/38 has function external dependency/mylib.c0000644000175000017500000000004113024065327027731 0ustar jpakkanejpakkane00000000000000int testfunc(void) { return 0; } meson-0.40.1/test cases/failing/27 output subdir/0000755000175000017500000000000013100703044022770 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/27 output subdir/meson.build0000644000175000017500000000017712660161176025155 0ustar jpakkanejpakkane00000000000000project('outdir path', 'c') configure_file(input : 'foo.in', output : 'subdir/foo', configuration : configuration_data()) meson-0.40.1/test cases/failing/27 output subdir/subdir/0000755000175000017500000000000013100703044024260 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/27 output subdir/subdir/dummy.txt0000644000175000017500000000006712660161176026175 0ustar jpakkanejpakkane00000000000000I'm only here because Git is stupid about empty dirs. meson-0.40.1/test cases/failing/27 output subdir/foo.in0000644000175000017500000000001612660161176024116 0ustar jpakkanejpakkane00000000000000Nothing here. meson-0.40.1/test cases/failing/14 invalid option name/0000755000175000017500000000000013100703044023773 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/14 invalid option name/meson.build0000644000175000017500000000002412650745767026164 0ustar jpakkanejpakkane00000000000000project('foo', 'c') meson-0.40.1/test cases/failing/14 invalid option name/meson_options.txt0000644000175000017500000000007013074426732027445 0ustar jpakkanejpakkane00000000000000option('invalid:name', type : 'boolean', value : false) meson-0.40.1/test cases/failing/7 go to subproject/0000755000175000017500000000000013100703044023246 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/7 go to subproject/subprojects/0000755000175000017500000000000013100703044025611 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/7 go to subproject/subprojects/meson.build0000644000175000017500000000001012650745767027775 0ustar jpakkanejpakkane00000000000000x = 'x' meson-0.40.1/test cases/failing/7 go to subproject/meson.build0000644000175000017500000000005312650745767025441 0ustar jpakkanejpakkane00000000000000project('fff', 'c') subdir('subprojects') meson-0.40.1/test cases/failing/31 invalid man extension/0000755000175000017500000000000013100703044024331 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/31 invalid man extension/meson.build0000644000175000017500000000006712763077471026524 0ustar jpakkanejpakkane00000000000000project('man install', 'c') m1 = install_man('foo.a1') meson-0.40.1/test cases/failing/37 pkgconfig dependency impossible conditions/0000755000175000017500000000000013100703044030507 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/37 pkgconfig dependency impossible conditions/meson.build0000644000175000017500000000014613024065327032664 0ustar jpakkanejpakkane00000000000000project('impossible-dep-test', 'c', version : '1.0') dependency('zlib', version : ['>=1.0', '<1.0']) meson-0.40.1/test cases/failing/13 array arithmetic/0000755000175000017500000000000013100703044023402 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/13 array arithmetic/meson.build0000644000175000017500000000006712650745767025602 0ustar jpakkanejpakkane00000000000000project('array arithmetic', 'c') foo = ['a', 'b'] * 3 meson-0.40.1/test cases/failing/26 badlang/0000755000175000017500000000000013100703044021546 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/26 badlang/meson.build0000644000175000017500000000006612653573126023734 0ustar jpakkanejpakkane00000000000000project('badlang', 'c') add_languages('nonexisting') meson-0.40.1/test cases/failing/20 version/0000755000175000017500000000000013100703044021635 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/20 version/meson.build0000644000175000017500000000007512650745767024034 0ustar jpakkanejpakkane00000000000000project('version mismatch', 'c', meson_version : '>100.0.0') meson-0.40.1/test cases/failing/19 target clash/0000755000175000017500000000000013100703044022521 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/19 target clash/clash.c0000644000175000017500000000013712650745767024013 0ustar jpakkanejpakkane00000000000000#include int main(int argc, char **argv) { printf("Clash 2.\n"); return 0; } meson-0.40.1/test cases/failing/19 target clash/meson.build0000644000175000017500000000075213074426732024707 0ustar jpakkanejpakkane00000000000000project('clash', 'c') # This setup causes a namespace clash when two Meson targets would # produce a Ninja targets with the same name. It only works on # unix, because on Windows the target has a '.exe' suffix. # # This test might fail to work on different backends or when # output location is redirected. if host_machine.system() == 'windows' or host_machine.system() == 'cygwin' error('This is expected.') endif executable('clash', 'clash.c') run_target('clash', 'echo', 'clash 1') meson-0.40.1/test cases/failing/32 no man extension/0000755000175000017500000000000013100703044023320 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/32 no man extension/meson.build0000644000175000017500000000006412763077471025510 0ustar jpakkanejpakkane00000000000000project('man install', 'c') m1 = install_man('foo') meson-0.40.1/test cases/failing/10 out of bounds/0000755000175000017500000000000013100703044022616 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/10 out of bounds/meson.build0000644000175000017500000000005712650745767025015 0ustar jpakkanejpakkane00000000000000project('out of bounds', 'c') x = [] y = x[0] meson-0.40.1/test cases/failing/6 missing incdir/0000755000175000017500000000000013100703044022776 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/6 missing incdir/meson.build0000644000175000017500000000010712650745767025171 0ustar jpakkanejpakkane00000000000000project('missing incdir', 'c') inc = include_directories('nosuchdir') meson-0.40.1/test cases/failing/18 wrong plusassign/0000755000175000017500000000000013100703044023464 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/18 wrong plusassign/meson.build0000644000175000017500000000005112650745767025655 0ustar jpakkanejpakkane00000000000000project('false plusassign', 'c') 3 += 4 meson-0.40.1/test cases/failing/43 custom target outputs not matching install_dirs/0000755000175000017500000000000013100703044031446 5ustar jpakkanejpakkane00000000000000././@LongLink0000000000000000000000000000014700000000000011217 Lustar 00000000000000meson-0.40.1/test cases/failing/43 custom target outputs not matching install_dirs/installed_files.txtmeson-0.40.1/test cases/failing/43 custom target outputs not matching install_dirs/installed_files.t0000644000175000017500000000014013074426732035007 0ustar jpakkanejpakkane00000000000000usr/include/diff.h usr/include/first.h usr/bin/diff.sh usr/bin/second.sh opt/same.h opt/same.sh meson-0.40.1/test cases/failing/43 custom target outputs not matching install_dirs/meson.build0000644000175000017500000000064413074426732033634 0ustar jpakkanejpakkane00000000000000project('outputs not matching install_dirs', 'c') gen = find_program('generator.py') if meson.backend() != 'ninja' error('Failing manually, test is only for the ninja backend') endif custom_target('too-few-install-dirs', output : ['toofew.h', 'toofew.c', 'toofew.sh'], command : [gen, 'toofew', '@OUTDIR@'], install : true, install_dir : [join_paths(get_option('prefix'), get_option('includedir')), false]) meson-0.40.1/test cases/failing/43 custom target outputs not matching install_dirs/generator.py0000755000175000017500000000066613074426732034041 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys, os if len(sys.argv) != 3: print(sys.argv[0], '', '') name = sys.argv[1] odir = sys.argv[2] with open(os.path.join(odir, name + '.h'), 'w') as f: f.write('int func();\n') with open(os.path.join(odir, name + '.c'), 'w') as f: f.write('int main(int argc, char *argv[]) { return 0; }') with open(os.path.join(odir, name + '.sh'), 'w') as f: f.write('#!/bin/bash') meson-0.40.1/test cases/failing/42 abs subdir/0000755000175000017500000000000013100703044022172 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/42 abs subdir/meson.build0000644000175000017500000000027613055371450024354 0ustar jpakkanejpakkane00000000000000project('abs subdir', 'c') # For some reason people insist on doing this, probably # because Make has taught them to never rely on anything. subdir(join_paths(meson.source_root(), 'bob')) meson-0.40.1/test cases/failing/42 abs subdir/bob/0000755000175000017500000000000013100703044022734 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/42 abs subdir/bob/meson.build0000644000175000017500000000004413055371450025107 0ustar jpakkanejpakkane00000000000000# This file is never reached. x = 3 meson-0.40.1/test cases/failing/36 project argument after target/0000755000175000017500000000000013100703044025761 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/36 project argument after target/meson.build0000644000175000017500000000036713016624375030150 0ustar jpakkanejpakkane00000000000000project('project argument after target failing', 'c', version : '2.3.4', license : 'mylicense') add_project_arguments('-DPROJECT_OPTION', language: 'c') e = executable('exe', 'exe.c') add_project_arguments('-DPROJECT_OPTION1', language: 'c') meson-0.40.1/test cases/failing/36 project argument after target/exe.c0000644000175000017500000000006213016624375026723 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/failing/23 rel testdir/0000755000175000017500000000000013100703044022374 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/23 rel testdir/simple.c0000644000175000017500000000006212650745767024062 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/failing/23 rel testdir/meson.build0000644000175000017500000000015212650745767024567 0ustar jpakkanejpakkane00000000000000project('nonabs workdir', 'c') exe = executable('simple', 'simple.c') test('simple', exe, workdir : '.') meson-0.40.1/test cases/failing/35 dependency not-required then required/0000755000175000017500000000000013100703044027413 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/35 dependency not-required then required/meson.build0000644000175000017500000000021713016624375031574 0ustar jpakkanejpakkane00000000000000project('dep-test', 'c', version : '1.0') foo_dep = dependency('foo-bar-xyz-12.3', required : false) bar_dep = dependency('foo-bar-xyz-12.3') meson-0.40.1/test cases/failing/15 kwarg before arg/0000755000175000017500000000000013100703044023244 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/15 kwarg before arg/meson.build0000644000175000017500000000011112650745767025432 0ustar jpakkanejpakkane00000000000000project('kwarg before arg', 'c') executable(sources : 'prog.c', 'prog') meson-0.40.1/test cases/failing/15 kwarg before arg/prog.c0000644000175000017500000000005612650745767024413 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/failing/28 noprog use/0000755000175000017500000000000013100703044022241 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/28 noprog use/meson.build0000644000175000017500000000030712674573632024432 0ustar jpakkanejpakkane00000000000000project('using not found exe', 'c') nope = find_program('nonexisting', required : false) custom_target( 'aa', input: 'meson.build', output: 'foobar', command: [nope, '@INPUT@', '@OUTPUT@'] ) meson-0.40.1/test cases/failing/42 custom target plainname many inputs/0000755000175000017500000000000013100703044027112 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/42 custom target plainname many inputs/meson.build0000644000175000017500000000033513055371477031301 0ustar jpakkanejpakkane00000000000000project('plain name many inputs', 'c') catfiles = find_program('catfiles.py') custom_target('plainname-inputs', input : ['1.txt', '2.txt'], output : '@PLAINNAME@.dat', command : [catfiles, '@INPUT@', '@OUTPUT@']) meson-0.40.1/test cases/failing/42 custom target plainname many inputs/1.txt0000644000175000017500000000000213055371477030027 0ustar jpakkanejpakkane000000000000001 meson-0.40.1/test cases/failing/42 custom target plainname many inputs/catfiles.py0000644000175000017500000000027013055371477031301 0ustar jpakkanejpakkane00000000000000#!/usr/bin/env python3 import sys out = sys.argv[-1] with open(out, 'wb') as o: for infile in sys.argv[1:-1]: with open(infile, 'rb') as f: o.write(f.read()) meson-0.40.1/test cases/failing/42 custom target plainname many inputs/2.txt0000644000175000017500000000000213055371477030030 0ustar jpakkanejpakkane000000000000002 meson-0.40.1/test cases/failing/11 object arithmetic/0000755000175000017500000000000013100703044023530 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/11 object arithmetic/meson.build0000644000175000017500000000006512650745767025726 0ustar jpakkanejpakkane00000000000000project('object arithmetic', 'c') foo = '5' + meson meson-0.40.1/test cases/failing/44 project name colon/0000755000175000017500000000000013100703044023620 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/44 project name colon/meson.build0000644000175000017500000000002713076164167026004 0ustar jpakkanejpakkane00000000000000project('name with :') meson-0.40.1/test cases/failing/16 extract from subproject/0000755000175000017500000000000013100703044024714 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/16 extract from subproject/main.c0000644000175000017500000000011612650745767026035 0ustar jpakkanejpakkane00000000000000int sub_lib_method(void); int main() { return 1337 - sub_lib_method(); } meson-0.40.1/test cases/failing/16 extract from subproject/subprojects/0000755000175000017500000000000013100703042027255 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/16 extract from subproject/subprojects/sub_project/0000755000175000017500000000000013100703044031576 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/16 extract from subproject/subprojects/sub_project/sub_lib.c0000644000175000017500000000005212650745767033411 0ustar jpakkanejpakkane00000000000000int sub_lib_method() { return 1337; } meson-0.40.1/test cases/failing/16 extract from subproject/subprojects/sub_project/meson.build0000644000175000017500000000014612650745767033774 0ustar jpakkanejpakkane00000000000000project('extract subproject object -- subproject', 'c') lib = shared_library('sub_lib', 'sub_lib.c') meson-0.40.1/test cases/failing/16 extract from subproject/meson.build0000644000175000017500000000033012650745767027105 0ustar jpakkanejpakkane00000000000000project('extract subproject object', 'c') sub = subproject('sub_project') lib = sub.get_variable('lib') exe = executable('exe', 'main.c', objects : lib.extract_objects('sub_lib.c')) test('extraction test', exe) meson-0.40.1/test cases/failing/22 assert/0000755000175000017500000000000013100703044021453 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/22 assert/meson.build0000644000175000017500000000007412650745767023651 0ustar jpakkanejpakkane00000000000000project('failing assert', 'c') assert(false, 'I am fail.') meson-0.40.1/test cases/failing/12 string arithmetic/0000755000175000017500000000000013100703044023571 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/12 string arithmetic/meson.build0000644000175000017500000000006112650745767025763 0ustar jpakkanejpakkane00000000000000project('string arithmetic', 'c') foo = 'a' + 3 meson-0.40.1/test cases/failing/40 prefix absolute/0000755000175000017500000000000013100703044023246 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/40 prefix absolute/meson.build0000644000175000017500000000011413043224360025411 0ustar jpakkanejpakkane00000000000000project('prefix-abs', 'c', default_options : ['prefix=some/path/notabs']) meson-0.40.1/test cases/failing/34 non-root subproject/0000755000175000017500000000000013100703044024071 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/34 non-root subproject/meson.build0000644000175000017500000000006413012152443026236 0ustar jpakkanejpakkane00000000000000project('non-root subproject', 'c') subdir('some') meson-0.40.1/test cases/failing/34 non-root subproject/some/0000755000175000017500000000000013100703044025034 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/34 non-root subproject/some/meson.build0000644000175000017500000000011313012152443027174 0ustar jpakkanejpakkane00000000000000dependency('definitely-doesnt-exist', fallback : ['someproj', 'some_dep']) meson-0.40.1/test cases/failing/5 misplaced option/0000755000175000017500000000000013100703044023325 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/5 misplaced option/meson.build0000644000175000017500000000010312650745767025514 0ustar jpakkanejpakkane00000000000000project('misplaced option', 'c') option('dummy', type : 'string') meson-0.40.1/test cases/failing/8 recursive/0000755000175000017500000000000013100703044022105 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/8 recursive/subprojects/0000755000175000017500000000000013100703042024446 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/8 recursive/subprojects/a/0000755000175000017500000000000013100703044024670 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/8 recursive/subprojects/a/meson.build0000644000175000017500000000004712650745767027066 0ustar jpakkanejpakkane00000000000000project('a', 'c') b = subproject('b') meson-0.40.1/test cases/failing/8 recursive/subprojects/b/0000755000175000017500000000000013100703044024671 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/8 recursive/subprojects/b/meson.build0000644000175000017500000000004712650745767027067 0ustar jpakkanejpakkane00000000000000project('b', 'c') a = subproject('a') meson-0.40.1/test cases/failing/8 recursive/meson.build0000644000175000017500000000005712650745767024304 0ustar jpakkanejpakkane00000000000000project('recursive', 'c') a = subproject('a') meson-0.40.1/test cases/failing/29 no crossprop/0000755000175000017500000000000013100703044022610 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/29 no crossprop/meson.build0000644000175000017500000000011712740763357024777 0ustar jpakkanejpakkane00000000000000project('no crossprop', 'c') message(meson.get_cross_property('nonexisting')) meson-0.40.1/test cases/failing/17 same name/0000755000175000017500000000000013100703044022004 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/17 same name/meson.build0000644000175000017500000000011112650745767024172 0ustar jpakkanejpakkane00000000000000project('same name', 'c') static_library('foo', 'file.c') subdir('sub') meson-0.40.1/test cases/failing/17 same name/file.c0000644000175000017500000000003512650745767023120 0ustar jpakkanejpakkane00000000000000int func() { return 0; } meson-0.40.1/test cases/failing/17 same name/sub/0000755000175000017500000000000013100703044022575 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/17 same name/sub/meson.build0000644000175000017500000000004112650745767024765 0ustar jpakkanejpakkane00000000000000static_library('foo', 'file2.c') meson-0.40.1/test cases/failing/17 same name/sub/file2.c0000644000175000017500000000003512650745767023773 0ustar jpakkanejpakkane00000000000000int func() { return 5; } meson-0.40.1/test cases/failing/4 missing meson.build/0000755000175000017500000000000013100703044023743 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/4 missing meson.build/meson.build0000644000175000017500000000006612650745767026142 0ustar jpakkanejpakkane00000000000000project('missing meson.build', 'c') subdir('subdir') meson-0.40.1/test cases/failing/4 missing meson.build/subdir/0000755000175000017500000000000013100703044025233 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/4 missing meson.build/subdir/dummy.txt0000644000175000017500000000007312650745767027162 0ustar jpakkanejpakkane00000000000000This needs to be here because Git can't handle empty dirs. meson-0.40.1/test cases/failing/41 kwarg assign/0000755000175000017500000000000013100703044022533 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/41 kwarg assign/meson.build0000644000175000017500000000012113043224360024674 0ustar jpakkanejpakkane00000000000000project('assign in kwarg', 'c') executable('prog', 'dummy.c', args = 'prog.c') meson-0.40.1/test cases/failing/41 kwarg assign/dummy.c0000644000175000017500000000006413043224360024037 0ustar jpakkanejpakkane00000000000000const char* dummy() { return "I do nothing."; } meson-0.40.1/test cases/failing/41 kwarg assign/prog.c0000644000175000017500000000006213043224360023651 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/failing/33 exe static shared/0000755000175000017500000000000013100703044023434 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/33 exe static shared/meson.build0000644000175000017500000000055613001212425025602 0ustar jpakkanejpakkane00000000000000project('statchain', 'c') host_system = host_machine.system() if host_system == 'windows' or host_system == 'darwin' error('Test only fails on Linux and BSD') endif statlib = static_library('stat', 'stat.c', pic : false) shlib2 = shared_library('shr2', 'shlib2.c', link_with : statlib) exe = executable('prog', 'prog.c', link_with : shlib2) test('runtest', exe) meson-0.40.1/test cases/failing/33 exe static shared/stat.c0000644000175000017500000000004513001212425024550 0ustar jpakkanejpakkane00000000000000int statlibfunc() { return 42; } meson-0.40.1/test cases/failing/33 exe static shared/prog.c0000644000175000017500000000026513001212425024550 0ustar jpakkanejpakkane00000000000000int shlibfunc2(); int statlibfunc(); int main(int argc, char **argv) { if (statlibfunc() != 42) return 1; if (shlibfunc2() != 24) return 1; return 0; } meson-0.40.1/test cases/failing/33 exe static shared/shlib2.c0000644000175000017500000000056013001212425024762 0ustar jpakkanejpakkane00000000000000#if defined _WIN32 || defined __CYGWIN__ #define DLL_PUBLIC __declspec(dllexport) #else #if defined __GNUC__ #define DLL_PUBLIC __attribute__ ((visibility("default"))) #else #pragma message ("Compiler does not support symbol visibility.") #define DLL_PUBLIC #endif #endif int statlibfunc(void); int DLL_PUBLIC shlibfunc2(void) { return 24; } meson-0.40.1/test cases/failing/42 abspath to srcdir/0000755000175000017500000000000013100703044023450 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/42 abspath to srcdir/meson.build0000644000175000017500000000010713055371450025623 0ustar jpakkanejpakkane00000000000000project('meson', 'c') include_directories(meson.current_source_dir()) meson-0.40.1/test cases/failing/2 missing file/0000755000175000017500000000000013100703044022441 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/2 missing file/meson.build0000644000175000017500000000007612650745767024641 0ustar jpakkanejpakkane00000000000000project('missing file', 'c') executable('prog', 'missing.c') meson-0.40.1/test cases/failing/9 missing extra file/0000755000175000017500000000000013100703044023554 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/9 missing extra file/meson.build0000644000175000017500000000014012650745767025744 0ustar jpakkanejpakkane00000000000000project('missing extra file', 'c') executable('myprog', 'prog.c', extra_files : 'missing.txt') meson-0.40.1/test cases/failing/9 missing extra file/prog.c0000644000175000017500000000006212650745767024720 0ustar jpakkanejpakkane00000000000000int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/failing/25 int conversion/0000755000175000017500000000000013100703044023115 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/25 int conversion/meson.build0000644000175000017500000000006612653573126025303 0ustar jpakkanejpakkane00000000000000project('int conversion', 'c') 'notanumber'.to_int() meson-0.40.1/test cases/failing/39 libdir must be inside prefix/0000755000175000017500000000000013100703044025461 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/failing/39 libdir must be inside prefix/meson.build0000644000175000017500000000010713043224360027626 0ustar jpakkanejpakkane00000000000000project('libdir prefix', 'c', default_options : ['libdir=/opt/lib']) meson-0.40.1/test cases/objc/0000755000175000017500000000000013100703042017250 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/objc/1 simple/0000755000175000017500000000000013100703045020665 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/objc/1 simple/prog.m0000644000175000017500000000010312650745767022036 0ustar jpakkanejpakkane00000000000000#import int main(int argc, char **argv) { return 0; }meson-0.40.1/test cases/objc/1 simple/meson.build0000644000175000017500000000013113100702547023030 0ustar jpakkanejpakkane00000000000000project('objective c', 'objc') exe = executable('prog', 'prog.m') test('objctest', exe) meson-0.40.1/test cases/objc/2 nsstring/0000755000175000017500000000000013100703045021244 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/objc/2 nsstring/stringprog.m0000644000175000017500000000026012650745767023650 0ustar jpakkanejpakkane00000000000000#import int main(int argc, char **argv) { int result; NSString *str = [NSString new]; result = [str length]; [str release]; return result; } meson-0.40.1/test cases/objc/2 nsstring/meson.build0000644000175000017500000000101713100702547023413 0ustar jpakkanejpakkane00000000000000project('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' error('MESON_SKIP_TEST: GNUstep is broken on Linux with Clang') endif endif exe = executable('stringprog', 'stringprog.m', dependencies : dep) test('stringtest', exe) meson-0.40.1/test cases/objc/3 objc++/0000755000175000017500000000000013100703045020441 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/objc/3 objc++/meson.build0000644000175000017500000000014213100702550022600 0ustar jpakkanejpakkane00000000000000project('Objective C++', 'objcpp') exe = executable('objcppprog', 'prog.mm') test('objcpp', exe) meson-0.40.1/test cases/objc/3 objc++/prog.mm0000644000175000017500000000012712650745767021775 0ustar jpakkanejpakkane00000000000000#import class MyClass { }; int main(int argc, char **argv) { return 0; } meson-0.40.1/test cases/frameworks/0000755000175000017500000000000013100703042020513 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/frameworks/14 doxygen/0000755000175000017500000000000013100703044022377 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/frameworks/14 doxygen/installed_files.txt0000644000175000017500000000710613057100622026311 0ustar jpakkanejpakkane00000000000000usr/share/doc/spede/html/annotated.html usr/share/doc/spede/html/arrowdown.png usr/share/doc/spede/html/arrowright.png usr/share/doc/spede/html/bc_s.png usr/share/doc/spede/html/bdwn.png usr/share/doc/spede/html/classComedy_1_1Comedian.html usr/share/doc/spede/html/classComedy_1_1Comedian.png usr/share/doc/spede/html/classComedy_1_1Comedian-members.html usr/share/doc/spede/html/classComedy_1_1Spede.html usr/share/doc/spede/html/classComedy_1_1Spede.png usr/share/doc/spede/html/classComedy_1_1Spede-members.html usr/share/doc/spede/html/classes.html usr/share/doc/spede/html/closed.png usr/share/doc/spede/html/comedian_8h_source.html usr/share/doc/spede/html/dir_7bdce917e28dfbd493cadd1d2e5c7d80.html usr/share/doc/spede/html/dir_44a4667d36a4476878de085754f6d2b9.html usr/share/doc/spede/html/dir_68b523c5b3a2dcea45d5ce70397fb722.html usr/share/doc/spede/html/dir_a7e6472d2301212032fd74682f8217f3.html usr/share/doc/spede/html/dir_ee191f21c02d247cc959e80c1a3acadf.html usr/share/doc/spede/html/doc.png usr/share/doc/spede/html/doxygen.css usr/share/doc/spede/html/doxygen.png usr/share/doc/spede/html/dynsections.js usr/share/doc/spede/html/files.html usr/share/doc/spede/html/folderclosed.png usr/share/doc/spede/html/folderopen.png usr/share/doc/spede/html/functions.html usr/share/doc/spede/html/functions_func.html usr/share/doc/spede/html/hierarchy.html usr/share/doc/spede/html/index.html usr/share/doc/spede/html/jquery.js usr/share/doc/spede/html/namespaceComedy.html usr/share/doc/spede/html/namespacemembers.html usr/share/doc/spede/html/namespacemembers_func.html usr/share/doc/spede/html/namespaces.html usr/share/doc/spede/html/nav_f.png usr/share/doc/spede/html/nav_g.png usr/share/doc/spede/html/nav_h.png usr/share/doc/spede/html/open.png usr/share/doc/spede/html/search/all_0.html usr/share/doc/spede/html/search/all_0.js usr/share/doc/spede/html/search/all_1.html usr/share/doc/spede/html/search/all_1.js usr/share/doc/spede/html/search/all_2.html usr/share/doc/spede/html/search/all_2.js usr/share/doc/spede/html/search/all_3.html usr/share/doc/spede/html/search/all_3.js usr/share/doc/spede/html/search/classes_0.html usr/share/doc/spede/html/search/classes_0.js usr/share/doc/spede/html/search/classes_1.html usr/share/doc/spede/html/search/classes_1.js usr/share/doc/spede/html/search/close.png usr/share/doc/spede/html/search/files_0.html usr/share/doc/spede/html/search/files_0.js usr/share/doc/spede/html/search/functions_0.html usr/share/doc/spede/html/search/functions_0.js usr/share/doc/spede/html/search/functions_1.html usr/share/doc/spede/html/search/functions_1.js usr/share/doc/spede/html/search/functions_2.html usr/share/doc/spede/html/search/functions_2.js usr/share/doc/spede/html/search/mag_sel.png usr/share/doc/spede/html/search/namespaces_0.html usr/share/doc/spede/html/search/namespaces_0.js usr/share/doc/spede/html/search/nomatches.html usr/share/doc/spede/html/search/pages_0.html usr/share/doc/spede/html/search/pages_0.js usr/share/doc/spede/html/search/search.css usr/share/doc/spede/html/search/search.js usr/share/doc/spede/html/search/searchdata.js usr/share/doc/spede/html/search/search_l.png usr/share/doc/spede/html/search/search_m.png usr/share/doc/spede/html/search/search_r.png usr/share/doc/spede/html/spede_8cpp.html usr/share/doc/spede/html/spede_8h.html usr/share/doc/spede/html/spede_8h_source.html usr/share/doc/spede/html/splitbar.png usr/share/doc/spede/html/sync_off.png usr/share/doc/spede/html/sync_on.png usr/share/doc/spede/html/tabs.css usr/share/doc/spede/html/tab_a.png usr/share/doc/spede/html/tab_b.png usr/share/doc/spede/html/tab_h.png usr/share/doc/spede/html/tab_s.png meson-0.40.1/test cases/frameworks/14 doxygen/meson.build0000644000175000017500000000061013100702474024544 0ustar jpakkanejpakkane00000000000000project('doxygen test', 'cpp', version : '0.1.0') doxygen = find_program('doxygen', required : false) if not doxygen.found() error('MESON_SKIP_TEST doxygen not found.') endif cdata = configuration_data() cdata.set('VERSION', meson.project_version()) if find_program('dot', required : false).found() cdata.set('HAVE_DOT', 'YES') else cdata.set('HAVE_DOT', 'NO') endif subdir('doc') meson-0.40.1/test cases/frameworks/14 doxygen/doc/0000755000175000017500000000000013100703044023144 5ustar jpakkanejpakkane00000000000000meson-0.40.1/test cases/frameworks/14 doxygen/doc/Doxyfile.in0000644000175000017500000032212713057037357025310 0ustar jpakkanejpakkane00000000000000# Doxyfile 1.8.13 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "The Vast Comedian Project" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = @VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = Comedy generator # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doc # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = YES # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 0. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete # parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = "@TOP_SRCDIR@/include" "@TOP_SRCDIR@/src" # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, # *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.idl \ *.ddl \ *.odl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.cs \ *.d \ *.php \ *.php4 \ *.php5 \ *.phtml \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.pyw \ *.f90 \ *.f95 \ *.f03 \ *.f08 \ *.f \ *.for \ *.tcl \ *.vhd \ *.vhdl \ *.ucf \ *.qsf # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /