diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2016-01-16 17:35:29 +0200 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2016-01-16 17:35:29 +0200 |
commit | 23b98cd6e66c6ae0f070e28e0f8b1566c0b5e585 (patch) | |
tree | e349597556abe3d22578cfb1f9529f4626ceb5aa /meson | |
parent | 1510522b1b9970376a1e1cc5f39e00d8749ec19a (diff) | |
download | meson-23b98cd6e66c6ae0f070e28e0f8b1566c0b5e585.zip meson-23b98cd6e66c6ae0f070e28e0f8b1566c0b5e585.tar.gz meson-23b98cd6e66c6ae0f070e28e0f8b1566c0b5e585.tar.bz2 |
Renamed meson package to mesonbuild so that we can have a script named meson in the same toplevel dir.
Diffstat (limited to 'meson')
42 files changed, 9 insertions, 16122 deletions
diff --git a/meson/modules/modtest.py b/meson index c9247e6..b977368 100644..100755 --- a/meson/modules/modtest.py +++ b/meson @@ -1,4 +1,6 @@ -# Copyright 2015 The Meson development team +#!/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. @@ -12,10 +14,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -class TestModule: +from mesonbuild import mesonmain +import sys, os - def print_hello(self, state, args, kwargs): - print('Hello from a Meson module') +thisfile = __file__ +if not os.path.isabs(thisfile): + thisfile = os.path.normpath(os.path.join(os.getcwd(), thisfile)) -def initialize(): - return TestModule() +sys.exit(mesonmain.run(thisfile, sys.argv[1:])) diff --git a/meson/__init__.py b/meson/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/meson/__init__.py +++ /dev/null diff --git a/meson/backends.py b/meson/backends.py deleted file mode 100644 index c583a7b..0000000 --- a/meson/backends.py +++ /dev/null @@ -1,423 +0,0 @@ -# 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 os, pickle, re -from . import build -from . import dependencies -from . import mesonlib -import json -from .coredata import MesonException - -class InstallData(): - def __init__(self, source_dir, build_dir, prefix, depfixer): - self.source_dir = source_dir - self.build_dir= build_dir - self.prefix = prefix - self.targets = [] - self.depfixer = depfixer - self.headers = [] - self.man = [] - self.data = [] - self.po_package_name = '' - self.po = [] - self.install_scripts = [] - self.install_subdirs = [] - -class TestSerialisation: - def __init__(self, name, suite, fname, is_cross, exe_wrapper, is_parallel, cmd_args, env, - should_fail, valgrind_args, 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.valgrind_args = valgrind_args - self.timeout = timeout - self.workdir = workdir - self.extra_paths = extra_paths - -# 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.dep_rules = {} - 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_compiler_for_lang(self, lang): - for i in self.build.compilers: - if i.language == lang: - return i - raise RuntimeError('No compiler for language ' + lang) - - def get_compiler_for_source(self, src): - for i in self.build.compilers: - if i.can_compile(src): - return i - if isinstance(src, mesonlib.File): - src = src.fname - raise RuntimeError('No specified compiler can handle file ' + src) - - def get_target_filename(self, target): - targetdir = self.get_target_dir(target) - fname = target.get_filename() - if isinstance(fname, list): - fname = fname[0] # HORROR, HORROR! Fix this. - filename = os.path.join(targetdir, fname) - return filename - - 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 generate_unity_files(self, target, unity_src): - langlist = {} - abs_files = [] - result = [] - for src in unity_src: - comp = self.get_compiler_for_source(src) - language = comp.get_language() - suffix = '.' + comp.get_default_suffix() - if language not in langlist: - outfilename = os.path.join(self.get_target_private_dir_abs(target), target.name + '-unity' + suffix) - outfileabs = os.path.join(self.environment.get_build_dir(), outfilename) - outfileabs_tmp = outfileabs + '.tmp' - abs_files.append(outfileabs) - outfile = open(outfileabs_tmp, 'w') - langlist[language] = outfile - result.append(outfilename) - ofile = langlist[language] - ofile.write('#include<%s>\n' % src) - [x.close() for x in langlist.values()] - [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, build.ExtractedObjects): - obj_list += self.determine_ext_objs(obj, proj_dir_to_build_root) - else: - raise MesonException('Unknown data type in object list.') - return obj_list - - def serialise_tests(self): - test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') - datafile = open(test_data, 'wb') - self.write_test_file(datafile) - datafile.close() - benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat') - datafile = open(benchmark_data, 'wb') - self.write_benchmark_file(datafile) - datafile.close() - - def has_source_suffix(self, target, suffix): - for s in target.get_sources(): - if s.endswith(suffix): - return True - return False - - def has_vala(self, target): - return self.has_source_suffix(target, '.vala') - - def has_rust(self, target): - return self.has_source_suffix(target, '.rs') - - def has_cs(self, target): - return self.has_source_suffix(target, '.cs') - - def has_swift(self, target): - return self.has_source_suffix(target, '.swift') - - def determine_linker(self, target, src): - if isinstance(target, build.StaticLibrary): - return self.build.static_linker - if len(self.build.compilers) == 1: - return self.build.compilers[0] - # Currently a bit naive. C++ must - # be linked with a C++ compiler, but - # otherwise we don't care. This will - # become trickier if and when Fortran - # and the like become supported. - cpp = None - for c in self.build.compilers: - if c.get_language() == 'cpp': - cpp = c - break - if cpp is not None: - for s in src: - if c.can_compile(s): - return cpp - for c in self.build.compilers: - if c.get_language() != 'vala': - return c - raise RuntimeError('Unreachable code') - - def determine_ext_objs(self, extobj, proj_dir_to_build_root=''): - result = [] - targetdir = self.get_target_private_dir(extobj.target) - suffix = '.' + self.environment.get_object_suffix() - for osrc in extobj.srclist: - osrc_base = osrc.fname - if not self.source_suffix_in_objs: - osrc_base = '.'.join(osrc.split('.')[:-1]) - # If extracting in a subproject, the subproject - # name gets duplicated in the file name. - pathsegs = osrc.subdir.split(os.sep) - if pathsegs[0] == 'subprojects': - pathsegs = pathsegs[2:] - fixedpath = os.sep.join(pathsegs) - objbase = osrc.fname.replace('/', '_').replace('\\', '_') - objname = os.path.join(proj_dir_to_build_root, - targetdir, os.path.basename(objbase) + suffix) - result.append(objname) - 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 - - def generate_basic_compiler_args(self, target, compiler): - commands = [] - commands += compiler.get_always_args() - if self.environment.coredata.get_builtin_option('buildtype') != 'plain': - commands += compiler.get_warn_args(self.environment.coredata.get_builtin_option('warning_level')) - commands += compiler.get_option_compile_args(self.environment.coredata.compiler_options) - commands += self.build.get_global_args(compiler) - commands += self.environment.coredata.external_args[compiler.get_language()] - commands += target.get_extra_args(compiler.get_language()) - commands += compiler.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype')) - if self.environment.coredata.get_builtin_option('coverage'): - commands += compiler.get_coverage_args() - if self.environment.coredata.get_builtin_option('werror'): - commands += compiler.get_werror_args() - if isinstance(target, build.SharedLibrary): - commands += compiler.get_pic_args() - for dep in target.get_external_deps(): - commands += dep.get_compile_args() - if isinstance(target, build.Executable): - commands += dep.get_exe_args() - - # 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) and\ - not isinstance(d, build.SharedLibrary): - raise RuntimeError('Tried to link with a non-library target "%s".' % d.get_basename()) - fname = self.get_target_filename(d) - if compiler.id == 'msvc': - if fname.endswith('dll'): - fname = fname[:-3] + 'lib' - args.append(fname) - # 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): - fname = exe.fullpath - else: - fname = [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() - if is_cross: - exe_wrapper = self.environment.cross_info.config['binaries'].get('exe_wrapper', None) - else: - exe_wrapper = None - if mesonlib.is_windows(): - extra_paths = self.determine_windows_extra_paths(exe) - else: - extra_paths = [] - cmd_args = [] - for a in t.cmd_args: - 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) - ts = TestSerialisation(t.get_name(), t.suite, fname, is_cross, exe_wrapper, - t.is_parallel, cmd_args, t.env, t.should_fail, t.valgrind_args, - 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 - open(ifilename, 'w').write(json.dumps(mfobj)) - d.data.append([ifilename, ofilename]) - - 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 \ - isinstance(exe, build.BuildTarget) and exe.is_cross: - if 'exe_wrapper' not in self.environment.cross_info: - 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 eval_custom_target_command(self, target, absolute_paths=False): - ofilenames = [os.path.join(self.get_target_dir(target), i) for i in target.output] - srcs = [] - outdir = self.get_target_dir(target) - # Many external programs fail on empty arguments. - if outdir == '': - outdir = '.' - if absolute_paths: - outdir = os.path.join(self.environment.get_build_dir(), outdir) - for i in target.sources: - if isinstance(i, str): - fname = os.path.join(self.build_to_src, target.subdir, i) - else: - fname = i.rel_to_builddir(self.build_to_src) - if absolute_paths: - fname = os.path.join(self.environment.get_build_dir(), fname) - srcs.append(fname) - cmd = [] - for i in target.command: - if isinstance(i, build.Executable): - cmd += self.exe_object_to_cmd_array(i) - continue - if isinstance(i, build.CustomTarget): - # GIR scanner will attempt to execute this binary but - # it assumes that it is in path, so always give it a full path. - tmp = i.get_filename()[0] - i = os.path.join(self.get_target_dir(i), tmp) - for (j, src) in enumerate(srcs): - i = i.replace('@INPUT%d@' % j, src) - for (j, res) in enumerate(ofilenames): - i = i.replace('@OUTPUT%d@' % j, res) - if i == '@INPUT@': - cmd += srcs - elif i == '@OUTPUT@': - cmd += ofilenames - else: - if '@OUTDIR@' in i: - i = i.replace('@OUTDIR@', outdir) - elif '@PRIVATE_OUTDIR_' in i: - match = re.search('@PRIVATE_OUTDIR_(ABS_)?([-a-zA-Z0-9.@:]*)@', i) - source = match.group(0) - if match.group(1) is None and not absolute_paths: - lead_dir = '' - else: - lead_dir = self.environment.get_build_dir() - target_id = match.group(2) - i = i.replace(source, - os.path.join(lead_dir, - outdir)) - cmd.append(i) - cmd = [i.replace('\\', '/') for i in cmd] - return (srcs, ofilenames, cmd) diff --git a/meson/build.py b/meson/build.py deleted file mode 100644 index c0ba895..0000000 --- a/meson/build.py +++ /dev/null @@ -1,969 +0,0 @@ -# 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. - -from . import coredata -from . import environment -from . import dependencies -from . import mlog -import copy, os -from .mesonlib import File, flatten - -known_basic_kwargs = {'install' : True, - 'c_pch' : True, - 'cpp_pch' : True, - 'c_args' : True, - 'cpp_args' : True, - 'cs_args' : True, - 'vala_args' : True, - 'link_args' : True, - 'link_depends': True, - 'link_with' : 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, - } - -known_shlib_kwargs = known_basic_kwargs.copy() -known_shlib_kwargs.update({'version' : True, - 'soversion' : True}) - -backslash_explanation = \ -'''Compiler arguments have a backslash "\\" character. This is unfortunately not -permitted. The reason for this is that backslash is a shell quoting character -that behaves differently across different systems. Because of this is it not -possible to make it work reliably across all the platforms Meson needs to -support. - -There are several different ways of working around this issue. Most of the time -you are using this to provide a -D define to your compiler. Try instead to -create a config.h file and put all of your definitions in it using -configure_file(). - -Another approach is to move the backslashes into the source and have the other -bits in the def. So you would have an arg -DPLAIN_TEXT="foo" and then in your -C sources something like this: - -const char *fulltext = "\\\\" PLAIN_TEXT; - -We are fully aware that these are not really usable or pleasant ways to do -this but it's the best we can do given the way shell quoting works. -''' - -class InvalidArguments(coredata.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 = {} - self.compilers = [] - self.cross_compilers = [] - self.global_args = {} - self.tests = [] - self.benchmarks = [] - self.headers = [] - self.man = [] - self.data = [] - self.static_linker = None - self.static_cross_linker = None - self.pot = [] - self.subprojects = {} - self.install_scripts = [] - self.install_dirs = [] - self.dep_manifest_name = None - self.dep_manifest = {} - - def has_language(self, language): - for i in self.compilers: - if i.get_language() == language: - return True - return False - - 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) - if self.has_language(compiler.get_language()): - return - self.compilers.append(compiler) - - def add_cross_compiler(self, compiler): - if len(self.cross_compilers) == 0: - self.static_cross_linker = self.environment.detect_static_linker(compiler) - for i in self.cross_compilers: - if i.get_language() == compiler.get_language(): - return - self.cross_compilers.append(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(), []) - -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 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(): - def __init__(self, target, srclist): - self.target = target - self.srclist = srclist - -class BuildTarget(): - def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): - self.name = name - self.subdir = subdir - self.subproject = subproject # Can not be calculated from subdir as subproject dirname can be changed per project. - self.is_cross = is_cross - self.sources = [] - self.objects = [] - self.external_deps = [] - self.include_dirs = [] - self.link_targets = [] - self.link_depends = [] - self.filename = 'no_name' - self.need_install = False - self.pch = {} - self.extra_args = {} - self.generated = [] - self.extra_files = [] - self.process_sourcelist(sources) - 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.validate_sources() - - 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 not k in known_kwargs: - unknowns.append(k) - if len(unknowns) > 0: - mlog.log(mlog.bold('Warning:'), 'Unknown keyword argument(s) in target %s: %s.' % - (self.name, ', '.join(unknowns))) - - 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): - self.objects.append(s) - elif isinstance(s, ExtractedObjects): - self.objects.append(s) - else: - raise InvalidArguments('Bad object in target %s.' % self.name) - - 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 not s in added_sources: - self.sources.append(s) - added_sources[s] = True - elif isinstance(s, GeneratedList) or isinstance(s, CustomTarget): - self.generated.append(s) - else: - raise InvalidArguments('Bad source in target %s.' % self.name) - - def validate_sources(self): - if len(self.sources) > 0: - firstname = self.sources[0] - if isinstance(firstname, File): - firstname = firstname.fname - first = os.path.split(firstname)[1] - (base, suffix) = os.path.splitext(first) - if suffix == '.rs': - if self.name != base: - raise InvalidArguments('In Rust targets, the first source file must be named projectname.rs.') - - 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, srcargs): - obj_src = [] - for srclist in srcargs: - if not isinstance(srclist, list): - srclist = [srclist] - for src in srclist: - if not isinstance(src, str): - raise coredata.MesonException('Extraction arguments must be strings.') - src = File(False, self.subdir, src) - if src not in self.sources: - raise coredata.MesonException('Tried to extract unknown source %s.' % src) - obj_src.append(src) - return ExtractedObjects(self, obj_src) - - def extract_all_objects(self): - return ExtractedObjects(self, self.sources) - - 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.custom_install_dir - - def process_kwargs(self, kwargs, environment): - 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) - 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) - 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.') - inclist = kwargs.get('include_directories', []) - if not isinstance(inclist, list): - inclist = [inclist] - self.add_include_dirs(inclist) - deplist = kwargs.get('dependencies', []) - if not isinstance(deplist, list): - deplist = [deplist] - self.add_external_deps(deplist) - 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 InvalidArguments('Custom_install_dir must be a string') - 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 - - def get_subdir(self): - return self.subdir - - def get_filename(self): - return self.filename - - def get_extra_args(self, language): - return self.extra_args.get(language, []) - - def get_dependencies(self): - transitive_deps = [] - for t in self.link_targets: - transitive_deps.append(t) - if isinstance(t, StaticLibrary): - transitive_deps += t.get_dependencies() - return transitive_deps - - def get_basename(self): - return self.name - - 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_external_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): - self.process_sourcelist(dep.sources) - self.add_include_dirs(dep.include_directories) - for l in dep.libraries: - self.link(l) - self.add_external_deps(dep.ext_deps) - elif isinstance(dep, dependencies.Dependency): - self.external_deps.append(dep) - self.process_sourcelist(dep.get_sources()) - else: - raise InvalidArguments('Argument is not an external dependency') - - 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) and \ - not isinstance(t, SharedLibrary): - raise InvalidArguments('Link target is not library.') - if self.is_cross != t.is_cross: - raise InvalidArguments('Tried to mix cross built and native libraries in target %s.' % self.name) - self.link_targets.append(t) - - def set_generated(self, genlist): - for g in genlist: - if not(isinstance(g, GeneratedList)): - raise InvalidArguments('Generated source argument is not the output of a generator.') - self.generated.append(g) - - 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 isinstance(a, str) and '\\' in a: - raise InvalidArguments(backslash_explanation) - if language in self.extra_args: - self.extra_args[language] += args - else: - self.extra_args[language] = args - - def get_aliaslist(self): - return [] - - -class Generator(): - def __init__(self, args, kwargs): - if len(args) != 1: - raise InvalidArguments('Generator requires one and only one positional argument') - - exe = args[0] - if hasattr(exe, 'held_object'): - exe = exe.held_object - if not isinstance(exe, Executable) and not isinstance(exe, dependencies.ExternalProgram): - raise InvalidArguments('First generator argument must be an executable.') - self.exe = exe - self.process_kwargs(kwargs) - - 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 not '@BASENAME@' in rule and not '@PLAINNAME@' 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 - - def get_base_outnames(self, inname): - plainname = os.path.split(inname)[1] - basename = plainname.split('.')[0] - return [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.outputs] - - def get_arglist(self): - return self.arglist - -class GeneratedList(): - def __init__(self, generator, extra_args=[]): - if hasattr(generator, 'held_object'): - generator = generator.held_object - self.generator = generator - 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) - self.outfilelist += outfiles - self.outmap[newfile] = outfiles - - def get_infilelist(self): - return self.infilelist - - def get_outfilelist(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) - self.prefix = '' - self.suffix = environment.get_exe_suffix() - suffix = environment.get_exe_suffix() - if len(self.sources) > 0 and self.sources[0].endswith('.cs'): - suffix = 'exe' - if suffix != '': - self.filename = self.name + '.' + suffix - else: - self.filename = self.name - - def type_suffix(self): - return "@exe" - -class StaticLibrary(BuildTarget): - def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): - super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs) - if len(self.sources) > 0 and self.sources[0].endswith('.cs'): - raise InvalidArguments('Static libraries not supported for C#.') - self.prefix = environment.get_static_lib_prefix() - self.suffix = environment.get_static_lib_suffix() - if len(self.sources) > 0 and self.sources[0].endswith('.rs'): - self.suffix = 'rlib' - self.filename = self.prefix + self.name + '.' + self.suffix - - def get_import_filename(self): - return self.filename - - def get_osx_filename(self): - return self.get_filename() - - def type_suffix(self): - return "@sta" - -class SharedLibrary(BuildTarget): - def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs): - self.version = None - self.soversion = None - super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs); - if len(self.sources) > 0 and self.sources[0].endswith('.cs'): - self.suffix = 'dll' - self.prefix = 'lib' - else: - self.prefix = environment.get_shared_lib_prefix() - self.suffix = environment.get_shared_lib_suffix() - if len(self.sources) > 0 and self.sources[0].endswith('.rs'): - self.suffix = 'rlib' - self.importsuffix = environment.get_import_lib_suffix() - self.filename = self.prefix + self.name + '.' + self.suffix - - def process_kwargs(self, kwargs, environment): - super().process_kwargs(kwargs, environment) - if 'version' in kwargs: - self.set_version(kwargs['version']) - if 'soversion' in kwargs: - self.set_soversion(kwargs['soversion']) - - def check_unknown_kwargs(self, kwargs): - self.check_unknown_kwargs_int(kwargs, known_shlib_kwargs) - - def get_shbase(self): - return self.prefix + self.name + '.' + self.suffix - - def get_import_filename(self): - return self.prefix + self.name + '.' + self.importsuffix - - def get_all_link_deps(self): - return [self] + self.get_transitive_link_deps() - - def get_filename(self): - '''Works on all platforms except OSX, which does its own thing.''' - fname = self.get_shbase() - if self.version is None: - return fname - else: - return fname + '.' + self.version - - def get_osx_filename(self): - if self.version is None: - return self.get_shbase() - return self.prefix + self.name + '.' + self.version + '.' + self.suffix - - def set_version(self, version): - if not isinstance(version, str): - raise InvalidArguments('Shared library version is not a string.') - self.version = version - - def set_soversion(self, version): - if isinstance(version, int): - version = str(version) - if not isinstance(version, str): - raise InvalidArguments('Shared library soversion is not a string or integer.') - self.soversion = version - - def get_aliaslist(self): - aliases = [] - if self.soversion is not None: - aliases.append(self.get_shbase() + '.' + self.soversion) - if self.version is not None: - aliases.append(self.get_shbase()) - return aliases - - def type_suffix(self): - return "@sha" - -class CustomTarget: - known_kwargs = {'input' : True, - 'output' : True, - 'command' : True, - 'install' : True, - 'install_dir' : True, - 'build_always' : True, - 'depends' : True, - 'depend_files' : True, - } - - def __init__(self, name, subdir, kwargs): - self.name = name - self.subdir = subdir - self.dependencies = [] - self.extra_depends = [] - self.depend_files = [] # Files that this target depends on but are not on the command line. - self.process_kwargs(kwargs) - self.extra_files = [] - self.install_rpath = '' - unknowns = [] - for k in kwargs: - if k not in CustomTarget.known_kwargs: - unknowns.append(k) - if len(unknowns) > 0: - mlog.log(mlog.bold('Warning:'), 'Unknown keyword arguments in target %s: %s' % - (self.name, ', '.join(unknowns))) - - def get_id(self): - return self.name + self.type_suffix() - - def process_kwargs(self, 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.output = kwargs['output'] - if not isinstance(self.output, list): - self.output = [self.output] - for i in self.output: - 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 'command' not in kwargs: - raise InvalidArguments('Missing keyword argument "command".') - cmd = kwargs['command'] - if not(isinstance(cmd, list)): - cmd = [cmd] - final_cmd = [] - for i, c in enumerate(cmd): - if hasattr(c, 'held_object'): - c = c.held_object - if isinstance(c, str): - final_cmd.append(c) - elif isinstance(c, dependencies.ExternalProgram): - final_cmd += c.get_command() - elif isinstance(c, BuildTarget) or isinstance(c, CustomTarget): - self.dependencies.append(c) - final_cmd.append(c) - elif isinstance(c, list): - # Hackety hack, only supports one level of flattening. Should really - # work to arbtrary depth. - for s in c: - if not isinstance(s, str): - raise InvalidArguments('Array as argument %d contains a non-string.' % i) - final_cmd.append(s) - else: - raise InvalidArguments('Argument %s in "command" is invalid.' % i) - self.command = final_cmd - if 'install' in kwargs: - self.install = kwargs['install'] - if not isinstance(self.install, bool): - raise InvalidArguments('"install" must be boolean.') - if 'install_dir' not in kwargs: - raise InvalidArguments('"install_dir" not specified.') - self.install_dir = kwargs['install_dir'] - if not(isinstance(self.install_dir, str)): - raise InvalidArguments('"install_dir" must be a string.') - else: - self.install = False - 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) and not isinstance(ed, BuildTarget): - raise InvalidArguments('Can only depend on toplevel targets.') - 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 in depend_files.') - - def get_basename(self): - return self.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_subdir(self): - return self.subdir - - def get_filename(self): - return self.output - - def get_aliaslist(self): - return [] - - def get_sources(self): - return self.sources - - def get_generated_sources(self): - return [] - - def type_suffix(self): - return "@cus" - -class RunTarget: - def __init__(self, name, command, args, subdir): - self.name = name - self.command = command - self.args = args - self.subdir = subdir - - def get_id(self): - return self.name + self.type_suffix() - - def get_basename(self): - return self.name - - def get_dependencies(self): - return [] - - def get_generated_sources(self): - return [] - - def get_sources(self): - return [] - - def get_subdir(self): - return self.subdir - - 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' - incdirs = kwargs.get('include_directories', []) - - def get_main_class(self): - return self.main_class - - def type_suffix(self): - return "@jar" - -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 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 get(self, name): - return self.values[name] - - 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, in_sourcetree, source_subdir, sources, install_dir): - self.in_sourcetree = in_sourcetree - self.source_subdir = source_subdir - self.sources = sources - self.install_dir = install_dir - -class InstallScript: - def __init__(self, cmd_arr): - assert(isinstance(cmd_arr, list)) - self.cmd_arr = cmd_arr diff --git a/meson/compilers.py b/meson/compilers.py deleted file mode 100644 index ec0181e..0000000 --- a/meson/compilers.py +++ /dev/null @@ -1,1837 +0,0 @@ -# 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 subprocess, os.path -import tempfile -from .import mesonlib -from . import mlog -from .coredata import MesonException -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', 'moc', 'vapi'] -cpp_suffixes = ['cc', 'cpp', 'cxx', 'h', 'hh', 'hpp', 'hxx', 'c++'] -c_suffixes = ['c'] -clike_suffixes = c_suffixes + cpp_suffixes -obj_suffixes = ['o', 'obj', 'res'] -lib_suffixes = ['a', 'lib', 'dll', 'dylib', 'so'] - -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] - return suffix in clike_suffixes - -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' : [], - 'debug' : ['-g'], - 'debugoptimized' : ['-O2', '-g'], - 'release' : ['-O3']} - -msvc_buildtype_args = {'plain' : [], - 'debug' : ["/MDd", "/ZI", "/Ob0", "/Od", "/RTC1"], - 'debugoptimized' : ["/MD", "/Zi", "/O2", "/Ob1", "/D"], - 'release' : ["/MD", "/O2", "/Ob2"]} - -gnulike_buildtype_linker_args = {} - -if mesonlib.is_osx(): - gnulike_buildtype_linker_args.update({'plain' : [], - 'debug' : [], - 'debugoptimized' : [], - 'release' : [], - }) -else: - gnulike_buildtype_linker_args.update({'plain' : [], - 'debug' : [], - 'debugoptimized' : [], - 'release' : ['-Wl,-O1'], - }) - -msvc_buildtype_linker_args = {'plain' : [], - 'debug' : [], - 'debugoptimized' : [], - 'release' : []} - -java_buildtype_args = {'plain' : [], - 'debug' : ['-g'], - 'debugoptimized' : ['-g'], - 'release' : []} - -rust_buildtype_args = {'plain' : [], - 'debug' : ['-g'], - 'debugoptimized' : ['-g', '--opt-level', '2'], - 'release' : ['--opt-level', '3']} - -mono_buildtype_args = {'plain' : [], - 'debug' : ['-debug'], - 'debugoptimized': ['-debug', '-optimize+'], - 'release' : ['-optimize+']} - -swift_buildtype_args = {'plain' : [], - 'debug' : ['-g'], - 'debugoptimized': ['-g', '-O'], - 'release' : ['-O']} - -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'] - -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 EnvironmentException(MesonException): - def __init(self, *args, **kwargs): - Exception.__init__(self, *args, **kwargs) - -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 Compiler(): - def __init__(self, exelist, version): - if type(exelist) == type(''): - self.exelist = [exelist] - elif type(exelist) == type([]): - self.exelist = exelist - else: - raise TypeError('Unknown argument to Compiler') - self.version = version - - def get_always_args(self): - return [] - - def get_linker_always_args(self): - 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 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) - - def unixtype_flags_to_native(self, args): - return args - -class CCompiler(Compiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version) - self.language = 'c' - self.default_suffix = 'c' - self.id = 'unknown' - self.is_cross = is_cross - 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): - return [] - - def get_warn_args(self, level): - return self.warn_args[level] - - def get_soname_args(self, shlib_name, path, soversion): - 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_id(self): - return self.id - - 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_language(self): - return self.language - - def get_default_suffix(self): - return self.default_suffix - - def get_exelist(self): - return self.exelist[:] - - def get_linker_exelist(self): - return self.exelist[:] - - def get_compile_only_args(self): - return ['-c'] - - 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 ['-lgcov'] - - 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 can_compile(self, filename): - suffix = filename.split('.')[-1] - if suffix == 'c' or suffix == 'h': - return True - return False - - 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 sanity_check(self, work_dir): - mlog.debug('Sanity testing C compiler:', ' '.join(self.exelist)) - mlog.debug('Is cross compiler: %s.' % str(self.is_cross)) - - source_name = os.path.join(work_dir, 'sanitycheckc.c') - if self.is_cross: - binname = 'sanitycheckc_cross' - else: - binname = 'sanitycheckc' - binary_name = os.path.join(work_dir, binname) - ofile = open(source_name, 'w') - ofile.write('int main(int argc, char **argv) { int class=0; return class; }\n') - ofile.close() - if self.is_cross and 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 = ['-c'] - else: - extra_flags = [] - cmdlist = self.exelist + extra_flags + [source_name, '-o', binary_name] - pc = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdo, stde) = pc.communicate() - stdo = stdo.decode() - stde = stde.decode() - 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 %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] - mlog.debug('Running test binary command: ' + ' '.join(cmdlist)) - pe = subprocess.Popen(cmdlist) - pe.wait() - if pe.returncode != 0: - raise EnvironmentException('Executables created by C compiler %s are not runnable.' % self.name_string()) - - def has_header(self, hname, extra_args=[]): - templ = '''#include<%s> -int someSymbolHereJustForFun; -''' - return self.compiles(templ % hname, extra_args) - - def compile(self, code, srcname, extra_args=[]): - commands = self.get_exelist() - commands.append(srcname) - commands += extra_args - mlog.debug('Running compile:') - mlog.debug('Command line: ', ' '.join(commands)) - mlog.debug('Code:\n', code) - p = subprocess.Popen(commands, cwd=os.path.split(srcname)[0], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stde, stdo) = p.communicate() - stde = stde.decode() - stdo = stdo.decode() - mlog.debug('Compiler stdout:\n', stdo) - mlog.debug('Compiler stderr:\n', stde) - os.remove(srcname) - return p - - def compiles(self, code, extra_args = []): - suflen = len(self.default_suffix) - (fd, srcname) = tempfile.mkstemp(suffix='.'+self.default_suffix) - os.close(fd) - ofile = open(srcname, 'w') - ofile.write(code) - ofile.close() - extra_args = extra_args + self.get_compile_only_args() - p = self.compile(code, srcname, extra_args) - try: - trial = srcname[:-suflen] + 'o' - os.remove(trial) - except FileNotFoundError: - pass - try: - os.remove(srcname[:-suflen] + 'obj') - except FileNotFoundError: - pass - return p.returncode == 0 - - def links(self, code, extra_args = []): - suflen = len(self.default_suffix) - (fd, srcname) = tempfile.mkstemp(suffix='.'+self.default_suffix) - os.close(fd) - (fd, dstname) = tempfile.mkstemp() - os.close(fd) - ofile = open(srcname, 'w') - ofile.write(code) - ofile.close() - extra_args = extra_args + self.get_output_args(dstname) - p = self.compile(code, srcname, extra_args) - try: - os.remove(dstname) - except FileNotFoundError: - pass - return p.returncode == 0 - - def run(self, code, extra_args=[]): - mlog.debug('Running code:\n\n', code) - if self.is_cross and self.exe_wrapper is None: - raise CrossNoRunException('Can not run test applications in this cross environment.') - (fd, srcname) = tempfile.mkstemp(suffix='.'+self.default_suffix) - os.close(fd) - ofile = open(srcname, 'w') - ofile.write(code) - ofile.close() - exename = srcname + '.exe' # Is guaranteed to be executable on every platform. - commands = self.get_exelist() - commands += extra_args - commands.append(srcname) - commands += self.get_output_args(exename) - p = subprocess.Popen(commands, cwd=os.path.split(srcname)[0], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdo, stde) = p.communicate() - stde = stde.decode() - stdo = stdo.decode() - mlog.debug('Compiler stdout:\n', stdo) - mlog.debug('Compiler stderr:\n', stde) - os.remove(srcname) - if p.returncode != 0: - return RunResult(False) - if self.is_cross: - cmdlist = self.exe_wrapper + [exename] - else: - cmdlist = exename - try: - pe = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except Exception as e: - mlog.debug('Could not run: %s (error: %s)\n' % (cmdlist, e)) - return RunResult(False) - - (so, se) = pe.communicate() - so = so.decode() - se = se.decode() - mlog.debug('Program stdout:\n', so) - mlog.debug('Program stderr:\n', se) - os.remove(exename) - return RunResult(True, pe.returncode, so, se) - - def cross_sizeof(self, element, prefix, env, extra_args=[]): - templ = '''%s -int temparray[%d-sizeof(%s)]; -''' - try: - extra_args += env.cross_info.config['properties'][self.language + '_args'] - except KeyError: - pass - for i in range(1, 1024): - code = templ % (prefix, i, element) - if self.compiles(code, extra_args): - return i - raise EnvironmentException('Cross checking sizeof overflowed.') - - def sizeof(self, element, prefix, env, extra_args=[]): - if self.is_cross: - return self.cross_sizeof(element, prefix, env, extra_args) - templ = '''#include<stdio.h> -%s - -int main(int argc, char **argv) { - printf("%%ld\\n", (long)(sizeof(%s))); - return 0; -}; -''' - res = self.run(templ % (prefix, element), extra_args) - if not res.compiled: - raise EnvironmentException('Could not compile sizeof test.') - if res.returncode != 0: - raise EnvironmentException('Could not run sizeof test binary.') - return int(res.stdout) - - def cross_alignment(self, typename, env, extra_args=[]): - templ = '''#include<stddef.h> -struct tmp { - char c; - %s target; -}; - -int testarray[%d-offsetof(struct tmp, target)]; -''' - try: - extra_args += env.cross_info.config['properties'][self.language + '_args'] - except KeyError: - pass - for i in range(1, 1024): - code = templ % (typename, i) - if self.compiles(code, extra_args): - return i - raise EnvironmentException('Cross checking offsetof overflowed.') - - def alignment(self, typename, env, extra_args=[]): - if self.is_cross: - return self.cross_alignment(typename, env, extra_args) - templ = '''#include<stdio.h> -#include<stddef.h> - -struct tmp { - char c; - %s target; -}; - -int main(int argc, char **argv) { - printf("%%d", (int)offsetof(struct tmp, target)); - return 0; -} -''' - res = self.run(templ % typename, extra_args) - 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 has_function(self, funcname, prefix, env, extra_args=[]): - # This fails (returns true) if funcname is a ptr or a variable. - # The correct check is a lot more difficult. - # Fix this to do that eventually. - templ = '''%s -int main(int argc, char **argv) { - void *ptr = (void*)(%s); - return 0; -}; -''' - 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)) - return self.compiles(templ % (prefix, funcname), extra_args) - - def has_member(self, typename, membername, prefix, extra_args=[]): - templ = '''%s -void bar() { - %s foo; - foo.%s; -}; -''' - return self.compiles(templ % (prefix, typename, membername), extra_args) - - def has_type(self, typename, prefix, extra_args): - templ = '''%s -void bar() { - sizeof(%s); -}; -''' - return self.compiles(templ % (prefix, typename), extra_args) - - def thread_flags(self): - return ['-pthread'] - - def thread_link_flags(self): - return ['-pthread'] - -class CPPCompiler(CCompiler): - def __init__(self, exelist, version, is_cross, exe_wrap): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) - self.language = 'cpp' - self.default_suffix = 'cpp' - - def can_compile(self, filename): - suffix = filename.split('.')[-1] - if suffix in cpp_suffixes: - return True - return False - - def sanity_check(self, work_dir): - source_name = os.path.join(work_dir, 'sanitycheckcpp.cc') - binary_name = os.path.join(work_dir, 'sanitycheckcpp') - ofile = open(source_name, 'w') - ofile.write('class breakCCompiler;int main(int argc, char **argv) { return 0; }\n') - ofile.close() - if self.is_cross and self.exe_wrapper is None: - # Skipping link because of the same reason as for C. - # The comment in CCompiler explains why this is done. - extra_flags = ['-c'] - else: - extra_flags = [] - cmdlist = self.exelist + extra_flags + [source_name, '-o', binary_name] - pc = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdo, stde) = pc.communicate() - stdo = stdo.decode() - stde = stde.decode() - 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('-----') - 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) - pe.wait() - if pe.returncode != 0: - raise EnvironmentException('Executables created by C++ compiler %s are not runnable.' % self.name_string()) - -class ObjCCompiler(CCompiler): - def __init__(self, exelist, version, is_cross, exe_wrap): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) - self.language = 'objc' - self.default_suffix = 'm' - - def can_compile(self, filename): - suffix = filename.split('.')[-1] - if suffix == 'm' or suffix == 'h': - return True - return False - - def sanity_check(self, work_dir): - source_name = os.path.join(work_dir, 'sanitycheckobjc.m') - binary_name = os.path.join(work_dir, 'sanitycheckobjc') - ofile = open(source_name, 'w') - ofile.write('#import<stdio.h>\nint main(int argc, char **argv) { return 0; }\n') - ofile.close() - pc = subprocess.Popen(self.exelist + [source_name, '-o', binary_name]) - pc.wait() - if pc.returncode != 0: - raise EnvironmentException('ObjC compiler %s can not compile programs.' % self.name_string()) - 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): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) - self.language = 'objcpp' - self.default_suffix = 'mm' - - def can_compile(self, filename): - suffix = filename.split('.')[-1] - if suffix == 'mm' or suffix == 'h': - return True - return False - - def sanity_check(self, work_dir): - source_name = os.path.join(work_dir, 'sanitycheckobjcpp.mm') - binary_name = os.path.join(work_dir, 'sanitycheckobjcpp') - ofile = open(source_name, 'w') - ofile.write('#import<stdio.h>\nclass MyClass;int main(int argc, char **argv) { return 0; }\n') - ofile.close() - pc = subprocess.Popen(self.exelist + [source_name, '-o', binary_name]) - pc.wait() - if pc.returncode != 0: - raise EnvironmentException('ObjC++ compiler %s can not compile programs.' % self.name_string()) - 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): - super().__init__(exelist, version) - self.language = 'cs' - self.default_suffix = 'cs' - 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, shlib_name, path, soversion): - 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_id(self): - return self.id - - def get_dependency_gen_args(self, outtarget, outfile): - return [] - - 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_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_std_shared_lib_link_args(self): - return [] - - def can_compile(self, filename): - suffix = filename.split('.')[-1] - if suffix == 'cs': - return True - return False - - 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): - src = 'sanity.cs' - obj = 'sanity.exe' - source_name = os.path.join(work_dir, src) - ofile = open(source_name, 'w') - ofile.write('''public class Sanity { - static public void Main () { - } -} -''') - ofile.close() - 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): - super().__init__(exelist, version) - self.language = 'java' - self.default_suffix = 'java' - self.id = 'unknown' - self.javarunner = 'java' - - def get_soname_args(self, shlib_name, path, soversion): - 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_id(self): - return self.id - - def get_dependency_gen_args(self, outtarget, outfile): - return [] - - 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_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_std_shared_lib_link_args(self): - return [] - - def can_compile(self, filename): - suffix = filename.split('.')[-1] - if suffix == 'java': - return True - return False - - 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): - src = 'SanityCheck.java' - obj = 'SanityCheck' - source_name = os.path.join(work_dir, src) - ofile = open(source_name, 'w') - ofile.write('''class SanityCheck { - public static void main(String[] args) { - int i; - } -} -''') - ofile.close() - 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()) - cmdlist = [self.javarunner, obj] - pe = subprocess.Popen(cmdlist, cwd=work_dir) - pe.wait() - if pe.returncode != 0: - raise EnvironmentException('Executables created by Java compiler %s are not runnable.' % self.name_string()) - - def needs_static_linker(self): - return False - -class ValaCompiler(Compiler): - def __init__(self, exelist, version): - super().__init__(exelist, version) - self.version = version - self.id = 'unknown' - self.language = 'vala' - - def name_string(self): - return ' '.join(self.exelist) - - def needs_static_linker(self): - return False # Because compiles into C. - - def get_exelist(self): - return self.exelist - - def get_werror_args(self): - return ['--fatal-warnings'] - - def get_language(self): - return self.language - - def sanity_check(self, work_dir): - src = 'valatest.vala' - source_name = os.path.join(work_dir, src) - ofile = open(source_name, 'w') - ofile.write('''class SanityCheck : Object { -} -''') - ofile.close() - pc = subprocess.Popen(self.exelist + ['-C', '-c', src], cwd=work_dir) - pc.wait() - if pc.returncode != 0: - raise EnvironmentException('Vala compiler %s can not compile programs.' % self.name_string()) - - def can_compile(self, filename): - suffix = filename.split('.')[-1] - return suffix in ('vala', 'vapi') - -class RustCompiler(Compiler): - def __init__(self, exelist, version): - super().__init__(exelist, version) - self.id = 'unknown' - self.language = 'rust' - - def needs_static_linker(self): - return False - - def name_string(self): - return ' '.join(self.exelist) - - def get_exelist(self): - return self.exelist - - def get_id(self): - return self.id - - def get_language(self): - return self.language - - def sanity_check(self, work_dir): - source_name = os.path.join(work_dir, 'sanity.rs') - output_name = os.path.join(work_dir, 'rusttest') - ofile = open(source_name, 'w') - ofile.write('''fn main() { -} -''') - ofile.close() - 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 can_compile(self, fname): - return fname.endswith('.rs') - - 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): - super().__init__(exelist, version) - self.version = version - self.id = 'llvm' - self.language = 'swift' - self.is_cross = False - - def get_id(self): - return self.id - - 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_exelist(self): - return self.exelist - - def get_werror_args(self): - return ['--fatal-warnings'] - - def get_language(self): - return self.language - - 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): - src = 'swifttest.swift' - source_name = os.path.join(work_dir, src) - output_name = os.path.join(work_dir, 'swifttest') - ofile = open(source_name, 'w') - ofile.write('''1 + 2 -''') - ofile.close() - pc = subprocess.Popen(self.exelist + ['-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()) - - def can_compile(self, filename): - suffix = filename.split('.')[-1] - return suffix in ('swift') - -class VisualStudioCCompiler(CCompiler): - std_warn_args = ['/W3'] - std_opt_args= ['/O2'] - vs2010_always_args = ['/nologo', '/showIncludes'] - vs2013_always_args = ['/nologo', '/showIncludes', '/FS'] - - def __init__(self, exelist, version, is_cross, exe_wrap): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) - self.id = 'msvc' - if int(version.split('.')[0]) > 17: - self.always_args = VisualStudioCCompiler.vs2013_always_args - else: - self.always_args = VisualStudioCCompiler.vs2010_always_args - self.warn_args = {'1': ['/W2'], - '2': ['/W3'], - '3': ['/w4']} - - def get_always_args(self): - return self.always_args - - 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_compile_only_args(self): - return ['/c'] - - 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_pic_args(self): - return ['/LD'] - - def get_std_shared_lib_link_args(self): - return ['/DLL'] - - def gen_pch_args(self, header, source, pchname): - objname = os.path.splitext(pchname)[0] + '.obj' - return (objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname ]) - - def sanity_check(self, work_dir): - source_name = 'sanitycheckc.c' - binary_name = 'sanitycheckc' - ofile = open(os.path.join(work_dir, source_name), 'w') - ofile.write('int main(int argc, char **argv) { return 0; }\n') - ofile.close() - pc = subprocess.Popen(self.exelist + [source_name, '/Fe' + binary_name], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - cwd=work_dir) - pc.wait() - if pc.returncode != 0: - raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string()) - pe = subprocess.Popen(os.path.join(work_dir, binary_name)) - pe.wait() - if pe.returncode != 0: - raise EnvironmentException('Executables created by C++ compiler %s are not runnable.' % self.name_string()) - - 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 - - def unixtype_flags_to_native(self, args): - result = [] - for i in args: - if i.startswith('-L'): - i = '/LIBPATH:' + i[2:] - result.append(i) - return result - - def get_include_args(self, path, is_system): - if path == '': - path = '.' - # msvc does not have a concept of system header dirs. - return ['-I' + path] - -class VisualStudioCPPCompiler(VisualStudioCCompiler): - def __init__(self, exelist, version, is_cross, exe_wrap): - VisualStudioCCompiler.__init__(self, exelist, version, is_cross, exe_wrap) - self.language = 'cpp' - self.default_suffix = 'cpp' - - def can_compile(self, filename): - suffix = filename.split('.')[-1] - if suffix in cpp_suffixes: - return True - return False - - def sanity_check(self, work_dir): - source_name = 'sanitycheckcpp.cpp' - binary_name = 'sanitycheckcpp' - ofile = open(os.path.join(work_dir, source_name), 'w') - ofile.write('class BreakPlainC;int main(int argc, char **argv) { return 0; }\n') - ofile.close() - pc = subprocess.Popen(self.exelist + [source_name, '/Fe' + binary_name], - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - cwd=work_dir) - pc.wait() - if pc.returncode != 0: - raise EnvironmentException('Compiler %s can not compile programs.' % self.name_string()) - pe = subprocess.Popen(os.path.join(work_dir, binary_name)) - pe.wait() - if pe.returncode != 0: - raise EnvironmentException('Executables created by C++ compiler %s are not runnable.' % self.name_string()) - - 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 - -GCC_STANDARD = 0 -GCC_OSX = 1 -GCC_MINGW = 2 - -def get_gcc_soname_args(gcc_type, shlib_name, path, soversion): - if soversion is None: - sostr = '' - else: - sostr = '.' + soversion - if gcc_type == GCC_STANDARD or gcc_type == GCC_MINGW: - # Might not be correct for mingw but seems to work. - return ['-Wl,-soname,lib%s.so%s' % (shlib_name, sostr)] - elif gcc_type == GCC_OSX: - return ['-install_name', os.path.join(path, 'lib' + shlib_name + '.dylib')] - else: - raise RuntimeError('Not implemented yet.') - - -class GnuCCompiler(CCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) - self.id = 'gcc' - self.gcc_type = gcc_type - self.warn_args = {'1': ['-Wall', '-Winvalid-pch'], - '2': ['-Wall', '-Wextra', '-Winvalid-pch'], - '3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']} - - def get_pic_args(self): - if self.gcc_type == GCC_MINGW: - return [] # On Window gcc defaults to fpic being always on. - return ['-fPIC'] - - def get_always_args(self): - return ['-pipe'] - - 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 'gch' - - def split_shlib_to_parts(self, fname): - return (os.path.split(fname)[0], fname) - - def get_soname_args(self, shlib_name, path, soversion): - return get_gcc_soname_args(self.gcc_type, shlib_name, path, soversion) - - def can_compile(self, filename): - return super().can_compile(filename) or filename.split('.')[-1].lower() == 's' # Gcc can do asm, too. - - 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 [] - -class GnuObjCCompiler(ObjCCompiler): - std_opt_args = ['-O2'] - - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - ObjCCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) - self.id = 'gcc' - # Not really correct, but GNU objc is only used on non-OSX non-win. File a bug - # if this breaks your use case. - self.gcc_type = GCC_STANDARD - self.warn_args = {'1': ['-Wall', '-Winvalid-pch'], - '2': ['-Wall', '-Wextra', '-Winvalid-pch'], - '3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch']} - - 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 'gch' - - def get_soname_args(self, shlib_name, path, soversion): - return get_gcc_soname_args(self.gcc_type, shlib_name, path, soversion) - -class GnuObjCPPCompiler(ObjCPPCompiler): - std_opt_args = ['-O2'] - - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - ObjCCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) - self.id = 'gcc' - # Not really correct, but GNU objc is only used on non-OSX non-win. File a bug - # if this breaks your use case. - self.gcc_type = GCC_STANDARD - self.warn_args = {'1': ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'], - '2': ['-Wall', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor'], - '3' : ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor']} - - 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 'gch' - - def get_soname_args(self, shlib_name, path, soversion): - return get_gcc_soname_args(self.gcc_type, shlib_name, path, soversion) - -class ClangObjCCompiler(GnuObjCCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper) - self.id = 'clang' - -class ClangObjCPPCompiler(GnuObjCPPCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper) - self.id = 'clang' - -class ClangCCompiler(CCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) - self.id = 'clang' - self.warn_args = {'1': ['-Wall', '-Winvalid-pch'], - '2': ['-Wall', '-Wextra', '-Winvalid-pch'], - '3' : ['-Weverything']} - - 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 'pch' - - def can_compile(self, filename): - return super().can_compile(filename) or filename.split('.')[-1].lower() == 's' # Clang can do asm, too. - - 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_options(self): - return {'c_std' : coredata.UserComboOption('c_std', 'C language standard to use', - ['none', 'c89', 'c99', 'c11'], - '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 GnuCPPCompiler(CPPCompiler): - # may need to separate the latter to extra_debug_args or something - std_debug_args = ['-g'] - - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) - self.id = 'gcc' - self.gcc_type = gcc_type - self.warn_args = {'1': ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'], - '2': ['-Wall', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor'], - '3': ['-Wall', '-Wpedantic', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor']} - - def get_always_args(self): - return ['-pipe'] - - 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 'gch' - - def get_soname_args(self, shlib_name, path, soversion): - return get_gcc_soname_args(self.gcc_type, shlib_name, path, soversion) - - def get_options(self): - opts = {'cpp_std' : coredata.UserComboOption('cpp_std', 'C++ language standard to use', - ['none', 'c++03', 'c++11', 'c++14'], - 'none')} - if self.gcc_type == GCC_MINGW: - opts.update({ - 'cpp_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['cpp_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['cpp_winlibs'].value - return [] - -class ClangCPPCompiler(CPPCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) - self.id = 'clang' - self.warn_args = {'1': ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'], - '2': ['-Wall', '-Wextra', '-Winvalid-pch', '-Wnon-virtual-dtor'], - '3': ['-Weverything']} - - 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 '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_options(self): - return {'cpp_std' : coredata.UserComboOption('cpp_std', 'C++ language standard to use', - ['none', 'c++03', 'c++11', 'c++14'], - '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 FortranCompiler(Compiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version) - self.is_cross = is_cross - self.exe_wrapper = exe_wrapper - self.language = 'fortran' - # 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 get_id(self): - return self.id - - def name_string(self): - return ' '.join(self.exelist) - - def get_exelist(self): - return self.exelist - - def get_language(self): - return self.language - - def get_pic_args(self): - if self.gcc_type == GCC_MINGW: - return [] # On Windows gcc defaults to fpic being 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): - source_name = os.path.join(work_dir, 'sanitycheckf.f90') - binary_name = os.path.join(work_dir, 'sanitycheckf') - ofile = open(source_name, 'w') - ofile.write('''program prog - print *, "Fortran compilation is working." -end program prog -''') - ofile.close() - pc = subprocess.Popen(self.exelist + [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): - 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, shlib_name, path, soversion): - return get_gcc_soname_args(self.gcc_type, shlib_name, path, soversion) - - 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_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 can_compile(self, src): - if hasattr(src, 'fname'): - src = src.fname - suffix = os.path.splitext(src)[1].lower() - if suffix == '.f' or suffix == '.f95' or suffix == '.f90': - return True - return False - - 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'] - - -class GnuFortranCompiler(FortranCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper=None) - self.gcc_type = gcc_type - self.id = 'gcc' - - def get_always_args(self): - return ['-pipe'] - -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'] - -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): - return [] - - def get_module_outdir_args(self, path): - return ['-moddir='+path] - -class IntelFortranCompiler(FortranCompiler): - std_warn_args = ['-warn', 'all'] - - def __init__(self, exelist, version, is_cross, exe_wrapper=None): - super().__init__(exelist, version, is_cross, exe_wrapper=None) - self.id = 'intel' - - def get_module_outdir_args(self, path): - return ['-module', path] - - def can_compile(self, src): - suffix = os.path.splitext(src)[1].lower() - if suffix == '.f' or suffix == '.f90': - return True - return False - - 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 can_compile(self, src): - suffix = os.path.splitext(src)[1].lower() - if suffix == '.f' or suffix == '.f90' or suffix == '.f95': - return True - return False - - 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 can_compile(self, src): - suffix = os.path.splitext(src)[1].lower() - if suffix == '.f' or suffix == '.f90' or suffix == '.f95': - return True - return False - - def get_warn_args(self, level): - return PGIFortranCompiler.std_warn_args - - -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 can_compile(self, src): - suffix = os.path.splitext(src)[1].lower() - if suffix == '.f' or suffix == '.f90' or suffix == '.f95': - return True - return False - - 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_always_args(self): - return [] - - def can_compile(self, src): - suffix = os.path.splitext(src)[1].lower() - if suffix == '.f' or suffix == '.f90' or suffix == '.f95': - return True - return False - - def get_warn_args(self, level): - return NAGFortranCompiler.std_warn_args - - -class VisualStudioLinker(): - 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 [] - - def unixtype_flags_to_native(self, args): - return args - -class ArLinker(): - std_args = ['csr'] - - def __init__(self, exelist): - self.exelist = exelist - self.id = 'ar' - - 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 [] - - def unixtype_flags_to_native(self, args): - return args diff --git a/meson/coredata.py b/meson/coredata.py deleted file mode 100644 index 5b1102c..0000000 --- a/meson/coredata.py +++ /dev/null @@ -1,222 +0,0 @@ -# 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. - -import pickle, os, uuid - -version = '0.29.0-research' - -build_types = ['plain', 'debug', 'debugoptimized', 'release'] -layouts = ['mirror', 'flat'] -warning_levels = ['1', '2', '3'] -libtypelist = ['shared', 'static'] - -builtin_options = {'buildtype': True, - 'strip': True, - 'coverage': True, - 'pch': True, - 'unity': True, - 'prefix': True, - 'libdir' : True, - 'bindir' : True, - 'includedir' : True, - 'datadir' : True, - 'mandir' : True, - 'localedir' : True, - 'werror' : True, - 'warning_level': True, - 'layout' : True, - 'default_library': True, - } - -class MesonException(Exception): - def __init__(self, *args, **kwargs): - Exception.__init__(self, *args, **kwargs) - -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 - -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(newvalue), self.name)) - if self.name == 'prefix' and not os.path.isabs(value): - raise MesonException('Prefix option must be an absolute path.') - if self.name in ('libdir', 'bindir', 'includedir', 'datadir', 'mandir', 'localedir') \ - and os.path.isabs(value): - raise MesonException('Option %s must not be an absolute path.' % self.name) - - def set_value(self, newvalue): - self.validate(newvalue) - self.value = newvalue - -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)) - -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 - -class UserStringArrayOption(UserOption): - def __init__(self, name, description, value, **kwargs): - super().__init__(name, description, kwargs.get('choices', [])) - self.set_value(value) - - def set_value(self, newvalue): - if isinstance(newvalue, str): - if not newvalue.startswith('['): - raise MesonException('Valuestring does not define an array: ' + newvalue) - newvalue = eval(newvalue, {}, {}) # Yes, it is unsafe. - if not isinstance(newvalue, list): - raise MesonException('String array value is not an array.') - for i in newvalue: - if not isinstance(i, str): - raise MesonException('String array element not a string.') - self.value = newvalue - -# 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.builtin_options = {} - self.init_builtins(options) - self.user_options = {} - self.compiler_options = {} - self.external_args = {} # These are set from "the outside" with e.g. mesonconf - self.external_link_args = {} - if options.cross_file is not None: - self.cross_file = os.path.join(os.getcwd(), options.cross_file) - else: - self.cross_file = None - - self.compilers = {} - self.cross_compilers = {} - self.deps = {} - self.ext_progs = {} - self.modules = {} - - def init_builtins(self, options): - self.builtin_options['prefix'] = UserStringOption('prefix', 'Installation prefix', options.prefix) - self.builtin_options['libdir'] = UserStringOption('libdir', 'Library dir', options.libdir) - self.builtin_options['bindir'] = UserStringOption('bindir', 'Executable dir', options.bindir) - self.builtin_options['includedir'] = UserStringOption('includedir', 'Include dir', options.includedir) - self.builtin_options['datadir'] = UserStringOption('datadir', 'Data directory', options.datadir) - self.builtin_options['mandir'] = UserStringOption('mandir', 'Man page dir', options.mandir) - self.builtin_options['localedir'] = UserStringOption('localedir', 'Locale dir', options.localedir) - self.builtin_options['backend'] = UserStringOption('backend', 'Backend to use', options.backend) - self.builtin_options['buildtype'] = UserComboOption('buildtype', 'Build type', build_types, options.buildtype) - self.builtin_options['strip'] = UserBooleanOption('strip', 'Strip on install', options.strip) - self.builtin_options['use_pch'] = UserBooleanOption('use_pch', 'Use precompiled headers', options.use_pch) - self.builtin_options['unity'] = UserBooleanOption('unity', 'Unity build', options.unity) - self.builtin_options['coverage'] = UserBooleanOption('coverage', 'Enable coverage', options.coverage) - self.builtin_options['warning_level'] = UserComboOption('warning_level', 'Warning level', warning_levels, options.warning_level) - self.builtin_options['werror'] = UserBooleanOption('werror', 'Warnings are errors', options.werror) - self.builtin_options['layout'] = UserComboOption('layout', 'Build dir layout', layouts, options.layout) - self.builtin_options['default_library'] = UserComboOption('default_library', 'Default_library type', libtypelist, options.default_library) - - def get_builtin_option(self, optname): - if optname in self.builtin_options: - return self.builtin_options[optname].value - raise RuntimeError('Tried to get unknown builtin option %s' % optname) - - def set_builtin_option(self, optname, value): - if optname in self.builtin_options: - self.builtin_options[optname].set_value(value) - else: - raise RuntimeError('Tried to set unknown builtin option %s' % optname) - - def is_builtin_option(self, optname): - return optname in self.builtin_options - -def load(filename): - obj = pickle.load(open(filename, 'rb')) - if not isinstance(obj, CoreData): - raise RuntimeError('Core data file is corrupted.') - if obj.version != version: - raise RuntimeError('Build tree has been generated with Meson version %s, which is incompatible with current version %s.'% - (obj.version, version)) - return obj - -def save(obj, filename): - if obj.version != version: - raise RuntimeError('Fatal version mismatch corruption.') - pickle.dump(obj, open(filename, 'wb')) - -forbidden_target_names = {'clean': None, - 'clean-gcno': None, - 'clean-gcda': None, - 'coverage-text': None, - 'coverage-xml': None, - 'coverage-html': None, - 'phony': None, - 'PHONY': None, - 'all': None, - 'test': None, - 'test-valgrind': None, - 'test-': None, - 'benchmark': None, - 'install': None, - 'build.ninja': None, - } diff --git a/meson/dependencies.py b/meson/dependencies.py deleted file mode 100644 index 974559f..0000000 --- a/meson/dependencies.py +++ /dev/null @@ -1,1120 +0,0 @@ -# Copyright 2013-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 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 os, stat, glob, subprocess, shutil -from . coredata import MesonException -from . import mlog -from . import mesonlib - -class DependencyException(MesonException): - def __init__(self, *args, **kwargs): - MesonException.__init__(self, *args, **kwargs) - -class Dependency(): - def __init__(self): - self.name = "null" - self.is_found = False - - 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_name(self): - return self.name - - def get_exe_args(self): - return [] - - def need_threads(self): - return False - -class InternalDependency(): - def __init__(self, incdirs, libraries, sources, ext_deps): - super().__init__() - self.include_directories = incdirs - self.libraries = libraries - self.sources = sources - self.ext_deps = ext_deps - -class PkgConfigDependency(Dependency): - pkgconfig_found = None - - def __init__(self, name, environment, kwargs): - Dependency.__init__(self) - self.is_libtool = False - self.required = kwargs.get('required', True) - if 'native' in kwargs and environment.is_cross_build(): - want_cross = not kwargs['native'] - else: - want_cross = environment.is_cross_build() - self.name = name - if PkgConfigDependency.pkgconfig_found is None: - self.check_pkgconfig() - - self.is_found = False - if not PkgConfigDependency.pkgconfig_found: - if self.required: - raise DependencyException('Pkg-config not found.') - self.cargs = [] - self.libs = [] - return - if environment.is_cross_build() and want_cross: - if "pkgconfig" not in environment.cross_info.config["binaries"]: - raise DependencyException('Pkg-config binary missing from cross file.') - pkgbin = environment.cross_info.config["binaries"]['pkgconfig'] - self.type_string = 'Cross' - else: - pkgbin = 'pkg-config' - self.type_string = 'Native' - - mlog.debug('Determining dependency %s with pkg-config executable %s.' % (name, pkgbin)) - self.pkgbin = pkgbin - p = subprocess.Popen([pkgbin, '--modversion', name], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode != 0: - if self.required: - raise DependencyException('%s dependency %s not found.' % (self.type_string, name)) - self.modversion = 'none' - self.cargs = [] - self.libs = [] - else: - self.modversion = out.decode().strip() - mlog.log('%s dependency' % self.type_string, mlog.bold(name), 'found:', - mlog.green('YES'), self.modversion) - self.version_requirement = kwargs.get('version', None) - if self.version_requirement is None: - self.is_found = True - else: - if not isinstance(self.version_requirement, str): - raise DependencyException('Version argument must be string.') - self.is_found = mesonlib.version_compare(self.modversion, self.version_requirement) - if not self.is_found and self.required: - raise DependencyException( - 'Invalid version of a dependency, needed %s %s found %s.' % - (name, self.version_requirement, self.modversion)) - if not self.is_found: - return - p = subprocess.Popen([pkgbin, '--cflags', name], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode != 0: - raise DependencyException('Could not generate cargs for %s:\n\n%s' % \ - (name, out.decode(errors='ignore'))) - self.cargs = out.decode().split() - - p = subprocess.Popen([pkgbin, '--libs', name], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode != 0: - raise DependencyException('Could not generate libs for %s:\n\n%s' % \ - (name, out.decode(errors='ignore'))) - self.libs = [] - for lib in out.decode().split(): - if lib.endswith(".la"): - shared_libname = self.extract_libtool_shlib(lib) - shared_lib = os.path.join(os.path.dirname(lib), shared_libname) - if not os.path.exists(shared_lib): - shared_lib = os.path.join(os.path.dirname(lib), ".libs", shared_libname) - - if not os.path.exists(shared_lib): - raise DependencyException('Got a libtools specific "%s" dependencies' - 'but we could not compute the actual shared' - 'library path' % lib) - lib = shared_lib - self.is_libtool = True - - self.libs.append(lib) - - def get_variable(self, variable_name): - p = subprocess.Popen([self.pkgbin, '--variable=%s' % variable_name, self.name], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode != 0: - if self.required: - raise DependencyException('%s dependency %s not found.' % - (self.type_string, self.name)) - else: - variable = out.decode().strip() - mlog.debug('return of subprocess : %s' % variable) - - return variable - - def get_modversion(self): - return self.modversion - - def get_compile_args(self): - return self.cargs - - def get_link_args(self): - return self.libs - - def check_pkgconfig(self): - try: - p = subprocess.Popen(['pkg-config', '--version'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode == 0: - mlog.log('Found pkg-config:', mlog.bold(shutil.which('pkg-config')), - '(%s)' % out.decode().strip()) - PkgConfigDependency.pkgconfig_found = True - return - except Exception: - pass - PkgConfigDependency.pkgconfig_found = False - mlog.log('Found Pkg-config:', mlog.red('NO')) - - def found(self): - return self.is_found - - def extract_field(self, la_file, fieldname): - for line in open(la_file): - 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) - if WxDependency.wx_found is None: - self.check_wxconfig() - - if not WxDependency.wx_found: - raise DependencyException('Wx-config not found.') - self.is_found = False - p = subprocess.Popen([self.wxc, '--version'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode != 0: - mlog.log('Dependency wxwidgets found:', mlog.red('NO')) - self.cargs = [] - self.libs = [] - else: - self.modversion = out.decode().strip() - version_req = kwargs.get('version', None) - if version_req is not None: - if not mesonlib.version_compare(self.modversion, version_req): - 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 = subprocess.Popen([self.wxc, '--cxxflags'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode != 0: - raise DependencyException('Could not generate cargs for wxwidgets.') - self.cargs = out.decode().split() - - p = subprocess.Popen([self.wxc, '--libs'] + self.requested_modules, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode != 0: - raise DependencyException('Could not generate libs for wxwidgets.') - self.libs = out.decode().split() - - def get_requested(self, kwargs): - modules = 'modules' - if not modules 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_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 = subprocess.Popen([wxc, '--version'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out = p.communicate()[0] - if p.returncode == 0: - mlog.log('Found wx-config:', mlog.bold(shutil.which(wxc)), - '(%s)' % out.decode().strip()) - self.wxc = wxc - WxDependency.wx_found = True - return - except Exception: - pass - WxDependency.wxconfig_found = False - mlog.log('Found wx-config:', mlog.red('NO')) - - def found(self): - return self.is_found - -class ExternalProgram(): - def __init__(self, name, fullpath=None, silent=False, search_dir=None): - self.name = name - self.fullpath = None - if fullpath is not None: - if not isinstance(fullpath, list): - self.fullpath = [fullpath] - else: - self.fullpath = fullpath - else: - self.fullpath = [shutil.which(name)] - if self.fullpath[0] is None and search_dir is not None: - trial = os.path.join(search_dir, name) - suffix = os.path.splitext(trial)[-1].lower()[1:] - if mesonlib.is_windows() and (suffix == 'exe' or suffix == 'com'\ - or suffix == 'bat'): - self.fullpath = [trial] - elif not mesonlib.is_windows() and os.access(trial, os.X_OK): - self.fullpath = [trial] - else: - # Now getting desperate. Maybe it is a script file that is a) not chmodded - # executable or b) we are on windows so they can't be directly executed. - try: - first_line = open(trial).readline().strip() - if first_line.startswith('#!'): - commands = first_line[2:].split('#')[0].strip().split() - if mesonlib.is_windows(): - # Windows does not have /usr/bin. - commands[0] = commands[0].split('/')[-1] - if commands[0] == 'env': - commands = commands[1:] - self.fullpath = commands + [trial] - except Exception: - pass - if not silent: - if self.found(): - mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'), - '(%s)' % ' '.join(self.fullpath)) - else: - mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO')) - - def found(self): - return self.fullpath[0] is not None - - def get_command(self): - return self.fullpath - - def get_name(self): - return self.name - -class ExternalLibrary(Dependency): - def __init__(self, name, fullpath=None, silent=False): - super().__init__() - self.name = name - self.fullpath = fullpath - if not silent: - if self.found(): - mlog.log('Library', mlog.bold(name), 'found:', mlog.green('YES'), - '(%s)' % self.fullpath) - else: - mlog.log('Library', mlog.bold(name), 'found:', mlog.red('NO')) - - def found(self): - return self.fullpath is not None - - def get_link_args(self): - if self.found(): - return [self.fullpath] - 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) - self.name = 'boost' - self.libdir = '' - 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 mesonlib.is_windows(): - self.boost_root = self.detect_win_root() - self.incdir = self.boost_root - 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')) - - 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 = [] - if self.boost_root is not None: - if mesonlib.is_windows(): - args.append('-I' + self.boost_root) - else: - args.append('-I' + os.path.join(self.boost_root, 'include')) - else: - args.append('-I' + self.incdir) - 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 - 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): - if mesonlib.is_32bit(): - gl = 'lib32*' - else: - gl = 'lib64*' - libdir = glob.glob(os.path.join(self.boost_root, gl)) - 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): - libsuffix = None - if mesonlib.is_osx(): - libsuffix = 'dylib' - else: - libsuffix = 'so' - - globber = 'libboost_*.{}'.format(libsuffix) - if 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')) - for module in self.requested_modules: - module = BoostDependency.name2lib.get(module, module) - if module in self.lib_modules or module in self.lib_modules_mt: - linkcmd = '-lboost_' + module - 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) - 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_include_dir = '/usr/src/gtest' - self.src_dir = '/usr/src/gtest/src' - 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.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 os.path.exists(self.src_dir): - 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 get_compile_args(self): - arr = [] - if self.include_dir != '/usr/include': - arr.append('-I' + self.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 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/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. - self.compile_args = ['-I/usr/src/gmock', '-I/usr/src/gmock/src'] - 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 Qt5Dependency(Dependency): - def __init__(self, environment, kwargs): - Dependency.__init__(self) - self.name = 'qt5' - self.root = '/usr' - 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 Qt5 modules specified.') - type_text = 'native' - if environment.is_cross_build() and kwargs.get('native', False): - type_text = 'cross' - self.pkgconfig_detect(mods, environment, kwargs) - elif not environment.is_cross_build() and shutil.which('pkg-config') is not None: - self.pkgconfig_detect(mods, environment, kwargs) - elif shutil.which('qmake') is not None: - self.qmake_detect(mods, kwargs) - else: - self.version = 'none' - if not self.is_found: - mlog.log('Qt5 %s dependency found: ' % type_text, mlog.red('NO')) - else: - mlog.log('Qt5 %s dependency found: ' % type_text, mlog.green('YES')) - - def pkgconfig_detect(self, mods, environment, kwargs): - modules = [] - for module in mods: - modules.append(PkgConfigDependency('Qt5' + module, environment, kwargs)) - for m in modules: - self.cargs += m.get_compile_args() - self.largs += m.get_link_args() - self.is_found = True - self.version = modules[0].modversion - - def qmake_detect(self, mods, kwargs): - pc = subprocess.Popen(['qmake', '-v'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - (stdo, _) = pc.communicate() - if pc.returncode != 0: - return - stdo = stdo.decode() - if not 'version 5' in stdo: - mlog.log('QMake is not for Qt5.') - return - self.version = re.search('5(\.\d+)+', stdo).group(0) - (stdo, _) = subprocess.Popen(['qmake', '-query'], stdout=subprocess.PIPE).communicate() - qvars = {} - for line in stdo.decode().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'] - bindir = qvars['QT_INSTALL_BINS'] - #self.largs.append('-L' + libdir) - for module in mods: - mincdir = os.path.join(incdir, 'Qt' + module) - self.cargs.append('-I' + mincdir) - libfile = os.path.join(libdir, 'Qt5' + module + '.lib') - if not os.path.isfile(libfile): - # MinGW links directly to .dll, not to .lib. - libfile = os.path.join(bindir, 'Qt5' + module + '.dll') - self.largs.append(libfile) - self.is_found = True - - 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) - self.cargs.append('-F' + libdir) - if fwdep.found(): - self.is_found = True - self.cargs += fwdep.get_compile_args() - self.largs += fwdep.get_link_args() - - - 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 found(self): - return self.is_found - - def get_exe_args(self): - # 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. - # Fix this to be more portable, especially to MSVC. - return ['-fPIC'] - -class Qt4Dependency(Dependency): - def __init__(self, environment, kwargs): - Dependency.__init__(self) - self.name = 'qt4' - self.root = '/usr' - self.modules = [] - mods = kwargs.get('modules', []) - if isinstance(mods, str): - mods = [mods] - for module in mods: - self.modules.append(PkgConfigDependency('Qt' + module, environment, kwargs)) - if len(self.modules) == 0: - raise DependencyException('No Qt4 modules specified.') - - def get_version(self): - return self.modules[0].get_version() - - def get_compile_args(self): - args = [] - for m in self.modules: - args += m.get_compile_args() - return args - - def get_sources(self): - return [] - - def get_link_args(self): - args = [] - for module in self.modules: - args += module.get_link_args() - return args - - def found(self): - for i in self.modules: - if not i.found(): - return False - return True - -class GnuStepDependency(Dependency): - def __init__(self, environment, kwargs): - Dependency.__init__(self) - self.modules = kwargs.get('modules', []) - self.detect() - - def detect(self): - confprog = 'gnustep-config' - try: - gp = subprocess.Popen([confprog, '--help'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - gp.communicate() - except FileNotFoundError: - 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 = subprocess.Popen([confprog, '--objc-flags'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (flagtxt, flagerr) = fp.communicate() - flagtxt = flagtxt.decode() - flagerr = flagerr.decode() - if fp.returncode != 0: - raise DependencyException('Error getting objc-args: %s %s' % (flagtxt, flagerr)) - args = flagtxt.split() - self.args = self.filter_arsg(args) - fp = subprocess.Popen([confprog, arg], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (libtxt, liberr) = fp.communicate() - libtxt = libtxt.decode() - liberr = liberr.decode() - if fp.returncode != 0: - raise DependencyException('Error getting objc-lib args: %s %s' % (libtxt, liberr)) - self.libs = self.weird_filter(libtxt.split()) - mlog.log('Dependency GnuStep found:', mlog.green('YES')) - - 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 found(self): - return self.args is not None - - 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) - 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() - -class GLDependency(Dependency): - def __init__(self, environment, kwargs): - Dependency.__init__(self) - self.is_found = False - self.cargs = [] - self.linkargs = [] - try: - pcdep = PkgConfigDependency('gl', environment, kwargs) - if pcdep.found(): - self.is_found = True - self.cargs = pcdep.get_compile_args() - self.linkargs = pcdep.get_link_args() - return - except Exception: - pass - if mesonlib.is_osx(): - self.is_found = True - self.linkargs = ['-framework', 'OpenGL'] - return - if mesonlib.is_windows(): - self.is_found = True - self.linkargs = ['-lopengl32'] - return - - def get_link_args(self): - return self.linkargs - -# 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) - self.is_found = False - self.cargs = [] - self.linkargs = [] - sdlconf = shutil.which('sdl2-config') - if sdlconf: - pc = subprocess.Popen(['sdl2-config', '--cflags'], - stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL) - (stdo, _) = pc.communicate() - self.cargs = stdo.decode().strip().split() - pc = subprocess.Popen(['sdl2-config', '--libs'], - stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL) - (stdo, _) = pc.communicate() - self.linkargs = stdo.decode().strip().split() - self.is_found = True - mlog.log('Dependency', mlog.bold('sdl2'), 'found:', mlog.green('YES'), '(%s)' % sdlconf) - return - try: - pcdep = PkgConfigDependency('sdl2', kwargs) - if pcdep.found(): - self.is_found = True - self.cargs = pcdep.get_compile_args() - self.linkargs = pcdep.get_link_args() - return - except Exception: - pass - if mesonlib.is_osx(): - fwdep = ExtraFrameworkDependency('sdl2', kwargs.get('required', True)) - if fwdep.found(): - self.is_found = True - self.cargs = fwdep.get_compile_args() - self.linkargs = fwdep.get_link_args() - 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 - -class ExtraFrameworkDependency(Dependency): - def __init__(self, name, required, path=None): - Dependency.__init__(self) - 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 - -class ThreadDependency(Dependency): - def __init__(self, environment, kwargs): - super().__init__() - 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_dep_identifier(name, kwargs): - elements = [name] - modlist = kwargs.get('modules', []) - if isinstance(modlist, str): - modlist = [modlist] - for module in modlist: - elements.append(module) - return '/'.join(elements) + '/main' + str(kwargs.get('main', False)) - -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.') - 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) - if required and not fwdep.found(): - raise DependencyException('Dependency "%s" not found' % 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, - } diff --git a/meson/environment.py b/meson/environment.py deleted file mode 100644 index 8df856c..0000000 --- a/meson/environment.py +++ /dev/null @@ -1,673 +0,0 @@ -# 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 -from . import coredata, mesonlib -from .compilers import * -import configparser - -build_filename = 'meson.build' - -class EnvironmentException(coredata.MesonException): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - -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 find_valgrind(): - valgrind_exe = 'valgrind' - if not mesonlib.exe_exists([valgrind_exe, '--version']): - valgrind_exe = None - return valgrind_exe - -def detect_ninja(): - for n in ['ninja', 'ninja-build']: - try: - p = subprocess.Popen([n, '--version'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except FileNotFoundError: - continue - p.communicate() - if p.returncode == 0: - return n - - -class Environment(): - private_dir = 'meson-private' - log_dir = 'meson-logs' - coredata_file = os.path.join(private_dir, 'coredata.dat') - version_regex = '\d+(\.\d+)+(-[a-zA-Z0-9]+)?' - def __init__(self, source_dir, build_dir, main_script_file, options): - assert(os.path.isabs(main_script_file)) - assert(not os.path.islink(main_script_file)) - self.source_dir = source_dir - self.build_dir = build_dir - self.meson_script_file = main_script_file - self.scratch_dir = os.path.join(build_dir, Environment.private_dir) - self.log_dir = os.path.join(build_dir, Environment.log_dir) - os.makedirs(self.scratch_dir, exist_ok=True) - os.makedirs(self.log_dir, exist_ok=True) - try: - cdf = os.path.join(self.get_build_dir(), Environment.coredata_file) - self.coredata = coredata.load(cdf) - self.first_invocation = False - except FileNotFoundError: - self.coredata = coredata.CoreData(options) - self.first_invocation = True - if self.coredata.cross_file: - self.cross_info = CrossBuildInfo(self.coredata.cross_file) - else: - self.cross_info = None - self.cmd_line_options = options - - # List of potential compilers. - if mesonlib.is_windows(): - self.default_c = ['cl', 'cc', 'gcc', 'clang'] - self.default_cpp = ['cl', 'c++', 'g++', 'clang++'] - else: - self.default_c = ['cc'] - self.default_cpp = ['c++'] - self.default_objc = ['cc'] - self.default_objcpp = ['c++'] - self.default_fortran = ['gfortran', 'g95', 'f95', 'f90', 'f77'] - self.default_static_linker = 'ar' - self.vs_static_linker = 'lib' - - cross = self.is_cross_build() - if (not cross and mesonlib.is_windows()) \ - or (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'windows'): - self.exe_suffix = 'exe' - self.import_lib_suffix = 'lib' - self.shared_lib_suffix = 'dll' - self.shared_lib_prefix = '' - self.static_lib_suffix = 'lib' - self.static_lib_prefix = '' - self.object_suffix = 'obj' - else: - self.exe_suffix = '' - if (not cross and mesonlib.is_osx()) or \ - (cross and self.cross_info.has_host() and self.cross_info.config['host_machine']['system'] == 'darwin'): - self.shared_lib_suffix = 'dylib' - else: - self.shared_lib_suffix = 'so' - self.shared_lib_prefix = 'lib' - self.static_lib_suffix = 'a' - self.static_lib_prefix = 'lib' - self.object_suffix = 'o' - self.import_lib_suffix = self.shared_lib_suffix - - def is_cross_build(self): - return self.cross_info is not None - - def generating_finished(self): - cdf = os.path.join(self.get_build_dir(), Environment.coredata_file) - coredata.save(self.coredata, cdf) - - def get_script_dir(self): - return os.path.join(os.path.dirname(self.meson_script_file), '../scripts') - - def get_log_dir(self): - return self.log_dir - - def get_coredata(self): - return self.coredata - - def get_build_command(self): - return self.meson_script_file - - def is_header(self, fname): - return is_header(fname) - - def is_source(self, fname): - return is_source(fname) - - def is_object(self, fname): - return is_object(fname) - - def is_library(self, fname): - return is_library(fname) - - def merge_options(self, options): - for (name, value) in options.items(): - if name not in self.coredata.user_options: - self.coredata.user_options[name] = value - else: - oldval = self.coredata.user_options[name] - if type(oldval) != type(value): - self.coredata.user_options[name] = value - - def detect_c_compiler(self, want_cross): - evar = 'CC' - if self.is_cross_build() and want_cross: - compilers = [self.cross_info.config['binaries']['c']] - ccache = [] - is_cross = True - exe_wrap = self.cross_info.config['binaries'].get('exe_wrapper', None) - elif evar in os.environ: - compilers = os.environ[evar].split() - ccache = [] - is_cross = False - exe_wrap = None - else: - compilers = self.default_c - ccache = self.detect_ccache() - is_cross = False - exe_wrap = None - for compiler in compilers: - try: - basename = os.path.basename(compiler).lower() - if basename == 'cl' or basename == 'cl.exe': - arg = '/?' - else: - arg = '--version' - p = subprocess.Popen([compiler] + [arg], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - except OSError: - continue - (out, err) = p.communicate() - out = out.decode(errors='ignore') - err = err.decode(errors='ignore') - vmatch = re.search(Environment.version_regex, out) - if vmatch: - version = vmatch.group(0) - else: - version = 'unknown version' - if 'apple' in out and 'Free Software Foundation' in out: - return GnuCCompiler(ccache + [compiler], version, GCC_OSX, is_cross, exe_wrap) - if (out.startswith('cc') or 'gcc' in out) and \ - 'Free Software Foundation' in out: - lowerout = out.lower() - if 'mingw' in lowerout or 'msys' in lowerout or 'mingw' in compiler.lower(): - gtype = GCC_MINGW - else: - gtype = GCC_STANDARD - return GnuCCompiler(ccache + [compiler], version, gtype, is_cross, exe_wrap) - if 'clang' in out: - return ClangCCompiler(ccache + [compiler], version, is_cross, exe_wrap) - if 'Microsoft' in out or 'Microsoft' in err: - # Visual Studio prints version number to stderr but - # everything else to stdout. Why? Lord only knows. - version = re.search(Environment.version_regex, err).group() - return VisualStudioCCompiler([compiler], version, is_cross, exe_wrap) - raise EnvironmentException('Unknown compiler(s): "' + ', '.join(compilers) + '"') - - def detect_fortran_compiler(self, want_cross): - evar = 'FC' - if self.is_cross_build() and want_cross: - compilers = [self.cross_info['fortran']] - is_cross = True - exe_wrap = self.cross_info.get('exe_wrapper', None) - elif evar in os.environ: - compilers = os.environ[evar].split() - is_cross = False - exe_wrap = None - else: - compilers = self.default_fortran - is_cross = False - exe_wrap = None - for compiler in compilers: - for arg in ['--version', '-V']: - try: - p = subprocess.Popen([compiler] + [arg], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - except OSError: - continue - (out, err) = p.communicate() - out = out.decode(errors='ignore') - err = err.decode(errors='ignore') - - version = 'unknown version' - vmatch = re.search(Environment.version_regex, out) - if vmatch: - version = vmatch.group(0) - - if 'GNU Fortran' in out: - return GnuFortranCompiler([compiler], version, GCC_STANDARD, is_cross, exe_wrap) - - if 'G95' in out: - return G95FortranCompiler([compiler], version, is_cross, exe_wrap) - - if 'Sun Fortran' in err: - version = 'unknown version' - vmatch = re.search(Environment.version_regex, err) - if vmatch: - version = vmatch.group(0) - return SunFortranCompiler([compiler], version, is_cross, exe_wrap) - - if 'ifort (IFORT)' in out: - return IntelFortranCompiler([compiler], version, is_cross, exe_wrap) - - if 'PathScale EKOPath(tm)' in err: - return PathScaleFortranCompiler([compiler], version, is_cross, exe_wrap) - - if 'pgf90' in out: - return PGIFortranCompiler([compiler], version, is_cross, exe_wrap) - - if 'Open64 Compiler Suite' in err: - return Open64FortranCompiler([compiler], version, is_cross, exe_wrap) - - if 'NAG Fortran' in err: - return NAGFortranCompiler([compiler], version, is_cross, exe_wrap) - - raise EnvironmentException('Unknown compiler(s): "' + ', '.join(compilers) + '"') - - def get_scratch_dir(self): - return self.scratch_dir - - def get_depfixer(self): - path = os.path.split(__file__)[0] - return os.path.join(path, 'depfixer.py') - - def detect_cpp_compiler(self, want_cross): - evar = 'CXX' - if self.is_cross_build() and want_cross: - compilers = [self.cross_info.config['binaries']['cpp']] - ccache = [] - is_cross = True - exe_wrap = self.cross_info.config['binaries'].get('exe_wrapper', None) - elif evar in os.environ: - compilers = os.environ[evar].split() - ccache = [] - is_cross = False - exe_wrap = None - else: - compilers = self.default_cpp - ccache = self.detect_ccache() - is_cross = False - exe_wrap = None - for compiler in compilers: - basename = os.path.basename(compiler).lower() - if basename == 'cl' or basename == 'cl.exe': - arg = '/?' - else: - arg = '--version' - try: - p = subprocess.Popen([compiler, arg], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - except OSError: - continue - (out, err) = p.communicate() - out = out.decode(errors='ignore') - err = err.decode(errors='ignore') - vmatch = re.search(Environment.version_regex, out) - if vmatch: - version = vmatch.group(0) - else: - version = 'unknown version' - if 'apple' in out and 'Free Software Foundation' in out: - return GnuCPPCompiler(ccache + [compiler], version, GCC_OSX, is_cross, exe_wrap) - if (out.startswith('c++ ') or 'g++' in out or 'GCC' in out) and \ - 'Free Software Foundation' in out: - lowerout = out.lower() - if 'mingw' in lowerout or 'msys' in lowerout or 'mingw' in compiler.lower(): - gtype = GCC_MINGW - else: - gtype = GCC_STANDARD - return GnuCPPCompiler(ccache + [compiler], version, gtype, is_cross, exe_wrap) - if 'clang' in out: - return ClangCPPCompiler(ccache + [compiler], version, is_cross, exe_wrap) - if 'Microsoft' in out or 'Microsoft' in err: - version = re.search(Environment.version_regex, err).group() - return VisualStudioCPPCompiler([compiler], version, is_cross, exe_wrap) - raise EnvironmentException('Unknown compiler(s) "' + ', '.join(compilers) + '"') - - def detect_objc_compiler(self, want_cross): - if self.is_cross_build() and want_cross: - exelist = [self.cross_info['objc']] - is_cross = True - exe_wrap = self.cross_info.get('exe_wrapper', None) - else: - exelist = self.get_objc_compiler_exelist() - is_cross = False - exe_wrap = None - try: - p = subprocess.Popen(exelist + ['--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError: - raise EnvironmentException('Could not execute ObjC compiler "%s"' % ' '.join(exelist)) - (out, err) = p.communicate() - out = out.decode(errors='ignore') - err = err.decode(errors='ignore') - vmatch = re.search(Environment.version_regex, out) - if vmatch: - version = vmatch.group(0) - else: - version = 'unknown version' - if (out.startswith('cc ') or 'gcc' in out) and \ - 'Free Software Foundation' in out: - return GnuObjCCompiler(exelist, version, is_cross, exe_wrap) - if out.startswith('Apple LLVM'): - return ClangObjCCompiler(exelist, version, is_cross, exe_wrap) - if 'apple' in out and 'Free Software Foundation' in out: - return GnuObjCCompiler(exelist, version, is_cross, exe_wrap) - raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - - def detect_objcpp_compiler(self, want_cross): - if self.is_cross_build() and want_cross: - exelist = [self.cross_info['objcpp']] - is_cross = True - exe_wrap = self.cross_info.get('exe_wrapper', None) - else: - exelist = self.get_objcpp_compiler_exelist() - is_cross = False - exe_wrap = None - try: - p = subprocess.Popen(exelist + ['--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError: - raise EnvironmentException('Could not execute ObjC++ compiler "%s"' % ' '.join(exelist)) - (out, err) = p.communicate() - out = out.decode(errors='ignore') - err = err.decode(errors='ignore') - vmatch = re.search(Environment.version_regex, out) - if vmatch: - version = vmatch.group(0) - else: - version = 'unknown version' - if (out.startswith('c++ ') or out.startswith('g++')) and \ - 'Free Software Foundation' in out: - return GnuObjCPPCompiler(exelist, version, is_cross, exe_wrap) - if out.startswith('Apple LLVM'): - return ClangObjCPPCompiler(exelist, version, is_cross, exe_wrap) - if 'apple' in out and 'Free Software Foundation' in out: - return GnuObjCPPCompiler(exelist, version, is_cross, exe_wrap) - raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - - def detect_java_compiler(self): - exelist = ['javac'] - try: - p = subprocess.Popen(exelist + ['-version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError: - raise EnvironmentException('Could not execute Java compiler "%s"' % ' '.join(exelist)) - (out, err) = p.communicate() - out = out.decode(errors='ignore') - err = err.decode(errors='ignore') - vmatch = re.search(Environment.version_regex, err) - if vmatch: - version = vmatch.group(0) - else: - version = 'unknown version' - if 'javac' in err: - return JavaCompiler(exelist, version) - raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - - def detect_cs_compiler(self): - exelist = ['mcs'] - try: - p = subprocess.Popen(exelist + ['--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError: - raise EnvironmentException('Could not execute C# compiler "%s"' % ' '.join(exelist)) - (out, err) = p.communicate() - out = out.decode(errors='ignore') - err = err.decode(errors='ignore') - vmatch = re.search(Environment.version_regex, out) - if vmatch: - version = vmatch.group(0) - else: - version = 'unknown version' - if 'Mono' in out: - return MonoCompiler(exelist, version) - raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - - def detect_vala_compiler(self): - exelist = ['valac'] - try: - p = subprocess.Popen(exelist + ['--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError: - raise EnvironmentException('Could not execute Vala compiler "%s"' % ' '.join(exelist)) - (out, _) = p.communicate() - out = out.decode(errors='ignore') - vmatch = re.search(Environment.version_regex, out) - if vmatch: - version = vmatch.group(0) - else: - version = 'unknown version' - if 'Vala' in out: - return ValaCompiler(exelist, version) - raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - - def detect_rust_compiler(self): - exelist = ['rustc'] - try: - p = subprocess.Popen(exelist + ['--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError: - raise EnvironmentException('Could not execute Rust compiler "%s"' % ' '.join(exelist)) - (out, _) = p.communicate() - out = out.decode(errors='ignore') - vmatch = re.search(Environment.version_regex, out) - if vmatch: - version = vmatch.group(0) - else: - version = 'unknown version' - if 'rustc' in out: - return RustCompiler(exelist, version) - raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - - def detect_swift_compiler(self): - exelist = ['swiftc'] - try: - p = subprocess.Popen(exelist + ['-v'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError: - raise EnvironmentException('Could not execute Swift compiler "%s"' % ' '.join(exelist)) - (_, err) = p.communicate() - err = err.decode(errors='ignore') - vmatch = re.search(Environment.version_regex, err) - if vmatch: - version = vmatch.group(0) - else: - version = 'unknown version' - if 'Swift' in err: - return SwiftCompiler(exelist, version) - raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - - def detect_static_linker(self, compiler): - if compiler.is_cross: - linker = self.cross_info.config['binaries']['ar'] - else: - evar = 'AR' - if evar in os.environ: - linker = os.environ[evar].strip() - if isinstance(compiler, VisualStudioCCompiler): - linker= self.vs_static_linker - else: - linker = self.default_static_linker - basename = os.path.basename(linker).lower() - if basename == 'lib' or basename == 'lib.exe': - arg = '/?' - else: - arg = '--version' - try: - p = subprocess.Popen([linker, arg], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError: - raise EnvironmentException('Could not execute static linker "%s".' % linker) - (out, err) = p.communicate() - out = out.decode(errors='ignore') - err = err.decode(errors='ignore') - if '/OUT:' in out or '/OUT:' in err: - return VisualStudioLinker([linker]) - if p.returncode == 0: - return ArLinker([linker]) - if p.returncode == 1 and err.startswith('usage'): # OSX - return ArLinker([linker]) - raise EnvironmentException('Unknown static linker "%s"' % linker) - - def detect_ccache(self): - try: - has_ccache = subprocess.call(['ccache', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError: - has_ccache = 1 - if has_ccache == 0: - cmdlist = ['ccache'] - else: - cmdlist = [] - return cmdlist - - def get_objc_compiler_exelist(self): - ccachelist = self.detect_ccache() - evar = 'OBJCC' - if evar in os.environ: - return os.environ[evar].split() - return ccachelist + self.default_objc - - def get_objcpp_compiler_exelist(self): - ccachelist = self.detect_ccache() - evar = 'OBJCXX' - if evar in os.environ: - return os.environ[evar].split() - return ccachelist + self.default_objcpp - - def get_source_dir(self): - return self.source_dir - - def get_build_dir(self): - return self.build_dir - - def get_exe_suffix(self): - return self.exe_suffix - - # On Windows the library has suffix dll - # but you link against a file that has suffix lib. - def get_import_lib_suffix(self): - return self.import_lib_suffix - - def get_shared_lib_prefix(self): - return self.shared_lib_prefix - - def get_shared_lib_suffix(self): - return self.shared_lib_suffix - - def get_static_lib_prefix(self): - return self.static_lib_prefix - - def get_static_lib_suffix(self): - return self.static_lib_suffix - - def get_object_suffix(self): - return self.object_suffix - - def get_prefix(self): - return self.coredata.get_builtin_option('prefix') - - def get_libdir(self): - return self.coredata.get_builtin_option('libdir') - - def get_bindir(self): - return self.coredata.get_builtin_option('bindir') - - def get_includedir(self): - return self.coredata.get_builtin_option('includedir') - - def get_mandir(self): - return self.coredata.get_builtin_option('mandir') - - def get_datadir(self): - return self.coredata.get_builtin_option('datadir') - - def find_library(self, libname, dirs): - if dirs is None: - dirs = mesonlib.get_library_dirs() - suffixes = [self.get_shared_lib_suffix(), self.get_static_lib_suffix()] - prefix = self.get_shared_lib_prefix() - for d in dirs: - for suffix in suffixes: - trial = os.path.join(d, prefix + libname + '.' + suffix) - if os.path.isfile(trial): - return trial - - -def get_args_from_envvars(lang): - if lang == 'c': - compile_args = os.environ.get('CFLAGS', '').split() - link_args = compile_args + os.environ.get('LDFLAGS', '').split() - compile_args += os.environ.get('CPPFLAGS', '').split() - elif lang == 'cpp': - compile_args = os.environ.get('CXXFLAGS', '').split() - link_args = compile_args + os.environ.get('LDFLAGS', '').split() - compile_args += os.environ.get('CPPFLAGS', '').split() - elif lang == 'objc': - compile_args = os.environ.get('OBJCFLAGS', '').split() - link_args = compile_args + os.environ.get('LDFLAGS', '').split() - compile_args += os.environ.get('CPPFLAGS', '').split() - elif lang == 'objcpp': - compile_args = os.environ.get('OBJCXXFLAGS', '').split() - link_args = compile_args + os.environ.get('LDFLAGS', '').split() - compile_args += os.environ.get('CPPFLAGS', '').split() - elif lang == 'fortran': - compile_args = os.environ.get('FFLAGS', '').split() - link_args = compile_args + os.environ.get('LDFLAGS', '').split() - else: - compile_args = [] - link_args = [] - return (compile_args, link_args) - -class CrossBuildInfo(): - def __init__(self, filename): - self.config = {} - self.parse_datafile(filename) - if 'target_machine' in self.config: - return - if not 'host_machine' in self.config: - raise coredata.MesonException('Cross info file must have either host or a target machine.') - if not 'properties' in self.config: - raise coredata.MesonException('Cross file is missing "properties".') - if not 'binaries' in self.config: - raise coredata.MesonException('Cross file is missing "binaries".') - - def ok_type(self, i): - return isinstance(i, str) or isinstance(i, int) or isinstance(i, bool) - - def parse_datafile(self, filename): - config = configparser.ConfigParser() - config.read(filename) - # This is a bit hackish at the moment. - for s in config.sections(): - self.config[s] = {} - for entry in config[s]: - value = config[s][entry] - if ' ' in entry or '\t' in entry or "'" in entry or '"' in entry: - raise EnvironmentException('Malformed variable name %s in cross file..' % varname) - try: - res = eval(value, {'true' : True, 'false' : False}) - except Exception: - raise EnvironmentException('Malformed value in cross file variable %s.' % varname) - if self.ok_type(res): - self.config[s][entry] = res - elif isinstance(res, list): - for i in res: - if not self.ok_type(i): - raise EnvironmentException('Malformed value in cross file variable %s.' % varname) - self.config[s][entry] = res - else: - raise EnvironmentException('Malformed value in cross file variable %s.' % varname) - - def has_host(self): - return 'host_machine' in self.config - - def has_target(self): - return 'target_machine' in self.config - - # Wehn compiling a cross compiler we use the native compiler for everything. - # But not when cross compiling a cross compiler. - def need_cross_compiler(self): - return 'host_machine' in self.config diff --git a/meson/interpreter.py b/meson/interpreter.py deleted file mode 100644 index 1a32998..0000000 --- a/meson/interpreter.py +++ /dev/null @@ -1,2259 +0,0 @@ -# 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. - -from . import mparser -from . import environment -from . import coredata -from . import dependencies -from . import mlog -from . import build -from . import optinterpreter -from .wrap import wrap -from . import mesonlib - -import os, sys, platform, subprocess, shutil, uuid, re -from functools import wraps - -import importlib - -class InterpreterException(coredata.MesonException): - pass - -class InvalidCode(InterpreterException): - pass - -class InvalidArguments(InterpreterException): - pass - -# 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 - -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 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 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, in_builddir=False): - super().__init__() - pc = self.run_command(command_array, source_dir, build_dir, subdir, in_builddir) - (stdout, stderr) = pc.communicate() - self.returncode = pc.returncode - self.stdout = stdout.decode().replace('\r\n', '\n') - self.stderr = stderr.decode().replace('\r\n', '\n') - self.methods.update({'returncode' : self.returncode_method, - 'stdout' : self.stdout_method, - 'stderr' : self.stderr_method, - }) - - def run_command(self, command_array, source_dir, build_dir, subdir, in_builddir): - cmd_name = command_array[0] - env = {'MESON_SOURCE_ROOT' : source_dir, - 'MESON_BUILD_ROOT' : build_dir, - 'MESON_SUBDIR' : subdir} - 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) - try: - return subprocess.Popen(command_array, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - 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 subprocess.Popen(command_array, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - 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 subprocess.Popen(command_array, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - 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 ConfigurationDataHolder(InterpreterObject): - 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, - 'has' : self.has_method, - }) - - def is_used(self): - return self.used - - def mark_used(self): - self.used = True - - def validate_args(self, args): - 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] - if not isinstance(name, str): - raise InterpreterException("First argument to set must be a string.") - return (name, val) - - def set_method(self, args, kwargs): - (name, val) = self.validate_args(args) - self.held_object.values[name] = val - - def set10_method(self, args, kwargs): - (name, val) = self.validate_args(args) - if val: - self.held_object.values[name] = 1 - else: - self.held_object.values[name] = 0 - - def has_method(self, args, kwargs): - return args[0] in self.held_object.values - - def get(self, name): - return self.held_object.values[name] - - 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}) - - def found_method(self, args, kwargs): - return self.held_object.found() - -class InternalDependencyHolder(InterpreterObject): - def __init__(self, dep): - InterpreterObject.__init__(self) - self.held_object = dep - self.methods.update({'found' : self.found_method}) - - def found_method(self, args, kwargs): - return True - -class ExternalProgramHolder(InterpreterObject): - def __init__(self, ep): - InterpreterObject.__init__(self) - self.held_object = ep - self.methods.update({'found': self.found_method}) - - def found_method(self, args, kwargs): - return self.found() - - def found(self): - return self.held_object.found() - - def get_command(self): - return self.held_object.fullpath - - def get_name(self): - return self.held_object.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_filename(self): - return self.held_object.fullpath - - 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): - check_stringlist(args) - extras = mesonlib.stringlistify(kwargs.get('extra_args', [])) - gl = GeneratedListHolder(self, extras) - [gl.add_file(os.path.join(self.interpreter.subdir, a)) for a in args] - return 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 add_file(self, a): - self.held_object.add_file(a) - -class BuildMachine(InterpreterObject): - def __init__(self): - InterpreterObject.__init__(self) - self.methods.update({'system' : self.system_method, - 'cpu_family' : self.cpu_family_method, - 'cpu' : self.cpu_method, - 'endian' : self.endian_method, - }) - - # 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. - def cpu_family_method(self, args, kwargs): - trial = platform.machine().lower() - if trial.startswith('i') and trial.endswith('86'): - return 'x86' - if trial.startswith('arm'): - return 'arm' - # Add fixes here as bugs are reported. - return trial - - def cpu_method(self, args, kwargs): - return platform.machine().lower() - - def system_method(self, args, kwargs): - return platform.system().lower() - - def endian_method(self, args, kwargs): - return sys.byteorder - -# 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.methods.update({'system' : self.system_method, - 'cpu' : self.cpu_method, - 'cpu_family' : self.cpu_family_method, - 'endian' : self.endian_method, - }) - - def system_method(self, args, kwargs): - return self.info['system'] - - def cpu_method(self, args, kwargs): - return self.info['cpu'] - - def cpu_family_method(self, args, kwargs): - return self.info['cpu_family'] - - def endian_method(self, args, kwargs): - return self.info['endian'] - -class IncludeDirsHolder(InterpreterObject): - def __init__(self, idobj): - super().__init__() - self.held_object = idobj - -class Headers(InterpreterObject): - - def __init__(self, src_subdir, sources, kwargs): - InterpreterObject.__init__(self) - self.sources = sources - self.source_subdir = src_subdir - 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_source_subdir(self): - return self.source_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, in_sourcetree, source_subdir, sources, kwargs): - super().__init__() - kwsource = mesonlib.stringlistify(kwargs.get('sources', [])) - sources += kwsource - check_stringlist(sources) - install_dir = kwargs.get('install_dir', None) - if not isinstance(install_dir, str): - raise InterpreterException('Custom_install_dir must be a string.') - self.held_object = build.Data(in_sourcetree, source_subdir, sources, install_dir) - - 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, source_subdir, installable_subdir, install_dir): - InterpreterObject.__init__(self) - self.source_subdir = source_subdir - self.installable_subdir = installable_subdir - self.install_dir = install_dir - -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: - num = int(s.split('.')[-1]) - 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 BuildTargetHolder(InterpreterObject): - 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, - 'private_dir_include' : self.private_dir_include_method, - }) - - 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 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 JarHolder(BuildTargetHolder): - def __init__(self, target, interp): - super().__init__(target, interp) - -class CustomTargetHolder(InterpreterObject): - def __init__(self, object_to_hold): - self.held_object = object_to_hold - - def is_cross(self): - return self.held_object.is_cross() - - def extract_objects_method(self, args, kwargs): - gobjs = self.held_object.extract_objects(args) - return GeneratedObjectsHolder(gobjs) - -class RunTargetHolder(InterpreterObject): - def __init__(self, name, command, args, subdir): - self.held_object = build.RunTarget(name, command, args, subdir) - -class Test(InterpreterObject): - def __init__(self, name, suite, exe, is_parallel, cmd_args, env, should_fail, valgrind_args, 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.valgrind_args = valgrind_args - 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.subinterpreter = 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.subinterpreter.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, - 'sizeof': self.sizeof_method, - 'has_header': self.has_header_method, - 'run' : self.run_method, - 'has_function' : self.has_function_method, - 'has_member' : self.has_member_method, - 'has_type' : self.has_type_method, - 'alignment' : self.alignment_method, - 'version' : self.version_method, - 'cmd_array' : self.cmd_array_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 = [] - 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 alignment_method(self, args, kwargs): - if len(args) != 1: - raise InterpreterException('Alignment method takes exactly one positional argument.') - check_stringlist(args) - typename = args[0] - extra_args = mesonlib.stringlistify(kwargs.get('args', [])) - result = self.compiler.alignment(typename, self.environment, extra_args) - 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.') - check_stringlist(args) - code = args[0] - testname = kwargs.get('name', '') - if not isinstance(testname, str): - raise InterpreterException('Testname argument must be a string.') - extra_args = self.determine_args(kwargs) - result = self.compiler.run(code, extra_args) - 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 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_function must be a string.') - extra_args = self.determine_args(kwargs) - had = self.compiler.has_member(typename, membername, prefix, extra_args) - 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_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) - had = self.compiler.has_function(funcname, prefix, self.environment, extra_args) - 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) - had = self.compiler.has_type(typename, prefix, extra_args) - if had: - hadtxt = mlog.green('YES') - else: - hadtxt = mlog.red('NO') - mlog.log('Checking for type "', mlog.bold(typename), '": ', hadtxt, sep='') - return had - - 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) - esize = self.compiler.sizeof(element, prefix, self.environment, extra_args) - mlog.log('Checking for size of "%s": %d' % (element, esize)) - return esize - - def compiles_method(self, args, kwargs): - if len(args) != 1: - raise InterpreterException('compiles method takes exactly one argument.') - check_stringlist(args) - code = args[0] - testname = kwargs.get('name', '') - if not isinstance(testname, str): - raise InterpreterException('Testname argument must be a string.') - extra_args = self.determine_args(kwargs) - result = self.compiler.compiles(code, extra_args) - 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.') - check_stringlist(args) - code = args[0] - testname = kwargs.get('name', '') - if not isinstance(testname, str): - raise InterpreterException('Testname argument must be a string.') - extra_args = self.determine_args(kwargs) - result = self.compiler.links(code, extra_args) - 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) - string = args[0] - extra_args = self.determine_args(kwargs) - haz = self.compiler.has_header(string, extra_args) - if haz: - h = mlog.green('YES') - else: - h = mlog.red('NO') - mlog.log('Has header "%s":' % string, h) - return haz - -class ModuleState: - pass - -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)) - state = ModuleState() - state.build_to_src = os.path.relpath(self.interpreter.environment.get_source_dir(), - self.interpreter.environment.get_build_dir()) - state.subdir = self.interpreter.subdir - state.environment = self.interpreter.environment - state.project_name = self.interpreter.build.project_name - state.project_version = self.interpreter.build.dep_manifest[self.interpreter.active_projectname] - state.compilers = self.interpreter.build.compilers - state.targets = self.interpreter.build.targets - state.headers = self.interpreter.build.get_headers() - state.man = self.interpreter.build.get_man() - state.global_args = self.interpreter.build.global_args - value = fn(state, args, kwargs) - 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.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, - 'install_dependency_manifest': self.install_dependency_manifest_method, - 'project_version': self.project_version_method, - }) - - def add_install_script_method(self, args, kwargs): - if len(args) != 1: - raise InterpreterException('Set_install_script takes exactly one argument.') - check_stringlist(args) - scriptbase = args[0] - scriptfile = os.path.join(self.interpreter.environment.source_dir, - self.interpreter.subdir, scriptbase) - if not os.path.isfile(scriptfile): - raise InterpreterException('Can not find install script %s.' % scriptbase) - self.build.install_scripts.append(build.InstallScript([scriptfile])) - - 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 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: - return 'exe_wrap' in self.build.environment.cross_info.config['binaries'] - return True # This is semantically confusing. - - 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 - for c in clist: - if c.get_language() == cname: - return CompilerHolder(c, self.build.environment) - raise InterpreterException('Tried to access compiler for unspecified language "%s".' % cname) - - def is_unity_method(self, args, kwargs): - return self.build.environment.coredata.get_builtin_option('unity') - - 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'] - -class Interpreter(): - - def __init__(self, build, backend, subproject='', subdir='', subproject_dir='subprojects'): - self.build = build - self.backend = backend - self.subproject = subproject - self.subdir = subdir - self.source_root = build.environment.get_source_dir() - self.subproject_dir = subproject_dir - option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt') - if os.path.exists(option_file): - oi = optinterpreter.OptionInterpreter(self.subproject, \ - self.build.environment.cmd_line_options.projectoptions) - oi.process(option_file) - self.build.environment.merge_options(oi.options) - 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) - code = open(mesonfile).read() - if len(code.strip()) == 0: - raise InvalidCode('Builder file is empty.') - assert(isinstance(code, str)) - try: - self.ast = mparser.Parser(code).parse() - except coredata.MesonException as me: - me.file = environment.build_filename - raise me - self.sanity_check_ast() - self.variables = {} - self.builtin = {} - self.builtin['build_machine'] = BuildMachine() - 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.builtin['meson'] = MesonMain(build, self) - self.environment = build.environment - self.build_func_dict() - self.build_def_files = [os.path.join(self.subdir, environment.build_filename)] - self.coredata = self.environment.get_coredata() - self.generators = [] - self.visited_subdirs = {} - self.global_args_frozen = False - self.subprojects = {} - self.subproject_stack = [] - - def build_func_dict(self): - self.funcs = {'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, - '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_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, - } - - def module_method_callback(self, invalues): - unwrap_single = False - if invalues is None: - return - if not isinstance(invalues, list): - unwrap_single = True - invalues = [invalues] - outvalues = [] - for v in invalues: - if isinstance(v, build.CustomTarget): - if v.name in self.build.targets: - raise InterpreterException('Tried to create target %s which already exists.' % v.name) - self.build.targets[v.name] = v - outvalues.append(CustomTargetHolder(v)) - elif isinstance(v, int) or isinstance(v, str): - outvalues.append(v) - elif isinstance(v, build.Executable): - if v.name in self.build.targets: - raise InterpreterException('Tried to create target %s which already exists.' % v.name) - self.build.targets[v.name] = v - outvalues.append(ExecutableHolder(v)) - elif isinstance(v, list): - outvalues.append(self.module_method_callback(v)) - elif isinstance(v, build.GeneratedList): - outvalues.append(GeneratedListHolder(v)) - elif isinstance(v, build.RunTarget): - if v.name in self.build.targets: - raise InterpreterException('Tried to create target %s which already exists.' % v.name) - self.build.targets[v.name] = v - elif isinstance(v, build.InstallScript): - self.build.install_scripts.append(v) - elif isinstance(v, build.Data): - self.build.data.append(v) - else: - print(v) - raise InterpreterException('Module returned a value of unknown type.') - if len(outvalues) == 1 and unwrap_single: - return outvalues[0] - return outvalues - - def get_build_def_files(self): - return self.build_def_files - - def get_variables(self): - return self.variables - - 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): - self.evaluate_codeblock(self.ast) - mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets)))) - - def evaluate_codeblock(self, node): - 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 - 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 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 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 - - @stringArgs - @noKwargs - def func_import(self, node, args, kwargs): - if len(args) != 1: - raise InvalidCode('Import takes one argument.') - modname = args[0] - if not modname in self.environment.coredata.modules: - module = importlib.import_module('meson.modules.' + modname).initialize() - self.environment.coredata.modules[modname] = module - 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): - 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 = kwargs.get('dependencies', []) - if not isinstance(deps, list): - deps = [deps] - 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(incs, libs, sources, final_deps) - return InternalDependencyHolder(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 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 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 self.is_elementary_type(cur): - return cur - else: - raise InvalidCode("Unknown statement.") - - 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 != 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 is of incorrect type.') - check_stringlist(cargs, 'Run_command arguments must be strings.') - args = cmd + cargs - in_builddir = kwargs.get('in_builddir', False) - if not isinstance(in_builddir, bool): - raise InterpreterException('in_builddir must be boolean.') - return RunProcess(args, self.environment.source_dir, self.environment.build_dir, - self.subdir, in_builddir) - - @stringArgs - def func_gettext(self, nodes, args, kwargs): - if len(args) != 1: - raise InterpreterException('Gettext requires one positional argument (package name).') - packagename = args[0] - languages = kwargs.get('languages', None) - check_stringlist(languages, 'Argument languages must be a list of strings.') - # TODO: check that elements are strings - if len(self.build.pot) > 0: - raise InterpreterException('More than one gettext definition currently not supported.') - self.build.pot.append((packagename, languages, self.subdir)) - - 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 self.subdir != '': - segs = os.path.split(self.subdir) - if len(segs) != 2 or segs[0] != self.subproject_dir: - raise InterpreterException('Subprojects must be defined at the root directory.') - if dirname in self.subproject_stack: - fullstack = self.subproject_stack + [dirname] - incpath = ' => '.join(fullstack) - raise InterpreterException('Recursive include of subprojects: %s.' % incpath) - if dirname in self.subprojects: - return self.subprojects[dirname] - r = wrap.Resolver(os.path.join(self.build.environment.get_source_dir(), self.subproject_dir)) - resolved = r.resolve(dirname) - if resolved is None: - raise InterpreterException('Subproject directory does not exist and can not be downloaded.') - 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) - 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 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] = True - 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 optname not in coredata.builtin_options and self.is_subproject(): - optname = self.subproject + ':' + optname - try: - return self.environment.coredata.user_options[optname].value - except KeyError: - 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) - builtin_options = self.coredata.builtin_options - if key in builtin_options: - if not hasattr(self.environment.cmd_line_options, value): - self.coredata.set_builtin_option(key, value) - # If this was set on the command line, do not override. - else: - newoptions = [option] + self.environment.cmd_line_options.projectoptions - self.environment.cmd_line_options.projectoptions = newoptions - - @stringArgs - def func_project(self, node, args, kwargs): - if len(args) < 2: - raise InvalidArguments('Not enough arguments to project(). Needs at least the project name and one language') - - if not self.is_subproject(): - self.build.project_name = args[0] - if self.environment.first_invocation and 'default_options' in kwargs: - self.parse_default_options(kwargs['default_options']) - self.active_projectname = args[0] - self.project_version = kwargs.get('version', 'undefined') - proj_license = mesonlib.stringlistify(kwargs.get('license', 'unknown')) - self.build.dep_manifest[args[0]] = {'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] = args[0] - mlog.log('Project name: ', mlog.bold(args[0]), sep='') - self.add_languages(node, args[1:]) - langs = self.coredata.compilers.keys() - if 'vala' in langs: - if not 'c' in langs: - raise InterpreterException('Compiling Vala requires C. Add C to your project languages and rerun Meson.') - - @noKwargs - @stringArgs - def func_add_languages(self, node, args, kwargs): - self.add_languages(node, args) - - @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) - return - - - @noKwargs - def func_error(self, node, args, kwargs): - self.validate_arguments(args, 1, [str]) - raise InterpreterException('Error encountered: ' + args[0]) - - def add_languages(self, node, args): - need_cross_compiler = self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler() - for lang in args: - lang = lang.lower() - if lang in self.coredata.compilers: - comp = self.coredata.compilers[lang] - cross_comp = self.coredata.cross_compilers.get(lang, None) - else: - 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 is too (I think). - elif lang == 'rust': - comp = self.environment.detect_rust_compiler() - if need_cross_compiler: - cross_comp = comp # FIXME, probably 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.coredata.compilers[lang] = comp - if cross_comp is not None: - cross_comp.sanity_check(self.environment.get_scratch_dir()) - self.coredata.cross_compilers[lang] = cross_comp - new_options = 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 - mlog.log('Native %s compiler: ' % lang, mlog.bold(' '.join(comp.get_exelist())), ' (%s %s)' % (comp.id, comp.version), sep='') - if not comp.get_language() in self.coredata.external_args: - (ext_compile_args, ext_link_args) = environment.get_args_from_envvars(comp.get_language()) - self.coredata.external_args[comp.get_language()] = ext_compile_args - self.coredata.external_link_args[comp.get_language()] = ext_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) - - def func_find_program(self, node, args, kwargs): - self.validate_arguments(args, 1, [str]) - required = kwargs.get('required', True) - if not isinstance(required, bool): - raise InvalidArguments('"required" argument must be a boolean.') - exename = args[0] - if exename in self.coredata.ext_progs and\ - self.coredata.ext_progs[exename].found(): - return ExternalProgramHolder(self.coredata.ext_progs[exename]) - # Search for scripts relative to current subdir. - search_dir = os.path.join(self.environment.get_source_dir(), self.subdir) - extprog = dependencies.ExternalProgram(exename, search_dir=search_dir) - progobj = ExternalProgramHolder(extprog) - self.coredata.ext_progs[exename] = extprog - if required and not progobj.found(): - raise InvalidArguments('Program "%s" not found.' % exename) - return progobj - - def func_find_library(self, node, args, kwargs): - self.validate_arguments(args, 1, [str]) - required = kwargs.get('required', True) - if not isinstance(required, bool): - raise InvalidArguments('"required" argument must be a boolean.') - libname = args[0] - # We do not cache found libraries because they can come - # and go between invocations wildly. As an example we - # may find the 64 bit version but need instead the 32 bit - # one that is not installed. If we cache the found path - # then we will never found the new one if it get installed. - # This causes a bit of a slowdown as libraries are rechecked - # on every regen, but since it is a fast operation it should be - # ok. - if 'dirs' in kwargs: - search_dirs = kwargs['dirs'] - if not isinstance(search_dirs, list): - search_dirs = [search_dirs] - for i in search_dirs: - if not isinstance(i, str): - raise InvalidCode('Directory entry is not a string.') - if not os.path.isabs(i): - raise InvalidCode('Search directory %s is not an absolute path.' % i) - else: - search_dirs = None - result = self.environment.find_library(libname, search_dirs) - extlib = dependencies.ExternalLibrary(libname, result) - libobj = ExternalLibraryHolder(extlib) - if required and not libobj.found(): - raise InvalidArguments('External library "%s" not found.' % libname) - return libobj - - def func_dependency(self, node, args, kwargs): - self.validate_arguments(args, 1, [str]) - name = args[0] - identifier = dependencies.get_dep_identifier(name, kwargs) - if identifier in self.coredata.deps: - dep = self.coredata.deps[identifier] - else: - dep = dependencies.Dependency() # Returns always false for dep.found() - if not dep.found(): - try: - dep = dependencies.find_external_dependency(name, self.environment, kwargs) - except dependencies.DependencyException: - if 'fallback' in kwargs: - return self.dependency_fallback(kwargs) - raise - self.coredata.deps[identifier] = dep - return DependencyHolder(dep) - - def dependency_fallback(self, kwargs): - fbinfo = kwargs['fallback'] - check_stringlist(fbinfo) - if len(fbinfo) != 2: - raise InterpreterException('Fallback info must have exactly two items.') - dirname, varname = fbinfo - self.do_subproject(dirname, kwargs) - return self.subprojects[dirname].get_variable_method([varname], {}) - - 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_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('Incorrect number of arguments') - name = args[0] - tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, kwargs)) - self.add_target(name, tg.held_object) - return tg - - @noKwargs - def func_run_target(self, node, args, kwargs): - if len(args) < 2: - raise InterpreterException('Incorrect number of arguments') - cleaned_args = [] - for i in args: - try: - i = i.held_object - except AttributeError: - pass - if not isinstance(i, (str, build.BuildTarget, build.CustomTarget)): - mlog.debug('Wrong type:', str(i)) - raise InterpreterException('Invalid argument to run_target.') - cleaned_args.append(i) - name = cleaned_args[0] - command = cleaned_args[1] - cmd_args = cleaned_args[2:] - tg = RunTargetHolder(name, command, cmd_args, 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 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)): - raise InterpreterException('Command line arguments must be strings') - envlist = kwargs.get('env', []) - 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 - valgrind_args = kwargs.get('valgrind_args', []) - if not isinstance(valgrind_args, list): - valgrind_args = [valgrind_args] - for a in valgrind_args: - if not isinstance(a, str): - raise InterpreterException('Valgrind_arg not a string.') - 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 = mesonlib.stringlistify(kwargs.get('suite', '')) - if self.is_subproject(): - newsuite = [] - for s in suite: - newsuite.append(self.subproject.replace(' ', '_').replace('.', '_') + '.' + s) - suite = newsuite - t = Test(args[0], suite, args[1].held_object, par, cmd_args, env, should_fail, valgrind_args, 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='') - - @stringArgs - def func_install_headers(self, node, args, kwargs): - h = Headers(self.subdir, args, 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 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 - try: - os.makedirs(os.path.join(self.environment.build_dir, subdir)) - except FileExistsError: - pass - 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): - raise InterpreterException('Nonexistant build def file %s.' % buildfilename) - code = open(absname).read() - assert(isinstance(code, str)) - try: - codeblock = mparser.Parser(code).parse() - except coredata.MesonException as me: - me.file = buildfilename - raise me - self.evaluate_codeblock(codeblock) - self.subdir = prev_subdir - - @stringArgs - def func_install_data(self, node, args, kwargs): - data = DataHolder(True, self.subdir, args, kwargs) - 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 not 'install_dir' 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.') - idir = InstallDir(self.subdir, args[0], install_dir) - 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 not 'input' in kwargs: - raise InterpreterException('Required keyword argument "input" not defined.') - if not 'output' in kwargs: - raise InterpreterException('Required keyword argument "output" not defined.') - inputfile = kwargs['input'] - output = kwargs['output'] - if not isinstance(inputfile, str): - raise InterpreterException('Input must be a string.') - if not isinstance(output, str): - raise InterpreterException('Output must be a string.') - if 'configuration' in kwargs: - conf = kwargs['configuration'] - if not isinstance(conf, ConfigurationDataHolder): - raise InterpreterException('Argument "configuration" is not of type configuration_data') - - conffile = os.path.join(self.subdir, inputfile) - if conffile not in self.build_def_files: - self.build_def_files.append(conffile) - os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True) - ifile_abs = os.path.join(self.environment.source_dir, self.subdir, inputfile) - ofile_abs = os.path.join(self.environment.build_dir, self.subdir, output) - mesonlib.do_conf_file(ifile_abs, ofile_abs, conf.held_object) - conf.mark_used() - elif 'command' in kwargs: - res = self.func_run_command(node, kwargs['command'], {}) - 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".') - if isinstance(kwargs.get('install_dir', None), str): - self.build.data.append(DataHolder(False, self.subdir, [output], kwargs).held_object) - return mesonlib.File.from_built_file(self.subdir, output) - - @stringArgs - def func_include_directories(self, node, args, kwargs): - absbase = os.path.join(self.environment.get_source_dir(), self.subdir) - for a in args: - absdir = os.path.join(absbase, a) - if not os.path.isdir(absdir): - 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_global_arguments(self, node, args, kwargs): - if self.subproject != '': - raise InvalidCode('Global arguments can not be set in subprojects because there is no way to make that reliable.') - if self.global_args_frozen: - raise InvalidCode('Tried to set global arguments after a build target has been declared.\nThis is not permitted. Please declare all global arguments before your targets.') - if not 'language' in kwargs: - raise InvalidCode('Missing language definition in add_global_arguments') - lang = kwargs['language'].lower() - if lang in self.build.global_args: - self.build.global_args[lang] += args - else: - self.build.global_args[lang] = args - - def flatten(self, args): - if isinstance(args, mparser.StringNode): - return args.value - if isinstance(args, str): - return args - if isinstance(args, InterpreterObject): - return args - if isinstance(args, int): - 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 source_strings_to_files(self, sources): - results = [] - for s in sources: - if isinstance(s, mesonlib.File) or isinstance(s, GeneratedListHolder) or \ - isinstance(s, 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 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): - 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 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) - l = targetholder(target, self) - self.add_target(name, l.held_object) - self.global_args_frozen = True - return 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 %s.' % s) - - 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: - raise InvalidCode('Unknown function "%s".' % func_name) - - def is_assignable(self, value): - if isinstance(value, InterpreterObject) or \ - isinstance(value, dependencies.Dependency) or\ - isinstance(value, str) or\ - isinstance(value, int) or \ - isinstance(value, list) or \ - isinstance(value, mesonlib.File): - return True - return False - - def assignment(self, node): - assert(isinstance(node, mparser.AssignmentNode)) - 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.') - self.set_variable(var_name, value) - return value - - def reduce_arguments(self, args): - assert(isinstance(args, mparser.ArgumentNode)) - if args.incorrect_order(): - raise InvalidArguments('All keyword arguments must be after positional arguments.') - 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] - return (reduced_pos, reduced_kw) - - 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 == '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 == 'endswith': - s = posargs[0] - if not isinstance(s, str): - raise InterpreterException('Argument must be a string.') - if method_name == 'startswith': - return obj.startswith(s) - return obj.endswith(s) - raise InterpreterException('Unknown method "%s" for a string.' % method_name) - - def to_native(self, arg): - if isinstance(arg, mparser.StringNode) or \ - isinstance(arg, mparser.NumberNode) or \ - isinstance(arg, mparser.BooleanNode): - return arg.value - return arg - - 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 - - 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 - if method_name == 'extract_objects' and self.environment.coredata.get_builtin_option('unity'): - raise InterpreterException('Single object files can not be extracted in Unity builds.') - 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, list): - return self.array_method_call(obj, method_name, self.reduce_arguments(args)[0]) - 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) - - # 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 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] - if not isinstance(index, int): - raise InvalidArguments('Array index must be a number.') - if index < -len(obj) or index >= len(obj): - raise InvalidArguments('Array index %s is out of bounds for array of size %d.' % (index, len(obj))) - return obj[index] - raise InterpreterException('Arrays do not have a method called "%s".' % method_name) - - 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 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)): - print(result) - raise InvalidCode('If clause does not evaluate to true or false.') - if result: - self.evaluate_codeblock(i.block) - return - if not isinstance(node.elseblock, mparser.EmptyNode): - self.evaluate_codeblock(node.elseblock) - - 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 not isinstance(old_variable, list): - raise InvalidArguments('The += operator currently only works with arrays.') - # 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 is_elementary_type(self, v): - if isinstance(v, (int, float, str, bool, list)): - return True - return False - - 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 - else: - raise InvalidCode('You broke me.') - - 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_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_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 - else: - raise InvalidCode('You broke me.') - - 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 is_subproject(self): - return self.subproject != '' diff --git a/meson/mconf.py b/meson/mconf.py deleted file mode 100644 index f174425..0000000 --- a/meson/mconf.py +++ /dev/null @@ -1,209 +0,0 @@ -#!/usr/bin/env python3 - -# 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 sys, os -import pickle -import argparse -from . import coredata, mesonlib -from .coredata import build_types, warning_levels, libtypelist - -parser = argparse.ArgumentParser() - -parser.add_argument('-D', action='append', default=[], dest='sets', - help='Set an option to the given value.') -parser.add_argument('directory', nargs='*') - -class ConfException(coredata.MesonException): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - -class Conf: - def __init__(self, build_dir): - self.build_dir = build_dir - self.coredata_file = os.path.join(build_dir, 'meson-private/coredata.dat') - self.build_file = os.path.join(build_dir, 'meson-private/build.dat') - if not os.path.isfile(self.coredata_file) or not os.path.isfile(self.build_file): - raise ConfException('Directory %s does not seem to be a Meson build directory.' % build_dir) - self.coredata = pickle.load(open(self.coredata_file, 'rb')) - self.build = pickle.load(open(self.build_file, 'rb')) - if self.coredata.version != coredata.version: - raise ConfException('Version mismatch (%s vs %s)' % - (coredata.version, self.coredata.version)) - - def save(self): - # Only called if something has changed so overwrite unconditionally. - pickle.dump(self.coredata, open(self.coredata_file, 'wb')) - # We don't write the build file because any changes to it - # are erased when Meson is executed the nex time, i.e. the next - # time Ninja is run. - - def print_aligned(self, arr): - if len(arr) == 0: - return - titles = ['Option', 'Description', 'Current Value', ''] - longest_name = len(titles[0]) - longest_descr = len(titles[1]) - longest_value = len(titles[2]) - longest_possible_value = len(titles[3]) - for x in arr: - longest_name = max(longest_name, len(x[0])) - longest_descr = max(longest_descr, len(x[1])) - longest_value = max(longest_value, len(str(x[2]))) - longest_possible_value = max(longest_possible_value, len(x[3])) - - if longest_possible_value > 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(value, bool): - value = 'true' if value else 'false' - possible_values = i[3] - 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 self.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.endswith('linkargs'): - lang = k[:-8] - if not lang 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[:-4] - if not lang 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 = [] - booleans = '[true, false]' - carr.append(['buildtype', 'Build type', self.coredata.get_builtin_option('buildtype'), build_types]) - carr.append(['warning_level', 'Warning level', self.coredata.get_builtin_option('warning_level'), warning_levels]) - carr.append(['strip', 'Strip on install', self.coredata.get_builtin_option('strip'), booleans]) - carr.append(['coverage', 'Coverage report', self.coredata.get_builtin_option('coverage'), booleans]) - carr.append(['use_pch', 'Precompiled headers', self.coredata.get_builtin_option('use_pch'), booleans]) - carr.append(['unity', 'Unity build', self.coredata.get_builtin_option('unity'), booleans]) - carr.append(['default_library', 'Default library type', self.coredata.get_builtin_option('default_library'), libtypelist]) - self.print_aligned(carr) - 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 + 'linkargs', 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 = [] - parr.append(['prefix', 'Install prefix', self.coredata.get_builtin_option('prefix'), '']) - parr.append(['libdir', 'Library directory', self.coredata.get_builtin_option('libdir'), '']) - parr.append(['bindir', 'Binary directory', self.coredata.get_builtin_option('bindir'), '']) - parr.append(['includedir', 'Header directory', self.coredata.get_builtin_option('includedir'), '']) - parr.append(['datadir', 'Data directory', self.coredata.get_builtin_option('datadir'), '']) - parr.append(['mandir', 'Man page directory', self.coredata.get_builtin_option('mandir'), '']) - parr.append(['localedir', 'Locale file directory', self.coredata.get_builtin_option('localedir'), '']) - 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) - -def run(args): - args = mesonlib.expand_arguments(args) - if not args: - sys.exit(1) - options = parser.parse_args(args) - if len(options.directory) > 1: - print('%s <build directory>' % 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) - if len(options.sets) > 0: - c.set_options(options.sets) - c.save() - else: - c.print_conf() - 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:])) diff --git a/meson/mesonlib.py b/meson/mesonlib.py deleted file mode 100644 index 2ab5ce4..0000000 --- a/meson/mesonlib.py +++ /dev/null @@ -1,284 +0,0 @@ -# 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 platform, subprocess, operator, os, shutil, re, sys - -from glob import glob - -from .coredata import MesonException - -class File: - def __init__(self, is_built, subdir, fname): - self.is_built = is_built - self.subdir = subdir - self.fname = fname - - @staticmethod - def from_source_file(source_root, subdir, fname): - if not os.path.isfile(os.path.join(source_root, subdir, fname)): - raise MesonException('File %s does not exist.' % fname) - return File(False, subdir, fname) - - @staticmethod - def from_built_file(subdir, fname): - return File(True, subdir, fname) - - @staticmethod - def from_absolute_file(fname): - return File(False, '', fname) - - def rel_to_builddir(self, build_to_src): - if self.is_built: - return os.path.join(self.subdir, self.fname) - else: - return os.path.join(build_to_src, self.subdir, self.fname) - - def endswith(self, ending): - return self.fname.endswith(ending) - - def split(self, s): - return self.fname.split(s) - - def __eq__(self, other): - return (self.fname, self.subdir, self.is_built) == (other.fname, other.subdir, other.is_built) - - def __hash__(self): - return hash((self.fname, self.subdir, self.is_built)) - -def flatten(item): - if not isinstance(item, list): - return item - result = [] - for i in item: - if isinstance(i, list): - result += flatten(i) - else: - result.append(i) - return result - -def is_osx(): - return platform.system().lower() == 'darwin' - -def is_linux(): - return platform.system().lower() == 'linux' - -def is_windows(): - platname = platform.system().lower() - return platname == 'windows' or 'mingw' in platname - -def is_32bit(): - return not(sys.maxsize > 2**32) - -def is_debianlike(): - try: - open('/etc/debian_version', 'r') - return True - except FileNotFoundError: - return False - -def exe_exists(arglist): - try: - p = subprocess.Popen(arglist, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - p.communicate() - if p.returncode == 0: - return True - except FileNotFoundError: - pass - return False - -def detect_vcs(source_dir): - vcs_systems = [ - dict(name = 'git', cmd = 'git', repo_dir = '.git', get_rev = 'git describe --dirty=+', rev_regex = '(.*)', dep = '.git/logs/HEAD'), - dict(name = 'mercurial', cmd = 'hg', repo_dir = '.hg', get_rev = 'hg id -n', rev_regex = '(.*)', dep = '.hg/dirstate'), - dict(name = 'subversion', cmd = 'svn', repo_dir = '.svn', get_rev = 'svn info', rev_regex = 'Revision: (.*)', dep = '.svn/wc.db'), - dict(name = 'bazaar', cmd = 'bzr', repo_dir = '.bzr', get_rev = 'bzr revno', rev_regex = '(.*)', dep = '.bzr'), - ] - - segs = source_dir.replace('\\', '/').split('/') - for i in range(len(segs), -1, -1): - curdir = '/'.join(segs[:i]) - for vcs in vcs_systems: - if os.path.isdir(os.path.join(curdir, vcs['repo_dir'])) and shutil.which(vcs['cmd']): - vcs['wc_dir'] = curdir - return vcs - return None - -numpart = re.compile('[0-9.]+') - -def version_compare(vstr1, vstr2): - match = numpart.match(vstr1.strip()) - if match is None: - raise MesonException('Unconparable version string %s.' % vstr1) - vstr1 = match.group(0) - if vstr2.startswith('>='): - 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 = [int(x) for x in vstr1.split('.')] - varr2 = [int(x) for x in vstr2.split('.')] - return cmpop(varr1, varr2) - -def default_libdir(): - try: - archpath = subprocess.check_output(['dpkg-architecture', '-qDEB_HOST_MULTIARCH']).decode().strip() - return 'lib/' + archpath - except: - pass - if os.path.isdir('/usr/lib64'): - return 'lib64' - return 'lib' - -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 = 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 = 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): - data = open(src).readlines() - regex = re.compile('@(.*?)@') - 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 + '~' - open(dst_tmp, 'w').writelines(result) - shutil.copymode(src, dst_tmp) - replace_if_different(dst, dst_tmp) - - -def replace_if_different(dst, dst_tmp): - # If contents are identical, don't touch the file to prevent - # unnecessary rebuilds. - try: - if open(dst, 'r').read() == open(dst_tmp, 'r').read(): - os.unlink(dst_tmp) - return - except FileNotFoundError: - pass - os.replace(dst_tmp, dst) - -def stringlistify(item): - if isinstance(item, str): - item = [item] - if not isinstance(item, list): - raise MesonException('Item is not an array') - for i in item: - if not isinstance(i, str): - raise MesonException('List item not a string.') - return item - -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 diff --git a/meson/mesonmain.py b/meson/mesonmain.py deleted file mode 100644 index 7b4f2c2..0000000 --- a/meson/mesonmain.py +++ /dev/null @@ -1,263 +0,0 @@ -#!/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. - -import sys, stat, traceback, pickle, argparse -import datetime -import os.path -from . import environment, interpreter, mesonlib -from . import build -import platform -from . import mlog, coredata - -from .coredata import MesonException, build_types, layouts, warning_levels, libtypelist - -backendlist = ['ninja', 'vs2010', 'xcode'] - -parser = argparse.ArgumentParser() - -default_warning = '1' - -if mesonlib.is_windows(): - def_prefix = 'c:/' -else: - def_prefix = '/usr/local' - -parser.add_argument('--prefix', default=def_prefix, dest='prefix', - help='the installation prefix (default: %(default)s)') -parser.add_argument('--libdir', default=mesonlib.default_libdir(), dest='libdir', - help='the installation subdir of libraries (default: %(default)s)') -parser.add_argument('--bindir', default='bin', dest='bindir', - help='the installation subdir of executables (default: %(default)s)') -parser.add_argument('--includedir', default='include', dest='includedir', - help='relative path of installed headers (default: %(default)s)') -parser.add_argument('--datadir', default='share', dest='datadir', - help='relative path to the top of data file subdirectory (default: %(default)s)') -parser.add_argument('--mandir', default='share/man', dest='mandir', - help='relative path of man files (default: %(default)s)') -parser.add_argument('--localedir', default='share/locale', dest='localedir', - help='relative path of locale data (default: %(default)s)') -parser.add_argument('--backend', default='ninja', dest='backend', choices=backendlist, - help='backend to use (default: %(default)s)') -parser.add_argument('--buildtype', default='debug', choices=build_types, dest='buildtype', - help='build type go use (default: %(default)s)') -parser.add_argument('--strip', action='store_true', dest='strip', default=False,\ - help='strip targets on install (default: %(default)s)') -parser.add_argument('--enable-gcov', action='store_true', dest='coverage', default=False,\ - help='measure test coverage') -parser.add_argument('--disable-pch', action='store_false', dest='use_pch', default=True,\ - help='do not use precompiled headers') -parser.add_argument('--unity', action='store_true', dest='unity', default=False,\ - help='unity build') -parser.add_argument('--werror', action='store_true', dest='werror', default=False,\ - help='Treat warnings as errors') -parser.add_argument('--layout', choices=layouts, dest='layout', default='mirror',\ - help='Build directory layout.') -parser.add_argument('--default-library', choices=libtypelist, dest='default_library', - default='shared', help='Default library type.') -parser.add_argument('--warnlevel', default=default_warning, dest='warning_level', choices=warning_levels,\ - help='Level of compiler warnings to use (larger is more, default is %(default)s)') -parser.add_argument('--cross-file', default=None, dest='cross_file', - 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='store_true', dest='print_version', default=False, - help='Print version.') -parser.add_argument('directories', nargs='*') - -class MesonApp(): - - def __init__(self, dir1, dir2, script_file, handshake, options): - (self.source_dir, self.build_dir) = self.validate_dirs(dir1, dir2, handshake) - if not os.path.isabs(options.prefix): - raise RuntimeError('--prefix must be an absolute path.') - self.meson_script_file = script_file - self.options = options - - 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 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.''' - raise RuntimeError(msg) - else: - if handshake: - raise RuntimeError('Something went terribly wrong. Please file a bug.') - return (src_dir, build_dir) - - def generate(self): - env = environment.Environment(self.source_dir, self.build_dir, self.meson_script_file, self.options) - 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')) - 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 . import ninjabackend - g = ninjabackend.NinjaBackend(b) - elif self.options.backend == 'vs2010': - from . import vs2010backend - g = vs2010backend.Vs2010Backend(b) - elif self.options.backend == 'xcode': - from . 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() - g.generate(intr) - env.generating_finished() - dumpfile = os.path.join(env.get_scratch_dir(), 'build.dat') - pickle.dump(b, open(dumpfile, 'wb')) - -def run_script_command(args): - cmdname = args[0] - cmdargs = args[1:] - if cmdname == 'test': - import meson.scripts.meson_test as abc - cmdfunc = abc.run - elif cmdname == 'benchmark': - import meson.scripts.meson_benchmark as abc - cmdfunc = abc.run - elif cmdname == 'install': - import meson.scripts.meson_install as abc - cmdfunc = abc.run - elif cmdname == 'commandrunner': - import meson.scripts.commandrunner as abc - cmdfunc = abc.run - elif cmdname == 'delsuffix': - import meson.scripts.delwithsuffix as abc - cmdfunc = abc.run - elif cmdname == 'depfixer': - import meson.scripts.depfixer as abc - cmdfunc = abc.run - elif cmdname == 'dirchanger': - import meson.scripts.dirchanger as abc - cmdfunc = abc.run - elif cmdname == 'gtkdoc': - import meson.scripts.gtkdochelper as abc - cmdfunc = abc.run - elif cmdname == 'regencheck': - import meson.scripts.regen_checker as abc - cmdfunc = abc.run - elif cmdname == 'symbolextractor': - import meson.scripts.symbolextractor as abc - cmdfunc = abc.run - elif cmdname == 'vcstagger': - import meson.scripts.vcstagger 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 args[0] == '--internal': - if args[1] != 'regenerate': - sys.exit(run_script_command(args[1:])) - args = args[2:] - handshake = True - else: - handshake = False - args = mesonlib.expand_arguments(args) - if not args: - return 1 - options = parser.parse_args(args) - if options.print_version: - print(coredata.version) - return 0 - args = options.directories - if len(args) == 0 or len(args) > 2: - print('%s <source directory> <build directory>' % sys.argv[0]) - print('If you omit either directory, the current directory is substituted.') - return 1 - dir1 = args[0] - if len(args) > 1: - dir2 = args[1] - else: - dir2 = '.' - while os.path.islink(mainfile): - resolved = os.readlink(mainfile) - if resolved[0] != '/': - mainfile = os.path.join(os.path.dirname(mainfile), resolved) - else: - mainfile = resolved - - try: - app = MesonApp(dir1, dir2, mainfile, handshake, options) - 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 diff --git a/meson/mesonmain.ui b/meson/mesonmain.ui deleted file mode 100644 index 209584b..0000000 --- a/meson/mesonmain.ui +++ /dev/null @@ -1,248 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>MainWindow</class> - <widget class="QMainWindow" name="MainWindow"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>740</width> - <height>613</height> - </rect> - </property> - <property name="windowTitle"> - <string>Meson</string> - </property> - <widget class="QWidget" name="centralwidget"> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Project</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="project_label"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>TextLabel</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Source directory</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLabel" name="srcdir_label"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>TextLabel</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_5"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Build directory</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLabel" name="builddir_label"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>TextLabel</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string>Build type</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLabel" name="buildtype_label"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>TextLabel</string> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Backend</string> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QLabel" name="backend_label"> - <property name="text"> - <string>Ninja</string> - </property> - </widget> - </item> - <item row="5" column="0" colspan="2"> - <widget class="QTabWidget" name="tabWidget"> - <property name="currentIndex"> - <number>2</number> - </property> - <widget class="QWidget" name="core_tab"> - <attribute name="title"> - <string>Core data</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_6"> - <item row="0" column="0"> - <widget class="QTreeView" name="core_view"/> - </item> - </layout> - </widget> - <widget class="QWidget" name="path_tab"> - <attribute name="title"> - <string>Paths</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <widget class="QTreeView" name="path_view"/> - </item> - </layout> - </widget> - <widget class="QWidget" name="option_tab"> - <attribute name="title"> - <string>Options</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_4"> - <item row="0" column="0"> - <layout class="QFormLayout" name="option_form"/> - </item> - </layout> - </widget> - <widget class="QWidget" name="dependency_tab"> - <attribute name="title"> - <string>Dependencies</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_5"> - <item row="0" column="0"> - <widget class="QTreeView" name="dep_view"/> - </item> - </layout> - </widget> - <widget class="QWidget" name="target_tab"> - <attribute name="title"> - <string>Build targets</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QTreeView" name="target_view"/> - </item> - </layout> - </widget> - </widget> - </item> - <item row="6" column="0" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QPushButton" name="save_button"> - <property name="text"> - <string>Save</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="compile_button"> - <property name="text"> - <string>Compile</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="test_button"> - <property name="text"> - <string>Run tests</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="install_button"> - <property name="text"> - <string>Install</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="clean_button"> - <property name="text"> - <string>Clean</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <widget class="QMenuBar" name="menubar"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>740</width> - <height>25</height> - </rect> - </property> - <widget class="QMenu" name="menuFile"> - <property name="title"> - <string>File</string> - </property> - <addaction name="actionSave"/> - <addaction name="actionQuit"/> - </widget> - <addaction name="menuFile"/> - </widget> - <widget class="QStatusBar" name="statusbar"/> - <action name="actionSave"> - <property name="text"> - <string>&Save</string> - </property> - </action> - <action name="actionQuit"> - <property name="text"> - <string>&Quit</string> - </property> - </action> - </widget> - <resources/> - <connections/> -</ui> diff --git a/meson/mesonrunner.ui b/meson/mesonrunner.ui deleted file mode 100644 index 942c6bd..0000000 --- a/meson/mesonrunner.ui +++ /dev/null @@ -1,52 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>rundialog</class> - <widget class="QDialog" name="rundialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>581</width> - <height>368</height> - </rect> - </property> - <property name="windowTitle"> - <string>External process output</string> - </property> - <property name="modal"> - <bool>true</bool> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="0"> - <widget class="QLabel" name="timelabel"> - <property name="text"> - <string>Compile time: 0:0</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QPushButton" name="termbutton"> - <property name="text"> - <string>Terminate</string> - </property> - </widget> - </item> - <item row="0" column="0" colspan="2"> - <widget class="QTextEdit" name="console"> - <property name="readOnly"> - <bool>true</bool> - </property> - <property name="html"> - <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/meson/mesonstart.ui b/meson/mesonstart.ui deleted file mode 100644 index c6c5f96..0000000 --- a/meson/mesonstart.ui +++ /dev/null @@ -1,119 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>MainWindow</class> - <widget class="QMainWindow" name="MainWindow"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>644</width> - <height>192</height> - </rect> - </property> - <property name="windowTitle"> - <string>Meson</string> - </property> - <widget class="QWidget" name="centralwidget"> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Source directory</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="source_entry"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QPushButton" name="source_browse_button"> - <property name="text"> - <string>Browse</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Build directory</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="build_entry"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QPushButton" name="build_browse_button"> - <property name="text"> - <string>Browse</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Cross file</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLineEdit" name="cross_entry"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QPushButton" name="cross_browse_button"> - <property name="text"> - <string>Browse</string> - </property> - </widget> - </item> - <item row="3" column="2"> - <widget class="QPushButton" name="generate_button"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Generate</string> - </property> - </widget> - </item> - </layout> - </widget> - <widget class="QMenuBar" name="menubar"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>644</width> - <height>25</height> - </rect> - </property> - </widget> - <widget class="QStatusBar" name="statusbar"/> - </widget> - <resources/> - <connections/> -</ui> diff --git a/meson/mgui.py b/meson/mgui.py deleted file mode 100644 index 6e57ce7..0000000 --- a/meson/mgui.py +++ /dev/null @@ -1,565 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2013-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 sys, os, pickle, time, shutil -from . import build, coredata, environment, mesonlib -from PyQt5 import uic -from PyQt5.QtWidgets import QApplication, QMainWindow, QHeaderView -from PyQt5.QtWidgets import QComboBox, QCheckBox -from PyQt5.QtCore import QAbstractItemModel, QModelIndex, QVariant, QTimer -import PyQt5.QtCore -import PyQt5.QtWidgets - -priv_dir = os.path.split(os.path.abspath(os.path.realpath(__file__)))[0] - -class PathModel(QAbstractItemModel): - def __init__(self, coredata): - super().__init__() - self.coredata = coredata - self.names = ['Prefix', 'Library dir', 'Binary dir', 'Include dir', 'Data dir',\ - 'Man dir', 'Locale dir'] - self.attr_name = ['prefix', 'libdir', 'bindir', 'includedir', 'datadir', \ - 'mandir', 'localedir'] - - def args(self, index): - if index.column() == 1: - editable = PyQt5.QtCore.Qt.ItemIsEditable - else: - editable= 0 - return PyQt5.QtCore.Qt.ItemIsSelectable | PyQt5.QtCore.Qt.ItemIsEnabled | editable - - def rowCount(self, index): - if index.isValid(): - return 0 - return len(self.names) - - def columnCount(self, index): - return 2 - - def headerData(self, section, orientation, role): - if role != PyQt5.QtCore.Qt.DisplayRole: - return QVariant() - if section == 1: - return QVariant('Path') - return QVariant('Type') - - def index(self, row, column, parent): - return self.createIndex(row, column) - - def data(self, index, role): - if role != PyQt5.QtCore.Qt.DisplayRole: - return QVariant() - row = index.row() - column = index.column() - if column == 0: - return self.names[row] - return getattr(self.coredata, self.attr_name[row]) - - def parent(self, index): - return QModelIndex() - - def setData(self, index, value, role): - if role != PyQt5.QtCore.Qt.EditRole: - return False - row = index.row() - column = index.column() - s = str(value) - setattr(self.coredata, self.attr_name[row], s) - self.dataChanged.emit(self.createIndex(row, column), self.createIndex(row, column)) - return True - -class TargetModel(QAbstractItemModel): - def __init__(self, builddata): - super().__init__() - self.targets = [] - for target in builddata.get_targets().values(): - name = target.get_basename() - num_sources = len(target.get_sources()) + len(target.get_generated_sources()) - 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' - else: - typename = 'unknown' - if target.should_install(): - installed = 'Yes' - else: - installed = 'No' - self.targets.append((name, typename, installed, num_sources)) - - def args(self, index): - return PyQt5.QtCore.Qt.ItemIsSelectable | PyQt5.QtCore.Qt.ItemIsEnabled - - def rowCount(self, index): - if index.isValid(): - return 0 - return len(self.targets) - - def columnCount(self, index): - return 4 - - def headerData(self, section, orientation, role): - if role != PyQt5.QtCore.Qt.DisplayRole: - return QVariant() - if section == 3: - return QVariant('Source files') - if section == 2: - return QVariant('Installed') - if section == 1: - return QVariant('Type') - return QVariant('Name') - - def data(self, index, role): - if role != PyQt5.QtCore.Qt.DisplayRole: - return QVariant() - row = index.row() - column = index.column() - return self.targets[row][column] - - def index(self, row, column, parent): - return self.createIndex(row, column) - - def parent(self, index): - return QModelIndex() - -class DependencyModel(QAbstractItemModel): - def __init__(self, coredata): - super().__init__() - self.deps = [] - for k in coredata.deps.keys(): - bd = coredata.deps[k] - name = k - found = bd.found() - if found: - cflags = str(bd.get_compile_args()) - libs = str(bd.get_link_args()) - found = 'yes' - else: - cflags = '' - libs = '' - found = 'no' - self.deps.append((name, found, cflags, libs)) - - def args(self, index): - return PyQt5.QtCore.Qt.ItemIsSelectable | PyQt5.QtCore.Qt.ItemIsEnabled - - def rowCount(self, index): - if index.isValid(): - return 0 - return len(self.deps) - - def columnCount(self, index): - return 4 - - def headerData(self, section, orientation, role): - if role != PyQt5.QtCore.Qt.DisplayRole: - return QVariant() - if section == 3: - return QVariant('Link args') - if section == 2: - return QVariant('Compile args') - if section == 1: - return QVariant('Found') - return QVariant('Name') - - def data(self, index, role): - if role != PyQt5.QtCore.Qt.DisplayRole: - return QVariant() - row = index.row() - column = index.column() - return self.deps[row][column] - - def index(self, row, column, parent): - return self.createIndex(row, column) - - def parent(self, index): - return QModelIndex() - -class CoreModel(QAbstractItemModel): - def __init__(self, core_data): - super().__init__() - self.elems = [] - for langname, comp in core_data.compilers.items(): - self.elems.append((langname + ' compiler', str(comp.get_exelist()))) - for langname, comp in core_data.cross_compilers.items(): - self.elems.append((langname + ' cross compiler', str(comp.get_exelist()))) - - def args(self, index): - return PyQt5.QtCore.Qt.ItemIsSelectable | PyQt5.QtCore.Qt.ItemIsEnabled - - def rowCount(self, index): - if index.isValid(): - return 0 - return len(self.elems) - - def columnCount(self, index): - return 2 - - def headerData(self, section, orientation, role): - if role != PyQt5.QtCore.Qt.DisplayRole: - return QVariant() - if section == 1: - return QVariant('Value') - return QVariant('Name') - - def data(self, index, role): - if role != PyQt5.QtCore.Qt.DisplayRole: - return QVariant() - row = index.row() - column = index.column() - return self.elems[row][column] - - def index(self, row, column, parent): - return self.createIndex(row, column) - - def parent(self, index): - return QModelIndex() - -class OptionForm: - def __init__(self, coredata, form): - self.coredata = coredata - self.form = form - form.addRow(PyQt5.QtWidgets.QLabel("Meson options")) - combo = QComboBox() - combo.addItem('plain') - combo.addItem('debug') - combo.addItem('debugoptimized') - combo.addItem('release') - combo.setCurrentText(self.coredata.get_builtin_option('buildtype')) - combo.currentTextChanged.connect(self.build_type_changed) - self.form.addRow('Build type', combo) - strip = QCheckBox("") - strip.setChecked(self.coredata.get_builtin_option('strip')) - strip.stateChanged.connect(self.strip_changed) - self.form.addRow('Strip on install', strip) - coverage = QCheckBox("") - coverage.setChecked(self.coredata.get_builtin_option('coverage')) - coverage.stateChanged.connect(self.coverage_changed) - self.form.addRow('Enable coverage', coverage) - pch = QCheckBox("") - pch.setChecked(self.coredata.get_builtin_option('use_pch')) - pch.stateChanged.connect(self.pch_changed) - self.form.addRow('Enable pch', pch) - unity = QCheckBox("") - unity.setChecked(self.coredata.get_builtin_option('unity')) - unity.stateChanged.connect(self.unity_changed) - self.form.addRow('Unity build', unity) - form.addRow(PyQt5.QtWidgets.QLabel("Project options")) - self.set_user_options() - - def set_user_options(self): - options = self.coredata.user_options - keys = list(options.keys()) - keys.sort() - self.opt_keys = keys - self.opt_widgets = [] - for key in keys: - opt = options[key] - if isinstance(opt, mesonlib.UserStringOption): - w = PyQt5.QtWidgets.QLineEdit(opt.value) - w.textChanged.connect(self.user_option_changed) - elif isinstance(opt, mesonlib.UserBooleanOption): - w = QCheckBox('') - w.setChecked(opt.value) - w.stateChanged.connect(self.user_option_changed) - elif isinstance(opt, mesonlib.UserComboOption): - w = QComboBox() - for i in opt.choices: - w.addItem(i) - w.setCurrentText(opt.value) - w.currentTextChanged.connect(self.user_option_changed) - else: - raise RuntimeError("Unknown option type") - self.opt_widgets.append(w) - self.form.addRow(opt.description, w) - - def user_option_changed(self, dummy=None): - for i in range(len(self.opt_keys)): - key = self.opt_keys[i] - w = self.opt_widgets[i] - if isinstance(w, PyQt5.QtWidgets.QLineEdit): - newval = w.text() - elif isinstance(w, QComboBox): - newval = w.currentText() - elif isinstance(w, QCheckBox): - if w.checkState() == 0: - newval = False - else: - newval = True - else: - raise RuntimeError('Unknown widget type') - self.coredata.user_options[key].set_value(newval) - - def build_type_changed(self, newtype): - self.coredata.buildtype = newtype - - def strip_changed(self, newState): - if newState == 0: - ns = False - else: - ns = True - self.coredata.strip = ns - - def coverage_changed(self, newState): - if newState == 0: - ns = False - else: - ns = True - self.coredata.coverage = ns - - def pch_changed(self, newState): - if newState == 0: - ns = False - else: - ns = True - self.coredata.use_pch = ns - - def unity_changed(self, newState): - if newState == 0: - ns = False - else: - ns = True - self.coredata.unity = ns - -class ProcessRunner(): - def __init__(self, rundir, cmdlist): - self.cmdlist = cmdlist - self.ui = uic.loadUi(os.path.join(priv_dir, 'mesonrunner.ui')) - self.timer = QTimer(self.ui) - self.timer.setInterval(1000) - self.timer.timeout.connect(self.timeout) - self.process = PyQt5.QtCore.QProcess() - self.process.setProcessChannelMode(PyQt5.QtCore.QProcess.MergedChannels) - self.process.setWorkingDirectory(rundir) - self.process.readyRead.connect(self.read_data) - self.process.finished.connect(self.finished) - self.ui.termbutton.clicked.connect(self.terminated) - self.return_value = 100 - - def run(self): - self.process.start(self.cmdlist[0], self.cmdlist[1:]) - self.timer.start() - self.start_time = time.time() - return self.ui.exec() - - def read_data(self): - while(self.process.canReadLine()): - txt = bytes(self.process.readLine()).decode('utf8') - self.ui.console.append(txt) - - def finished(self): - self.read_data() - self.ui.termbutton.setText('Done') - self.timer.stop() - self.return_value = self.process.exitCode() - - def terminated(self, foo): - self.process.kill() - self.timer.stop() - self.ui.done(self.return_value) - - def timeout(self): - now = time.time() - duration = int(now - self.start_time) - msg = 'Elapsed time: %d:%d' % (duration // 60, duration % 60) - self.ui.timelabel.setText(msg) - -class MesonGui(): - def __init__(self, respawner, build_dir): - self.respawner = respawner - uifile = os.path.join(priv_dir, 'mesonmain.ui') - self.ui = uic.loadUi(uifile) - self.coredata_file = os.path.join(build_dir, 'meson-private/coredata.dat') - self.build_file = os.path.join(build_dir, 'meson-private/build.dat') - if not os.path.exists(self.coredata_file): - print("Argument is not build directory.") - sys.exit(1) - self.coredata = pickle.load(open(self.coredata_file, 'rb')) - self.build = pickle.load(open(self.build_file, 'rb')) - self.build_dir = self.build.environment.build_dir - self.src_dir = self.build.environment.source_dir - self.build_models() - self.options = OptionForm(self.coredata, self.ui.option_form) - self.ui.show() - - def hide(self): - self.ui.hide() - - def geometry(self): - return self.ui.geometry() - - def move(self, x, y): - return self.ui.move(x, y) - - def size(self): - return self.ui.size() - - def resize(self, s): - return self.ui.resize(s) - - def build_models(self): - self.path_model = PathModel(self.coredata) - self.target_model = TargetModel(self.build) - self.dep_model = DependencyModel(self.coredata) - self.core_model = CoreModel(self.coredata) - self.fill_data() - self.ui.core_view.setModel(self.core_model) - hv = QHeaderView(1) - hv.setModel(self.core_model) - self.ui.core_view.setHeader(hv) - self.ui.path_view.setModel(self.path_model) - hv = QHeaderView(1) - hv.setModel(self.path_model) - self.ui.path_view.setHeader(hv) - self.ui.target_view.setModel(self.target_model) - hv = QHeaderView(1) - hv.setModel(self.target_model) - self.ui.target_view.setHeader(hv) - self.ui.dep_view.setModel(self.dep_model) - hv = QHeaderView(1) - hv.setModel(self.dep_model) - self.ui.dep_view.setHeader(hv) - self.ui.compile_button.clicked.connect(self.compile) - self.ui.test_button.clicked.connect(self.run_tests) - self.ui.install_button.clicked.connect(self.install) - self.ui.clean_button.clicked.connect(self.clean) - self.ui.save_button.clicked.connect(self.save) - - def fill_data(self): - self.ui.project_label.setText(self.build.projects['']) - self.ui.srcdir_label.setText(self.src_dir) - self.ui.builddir_label.setText(self.build_dir) - if self.coredata.cross_file is None: - btype = 'Native build' - else: - btype = 'Cross build' - self.ui.buildtype_label.setText(btype) - - def run_process(self, cmdlist): - cmdlist = [shutil.which(environment.detect_ninja())] + cmdlist - dialog = ProcessRunner(self.build.environment.build_dir, cmdlist) - dialog.run() - # All processes (at the moment) may change cache state - # so reload. - self.respawner.respawn() - - def compile(self, foo): - self.run_process([]) - - def run_tests(self, foo): - self.run_process(['test']) - - def install(self, foo): - self.run_process(['install']) - - def clean(self, foo): - self.run_process(['clean']) - - def save(self, foo): - pickle.dump(self.coredata, open(self.coredata_file, 'wb')) - -class Starter(): - def __init__(self, sdir): - uifile = os.path.join(priv_dir, 'mesonstart.ui') - self.ui = uic.loadUi(uifile) - self.ui.source_entry.setText(sdir) - self.dialog = PyQt5.QtWidgets.QFileDialog() - if len(sdir) == 0: - self.dialog.setDirectory(os.getcwd()) - else: - self.dialog.setDirectory(sdir) - self.ui.source_browse_button.clicked.connect(self.src_browse_clicked) - self.ui.build_browse_button.clicked.connect(self.build_browse_clicked) - self.ui.cross_browse_button.clicked.connect(self.cross_browse_clicked) - self.ui.source_entry.textChanged.connect(self.update_button) - self.ui.build_entry.textChanged.connect(self.update_button) - self.ui.generate_button.clicked.connect(self.generate) - self.update_button() - self.ui.show() - - def generate(self): - srcdir = self.ui.source_entry.text() - builddir = self.ui.build_entry.text() - cross = self.ui.cross_entry.text() - cmdlist = [os.path.join(os.path.split(__file__)[0], 'meson.py'), srcdir, builddir] - if cross != '': - cmdlist += ['--cross', cross] - pr = ProcessRunner(os.getcwd(), cmdlist) - rvalue = pr.run() - if rvalue == 0: - os.execl(__file__, 'dummy', builddir) - - def update_button(self): - if self.ui.source_entry.text() == '' or self.ui.build_entry.text() == '': - self.ui.generate_button.setEnabled(False) - else: - self.ui.generate_button.setEnabled(True) - - def src_browse_clicked(self): - self.dialog.setFileMode(2) - if self.dialog.exec(): - self.ui.source_entry.setText(self.dialog.selectedFiles()[0]) - - def build_browse_clicked(self): - self.dialog.setFileMode(2) - if self.dialog.exec(): - self.ui.build_entry.setText(self.dialog.selectedFiles()[0]) - - def cross_browse_clicked(self): - self.dialog.setFileMode(1) - if self.dialog.exec(): - self.ui.cross_entry.setText(self.dialog.selectedFiles()[0]) - -# Rather than rewrite all classes and arrays to be -# updateable, just rebuild the entire GUI from -# scratch whenever data on disk changes. - -class MesonGuiRespawner(): - def __init__(self, arg): - self.arg = arg - self.gui = MesonGui(self, self.arg) - - def respawn(self): - geo = self.gui.geometry() - s = self.gui.size() - self.gui.hide() - self.gui = MesonGui(self, self.arg) - self.gui.move(geo.x(), geo.y()) - self.gui.resize(s) - # Garbage collection takes care of the old gui widget - - -def run(args): # SPECIAL, Qt wants all args, including command name. - app = QApplication(sys.argv) - if len(args) == 1: - arg = "" - elif len(args) == 2: - arg = sys.argv[1] - else: - print(sys.argv[0], "<build or source dir>") - return 1 - if os.path.exists(os.path.join(arg, 'meson-private/coredata.dat')): - guirespawner = MesonGuiRespawner(arg) - else: - runner = Starter(arg) - return app.exec_() - -if __name__ == '__main__': - sys.exit(run(sys.argv)) diff --git a/meson/mintro.py b/meson/mintro.py deleted file mode 100644 index b088117..0000000 --- a/meson/mintro.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python3 - -# 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, mesonlib -import argparse -import sys, os - -parser = argparse.ArgumentParser() -parser.add_argument('--targets', action='store_true', dest='list_targets', default=False, - help='List top level targets.') -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('args', nargs='+') - -def list_targets(coredata, builddata): - 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 target.should_install(): - t['installed'] = True - 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 - subdir = t.subdir - 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): - buildtype= {'choices': ['plain', 'debug', 'debugoptimized', 'release'], - 'type' : 'combo', - 'value' : coredata.buildtype, - 'description' : 'Build type', - 'name' : 'type'} - strip = {'value' : coredata.strip, - 'type' : 'boolean', - 'description' : 'Strip on install', - 'name' : 'strip'} - coverage = {'value': coredata.coverage, - 'type' : 'boolean', - 'description' : 'Enable coverage', - 'name' : 'coverage'} - pch = {'value' : coredata.use_pch, - 'type' : 'boolean', - 'description' : 'Use precompiled headers', - 'name' : 'pch'} - unity = {'value' : coredata.unity, - 'type' : 'boolean', - 'description' : 'Unity build', - 'name' : 'unity'} - optlist = [buildtype, strip, coverage, pch, unity] - add_keys(optlist, coredata.user_options) - add_keys(optlist, coredata.compiler_options) - 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, mesonlib.UserStringOption): - typestr = 'string' - elif isinstance(opt, mesonlib.UserBooleanOption): - typestr = 'boolean' - elif isinstance(opt, mesonlib.UserComboOption): - optdict['choices'] = opt.choices - typestr = 'combo' - elif isinstance(opt, mesonlib.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 - 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 run(args): - options = parser.parse_args(args) - if len(options.args) > 1: - print('Too many arguments') - return 1 - elif len(options.args) == 1: - bdir = options.args[0] - else: - bdir = '' - corefile = os.path.join(bdir, 'meson-private/coredata.dat') - buildfile = os.path.join(bdir, 'meson-private/build.dat') - testfile = os.path.join(bdir, 'meson-private/meson_test_setup.dat') - benchmarkfile = os.path.join(bdir, 'meson-private/meson_benchmark_setup.dat') - coredata = pickle.load(open(corefile, 'rb')) - builddata = pickle.load(open(buildfile, 'rb')) - testdata = pickle.load(open(testfile, 'rb')) - benchmarkdata = pickle.load(open(benchmarkfile, 'rb')) - if options.list_targets: - list_targets(coredata, builddata) - 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) - else: - print('No command specified') - return 1 - return 0 - -if __name__ == '__main__': - sys.exit(run(sys.argv[1:])) diff --git a/meson/mlog.py b/meson/mlog.py deleted file mode 100644 index 2807c2b..0000000 --- a/meson/mlog.py +++ /dev/null @@ -1,81 +0,0 @@ -# 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 - -"""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()) -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') - -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 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 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. - -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. - if colorize_console: - arr = process_markup(args, True) - print(*arr, **kwargs) diff --git a/meson/modules/gnome.py b/meson/modules/gnome.py deleted file mode 100644 index e552b84..0000000 --- a/meson/modules/gnome.py +++ /dev/null @@ -1,330 +0,0 @@ -# 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, sys -import subprocess -from ..coredata import MesonException -from .. import mlog -import xml.etree.ElementTree as ET -from ..mesonlib import File - -girwarning_printed = False - -class GnomeModule: - - def compile_resources(self, state, args, kwargs): - cmd = ['glib-compile-resources', '@INPUT@', '--generate'] - if 'source_dir' in kwargs: - resource_loc = os.path.join(state.subdir, kwargs.pop('source_dir')) - d = os.path.join(state.build_to_src, resource_loc) - cmd += ['--sourcedir', d] - else: - resource_loc = state.subdir - if 'c_name' in kwargs: - cmd += ['--c-name', kwargs.pop('c_name')] - cmd += ['--target', '@OUTPUT@'] - kwargs['command'] = cmd - output_c = args[0] + '.c' - output_h = args[0] + '.h' - resfile = args[1] - kwargs['depend_files'] = self.parse_gresource_xml(state, resfile, resource_loc) - kwargs['input'] = resfile - kwargs['output'] = output_c - target_c = build.CustomTarget(args[0]+'_c', state.subdir, kwargs) - kwargs['output'] = output_h - target_h = build.CustomTarget(args[0] + '_h', state.subdir, kwargs) - return [target_c, target_h] - - def parse_gresource_xml(self, state, fobj, resource_loc): - if isinstance(fobj, File): - fname = fobj.fname - subdir = fobj.subdir - else: - fname = fobj - subdir = state.subdir - 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.log("Warning, malformed rcc file: ", os.path.join(state.subdir, fname)) - break - else: - relfname = os.path.join(resource_loc, child.text) - absfname = os.path.join(state.environment.source_dir, relfname) - if os.path.isfile(absfname): - result.append(relfname) - else: - mlog.log('Warning, resource file points to nonexisting file %s.' % relfname) - return result - except Exception: - return [] - - def generate_gir(self, state, args, kwargs): - if len(args) != 1: - raise MesonException('Gir takes one argument') - 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: - pkgstr = subprocess.check_output(['pkg-config', '--cflags', 'gobject-introspection-1.0']) - except Exception: - global girwarning_printed - if not girwarning_printed: - mlog.log(mlog.bold('Warning:'), 'gobject-introspection dependency was not found, disabling gir generation.') - girwarning_printed = True - return [] - pkgargs = pkgstr.decode().strip().split() - ns = kwargs.pop('namespace') - nsversion = kwargs.pop('nsversion') - libsources = kwargs.pop('sources') - girfile = '%s-%s.gir' % (ns, nsversion) - depends = [girtarget] - - scan_command = ['g-ir-scanner', '@INPUT@'] - scan_command += pkgargs - scan_command += ['--no-libtool', '--namespace='+ns, '--nsversion=' + nsversion, '--warn-all', - '--output', '@OUTPUT@'] - - extra_args = kwargs.pop('extra_args', []) - if not isinstance(extra_args, list): - extra_args = [extra_args] - scan_command += extra_args - - for incdirs in girtarget.include_dirs: - for incdir in incdirs.get_incdirs(): - scan_command += ['-I%s' % os.path.join(state.environment.get_source_dir(), incdir)] - - 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: - lib = link.held_object - scan_command += ['-l%s' % lib.name] - if isinstance(lib, build.SharedLibrary): - scan_command += ['-L%s' % - os.path.join(state.environment.get_build_dir(), - lib.subdir)] - depends.append(lib) - - if 'includes' in kwargs: - includes = kwargs.pop('includes') - if isinstance(includes, str): - scan_command += ['--include=%s' % includes] - elif isinstance(includes, list): - scan_command += ['--include=%s' % inc for inc in includes] - else: - raise MesonException('Gir includes must be str or list') - if state.global_args.get('c'): - scan_command += ['--cflags-begin'] - scan_command += state.global_args['c'] - 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 = None - if 'dependencies' in kwargs: - deps = kwargs.pop('dependencies') - if not isinstance (deps, list): - deps = [deps] - for dep in deps: - girdir = dep.held_object.get_variable ("girdir") - if girdir: - scan_command += ["--add-include-path=%s" % girdir] - for lib in dep.held_object.libs: - if os.path.isabs(lib) and dep.held_object.is_libtool: - scan_command += ["-L%s" % os.path.dirname(lib)] - libname = os.path.basename(lib) - if libname.startswith("lib"): - libname = libname[3:] - libname = libname.split(".so")[0] - lib = "-l%s" % libname - scan_command += [lib] - - inc_dirs = None - if kwargs.get('include_directories'): - inc_dirs = kwargs.pop('include_directories') - if not isinstance(inc_dirs, list): - inc_dirs = [inc_dirs] - for ind in inc_dirs: - if isinstance(ind.held_object, build.IncludeDirs): - scan_command += ['--add-include-path=%s' % inc for inc in ind.held_object.get_incdirs()] - else: - raise MesonException('Gir include dirs should be include_directories()') - if isinstance(girtarget, build.Executable): - scan_command += ['--program', girtarget] - elif isinstance(girtarget, build.SharedLibrary): - scan_command += ["-L@PRIVATE_OUTDIR_ABS_%s@" % girtarget.get_id()] - 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'] = 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 = ['g-ir-compiler', scan_target, '--output', '@OUTPUT@'] - if inc_dirs: - for incd in inc_dirs: - typelib_cmd += ['--includedir=%s' % inc for inc in - incd.held_object.get_incdirs()] - if deps: - for dep in deps: - girdir = dep.held_object.get_variable ("girdir") - if girdir: - typelib_cmd += ["--includedir=%s" % girdir] - - kwargs['output'] = typelib_output - kwargs['command'] = typelib_cmd - # Note that this can't be libdir, because e.g. on Debian it points to - # lib/x86_64-linux-gnu but the girepo dir is always under lib. - kwargs['install_dir'] = 'lib/girepository-1.0' - typelib_target = TypelibTarget(typelib_output, state.subdir, kwargs) - return [scan_target, typelib_target] - - 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 = ['glib-compile-schemas', '--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 target_g - - 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 not 'src_dir' 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 - src_dir = kwargs['src_dir'] - targetname = modulename + '-doc' - command = os.path.normpath(os.path.join(os.path.split(__file__)[0], "../gtkdochelper.py")) - if hasattr(src_dir, 'held_object'): - src_dir= src_dir.held_object - if not isinstance(src_dir, build.IncludeDirs): - raise MesonException('Invalidt keyword argument for src_dir.') - incdirs = src_dir.get_incdirs() - if len(incdirs) != 1: - raise MesonException('Argument src_dir has more than one directory specified.') - header_dir = os.path.join(state.environment.get_source_dir(), src_dir.get_curdir(), incdirs[0]) - else: - header_dir = os.path.normpath(os.path.join(state.subdir, src_dir)) - args = ['--sourcedir=' + state.environment.get_source_dir(), - '--builddir=' + state.environment.get_build_dir(), - '--subdir=' + state.subdir, - '--headerdir=' + header_dir, - '--mainfile=' + main_file, - '--modulename=' + modulename] - args += self.unpack_args('--htmlargs=', 'html_args', kwargs) - args += self.unpack_args('--scanargs=', 'scan_args', kwargs) - res = [build.RunTarget(targetname, command, args, state.subdir)] - if kwargs.get('install', True): - res.append(build.InstallScript([command] + args)) - return res - - def unpack_args(self, arg, kwarg_name, kwargs): - try: - new_args = kwargs[kwarg_name] - if not isinstance(new_args, list): - new_args = [new_args] - for i in new_args: - if not isinstance(i, str): - raise MesonException('html_args values must be strings.') - except KeyError: - return[] - if len(new_args) > 0: - return [arg + '@@'.join(new_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] - cmd = ['gdbus-codegen'] - if 'interface_prefix' in kwargs: - cmd += ['--interface-prefix', kwargs.pop('interface_prefix')] - if 'namespace' in kwargs: - cmd += ['--c-namespace', kwargs.pop('namespace')] - cmd += ['--generate-c-code', '@OUTDIR@/' + namebase, '@INPUT@'] - outputs = [namebase + '.c', namebase + '.h'] - custom_kwargs = {'input' : xml_file, - 'output' : outputs, - 'command' : cmd - } - return build.CustomTarget(namebase + '-gdbus', state.subdir, custom_kwargs) - -def initialize(): - mlog.log('Warning, glib compiled dependencies will not work until this upstream issue is fixed:', - mlog.bold('https://bugzilla.gnome.org/show_bug.cgi?id=745754')) - return GnomeModule() - -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) diff --git a/meson/modules/pkgconfig.py b/meson/modules/pkgconfig.py deleted file mode 100644 index f18decf..0000000 --- a/meson/modules/pkgconfig.py +++ /dev/null @@ -1,82 +0,0 @@ -# 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 coredata, build -from .. import mesonlib -import os - -class PkgConfigModule: - - def print_hello(self, state, args, kwargs): - print('Hello from a Meson module') - - def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, version, filebase): - outdir = state.environment.scratch_dir - fname = os.path.join(outdir, filebase + '.pc') - ofile = open(fname, 'w') - coredata = state.environment.get_coredata() - ofile.write('prefix=%s\n' % coredata.get_builtin_option('prefix')) - ofile.write('libdir=${prefix}/%s\n' % coredata.get_builtin_option('libdir')) - ofile.write('includedir=${prefix}/%s\n\n' % coredata.get_builtin_option('includedir')) - ofile.write('Name: %s\n' % name) - if len(description) > 0: - ofile.write('Description: %s\n' % description) - if len(version) > 0: - ofile.write('Version: %s\n' % version) - ofile.write('Libs: -L${libdir} ') - for l in libraries: - ofile.write('-l%s ' % l.name) - ofile.write('\n') - ofile.write('CFlags: ') - for h in subdirs: - if h == '.': - h = '' - ofile.write(os.path.join('-I${includedir}', h)) - ofile.write(' ') - ofile.write('\n') - - def generate(self, state, args, kwargs): - if len(args) > 0: - raise coredata.MesonException('Pkgconfig_gen takes no positional arguments.') - libs = kwargs.get('libraries', []) - 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) or isinstance(l, build.StaticLibrary)): - raise coredata.MesonException('Library argument not a library object.') - processed_libs.append(l) - libs = processed_libs - subdirs = mesonlib.stringlistify(kwargs.get('subdirs', ['.'])) - version = kwargs.get('version', '') - if not isinstance(version, str): - raise coredata.MesonException('Version must be a string.') - name = kwargs.get('name', None) - if not isinstance(name, str): - raise coredata.MesonException('Name not specified.') - filebase = kwargs.get('filebase', name) - if not isinstance(filebase, str): - raise coredata.MesonException('Filebase must be a string.') - description = kwargs.get('description', None) - if not isinstance(description, str): - raise coredata.MesonException('Description is not a string.') - pcfile = filebase + '.pc' - pkgroot = os.path.join(state.environment.coredata.get_builtin_option('libdir'), 'pkgconfig') - self.generate_pkgconfig_file(state, libs, subdirs, name, description, version, filebase) - return build.Data(False, state.environment.get_scratch_dir(), [pcfile], pkgroot) - -def initialize(): - return PkgConfigModule() diff --git a/meson/modules/qt4.py b/meson/modules/qt4.py deleted file mode 100644 index 162b553..0000000 --- a/meson/modules/qt4.py +++ /dev/null @@ -1,155 +0,0 @@ -# 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 dependencies, mlog -import os, subprocess -from .. import build -from ..coredata import MesonException -import xml.etree.ElementTree as ET - -class Qt4Module(): - def __init__(self): - mlog.log('Detecting Qt tools.') - # The binaries have different names on different - # distros. Joy. - self.moc = dependencies.ExternalProgram('moc-qt4', silent=True) - if not self.moc.found(): - self.moc = dependencies.ExternalProgram('moc', silent=True) - self.uic = dependencies.ExternalProgram('uic-qt4', silent=True) - if not self.uic.found(): - self.uic = dependencies.ExternalProgram('uic', silent=True) - self.rcc = dependencies.ExternalProgram('rcc-qt4', silent=True) - if not self.rcc.found(): - self.rcc = dependencies.ExternalProgram('rcc', silent=True) - # 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(): - mp = subprocess.Popen(self.moc.get_command() + ['-v'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout, stderr) = mp.communicate() - stdout = stdout.decode().strip() - stderr = stderr.decode().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)' % \ - (' '.join(self.moc.fullpath), moc_ver.split()[-1])) - else: - mlog.log(' moc:', mlog.red('NO')) - if self.uic.found(): - up = subprocess.Popen(self.uic.get_command() + ['-v'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout, stderr) = up.communicate() - stdout = stdout.decode().strip() - stderr = stderr.decode().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)' % \ - (' '.join(self.uic.fullpath), uic_ver.split()[-1])) - else: - mlog.log(' uic:', mlog.red('NO')) - if self.rcc.found(): - rp = subprocess.Popen(self.rcc.get_command() + ['-v'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout, stderr) = rp.communicate() - stdout = stdout.decode().strip() - stderr = stderr.decode().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)'\ - % (' '.join(self.rcc.fullpath), rcc_ver.split()[-1])) - else: - mlog.log(' rcc:', mlog.red('NO')) - - 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.log("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] - srctmp = kwargs.pop('sources', []) - if not isinstance(srctmp, list): - srctmp = [srctmp] - sources = args[1:] + srctmp - if len(rcc_files) > 0: - rcc_kwargs = {'output' : '@BASENAME@.cpp', - 'arguments' : ['@INPUT@', '-o', '@OUTPUT@']} - rcc_gen = build.Generator([self.rcc], rcc_kwargs) - rcc_output = build.GeneratedList(rcc_gen) - qrc_deps = [] - for i in rcc_files: - qrc_deps += self.parse_qrc(state, i) - rcc_output.extra_depends = qrc_deps - [rcc_output.add_file(os.path.join(state.subdir, a)) for a in rcc_files] - sources.append(rcc_output) - if len(ui_files) > 0: - ui_kwargs = {'output' : 'ui_@BASENAME@.h', - 'arguments' : ['-o', '@OUTPUT@', '@INPUT@']} - ui_gen = build.Generator([self.uic], ui_kwargs) - ui_output = build.GeneratedList(ui_gen) - [ui_output.add_file(os.path.join(state.subdir, a)) for a in ui_files] - 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 = build.GeneratedList(moc_gen) - [moc_output.add_file(os.path.join(state.subdir, a)) for a in moc_headers] - 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 = build.GeneratedList(moc_gen) - [moc_output.add_file(os.path.join(state.subdir, a)) for a in moc_sources] - sources.append(moc_output) - return sources - -def initialize(): - mlog.log('Warning, rcc dependencies will not work properly until this upstream issue is fixed:', - mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460')) - return Qt4Module() diff --git a/meson/modules/qt5.py b/meson/modules/qt5.py deleted file mode 100644 index 81edc76..0000000 --- a/meson/modules/qt5.py +++ /dev/null @@ -1,162 +0,0 @@ -# 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 dependencies, mlog -import os, subprocess -from .. import build -from ..coredata import MesonException -import xml.etree.ElementTree as ET - -class Qt5Module(): - - def __init__(self): - mlog.log('Detecting Qt tools.') - # The binaries have different names on different - # distros. Joy. - self.moc = dependencies.ExternalProgram('moc-qt5', silent=True) - if not self.moc.found(): - self.moc = dependencies.ExternalProgram('moc', silent=True) - self.uic = dependencies.ExternalProgram('uic-qt5', silent=True) - if not self.uic.found(): - self.uic = dependencies.ExternalProgram('uic', silent=True) - self.rcc = dependencies.ExternalProgram('rcc-qt5', silent=True) - if not self.rcc.found(): - self.rcc = dependencies.ExternalProgram('rcc', silent=True) - # 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(): - mp = subprocess.Popen(self.moc.get_command() + ['-v'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout, stderr) = mp.communicate() - stdout = stdout.decode().strip() - stderr = stderr.decode().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)' % \ - (' '.join(self.moc.fullpath), moc_ver.split()[-1])) - else: - mlog.log(' moc:', mlog.red('NO')) - if self.uic.found(): - up = subprocess.Popen(self.uic.get_command() + ['-v'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout, stderr) = up.communicate() - stdout = stdout.decode().strip() - stderr = stderr.decode().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)' % \ - (' '.join(self.uic.fullpath), uic_ver.split()[-1])) - else: - mlog.log(' uic:', mlog.red('NO')) - if self.rcc.found(): - rp = subprocess.Popen(self.rcc.get_command() + ['-v'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdout, stderr) = rp.communicate() - stdout = stdout.decode().strip() - stderr = stderr.decode().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)'\ - % (' '.join(self.rcc.fullpath), rcc_ver.split()[-1])) - else: - mlog.log(' rcc:', mlog.red('NO')) - - 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.log("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] - srctmp = kwargs.pop('sources', []) - if not isinstance(srctmp, list): - srctmp = [srctmp] - sources = args[1:] + srctmp - if len(rcc_files) > 0: - rcc_kwargs = {'output' : '@BASENAME@.cpp', - 'arguments' : ['@INPUT@', '-o', '@OUTPUT@']} - rcc_gen = build.Generator([self.rcc], rcc_kwargs) - rcc_output = build.GeneratedList(rcc_gen) - qrc_deps = [] - for i in rcc_files: - qrc_deps += self.parse_qrc(state, i) - rcc_output.extra_depends = qrc_deps - [rcc_output.add_file(os.path.join(state.subdir, a)) for a in rcc_files] - sources.append(rcc_output) - if len(ui_files) > 0: - ui_kwargs = {'output' : 'ui_@BASENAME@.h', - 'arguments' : ['-o', '@OUTPUT@', '@INPUT@']} - ui_gen = build.Generator([self.uic], ui_kwargs) - ui_output = build.GeneratedList(ui_gen) - [ui_output.add_file(os.path.join(state.subdir, a)) for a in ui_files] - 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 = build.GeneratedList(moc_gen) - [moc_output.add_file(os.path.join(state.subdir, a)) for a in moc_headers] - 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 = build.GeneratedList(moc_gen) - [moc_output.add_file(os.path.join(state.subdir, a)) for a in moc_sources] - sources.append(moc_output) - return sources - -def initialize(): - mlog.log('Warning, rcc dependencies will not work properly until this upstream issue is fixed:', - mlog.bold('https://bugreports.qt.io/browse/QTBUG-45460')) - return Qt5Module() diff --git a/meson/modules/rpm.py b/meson/modules/rpm.py deleted file mode 100644 index a2c0502..0000000 --- a/meson/modules/rpm.py +++ /dev/null @@ -1,163 +0,0 @@ -# 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 -from .. import datetime -from .. import mlog -from .. import modules.gnome -import os - -class RPMModule: - - def generate_spec_template(self, state, args, kwargs): - compiler_deps = set() - for compiler in state.compilers: - 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_aliaslist(): - 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.log('Warning, removing', mlog.bold(target.get_filename()), - 'from package because packaging static libs not recommended') - elif isinstance(target, modules.gnome.GirTarget) and target.should_install(): - files_devel.add('%%{_datadir}/gir-1.0/%s' % target.get_filename()[0]) - elif isinstance(target, modules.gnome.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)) - for pkgconfig in state.pkgconfig_gens: - files_devel.add('%%{_libdir}/pkgconfig/%s.pc' % pkgconfig.filebase) - if len(files_devel) > 0: - devel_subpkg = True - fn = open('%s.spec' % os.path.join(state.environment.get_build_dir(), proj), 'w+') - 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) - for lib in state.environment.coredata.ext_libs.values(): - fn.write('BuildRequires: %s # FIXME\n' % lib.fullpath) - mlog.log('Warning, replace', mlog.bold(lib.fullpath), 'with real package.', - 'You can use following command to find package which contains this lib:', - mlog.bold('dnf provides %s' % lib.fullpath)) - for prog in state.environment.coredata.ext_progs.values(): - if not prog.found(): - fn.write('BuildRequires: /usr/bin/%s # FIXME\n' % prog.get_name()) - else: - fn.write('BuildRequires: %s\n' % ' '.join(prog.fullpath)) - 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} = %{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('rm -rf rpmbuilddir && mkdir rpmbuilddir\n') - fn.write('\n') - fn.write('%build\n') - fn.write('pushd rpmbuilddir\n') - fn.write(' %meson ..\n') - fn.write(' ninja-build -v\n') - fn.write('popd\n') - fn.write('\n') - fn.write('%install\n') - fn.write('pushd rpmbuilddir\n') - fn.write(' DESTDIR=%{buildroot} ninja-build -v install\n') - fn.write('popd\n') - if len(to_delete) > 0: - fn.write('rm -rf %s\n' % ' '.join(to_delete)) - fn.write('\n') - fn.write('%check\n') - fn.write('pushd rpmbuilddir\n') - fn.write(' ninja-build -v test\n') - fn.write('popd\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('\n') - fn.write('%postun -p /sbin/ldconfig\n') - fn.write('\n') - fn.write('%changelog\n') - fn.write('* %s meson <meson@example.com> - \n' % datetime.date.today().strftime('%a %b %d %Y')) - fn.write('- \n') - fn.write('\n') - fn.close() - mlog.log('RPM spec template written to %s.spec.\n' % proj) - -def initialize(): - return RPMModule() diff --git a/meson/modules/windows.py b/meson/modules/windows.py deleted file mode 100644 index a785250..0000000 --- a/meson/modules/windows.py +++ /dev/null @@ -1,47 +0,0 @@ -# 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 mesonlib, dependencies, build -from ..coredata import MesonException -import os - -class WindowsModule: - - def detect_compiler(self, compilers): - for c in compilers: - if c.language == 'c' or c.language == 'cpp': - return c - 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', [])) - if comp.id == 'msvc': - rescomp = dependencies.ExternalProgram('rc', silent=True) - res_args = extra_args + ['/nologo', '/fo@OUTPUT@', '@INPUT@'] - suffix = 'res' - else: - rescomp = dependencies.ExternalProgram('windres', silent=True) - res_args = extra_args + ['@INPUT@', '@OUTPUT@'] - suffix = 'o' - res_files = mesonlib.stringlistify(args) - res_kwargs = {'output' : '@BASENAME@.' + suffix, - 'arguments': res_args} - res_gen = build.Generator([rescomp], res_kwargs) - res_output = build.GeneratedList(res_gen) - [res_output.add_file(os.path.join(state.subdir, a)) for a in res_files] - return res_output - -def initialize(): - return WindowsModule() diff --git a/meson/mparser.py b/meson/mparser.py deleted file mode 100644 index 1d569d5..0000000 --- a/meson/mparser.py +++ /dev/null @@ -1,565 +0,0 @@ -# Copyright 2014-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 re -from .coredata import MesonException - -class ParseException(MesonException): - def __init__(self, text, lineno, colno): - super().__init__(text) - self.lineno = lineno - self.colno = colno - -class Token: - def __init__(self, tid, lineno, colno, value): - self.tid = tid - self.lineno = lineno - self.colno = colno - 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): - 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'\*')), - ('fslash', re.compile(r'/')), - ('colon', re.compile(r':')), - ('equal', re.compile(r'==')), - ('nequal', re.compile(r'\!=')), - ('assign', re.compile(r'=')), - ] - - def lex(self, code): - lineno = 1 - line_start = 0 - loc = 0; - par_count = 0 - bracket_count = 0 - col = 0 - while(loc < len(code)): - matched = False - value = None - for (tid, reg) in self.token_specification: - mo = reg.match(code, loc) - if mo: - curline = lineno - col = mo.start()-line_start - matched = True - loc = mo.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.', 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, curline, col, value) - break - if not matched: - raise ParseException('lexer', lineno, col) - -class BooleanNode: - def __init__(self, token, value): - self.lineno = token.lineno - self.colno = token.colno - self.value = value - assert(isinstance(self.value, bool)) - -class IdNode: - def __init__(self, token): - self.lineno = token.lineno - self.colno = token.colno - self.value = token.value - assert(isinstance(self.value, str)) - - def __str__(self): - return "Id node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno) - -class NumberNode: - def __init__(self, token): - self.lineno = token.lineno - self.colno = token.colno - self.value = token.value - assert(isinstance(self.value, int)) - -class StringNode: - def __init__(self, token): - self.lineno = token.lineno - self.colno = token.colno - self.value = token.value - 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.lineno = args.lineno - self.colno = args.colno - self.args = args - -class EmptyNode: - def __init__(self): - self.lineno = 0 - self.colno = 0 - self.value = None - -class OrNode: - def __init__(self, lineno, colno, left, right): - self.lineno = lineno - self.colno = colno - self.left = left - self.right = right - -class AndNode: - def __init__(self, lineno, colno, left, right): - self.lineno = lineno - self.colno = colno - self.left = left - self.right = right - -class ComparisonNode: - def __init__(self, lineno, colno, ctype, left, right): - self.lineno = lineno - self.colno = colno - self.left = left - self.right = right - self.ctype = ctype - -class ArithmeticNode: - def __init__(self, lineno, colno, operation, left, right): - self.lineno = lineno - self.colno = colno - self.left = left - self.right = right - self.operation = operation - -class NotNode: - def __init__(self, lineno, colno, value): - self.lineno = lineno - self.colno = colno - self.value = value - -class CodeBlockNode: - def __init__(self, lineno, colno): - self.lineno = lineno - self.colno = colno - self.lines = [] - -class IndexNode: - def __init__(self, iobject, index): - self.iobject = iobject - self.index = index - self.lineno = iobject.lineno - self.colno = iobject.colno - -class MethodNode: - def __init__(self, lineno, colno, source_object, name, args): - 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, lineno, colno, func_name, args): - 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() - -class UMinusNode(): - def __init__(self, lineno, colno, value): - self.lineno = lineno - self.colno = 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 ArgumentNode(): - def __init__(self, token): - self.lineno = token.lineno - self.colno = token.colno - self.arguments = [] - 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 = self.arguments + [statement] - - def set_kwarg(self, name, value): - 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 - -# 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): - self.stream = Lexer().lex(code) - self.getsym() - - def getsym(self): - try: - self.current = next(self.stream) - except StopIteration: - self.current = Token('eof', 0, 0, None) - - 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.current.lineno, self.current.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.', 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.', - left.lineno, left.colno) - return AssignmentNode(left.lineno, left.colno, left.value, value) - return left - - def e2(self): - left = self.e3() - while self.accept('or'): - left = OrNode(left.lineno, left.colno, left, self.e3()) - return left - - def e3(self): - left = self.e4() - while self.accept('and'): - left = AndNode(left.lineno, left.colno, left, self.e4()) - return left - - def e4(self): - left = self.e5() - if self.accept('equal'): - return ComparisonNode(left.lineno, left.colno, '==', left, self.e5()) - if self.accept('nequal'): - return ComparisonNode(left.lineno, left.colno, '!=', left, self.e5()) - return left - - def e5(self): - return self.e5add() - - def e5add(self): - left = self.e5sub() - if self.accept('plus'): - return ArithmeticNode(left.lineno, left.colno, 'add', left, self.e5add()) - return left - - def e5sub(self): - left = self.e5mul() - if self.accept('dash'): - return ArithmeticNode(left.lineno, left.colno, 'sub', left, self.e5sub()) - return left - - def e5mul(self): - left = self.e5div() - if self.accept('star'): - return ArithmeticNode(left.lineno, left.colno, 'mul', left, self.e5mul()) - return left - - def e5div(self): - left = self.e6() - if self.accept('fslash'): - return ArithmeticNode(left.lineno, left.colno, 'div', left, self.e5div()) - return left - - def e6(self): - if self.accept('not'): - return NotNode(self.current.lineno, self.current.colno, self.e7()) - if self.accept('dash'): - return UMinusNode(self.current.lineno, self.current.colno, self.e7()) - return self.e7() - - def e7(self): - left = self.e8() - if self.accept('lparen'): - args = self.args() - self.expect('rparen') - if not isinstance(left, IdNode): - raise ParseException('Function call must be applied to plain id', - left.lineno, left.colno) - left = FunctionNode(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): - if self.accept('lparen'): - e = self.statement() - self.expect('rparen') - return e - elif self.accept('lbracket'): - args = self.args() - self.expect('rbracket') - 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() - - def args(self): - s = self.statement() - a = ArgumentNode(s) - - while not isinstance(s, EmptyNode): - if self.accept('comma'): - a.append(s) - elif self.accept('colon'): - if not isinstance(s, IdNode): - raise ParseException('Keyword argument must be a plain identifier.', - s.lineno, s.colno) - a.set_kwarg(s.value, self.statement()) - if not self.accept('comma'): - return a - 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.current.lineno, self.current.colno) - self.expect('lparen') - args = self.args() - self.expect('rparen') - method = MethodNode(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): - if self.current == 'eol': - return EmptyNode() - if self.accept('if'): - block = self.ifblock() - self.expect('endif') - return block - if self.accept('foreach'): - block = self.foreachblock() - self.expect('endforeach') - return block - return self.statement() - - def codeblock(self): - block = CodeBlockNode(self.current.lineno, self.current.colno) - cond = True - while cond: - curline = self.line() - if not isinstance(curline, EmptyNode): - block.lines.append(curline) - cond = self.accept('eol') - return block diff --git a/meson/ninjabackend.py b/meson/ninjabackend.py deleted file mode 100644 index 36c5ce9..0000000 --- a/meson/ninjabackend.py +++ /dev/null @@ -1,1819 +0,0 @@ -# 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 environment, mesonlib -from . import build -from . import mlog -from . import dependencies -from .mesonlib import File -from .backends import InstallData -from .build import InvalidArguments -from .coredata import MesonException -import os, sys, pickle, re -import subprocess, shutil - -if mesonlib.is_windows(): - quote_char = '"' - execute_wrapper = 'cmd /c' -else: - quote_char = "'" - execute_wrapper = '' - -def ninja_quote(text): - return text.replace(' ', '$ ').replace(':', '$:') - -class RawFilename(): - def __init__(self, fname): - self.fname = fname - - def split(self, c): - return self.fname.split(c) - - def startswith(self, s): - return self.fname.startswith(s) - -class NinjaBuildElement(): - def __init__(self, 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 = [] - - 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): - 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') - -class NinjaBackend(backends.Backend): - - def __init__(self, build): - super().__init__(build) - self.source_suffix_in_objs = True - self.ninja_filename = 'build.ninja' - self.fortran_deps = {} - self.all_outputs = {} - - def check_outputs(self, elem): - for n in elem.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 - - def detect_vs_dep_prefix(self, outfile, tempfilename): - '''VS writes its dependency in a locale dependent format. - Detect the search prefix to use.''' - if shutil.which('cl') is None: - return outfile - outfile.close() - open(os.path.join(self.environment.get_scratch_dir(), 'incdetect.c'), - 'w').write('''#include<stdio.h> -int dummy; -''') - - pc = subprocess.Popen(['cl', '/showIncludes', '/c', 'incdetect.c'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=self.environment.get_scratch_dir()) - - (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':' - binfile = open(tempfilename, 'ab') - binfile.write(b'msvc_deps_prefix = ' + matchstr + b'\r\n') - binfile.close() - 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 + '~' - outfile = open(tempfilename, 'w') - 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') - outfile = self.detect_vs_dep_prefix(outfile, tempfilename) - self.generate_rules(outfile) - self.generate_phony(outfile) - outfile.write('# Build rules for targets\n\n') - [self.generate_target(t, outfile) for t in self.build.get_targets().values()] - if len(self.build.pot) > 0: - outfile.write('# Build rules for localisation.\n\n') - self.generate_po(outfile) - outfile.write('# Test rules\n\n') - self.generate_tests(outfile) - outfile.write('# Install rules\n\n') - self.generate_install(outfile) - if self.environment.coredata.get_builtin_option('coverage'): - outfile.write('# Coverage rules\n\n') - self.generate_coverage_rules(outfile) - outfile.write('# Suffix\n\n') - self.generate_ending(outfile) - # Only ovewrite the old build file after the new one has been - # fully created. - outfile.close() - os.replace(tempfilename, outfilename) - self.generate_compdb() - - # http://clang.llvm.org/docs/JSONCompilationDatabase.html - def generate_compdb(self): - ninja_exe = environment.detect_ninja() - builddir = self.environment.get_build_dir() - jsondb = subprocess.check_output([ninja_exe, '-t', 'compdb', 'c_COMPILER', 'cpp_COMPILER'], cwd=builddir) - open(os.path.join(builddir, 'compile_commands.json'), 'wb').write(jsondb) - - # 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 = [] - for gensource in target.get_generated_sources(): - if isinstance(gensource, build.CustomTarget): - continue - for src in gensource.get_outfilelist(): - if self.environment.is_header(src): - header_deps.append(os.path.join(self.get_target_private_dir(target), src)) - for dep in target.link_targets: - if isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): - header_deps += self.get_generated_headers(dep) - return header_deps - - 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() - gen_src_deps = [] - if name in self.processed_targets: - return - if isinstance(target, build.Jar): - self.generate_jar_target(target, outfile) - return - if 'rust' in self.environment.coredata.compilers.keys() and self.has_rust(target): - self.generate_rust_target(target, outfile) - return - if 'cs' in self.environment.coredata.compilers.keys() and self.has_cs(target): - self.generate_cs_target(target, outfile) - return - if 'vala' in self.environment.coredata.compilers.keys() and self.has_vala(target): - gen_src_deps += self.generate_vala_compile(target, outfile) - if 'swift' in self.environment.coredata.compilers.keys() and self.has_swift(target): - self.generate_swift_target(target, outfile) - return - self.scan_fortran_module_outputs(target) - # The following deals with C/C++ compilation. - (gen_src, gen_other_deps) = self.process_dep_gens(outfile, target) - gen_src_deps += gen_src - self.process_target_dependencies(target, outfile) - self.generate_custom_generator_rules(target, outfile) - outname = self.get_target_filename(target) - obj_list = [] - use_pch = self.environment.coredata.get_builtin_option('use_pch') - is_unity = self.environment.coredata.get_builtin_option('unity') - if use_pch and target.has_pch(): - pch_objects = self.generate_pch(target, outfile) - else: - pch_objects = [] - header_deps = gen_other_deps - unity_src = [] - unity_deps = [] # Generated sources that must be built before compiling a Unity target. - header_deps += self.get_generated_headers(target) - for gensource in target.get_generated_sources(): - if isinstance(gensource, build.CustomTarget): - for src in gensource.output: - src = os.path.join(self.get_target_dir(gensource), src) - if self.environment.is_source(src) and not self.environment.is_header(src): - if is_unity: - unity_deps.append(os.path.join(self.environment.get_build_dir(), RawFilename(src))) - else: - obj_list.append(self.generate_single_compile(target, outfile, RawFilename(src), True, - header_deps)) - elif self.environment.is_object(src): - obj_list.append(src) - elif self.environment.is_library(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(RawFilename(src)) - else: - for src in gensource.get_outfilelist(): - if self.environment.is_object(src): - obj_list.append(os.path.join(self.get_target_private_dir(target), src)) - elif not self.environment.is_header(src): - if is_unity: - if self.has_dir_part(src): - rel_src = src - else: - rel_src = os.path.join(self.get_target_private_dir(target), src) - unity_deps.append(rel_src) - abs_src = os.path.join(self.environment.get_build_dir(), rel_src) - unity_src.append(abs_src) - else: - obj_list.append(self.generate_single_compile(target, outfile, src, True, - header_deps=header_deps)) - src_list = [] - for src in gen_src_deps: - src_list.append(src) - if is_unity: - unity_src.append(os.path.join(self.environment.get_build_dir(), src)) - header_deps.append(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. - obj_list.append(self.generate_single_compile(target, outfile, src, True, [], header_deps)) - for src in target.get_sources(): - if src.endswith('.vala'): - continue - if not self.environment.is_header(src): - src_list.append(src) - if is_unity: - 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, src_list) - 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) - self.processed_targets[name] = True - - def process_target_dependencies(self, target, outfile): - for t in target.get_dependencies(): - tname = t.get_basename() + t.type_suffix() - if not tname in self.processed_targets: - self.generate_target(t, outfile) - - def generate_custom_target(self, target, outfile): - (srcs, ofilenames, cmd) = self.eval_custom_target_command(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] - fname = i.get_filename() - if isinstance(fname, list): - fname = fname[0] - deps.append(os.path.join(self.get_target_dir(i), fname)) - if target.build_always: - deps.append('PHONY') - elem = NinjaBuildElement(ofilenames, 'CUSTOM_COMMAND', srcs) - for i in target.depend_files: - if isinstance(i, mesonlib.File): - deps.append(i.rel_to_builddir(self.build_to_src)) - else: - deps.append(os.path.join(self.build_to_src, i)) - elem.add_dep(deps) - for d in target.extra_depends: - tmp = d.get_filename() - if not isinstance(tmp, list): - tmp = [tmp] - for fname in tmp: - elem.add_dep(os.path.join(self.get_target_dir(d), fname)) - - elem.add_item('COMMAND', cmd) - elem.add_item('description', 'Generating %s with a custom command.' % target.name) - elem.write(outfile) - self.check_outputs(elem) - self.processed_targets[target.name + target.type_suffix()] = True - - def generate_run_target(self, target, outfile): - runnerscript = os.path.join(self.environment.get_script_dir(), 'commandrunner.py') - deps = [] - 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) - deps.append(relfname) - arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname)) - else: - mlog.debug(str(i)) - raise MesonException('Unreachable code in generate_run_target.') - elem = NinjaBuildElement(target.name, 'CUSTOM_COMMAND', deps) - cmd = [sys.executable, runnerscript, self.environment.get_source_dir(), self.environment.get_build_dir(), target.subdir] - 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.config['binaries'].get('exe_wrapper', None) is not None: - cmd += [self.environment.cross_info.config['binaries']['exe_wrapper']] - cmd.append(abs_exe) - else: - cmd.append(target.command) - cmd += arg_strings - elem.add_item('COMMAND', cmd) - elem.add_item('description', 'Running external command %s.' % target.name) - elem.add_item('pool', 'console') - elem.write(outfile) - self.check_outputs(elem) - self.processed_targets[target.name + target.type_suffix()] = True - - def generate_po(self, outfile): - for p in self.build.pot: - (packagename, languages, subdir) = p - input_file = os.path.join(subdir, 'POTFILES') - elem = NinjaBuildElement('pot', 'GEN_POT', []) - elem.add_item('PACKAGENAME', packagename) - elem.add_item('OUTFILE', packagename + '.pot') - elem.add_item('FILELIST', os.path.join(self.environment.get_source_dir(), input_file)) - elem.add_item('OUTDIR', os.path.join(self.environment.get_source_dir(), subdir)) - elem.write(outfile) - self.check_outputs(elem) - for l in languages: - infile = os.path.join(self.environment.get_source_dir(), subdir, l + '.po') - outfilename = os.path.join(subdir, l + '.gmo') - lelem = NinjaBuildElement(outfilename, 'GEN_GMO', infile) - lelem.add_item('INFILE', infile) - lelem.add_item('OUTFILE', outfilename) - lelem.write(outfile) - self.check_outputs(lelem) - - 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('coverage-xml', 'CUSTOM_COMMAND', '') - elem.add_item('COMMAND', [gcovr_exe, '-x', '-r', self.environment.get_build_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('coverage-text', 'CUSTOM_COMMAND', '') - elem.add_item('COMMAND', [gcovr_exe, '-r', self.environment.get_build_dir(),\ - '-o', os.path.join(self.environment.get_log_dir(), 'coverage.txt')]) - elem.add_item('DESC', 'Generating text coverage report.') - elem.write(outfile) - self.check_outputs(elem) - if lcov_exe and genhtml_exe: - added_rule = True - phony_elem = NinjaBuildElement('coverage-html', 'phony', 'coveragereport/index.html') - phony_elem.write(outfile) - - elem = NinjaBuildElement('coveragereport/index.html', 'CUSTOM_COMMAND', '') - command = [lcov_exe, '--directory', self.environment.get_build_dir(),\ - '--capture', '--output-file', 'coverage.info', '--no-checksum',\ - '&&', genhtml_exe, '--prefix', self.environment.get_build_dir(),\ - '--output-directory', self.environment.get_log_dir(), '--title', 'Code coverage',\ - '--legend', '--show-details', 'coverage.info'] - elem.add_item('COMMAND', command) - elem.add_item('DESC', 'Generating HTML coverage report.') - self.check_outputs(elem) - elem.write(outfile) - if not added_rule: - mlog.log(mlog.red('Warning:'), 'coverage requested but neither gcovr nor lcov/genhtml found.') - - def generate_install(self, outfile): - script_root = self.environment.get_script_dir() - install_script = os.path.join(script_root, 'meson_install.py') - install_data_file = os.path.join(self.environment.get_scratch_dir(), 'install.dat') - depfixer = [sys.executable, self.environment.get_build_command(), '--internal', 'depfixer'] - d = InstallData(self.environment.get_source_dir(), - self.environment.get_build_dir(), - self.environment.get_prefix(), depfixer) - elem = NinjaBuildElement('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_po_install(d, elem) - self.generate_custom_install_script(d) - self.generate_subdir_install(d) - elem.write(outfile) - self.check_outputs(elem) - - ofile = open(install_data_file, 'wb') - pickle.dump(d, ofile) - - def generate_po_install(self, d, elem): - for p in self.build.pot: - (package_name, languages, subdir) = p - # FIXME: assumes only one po package per source - d.po_package_name = package_name - for lang in languages: - rel_src = os.path.join(subdir, lang + '.gmo') - src_file = os.path.join(self.environment.get_build_dir(), rel_src) - d.po.append((src_file, self.environment.coredata.get_builtin_option('localedir'), lang)) - elem.add_dep(rel_src) - - def generate_target_install(self, d): - libdir = self.environment.get_libdir() - bindir = self.environment.get_bindir() - - should_strip = self.environment.coredata.get_builtin_option('strip') - for t in self.build.get_targets().values(): - if t.should_install(): - outdir = t.get_custom_install_dir() - if outdir is None: - if isinstance(t, build.Executable): - outdir = bindir - else: - outdir = libdir - i = [self.get_target_filename(t), outdir, t.get_aliaslist(),\ - should_strip, t.install_rpath] - d.targets.append(i) - - def generate_custom_install_script(self, d): - d.install_scripts = self.build.install_scripts - - def generate_header_install(self, d): - incroot = self.environment.get_includedir() - headers = self.build.get_headers() - - 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(): - abspath = os.path.join(self.environment.get_source_dir(), h.get_source_subdir(), f) - 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, f + '.gz') - i = [srcabs, dstabs] - d.man.append(i) - - def generate_data_install(self, d): - data = self.build.get_data() - for de in data: - assert(isinstance(de, build.Data)) - subdir = de.install_dir - for f in de.sources: - if de.in_sourcetree: - srcprefix = self.environment.get_source_dir() - else: - srcprefix = self.environment.get_build_dir() - srcabs = os.path.join(srcprefix, de.source_subdir, f) - dstabs = os.path.join(subdir, f) - i = [srcabs, dstabs] - d.data.append(i) - - def generate_subdir_install(self, d): - for sd in self.build.get_install_subdirs(): - src_dir = os.path.join(self.environment.get_source_dir(), sd.source_subdir, sd.installable_subdir) - dst_dir = os.path.join(self.environment.get_prefix(), sd.install_dir) - d.install_subdirs.append([src_dir, dst_dir]) - - def write_test_suite_targets(self, cmd, outfile): - suites = {} - for t in self.build.get_tests(): - for s in t.suite: - suites[s] = True - suites = list(suites.keys()) - suites.sort() - for s in suites: - if s == '': - visible_name = 'for top level tests' - else: - visible_name = s - elem = NinjaBuildElement('test-' + s, 'CUSTOM_COMMAND', ['all', 'PHONY']) - elem.add_item('COMMAND', cmd + ['--suite=' + s]) - elem.add_item('DESC', 'Running test suite %s.' % visible_name) - elem.add_item('pool', 'console') - elem.write(outfile) - self.check_outputs(elem) - - def generate_tests(self, outfile): - self.serialise_tests() - valgrind = environment.find_valgrind() - script_root = self.environment.get_script_dir() - test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') - cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'test', test_data] - elem = NinjaBuildElement('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) - self.check_outputs(elem) - self.write_test_suite_targets(cmd, outfile) - - if valgrind: - velem = NinjaBuildElement('test-valgrind', 'CUSTOM_COMMAND', ['all', 'PHONY']) - velem.add_item('COMMAND', cmd + ['--wrapper=' + valgrind]) - velem.add_item('DESC', 'Running test suite under Valgrind.') - velem.add_item('pool', 'console') - velem.write(outfile) - self.check_outputs(velem) - - # And then benchmarks. - benchmark_script = os.path.join(script_root, 'meson_benchmark.py') - benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat') - cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'benchmark', benchmark_data] - elem = NinjaBuildElement('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) - self.check_outputs(elem) - - 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') - 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') - if len(self.build.pot) > 0: - self.generate_gettext_rules(outfile) - outfile.write('\n') - - def generate_gettext_rules(self, outfile): - rule = 'rule GEN_POT\n' - command = " command = xgettext --package-name=$PACKAGENAME -p $OUTDIR -f $FILELIST -D '%s' -k_ -o $OUTFILE\n" % \ - self.environment.get_source_dir() - desc = " description = Creating pot file for package $PACKAGENAME.\n" - outfile.write(rule) - outfile.write(command) - outfile.write(desc) - outfile.write('\n') - rule = 'rule GEN_GMO\n' - command = ' command = msgfmt $INFILE -o $OUTFILE\n' - desc = ' description = Generating gmo file $OUTFILE\n' - outfile.write(rule) - outfile.write(command) - outfile.write(desc) - 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() - subdir = target.get_subdir() - outname_rel = os.path.join(self.get_target_dir(target), fname) - src_list = target.get_sources() - class_list = [] - compiler = self.get_compiler_for_source(src_list[0]) - assert(compiler.get_language() == '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)) - for cls in class_list: - commands += ['-C', self.get_target_private_dir(target), cls] - elem = NinjaBuildElement(outname_rel, jar_rule, []) - elem.add_dep(class_dep_list) - elem.add_item('ARGS', commands) - elem.write(outfile) - self.check_outputs(elem) - - 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(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) - self.check_outputs(elem) - 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.environment.coredata.get_builtin_option('buildtype') - fname = target.get_filename() - outname_rel = os.path.join(self.get_target_dir(target), fname) - src_list = target.get_sources() - compiler = self.get_compiler_for_source(src_list[0]) - assert(compiler.get_language() == '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(outputs, 'cs_COMPILER', rel_srcs) - elem.add_dep(deps) - elem.add_item('ARGS', commands) - self.check_outputs(elem) - elem.write(outfile) - - def generate_single_java_compile(self, src, target, compiler, outfile): - args = [] - args += compiler.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype')) - 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(rel_obj, compiler.get_language() + '_COMPILER', rel_src) - element.add_item('ARGS', args) - element.write(outfile) - self.check_outputs(element) - 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 generate_fastvapi_compile(self, target, valac, outfile): - fastvapis = {} - for s in target.get_sources(): - if not s.endswith('.vala'): - continue - vapibase = os.path.basename(s.fname)[:-4] + 'vapi' - rel_vapi = os.path.join(self.get_target_private_dir(target), vapibase) - args = ['--fast-vapi=' + rel_vapi] - rel_s = s.rel_to_builddir(self.build_to_src) - element = NinjaBuildElement(rel_vapi, valac.get_language() + '_COMPILER', rel_s) - element.add_item('ARGS', args) - element.write(outfile) - self.check_outputs(element) - fastvapis[s] = (vapibase, rel_vapi) - return fastvapis - - def split_vala_sources(self, sources): - src = [] - vapi_src = [] - for s in sources: - if s.endswith('.vapi'): - vapi_src.append(s) - else: - src.append(s) - return (src, vapi_src) - - def generate_vala_compile(self, target, outfile): - """Vala is compiled into C. Set up all necessary build steps here.""" - valac = self.environment.coredata.compilers['vala'] - fast_vapis = self.generate_fastvapi_compile(target, valac, outfile) - generated_c = [] - (src, vapi_src) = self.split_vala_sources(target.get_sources()) - vapi_src = [x.rel_to_builddir(self.build_to_src) for x in vapi_src] - extra_dep_files = [] - for s in src: - if not s.endswith('.vala'): - continue - args = ['-d', self.get_target_private_dir(target)] - sc = os.path.basename(s.fname)[:-4] + 'c' - args += ['-C'] - vapi_order_deps = [] - for (sourcefile, vapi_info) in fast_vapis.items(): - if sourcefile == s: - continue - (vapibase, rel_vapi) = vapi_info - args += ['--use-fast-vapi=' + rel_vapi] - vapi_order_deps.append(rel_vapi) - relsc = os.path.join(self.get_target_private_dir(target), sc) - rel_s = s.rel_to_builddir(self.build_to_src) - args += ['--deps', relsc + '.d'] - if self.environment.coredata.get_builtin_option('werror'): - args += valac.get_werror_args() - for d in target.external_deps: - if isinstance(d, dependencies.PkgConfigDependency): - if d.name == 'glib-2.0' and d.version_requirement is not None \ - and d.version_requirement.startswith(('>=', '==')): - args += ['--target-glib', d.version_requirement[2:]] - args += ['--pkg', d.name] - args += vapi_src - 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) - args += extra_args - generated_c += [relsc] - element = NinjaBuildElement(relsc, valac.get_language() + '_COMPILER', rel_s) - element.add_item('ARGS', args) - element.add_orderdep(vapi_order_deps) - element.add_dep(extra_dep_files) - element.write(outfile) - self.check_outputs(element) - return generated_c - - def generate_rust_target(self, target, outfile): - rustc = self.environment.coredata.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.environment.coredata.get_builtin_option('buildtype')) - depfile = target.name + '.d' - args += ['--out-dir', target.subdir] - args += ['--emit', 'dep-info', '--emit', 'link'] - orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets] - linkdirs = {} - for d in target.link_targets: - linkdirs[d.subdir] = True - for d in linkdirs.keys(): - if d == '': - d = '.' - args += ['-L', d] - element = NinjaBuildElement(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) - self.check_outputs(element) - - 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 = [] - for genlist in target.get_generated_sources(): - if isinstance(genlist, build.CustomTarget): - for ifile in genlist.get_filename(): - rel = os.path.join(self.get_target_dir(genlist), ifile) - all_srcs.append(rel) - else: - for ifile in genlist.get_outfilelist(): - rel = os.path.join(self.get_target_private_dir(target), ifile) - all_srcs.append(rel) - 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 = self.environment.coredata.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(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) - self.check_outputs(elem) - elem = NinjaBuildElement(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) - self.check_outputs(elem) - 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.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) - self.check_outputs(elem) - else: - raise MesonException('Swift supports only executable and static library targets.') - - def generate_static_link_rules(self, is_cross, outfile): - if self.build.has_language('java'): - 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 - if mesonlib.is_windows(): - command_templ = ''' command = %s @$out.rsp - rspfile = $out.rsp - rspfile_content = $LINK_ARGS %s $in -''' - else: - command_templ = ' command = %s $LINK_ARGS %s $in\n' - command = command_templ %\ - (' '.join(static_linker.get_exelist()), - ' '.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 compiler in complist: - langname = compiler.get_language() - 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 = %s @$out.rsp - rspfile = $out.rsp - rspfile_content = %s $ARGS %s $in $LINK_ARGS $aliasing -''' - else: - command_template = ' command = %s %s $ARGS %s $in $LINK_ARGS $aliasing\n' - command = command_template % \ - (' '.join(compiler.get_linker_exelist()),\ - ' '.join(cross_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') - scriptdir = self.environment.get_script_dir() - 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. - depfile = ' depfile = $out.d\n' - depstyle = ' deps = gcc\n' - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write(restat) - outfile.write(depfile) - outfile.write(depstyle) - 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, - os.path.join(self.environment.get_script_dir(), 'dirchanger.py'), - '$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_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 = [] - if is_cross: - try: - cross_args = self.environment.cross_info.config['properties'][langname + '_args'] - except KeyError: - pass - if mesonlib.is_windows(): - command_template = ''' command = %s @$out.rsp - rspfile = $out.rsp - rspfile_content = %s $ARGS %s %s %s $in -''' - else: - command_template = ' command = %s %s $ARGS %s %s %s $in\n' - command = command_template % \ - (' '.join(compiler.get_exelist()),\ - ' '.join(cross_args), - ' '.join(quoted_depargs),\ - ' '.join(compiler.get_output_args('$out')),\ - ' '.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 = %s %s $ARGS %s %s %s $in\n" % \ - (' '.join(compiler.get_exelist()),\ - ' '.join(cross_args),\ - ' '.join(quoted_depargs),\ - output,\ - ' '.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 compiler in self.build.compilers: - langname = compiler.get_language() - 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 compiler in cclist: - langname = compiler.get_language() - self.generate_compile_rule_for(langname, compiler, qstr, True, outfile) - self.generate_pch_rule_for(langname, compiler, qstr, True, outfile) - outfile.write('\n') - - 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 generate_custom_generator_rules(self, target, outfile): - for genlist in target.get_generated_sources(): - if isinstance(genlist, build.CustomTarget): - continue # Customtarget has already written its output rules - generator = genlist.get_generator() - exe = generator.get_exe() - exe_arr = self.exe_object_to_cmd_array(exe) - infilelist = genlist.get_infilelist() - outfilelist = genlist.get_outfilelist() - 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 = os.path.join(self.build_to_src, curfile) - outfiles = genlist.get_outputs_for(curfile) - outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles] - args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output)\ - for x in base_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] - final_args = [] - for a in args: - if a == '@EXTRA_ARGS@': - final_args += genlist.get_extra_args() - else: - final_args.append(a) - cmdlist = exe_arr + final_args - elem = NinjaBuildElement(outfiles, 'CUSTOM_COMMAND', infilename) - 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) - self.check_outputs(elem) - - def scan_fortran_module_outputs(self, target): - compiler = None - for c in self.build.compilers: - if c.get_language() == '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 - for line in open(os.path.join(self.environment.get_source_dir(), s.subdir, s.fname)): - 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()] - for line in open(src): - 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 occurrance, - # 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 generate_single_compile(self, target, outfile, src, is_generated=False, header_deps=[], order_deps=[]): - if(isinstance(src, str) and src.endswith('.h')): - raise RuntimeError('Fug') - if isinstance(src, RawFilename) and src.fname.endswith('.h'): - raise RuntimeError('Fug') - extra_orderdeps = [] - compiler = self.get_compiler_for_source(src) - commands = self.generate_basic_compiler_args(target, compiler) - commands += compiler.get_include_args(self.get_target_private_dir(target), False) - curdir = target.get_subdir() - tmppath = os.path.normpath(os.path.join(self.build_to_src, curdir)) - commands += compiler.get_include_args(tmppath, False) - if curdir == '': - curdir = '.' - commands += compiler.get_include_args(curdir, False) - for d in target.external_deps: - if d.need_threads(): - commands += compiler.thread_flags() - break - if isinstance(src, RawFilename): - rel_src = src.fname - elif is_generated: - if self.has_dir_part(src): - rel_src = src - else: - rel_src = os.path.join(self.get_target_private_dir(target), src) - abs_src = os.path.join(self.environment.get_source_dir(), rel_src) - else: - if isinstance(src, File): - rel_src = src.rel_to_builddir(self.build_to_src) - else: - raise build.InvalidArguments('Invalid source type.') - abs_src = os.path.join(self.environment.get_build_dir(), rel_src) - if isinstance(src, RawFilename): - src_filename = src.fname - elif isinstance(src, 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) - if self.environment.coredata.get_builtin_option('use_pch'): - pchlist = target.get_pch(compiler.language) - else: - pchlist = [] - if len(pchlist) == 0: - 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 - for i in target.get_include_dirs(): - basedir = i.get_curdir() - for d in i.get_incdirs(): - expdir = os.path.join(basedir, d) - srctreedir = os.path.join(self.build_to_src, expdir) - bargs = compiler.get_include_args(expdir, i.is_system) - sargs = compiler.get_include_args(srctreedir, i.is_system) - commands += bargs - commands += sargs - for d in i.get_extra_build_dirs(): - commands += compiler.get_include_args(d, i.is_system) - custom_target_include_dirs = [] - for i in target.generated: - if isinstance(i, build.CustomTarget): - idir = self.get_target_dir(i) - if idir not in custom_target_include_dirs: - custom_target_include_dirs.append(idir) - for i in custom_target_include_dirs: - commands+= compiler.get_include_args(i, False) - if self.environment.coredata.get_builtin_option('use_pch'): - commands += self.get_pch_include_args(compiler, target) - crstr = '' - if target.is_cross: - crstr = '_CROSS' - compiler_name = '%s%s_COMPILER' % (compiler.get_language(), crstr) - extra_deps = [] - if compiler.get_language() == 'fortran': - 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(modfile, 'FORTRAN_DEP_HACK', rel_obj) - depelem.write(outfile) - self.check_outputs(depelem) - commands += compiler.get_module_outdir_args(self.get_target_private_dir(target)) - - element = NinjaBuildElement(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) - element.add_orderdep(extra_orderdeps) - 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) - self.check_outputs(element) - return rel_obj - - def has_dir_part(self, fname): - 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 - 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]: - raise build.InvalidArguments('Precompiled header of "%s" must not be in the same directory as source, please put it in a subdirectory.' % target.get_basename()) - compiler = self.get_compiler_for_lang(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]) - 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(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) - self.check_outputs(elem) - 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(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) - self.check_outputs(elem) - - 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' - abspath = os.path.join(self.environment.get_build_dir(), target.subdir) - commands = [] - commands += linker.get_linker_always_args() - commands += linker.get_buildtype_linker_args(self.environment.coredata.get_builtin_option('buildtype')) - commands += linker.get_option_link_args(self.environment.coredata.compiler_options) - if not(isinstance(target, build.StaticLibrary)): - commands += self.environment.coredata.external_link_args[linker.get_language()] - if isinstance(target, build.Executable): - commands += linker.get_std_exe_link_args() - elif isinstance(target, build.SharedLibrary): - commands += linker.get_std_shared_lib_link_args() - commands += linker.get_pic_args() - if hasattr(target, 'soversion'): - soversion = target.soversion - else: - soversion = None - commands += linker.get_soname_args(target.name, abspath, soversion) - elif isinstance(target, build.StaticLibrary): - commands += linker.get_std_link_args() - else: - raise RuntimeError('Unknown build target type.') - # 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. - if linker_base == 'STATIC': - dependencies = [] - else: - dependencies = target.get_dependencies() - commands += self.build_target_link_arguments(linker, dependencies) - for d in target.external_deps: - if d.need_threads(): - commands += linker.thread_link_flags() - if not isinstance(target, build.StaticLibrary): - commands += target.link_args - # External deps must be last because target link libraries may depend on them. - if not(isinstance(target, build.StaticLibrary)): - 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() - commands += linker.build_rpath_args(self.environment.get_build_dir(),\ - self.determine_rpath_dirs(target), target.install_rpath) - if self.environment.coredata.get_builtin_option('coverage'): - commands += linker.get_coverage_link_args() - custom_target_libraries = self.get_custom_target_provided_libraries(target) - commands += extra_args - commands += custom_target_libraries - commands = linker.unixtype_flags_to_native(commands) - 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(outname, linker_rule, obj_list) - elem.add_dep(dep_targets + custom_target_libraries) - elem.add_item('LINK_ARGS', commands) - self.check_outputs(elem) - return elem - - 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.output: - if self.environment.is_library(f): - libs.append(os.path.join(self.get_target_dir(t), f)) - return libs - - 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 not prospective 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): - basename = target.get_filename() - aliases = target.get_aliaslist() - if not mesonlib.is_windows(): - for alias in aliases: - aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias) - try: - os.remove(aliasfile) - except Exception: - pass - os.symlink(basename, aliasfile) - else: - mlog.debug("Library versioning disabled because host does not support symlinks.") - - def generate_gcov_clean(self, outfile): - gcno_elem = NinjaBuildElement('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) - self.check_outputs(gcno_elem) - - gcda_elem = NinjaBuildElement('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) - self.check_outputs(gcda_elem) - - def is_compilable_file(self, filename): - if filename.endswith('.cpp') or\ - filename.endswith('.c') or\ - filename.endswith('.cxx') or\ - filename.endswith('.cc') or\ - filename.endswith('.C'): - return True - return False - - def process_dep_gens(self, outfile, target): - src_deps = [] - other_deps = [] - for rule in self.dep_rules.values(): - srcs = target.get_original_kwargs().get(rule.src_keyword, []) - if isinstance(srcs, str): - srcs = [srcs] - for src in srcs: - plainname = os.path.split(src)[1] - basename = plainname.split('.')[0] - outname = rule.name_templ.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) - outfilename = os.path.join(self.get_target_private_dir(target), outname) - infilename = os.path.join(self.build_to_src, target.get_source_subdir(), src) - elem = NinjaBuildElement(outfilename, rule.name, infilename) - elem.write(outfile) - self.check_outputs(elem) - if self.is_compilable_file(outfilename): - src_deps.append(outfilename) - else: - other_deps.append(outfilename) - return (src_deps, other_deps) - - def generate_ending(self, outfile): - targetlist = [self.get_target_filename(t) for t in self.build.get_targets().values()\ - if not isinstance(t, build.RunTarget)] - - elem = NinjaBuildElement('all', 'phony', targetlist) - elem.write(outfile) - self.check_outputs(elem) - - default = 'default all\n\n' - outfile.write(default) - - ninja_command = environment.detect_ninja() - if ninja_command is None: - raise MesonException('Could not detect ninja command') - elem = NinjaBuildElement('clean', 'CUSTOM_COMMAND', 'PHONY') - elem.add_item('COMMAND', [ninja_command, '-t', 'clean']) - elem.add_item('description', 'Cleaning') - if self.environment.coredata.get_builtin_option('coverage'): - self.generate_gcov_clean(outfile) - elem.add_dep('clean-gcda') - elem.add_dep('clean-gcno') - elem.write(outfile) - self.check_outputs(elem) - - deps = self.get_regen_filelist() - elem = NinjaBuildElement('build.ninja', 'REGENERATE_BUILD', deps) - elem.add_item('pool', 'console') - elem.write(outfile) - - elem = NinjaBuildElement(deps, 'phony', '') - elem.write(outfile) - self.check_outputs(elem) diff --git a/meson/optinterpreter.py b/meson/optinterpreter.py deleted file mode 100644 index f0c93ae..0000000 --- a/meson/optinterpreter.py +++ /dev/null @@ -1,148 +0,0 @@ -# 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, mesonlib -import os, re - -forbidden_option_names = coredata.builtin_options -forbidden_prefixes = {'c_': True, - 'cpp_': True, - 'rust_': True, - 'fortran_': True, - 'objc_': True, - 'objcpp_': True, - 'vala_': True, - 'csharp_': True - } - -def is_invalid_name(name): - if name in forbidden_option_names: - return True - if name in forbidden_prefixes: - return True - return False - -class OptionException(coredata.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.cmd_line_options = {} - for o in command_line_options: - (key, value) = o.split('=', 1) - self.cmd_line_options[key] = value - - def process(self, option_file): - try: - ast = mparser.Parser(open(option_file, 'r').read()).parse() - except coredata.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): - return arg.value - elif isinstance(arg, mparser.BooleanNode): - return arg.value - elif isinstance(arg, mparser.ArrayNode): - return [self.reduce_single(curarg) for curarg in arg.args.arguments] - elif isinstance(arg, mparser.NumberNode): - return arg.value - 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 not opt_type 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 diff --git a/meson/scripts/commandrunner.py b/meson/scripts/commandrunner.py deleted file mode 100644 index f5a2fff..0000000 --- a/meson/scripts/commandrunner.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 - -# 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, command, arguments): - env = {'MESON_SOURCE_ROOT' : source_dir, - 'MESON_BUILD_ROOT' : build_dir, - 'MESON_SUBDIR' : subdir - } - 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(sys.argv) < 4: - print('commandrunner.py <source dir> <build dir> <subdir> <command> [arguments]') - sys.exit(1) - src_dir = sys.argv[1] - build_dir = sys.argv[2] - subdir = sys.argv[3] - command = sys.argv[4] - arguments = sys.argv[5:] - pc = run_command(src_dir, build_dir, subdir, command, arguments) - pc.wait() - return pc.returncode - -if __name__ == '__main__': - sys.exit(run(sys.argv[1:])) diff --git a/meson/scripts/delwithsuffix.py b/meson/scripts/delwithsuffix.py deleted file mode 100644 index 38ab406..0000000 --- a/meson/scripts/delwithsuffix.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 - -# 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) != 2: - print('delwithsuffix.py <root of subdir to process> <suffix to delete>') - 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:]) diff --git a/meson/scripts/depfixer.py b/meson/scripts/depfixer.py deleted file mode 100644 index 1ab83b6..0000000 --- a/meson/scripts/depfixer.py +++ /dev/null @@ -1,302 +0,0 @@ -#!/usr/bin/env python3 - -# 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, struct - -SHT_STRTAB = 3 -DT_NEEDED = 1 -DT_RPATH = 15 -DT_STRTAB = 5 -DT_SONAME = 14 - -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): - self.bfile = bfile - self.bf = open(bfile, 'r+b') - (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() - - 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. - 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: - print('File "%s" has unknown ELF class.' % self.bfile) - sys.exit(1) - if data[5] == 1: - is_le = True - elif data[5] == 2: - is_le = False - else: - print('File "%s" has unknown ELF endianness.' % self.bfile) - sys.exit(1) - 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 = [] - 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 - self.bf.seek(strtab.val + soname.val) - print(self.read_str()) - - def get_rpath_offset(self): - sec = self.find_section(b'.dynstr') - for i in self.dynamic: - if i.d_tag == DT_RPATH: - return sec.sh_offset + i.val - return None - - def print_rpath(self): - offset = self.get_rpath_offset() - if offset is None: - print("This file does not have an rpath.") - 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): - rp_off = self.get_rpath_offset() - if rp_off is None: - 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): - print("New rpath must not be longer than the old one.") - self.bf.seek(rp_off) - self.bf.write(new_rpath) - self.bf.write(b'\0'*(len(old_rpath) - len(new_rpath) + 1)) - if len(new_rpath) == 0: - self.remove_rpath_entry() - - def remove_rpath_entry(self): - sec = self.find_section(b'.dynamic') - for (i, entry) in enumerate(self.dynamic): - if entry.d_tag == DT_RPATH: - rpentry = self.dynamic[i] - rpentry.d_tag = 0 - self.dynamic = self.dynamic[:i] + self.dynamic[i+1:] + [rpentry] - 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: <binary file> <prefix>' % sys.argv[0]) - exit(1) - e = Elf(args[0]) - if len(args) == 1: - e.print_rpath() - else: - new_rpath = args[1] - e.fix_rpath(new_rpath.encode('utf8')) - return 0 - -if __name__ == '__main__': - run(sys.argv[1:]) diff --git a/meson/scripts/dirchanger.py b/meson/scripts/dirchanger.py deleted file mode 100644 index 93a901d..0000000 --- a/meson/scripts/dirchanger.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 - -# 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:])) diff --git a/meson/scripts/gtkdochelper.py b/meson/scripts/gtkdochelper.py deleted file mode 100644 index 68be8f2..0000000 --- a/meson/scripts/gtkdochelper.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python3 -# 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 - -parser = argparse.ArgumentParser() - -parser.add_argument('--sourcedir', dest='sourcedir') -parser.add_argument('--builddir', dest='builddir') -parser.add_argument('--subdir', dest='subdir') -parser.add_argument('--headerdir', dest='headerdir') -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='') - -def build_gtkdoc(source_root, build_root, doc_subdir, src_subdir, - main_file, module, html_args, scan_args): - abs_src = os.path.join(source_root, src_subdir) - abs_out = os.path.join(build_root, doc_subdir) - htmldir = os.path.join(abs_out, 'html') - scan_cmd = ['gtkdoc-scan', - '--module=' + module, - '--source-dir=' + abs_src] + scan_args -# print(scan_cmd) -# sys.exit(1) - subprocess.check_call(scan_cmd, - cwd=abs_out) - if main_file.endswith('sgml'): - modeflag = '--sgml-mode' - else: - modeflag = '--xml-mode' - mkdb_cmd = ['gtkdoc-mkdb', - '--module=' + module, - '--output-format=xml', - modeflag, - '--source-dir=' + abs_src] - main_abs = os.path.join(source_root, doc_subdir, main_file) - if len(main_file) > 0: - # Yes, this is the flag even if the file is in xml. - mkdb_cmd.append('--main-sgml-file=' + main_file) -# print(mkdb_cmd) -# sys.exit(1) - subprocess.check_call(mkdb_cmd, cwd=abs_out) - shutil.rmtree(htmldir, ignore_errors=True) - try: - os.mkdir(htmldir) - except Exception: - pass - mkhtml_cmd = ['gtkdoc-mkhtml', - '--path=' + abs_src, - 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 -# print(mkhtml_cmd) -# sys.exit(1) - subprocess.check_call(mkhtml_cmd, cwd=os.path.join(abs_out, 'html'), shell=False) - fixref_cmd = ['gtkdoc-fixxref', - '--module=' + module, - '--module-dir=html'] -# print(fixref_cmd) -# sys.exit(1) - subprocess.check_call(fixref_cmd, cwd=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 = [] - build_gtkdoc(options.sourcedir, - options.builddir, - options.subdir, - options.headerdir, - options.mainfile, - options.modulename, - htmlargs, - scanargs) - - if 'MESON_INSTALL_PREFIX' in os.environ: - if 'DESTDIR' in os.environ: - installdir = os.environ['DESTDIR'] + os.environ['MESON_INSTALL_PREFIX'] - else: - installdir = os.environ['MESON_INSTALL_PREFIX'] - install_gtkdoc(options.builddir, - options.subdir, - installdir, - 'share/gtk-doc/html', - options.modulename) - return 0 - -if __name__ == '__main__': - sys.exit(run(sys.argv[1:])) diff --git a/meson/scripts/meson_benchmark.py b/meson/scripts/meson_benchmark.py deleted file mode 100644 index 26f1f95..0000000 --- a/meson/scripts/meson_benchmark.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python3 - -# 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 subprocess, sys, os, argparse -import pickle, statistics, json -from . import meson_test - -parser = argparse.ArgumentParser() -parser.add_argument('--wd', default=None, dest='wd', - help='directory to cd into before running') -parser.add_argument('args', nargs='+') - -def print_stats(numlen, num_tests, name, res, i, duration, stdev): - startpad = ' '*(numlen - len('%d' % (i+1))) - num = '%s%d/%d' % (startpad, i+1, num_tests) - padding1 = ' '*(38-len(name)) - padding2 = ' '*(8-len(res)) - result_str = '%s %s %s%s%s%5.5f s +- %5.5f s' % \ - (num, name, padding1, res, padding2, duration, stdev) - print(result_str) -# write_json_log(jsonlogfile, name, result) - -def print_json_log(jsonlogfile, rawruns, test_name, i): - jsonobj = {'name' : test_name} - runs = [] - for r in rawruns: - runobj = {'duration': r.duration, - 'stdout': r.stdo, - 'stderr': r.stde, - 'returncode' : r.returncode, - 'duration' : r.duration} - runs.append(runobj) - jsonobj['runs'] = runs - jsonlogfile.write(json.dumps(jsonobj) + '\n') - jsonlogfile.flush() - -def run_benchmarks(options, datafile): - failed_tests = 0 - logfile_base = 'meson-logs/benchmarklog' - jsonlogfilename = logfile_base+ '.json' - jsonlogfile = open(jsonlogfilename, 'w') - tests = pickle.load(open(datafile, 'rb')) - num_tests = len(tests) - if num_tests == 0: - print('No benchmarks defined.') - return 0 - iteration_count = 5 - wrap = [] # Benchmarks on cross builds are pointless so don't support them. - for i, test in enumerate(tests): - runs = [] - durations = [] - failed = False - for _ in range(iteration_count): - res = meson_test.run_single_test(wrap, test) - runs.append(res) - durations.append(res.duration) - if res.returncode != 0: - failed = True - mean = statistics.mean(durations) - stddev = statistics.stdev(durations) - if failed: - resultstr = 'FAIL' - failed_tests += 1 - else: - resultstr = 'OK' - print_stats(3, num_tests, test.name, resultstr, i, mean, stddev) - print_json_log(jsonlogfile, runs, test.name, i) - print('\nFull log written to meson-logs/benchmarklog.json.') - return failed_tests - -def run(args): - global failed_tests - options = parser.parse_args(args) - if len(options.args) != 1: - print('Benchmark runner for Meson. Do not run on your own, mmm\'kay?') - print('%s [data file]' % sys.argv[0]) - if options.wd is not None: - os.chdir(options.wd) - datafile = options.args[0] - returncode = run_benchmarks(options, datafile) - return returncode - -if __name__ == '__main__': - sys.exit(run(sys.argv[1:])) diff --git a/meson/scripts/meson_install.py b/meson/scripts/meson_install.py deleted file mode 100644 index 1ede757..0000000 --- a/meson/scripts/meson_install.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env python3 - -# 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 -from glob import glob - -def do_install(datafilename): - ifile = open(datafilename, 'rb') - d = pickle.load(ifile) - destdir_var = 'DESTDIR' - if destdir_var in os.environ: - d.destdir = os.environ[destdir_var] - else: - d.destdir = '' - d.fullprefix = 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) - install_po(d) - run_install_script(d) - -def install_subdirs(d): - for (src_dir, dst_dir) in d.install_subdirs: - if os.path.isabs(dst_dir): - dst_dir = d.destdir + dst_dir - else: - dst_dir = d.fullprefix + dst_dir - # Python's copytree works in strange ways. - last_level = os.path.split(src_dir)[-1] - final_dst = os.path.join(dst_dir, last_level) -# Don't do rmtree because final_dst might point to e.g. /var/www -# We might need to revert to walking the directory tree by hand. -# shutil.rmtree(final_dst, ignore_errors=True) - shutil.copytree(src_dir, final_dst, symlinks=True) - print('Installing subdir %s to %s.' % (src_dir, dst_dir)) - -def install_po(d): - packagename = d.po_package_name - for f in d.po: - srcfile = f[0] - localedir = f[1] - languagename = f[2] - outfile = os.path.join(d.fullprefix, localedir, languagename, 'LC_MESSAGES', - packagename + '.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)) - -def install_data(d): - for i in d.data: - fullfilename = i[0] - outfilename = i[1] - if os.path.isabs(outfilename): - outdir = d.destdir + os.path.split(outfilename)[0] - outfilename = d.destdir + outfilename - else: - outdir = os.path.join(d.fullprefix, os.path.split(outfilename)[0]) - outfilename = os.path.join(outdir, os.path.split(outfilename)[1]) - os.makedirs(outdir, exist_ok=True) - print('Installing %s to %s.' % (fullfilename, outdir)) - shutil.copyfile(fullfilename, outfilename) - shutil.copystat(fullfilename, outfilename) - -def install_man(d): - for m in d.man: - outfileroot = m[1] - outfilename = os.path.join(d.fullprefix, outfileroot) - full_source_filename = m[0] - 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'): - open(outfilename, 'wb').write(gzip.compress(open(full_source_filename, 'rb').read())) - else: - shutil.copyfile(full_source_filename, outfilename) - shutil.copystat(full_source_filename, outfilename) - -def install_headers(d): - for t in d.headers: - fullfilename = t[0] - outdir = os.path.join(d.fullprefix, t[1]) - fname = os.path.split(fullfilename)[1] - outfilename = os.path.join(outdir, fname) - print('Installing %s to %s' % (fname, outdir)) - os.makedirs(outdir, exist_ok=True) - shutil.copyfile(fullfilename, outfilename) - shutil.copystat(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 - } - child_env = os.environ.copy() - child_env.update(env) - - for i in d.install_scripts: - script = i.cmd_arr[0] - print('Running custom install script %s' % script) - suffix = os.path.splitext(script)[1].lower() - if platform.system().lower() == 'windows' and suffix != '.bat': - first_line = open(script).readline().strip() - if first_line.startswith('#!'): - commands = first_line[2:].split('#')[0].strip().split() - commands[0] = shutil.which(commands[0].split('/')[-1]) - if commands[0] is None: - raise RuntimeError("Don't know how to run script %s." % script) - final_command = commands + [script] + i.cmd_arr[1:] - else: - final_command = i.cmd_arr - subprocess.check_call(final_command, env=child_env) - -def is_elf_platform(): - platname = platform.system().lower() - if platname == 'darwin' or platname == 'windows': - 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 = os.path.join(d.fullprefix, t[1]) - aliases = t[2] - outname = os.path.join(outdir, os.path.split(fname)[-1]) - should_strip = t[3] - install_rpath = t[4] - print('Installing %s to %s' % (fname, outname)) - os.makedirs(outdir, exist_ok=True) - shutil.copyfile(fname, outname) - shutil.copystat(fname, outname) - if should_strip: - print('Stripping target') - ps = subprocess.Popen(['strip', outname], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdo, stde) = ps.communicate() - if ps.returncode != 0: - print('Could not strip file.\n') - print('Stdout:\n%s\n' % stdo.decode()) - print('Stderr:\n%s\n' % stde.decode()) - sys.exit(1) - printed_symlink_error = False - for alias in aliases: - try: - symlinkfilename = os.path.join(outdir, alias) - try: - os.unlink(symlinkfilename) - except FileNotFoundError: - pass - os.symlink(os.path.split(fname)[-1], symlinkfilename) - except NotImplementedError: - if not printed_symlink_error: - print("Symlink creation does not work on this platform.") - printed_symlink_error = True - if is_elf_platform(): - p = subprocess.Popen(d.depfixer + [outname, install_rpath], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - (stdo, stde) = p.communicate() - if p.returncode != 0: - print('Could not fix dependency info.\n') - print('Stdout:\n%s\n' % stdo.decode()) - print('Stderr:\n%s\n' % stde.decode()) - sys.exit(1) - -def run(args): - if len(args) != 1: - print('Installer script for Meson. Do not run on your own, mmm\'kay?') - print('meson_install.py [install info file]') - datafilename = args[0] - do_install(datafilename) - return 0 - -if __name__ == '__main__': - sys.exit(run(sys.argv[1:])) diff --git a/meson/scripts/meson_test.py b/meson/scripts/meson_test.py deleted file mode 100644 index c5814ef..0000000 --- a/meson/scripts/meson_test.py +++ /dev/null @@ -1,233 +0,0 @@ -#!/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. - -import meson -import sys, os, subprocess, time, datetime, pickle, multiprocessing, json -import concurrent.futures as conc -import argparse -import platform - -def is_windows(): - platname = platform.system().lower() - return platname == 'windows' or 'mingw' in platname - -tests_failed = [] - -parser = argparse.ArgumentParser() -parser.add_argument('--wrapper', default=None, dest='wrapper', - help='wrapper to run tests with (e.g. valgrind)') -parser.add_argument('--wd', default=None, dest='wd', - help='directory to cd into before running') -parser.add_argument('--suite', default=None, dest='suite', - help='Only run tests belonging to this suite.') -parser.add_argument('args', nargs='+') - - -class TestRun(): - def __init__(self, res, returncode, duration, stdo, stde, cmd): - self.res = res - self.returncode = returncode - self.duration = duration - self.stdo = stdo - self.stde = stde - self.cmd = cmd - -def decode(stream): - try: - return stream.decode('utf-8') - except UnicodeDecodeError: - return stream.decode('iso-8859-1', errors='ignore') - -def write_log(logfile, test_name, result_str, result): - logfile.write(result_str + '\n\n') - logfile.write('--- command ---\n') - if result.cmd is None: - logfile.write('NONE') - else: - logfile.write(' '.join(result.cmd)) - logfile.write('\n--- "%s" stdout ---\n' % test_name) - logfile.write(result.stdo) - logfile.write('\n--- "%s" stderr ---\n' % test_name) - logfile.write(result.stde) - logfile.write('\n-------\n\n') - -def write_json_log(jsonlogfile, test_name, result): - result = {'name' : test_name, - 'stdout' : result.stdo, - 'stderr' : result.stde, - 'result' : result.res, - 'duration' : result.duration, - 'returncode' : result.returncode, - 'command' : result.cmd} - jsonlogfile.write(json.dumps(result) + '\n') - -def run_with_mono(fname): - if fname.endswith('.exe') and not is_windows(): - return True - return False - -def run_single_test(wrap, test): - global tests_failed - if test.fname[0].endswith('.jar'): - cmd = ['java', '-jar'] + test.fname - elif not test.is_cross and run_with_mono(test.fname[0]): - cmd = ['mono'] + test.fname - else: - if test.is_cross: - if test.exe_runner is None: - # Can not run test on cross compiled executable - # because there is no execute wrapper. - cmd = None - else: - cmd = [test.exe_runner] + test.fname - else: - cmd = test.fname - if len(wrap) > 0 and 'valgrind' in wrap[0]: - wrap += test.valgrind_args - if cmd is None: - res = 'SKIP' - duration = 0.0 - stdo = 'Not run because can not execute cross compiled binaries.' - stde = '' - returncode = -1 - else: - cmd = wrap + cmd + test.cmd_args - starttime = time.time() - child_env = os.environ.copy() - child_env.update(test.env) - if len(test.extra_paths) > 0: - child_env['PATH'] = child_env['PATH'] + ';'.join([''] + test.extra_paths) - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=child_env, cwd=test.workdir) - timed_out = False - try: - (stdo, stde) = p.communicate(timeout=test.timeout) - except subprocess.TimeoutExpired: - timed_out = True - p.kill() - (stdo, stde) = p.communicate() - endtime = time.time() - duration = endtime - starttime - stdo = decode(stdo) - stde = decode(stde) - if timed_out: - res = 'TIMEOUT' - tests_failed.append((test.name, stdo, stde)) - elif (not test.should_fail and p.returncode == 0) or \ - (test.should_fail and p.returncode != 0): - res = 'OK' - else: - res = 'FAIL' - tests_failed.append((test.name, stdo, stde)) - returncode = p.returncode - return TestRun(res, returncode, duration, stdo, stde, cmd) - -def print_stats(numlen, tests, name, result, i, logfile, jsonlogfile): - startpad = ' '*(numlen - len('%d' % (i+1))) - num = '%s%d/%d' % (startpad, i+1, len(tests)) - padding1 = ' '*(38-len(name)) - padding2 = ' '*(8-len(result.res)) - result_str = '%s %s %s%s%s%5.2f s' % \ - (num, name, padding1, result.res, padding2, result.duration) - print(result_str) - write_log(logfile, name, result_str, result) - write_json_log(jsonlogfile, name, result) - -def drain_futures(futures): - for i in futures: - (result, numlen, tests, name, i, logfile, jsonlogfile) = i - print_stats(numlen, tests, name, result.result(), i, logfile, jsonlogfile) - -def filter_tests(suite, tests): - if suite is None: - return tests - return [x for x in tests if suite in x.suite] - -def run_tests(options, datafilename): - logfile_base = 'meson-logs/testlog' - if options.wrapper is None: - wrap = [] - logfilename = logfile_base + '.txt' - jsonlogfilename = logfile_base+ '.json' - else: - wrap = [options.wrapper] - logfilename = logfile_base + '-' + options.wrapper.replace(' ', '_') + '.txt' - jsonlogfilename = logfile_base + '-' + options.wrapper.replace(' ', '_') + '.json' - logfile = open(logfilename, 'w') - jsonlogfile = open(jsonlogfilename, 'w') - logfile.write('Log of Meson test suite run on %s.\n\n' % datetime.datetime.now().isoformat()) - tests = pickle.load(open(datafilename, 'rb')) - if len(tests) == 0: - print('No tests defined.') - return - numlen = len('%d' % len(tests)) - varname = 'MESON_TESTTHREADS' - if varname in os.environ: - try: - num_workers = int(os.environ[varname]) - except ValueError: - print('Invalid value in %s, using 1 thread.' % varname) - num_workers = 1 - else: - num_workers = multiprocessing.cpu_count() - executor = conc.ThreadPoolExecutor(max_workers=num_workers) - futures = [] - filtered_tests = filter_tests(options.suite, tests) - for i, test in enumerate(filtered_tests): - if test.suite[0] == '': - visible_name = test.name - else: - if options.suite is not None: - visible_name = options.suite + ' / ' + test.name - else: - visible_name = test.suite[0] + ' / ' + test.name - - if not test.is_parallel: - drain_futures(futures) - futures = [] - res = run_single_test(wrap, test) - print_stats(numlen, filtered_tests, visible_name, res, i, logfile, jsonlogfile) - else: - f = executor.submit(run_single_test, wrap, test) - futures.append((f, numlen, filtered_tests, visible_name, i, logfile, jsonlogfile)) - drain_futures(futures) - return logfilename - -def run(args): - global tests_failed - options = parser.parse_args(args) - if len(options.args) != 1: - print('Test runner for Meson. Do not run on your own, mmm\'kay?') - print('%s [data file]' % sys.argv[0]) - if options.wd is not None: - os.chdir(options.wd) - datafile = options.args[0] - logfilename = run_tests(options, datafile) - returncode = 0 - if len(tests_failed) > 0: - print('\nOutput of failed tests (max 10):') - for (name, stdo, stde) in tests_failed[:10]: - print("{} stdout:\n".format(name)) - print(stdo) - print('\n{} stderr:\n'.format(name)) - print(stde) - print('\n') - returncode = 1 - print('\nFull log written to %s.' % logfilename) - return returncode - -if __name__ == '__main__': - sys.exit(run(sys.argv[1:])) diff --git a/meson/scripts/regen_checker.py b/meson/scripts/regen_checker.py deleted file mode 100644 index f360a7c..0000000 --- a/meson/scripts/regen_checker.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 - -# 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): - sln_time = os.stat(os.path.join(regeninfo.build_dir, regeninfo.solutionfile)).st_mtime - for i in regeninfo.depfiles: - curfile = os.path.join(regeninfo.build_dir, i) - curtime = os.stat(curfile).st_mtime - if curtime > sln_time: - return True - return False - -def regen(regeninfo): - scriptdir = os.path.split(__file__)[0] - mesonscript = os.path.join(scriptdir, 'meson.py') - cmd = [sys.executable, mesonscript, regeninfo.build_dir, regeninfo.source_dir, - '--backend=vs2010', 'secret-handshake'] - subprocess.check_call(cmd) - -def run(args): - regeninfo = pickle.load(open(os.path.join(args[0], 'regeninfo.dump'), 'rb')) - if need_regen(regeninfo): - regen(regeninfo) - sys.exit(0) - -if __name__ == '__main__': - run(sys.argv[1:]) diff --git a/meson/scripts/symbolextractor.py b/meson/scripts/symbolextractor.py deleted file mode 100644 index 9607466..0000000 --- a/meson/scripts/symbolextractor.py +++ /dev/null @@ -1,106 +0,0 @@ -#!/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. - -# 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 sys, subprocess -from meson import mesonlib -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.""" - open(outfilename, 'w').close() - -def write_if_changed(text, outfilename): - try: - oldtext = open(outfilename, 'r').read() - if text == oldtext: - return - except FileNotFoundError: - pass - open(outfilename, 'w').write(text) - -def linux_syms(libfilename, outfilename): - pe = subprocess.Popen(['readelf', '-d', libfilename], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output = pe.communicate()[0].decode() - 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 = subprocess.Popen(['nm', '--dynamic', '--extern-only', '--defined-only', '--format=posix', libfilename], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output = pnm.communicate()[0].decode() - 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 = subprocess.Popen(['otool', '-l', libfilename], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output = pe.communicate()[0].decode() - 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 = subprocess.Popen(['nm', '-g', '-P', libfilename], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output = pnm.communicate()[0].decode() - 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 <shared library file> <output file>') - 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:])) diff --git a/meson/scripts/vcstagger.py b/meson/scripts/vcstagger.py deleted file mode 100644 index 390e37a..0000000 --- a/meson/scripts/vcstagger.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -# 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 - - new_data = open(infile).read().replace(replace_string, new_string) - if (not os.path.exists(outfile)) or (open(outfile).read() != new_data): - open(outfile, 'w').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:])) diff --git a/meson/vs2010backend.py b/meson/vs2010backend.py deleted file mode 100644 index 33e9646..0000000 --- a/meson/vs2010backend.py +++ /dev/null @@ -1,640 +0,0 @@ -# Copyright 2014-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, sys -import pickle -from . import backends, build -from . import dependencies -from . import mlog -import xml.etree.ElementTree as ET -import xml.dom.minidom -from .coredata import MesonException - -class RegenInfo(): - def __init__(self, source_dir, build_dir, depfiles, solutionfile): - self.source_dir = source_dir - self.build_dir = build_dir - self.depfiles = depfiles - self.solutionfile = solutionfile - -class Vs2010Backend(backends.Backend): - def __init__(self, build): - super().__init__(build) - self.project_file_version = '10.0.30319.1' - # foo.c compiles to foo.obj, not foo.c.obj - self.source_suffix_in_obj = False - - def generate_custom_generator_commands(self, target, parent_node): - idgroup = ET.SubElement(parent_node, 'ItemDefinitionGroup') - all_output_files = [] - for genlist in target.get_generated_sources(): - if isinstance(genlist, build.CustomTarget): - all_output_files += [os.path.join(self.get_target_dir(genlist), i) for i in genlist.output] - else: - generator = genlist.get_generator() - exe = generator.get_exe() - infilelist = genlist.get_infilelist() - outfilelist = genlist.get_outfilelist() - if isinstance(exe, build.BuildTarget): - exe_file = os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe)) - else: - exe_file = exe.get_command() - base_args = generator.get_arglist() - for i in range(len(infilelist)): - if len(infilelist) == len(outfilelist): - sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i]) - else: - sole_output = '' - curfile = infilelist[i] - infilename = os.path.join(self.environment.get_source_dir(), curfile) - outfiles = genlist.get_outputs_for(curfile) - outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles] - all_output_files += outfiles - args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output)\ - for x in base_args] - args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()).replace("@BUILD_DIR@", self.get_target_private_dir(target)) - for x in args] - fullcmd = [exe_file] + args - cbs = ET.SubElement(idgroup, 'CustomBuildStep') - ET.SubElement(cbs, 'Command').text = ' '.join(self.special_quote(fullcmd)) - ET.SubElement(cbs, 'Inputs').text = infilename - ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles) - ET.SubElement(cbs, 'Message').text = 'Generating sources from %s.' % infilename - pg = ET.SubElement(parent_node, 'PropertyGroup') - ET.SubElement(pg, 'CustomBuildBeforeTargets').text = 'ClCompile' - return all_output_files - - def generate(self, interp): - self.interpreter = interp - self.platform = 'Win32' - 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(sln_filename) - open(os.path.join(self.environment.get_scratch_dir(), 'regen.stamp'), 'wb') - rulefile = os.path.join(self.environment.get_scratch_dir(), 'regen.rule') - if not os.path.exists(rulefile): - open(rulefile, 'w').write("# For some reason this needs to be here.") - - def generate_regen_info(self, sln_filename): - deps = self.get_regen_filelist() - regeninfo = RegenInfo(self.environment.get_source_dir(), - self.environment.get_build_dir(), - deps, - sln_filename) - pickle.dump(regeninfo, open(os.path.join(self.environment.get_scratch_dir(), 'regeninfo.dump'), 'wb')) - - def get_obj_target_deps(self, obj_list): - result = {} - for o in obj_list: - if isinstance(o, build.ExtractedObjects): - result[o.target.get_basename()] = True - return result.keys() - - def determine_deps(self, p): - all_deps = {} - target = self.build.targets[p[0]] - if isinstance(target, build.CustomTarget): - for d in target.dependencies: - all_deps[d.get_id()] = True - return all_deps - if isinstance(target, build.RunTarget): - for d in [target.command] + target.args: - if isinstance(d, build.BuildTarget): - all_deps[d.get_id()] = True - return all_deps - for ldep in target.link_targets: - all_deps[ldep.get_id()] = True - for objdep in self.get_obj_target_deps(target.objects): - all_deps[objdep] = True - for gendep in target.generated: - if isinstance(gendep, build.CustomTarget): - all_deps[gendep.get_id()] = True - else: - gen_exe = gendep.generator.get_exe() - if isinstance(gen_exe, build.Executable): - all_deps[gen_exe.get_id()] = True - return all_deps - - def generate_solution(self, sln_filename, projlist): - ofile = open(sln_filename, 'w') - ofile.write('Microsoft Visual Studio Solution File, Format Version 11.00\n') - ofile.write('# Visual Studio 2010\n') - prj_templ = prj_line = 'Project("{%s}") = "%s", "%s", "{%s}"\n' - for p in projlist: - prj_line = prj_templ % (self.environment.coredata.guid, p[0], p[1], p[2]) - ofile.write(prj_line) - all_deps = self.determine_deps(p) - 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') - 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)) - for p in projlist: - ofile.write('\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n' % - (p[2], self.buildtype, self.platform, - self.buildtype, self.platform)) - if not isinstance(self.build.targets[p[0]], build.RunTarget): - 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 = [] - comp = None - for l, c in self.environment.coredata.compilers.items(): - if l == 'c' or l == 'cpp': - comp = c - break - if comp is None: - raise RuntimeError('C and C++ compilers missing.') - for name, target in self.build.targets.items(): - outdir = os.path.join(self.environment.get_build_dir(), self.get_target_dir(target)) - fname = name + '.vcxproj' - relname = os.path.join(target.subdir, fname) - projfile = os.path.join(outdir, fname) - uuid = self.environment.coredata.target_guids[name] - self.gen_vcxproj(target, projfile, uuid, comp) - projlist.append((name, relname, uuid)) - return projlist - - def split_sources(self, srclist): - sources = [] - headers = [] - for i in srclist: - if self.environment.is_header(i): - headers.append(i) - else: - sources.append(i) - return (sources, headers) - - def target_to_build_root(self, target): - if target.subdir == '': - return '' - - directories = os.path.split(target.subdir) - directories = list(filter(bool,directories)) #Filter out empty strings - - return '/'.join(['..']*len(directories)) - - def special_quote(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 - 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' - 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 - 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)] - 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.fullpath - 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') - tree = ET.ElementTree(root) - tree.write(ofname, encoding='utf-8', xml_declaration=True) - - 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') - (srcs, ofilenames, cmd) = self.eval_custom_target_command(target, True) - cmd_templ = '''"%s" '''*len(cmd) - ET.SubElement(customstep, 'Command').text = cmd_templ % tuple(cmd) - ET.SubElement(customstep, 'Outputs').text = ';'.join([os.path.join(self.environment.get_build_dir(), i)\ - for i in ofilenames]) - ET.SubElement(customstep, 'Inputs').text = ';'.join([os.path.join(self.environment.get_build_dir(), i) \ - for i in srcs]) - ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets') - tree = ET.ElementTree(root) - tree.write(ofname, encoding='utf-8', xml_declaration=True) - - def gen_vcxproj(self, target, ofname, guid, compiler): - 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()) - down = self.target_to_build_root(target) - proj_to_src_root = os.path.join(down, self.build_to_src) - proj_to_src_dir = os.path.join(proj_to_src_root, target.subdir) - (sources, headers) = self.split_sources(target.sources) - buildtype = 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= buildtype - pl = ET.SubElement(prjconf, 'Platform') - pl.text = self.platform - 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 - ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props') - type_config = ET.SubElement(root, 'PropertyGroup', Label='Configuration') - ET.SubElement(type_config, 'ConfigurationType').text = conftype - ET.SubElement(type_config, 'CharacterSet').text = 'MultiByte' - ET.SubElement(type_config, 'WholeProgramOptimization').text = 'false' - ET.SubElement(type_config, 'UseDebugLibraries').text = 'true' - ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.props') - generated_files = self.generate_custom_generator_commands(target, root) - (gen_src, gen_hdrs) = self.split_sources(generated_files) - 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 = os.path.join(self.get_target_dir(target), target.get_basename() + '.dir') + '\\' - tname = ET.SubElement(direlem, 'TargetName') - tname.text = target_name - inclinc = ET.SubElement(direlem, 'LinkIncremental') - inclinc.text = 'true' - - compiles = ET.SubElement(root, 'ItemDefinitionGroup') - clconf = ET.SubElement(compiles, 'ClCompile') - opt = ET.SubElement(clconf, 'Optimization') - opt.text = 'disabled' - inc_dirs = [proj_to_src_dir, self.get_target_private_dir(target)] - cur_dir = target.subdir - if cur_dir == '': - cur_dir= '.' - inc_dirs.append(cur_dir) - extra_args = [] - # SUCKS, VS can not handle per-language type flags, so just use - # them all. - extra_args += compiler.get_buildtype_args(self.buildtype) - for l in self.environment.coredata.external_args.values(): - for a in l: - extra_args.append(a) - for l in self.build.global_args.values(): - for a in l: - extra_args.append(a) - for l in target.extra_args.values(): - for a in l: - extra_args.append(a) - # FIXME all the internal flags of VS (optimization etc) are represented - # by their own XML elements. In theory we should split all flags to those - # that have an XML element and those that don't and serialise them - # properly. This is a crapton of work for no real gain, so just dump them - # here. - extra_args = compiler.get_option_compile_args(self.environment.coredata.compiler_options) - if len(extra_args) > 0: - extra_args.append('%(AdditionalOptions)') - ET.SubElement(clconf, "AdditionalOptions").text = ' '.join(extra_args) - for d in target.include_dirs: - for i in d.incdirs: - curdir = os.path.join(d.curdir, i) - inc_dirs.append(self.relpath(curdir, target.subdir)) # build dir - inc_dirs.append(os.path.join(proj_to_src_root, curdir)) # src dir - inc_dirs.append('%(AdditionalIncludeDirectories)') - ET.SubElement(clconf, 'AdditionalIncludeDirectories').text = ';'.join(inc_dirs) - preproc = ET.SubElement(clconf, 'PreprocessorDefinitions') - rebuild = ET.SubElement(clconf, 'MinimalRebuild') - rebuild.text = 'true' - rtlib = ET.SubElement(clconf, 'RuntimeLibrary') - rtlib.text = 'MultiThreadedDebugDLL' - funclink = ET.SubElement(clconf, 'FunctionLevelLinking') - funclink.text = 'true' - pch = ET.SubElement(clconf, 'PrecompiledHeader') - warnings = ET.SubElement(clconf, 'WarningLevel') - warnings.text = 'Level3' - debinfo = ET.SubElement(clconf, 'DebugInformationFormat') - debinfo.text = 'EditAndContinue' - resourcecompile = ET.SubElement(compiles, 'ResourceCompile') - ET.SubElement(resourcecompile, 'PreprocessorDefinitions') - link = ET.SubElement(compiles, 'Link') - # Put all language args here, too. - extra_link_args = compiler.get_option_link_args(self.environment.coredata.compiler_options) - extra_link_args += compiler.get_buildtype_linker_args(self.buildtype) - for l in self.environment.coredata.external_link_args.values(): - for a in l: - extra_link_args.append(a) - for l in target.link_args: - for a in l: - extra_link_args.append(a) - if len(extra_args) > 0: - extra_args.append('%(AdditionalOptions)') - ET.SubElement(link, "AdditionalOptions").text = ' '.join(extra_args) - - additional_links = [] - for t in target.link_targets: - lobj = self.build.targets[t.get_id()] - rel_path = self.relpath(lobj.subdir, target.subdir) - linkname = os.path.join(rel_path, lobj.get_import_filename()) - additional_links.append(linkname) - for o in self.flatten_object_list(target, down): - assert(isinstance(o, str)) - additional_links.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() - addlibdir = ET.SubElement(link, 'AdditionalLibraryDirectories') - addlibdir.text = '%(AdditionalLibraryDirectories)' - subsys = ET.SubElement(link, 'SubSystem') - subsys.text = subsystem - gendeb = ET.SubElement(link, 'GenerateDebugInformation') - gendeb.text = 'true' - if isinstance(target, build.SharedLibrary): - ET.SubElement(link, 'ImportLibrary').text = target.get_import_filename() - pdb = ET.SubElement(link, 'ProgramDataBaseFileName') - pdb.text = '$(OutDir}%s.pdb' % target_name - if isinstance(target, build.Executable): - ET.SubElement(link, 'EntryPointSymbol').text = entrypoint - targetmachine = ET.SubElement(link, 'TargetMachine') - targetmachine.text = 'MachineX86' - - if len(headers) + len(gen_hdrs) > 0: - inc_hdrs = ET.SubElement(root, 'ItemGroup') - for h in headers: - relpath = h.rel_to_builddir(proj_to_src_root) - ET.SubElement(inc_hdrs, 'CLInclude', Include=relpath) - for h in gen_hdrs: - if isinstance(h, str): - relpath = h - else: - relpath = h.rel_to_builddir(proj_to_src_root) - ET.SubElement(inc_hdrs, 'CLInclude', Include = relpath) - if len(sources) + len(gen_src) > 0: - inc_src = ET.SubElement(root, 'ItemGroup') - for s in sources: - relpath = s.rel_to_builddir(proj_to_src_root) - ET.SubElement(inc_src, 'CLCompile', Include=relpath) - for s in gen_src: - relpath = self.relpath(s, target.subdir) - ET.SubElement(inc_src, 'CLCompile', Include=relpath) - 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 - tree = ET.ElementTree(root) - tree.write(ofname, encoding='utf-8', xml_declaration=True) - # ElementTree can not do prettyprinting so do it manually - doc = xml.dom.minidom.parse(ofname) - open(ofname, 'w').write(doc.toprettyxml()) - # World of horror! Python insists on not quoting quotes and - # fixing the escaped " into &quot; whereas MSVS - # requires quoted but not fixed elements. Enter horrible hack. - txt = open(ofname, 'r').read() - open(ofname, 'w').write(txt.replace('&quot;', '"')) - - 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 - 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' - 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 = 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' - script_root = self.environment.get_script_dir() - regen_script = os.path.join(script_root, 'regen_checker.py') - private_dir = self.environment.get_scratch_dir() - cmd_templ = '''setlocal -"%s" "%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') - custombuild = ET.SubElement(igroup, 'CustomBuild', Include='meson-private/regen.rule') - message = ET.SubElement(custombuild, 'Message') - message.text = 'Checking whether solution needs to be regenerated.' - ET.SubElement(custombuild, 'Command').text = cmd_templ % \ - (sys.executable, regen_script, private_dir) - ET.SubElement(custombuild, 'Outputs').text = os.path.join(self.environment.get_scratch_dir(), 'regen.stamp') - deps = self.get_regen_filelist() - depstr = ';'.join([os.path.join(self.environment.get_source_dir(), d) for d in deps]) - ET.SubElement(custombuild, 'AdditionalInputs').text = depstr - ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets') - ET.SubElement(root, 'ImportGroup', Label='ExtensionTargets') - tree = ET.ElementTree(root) - tree.write(ofname, encoding='utf-8', xml_declaration=True) - - 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 - 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' - 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') - script_root = self.environment.get_script_dir() - test_script = os.path.join(script_root, 'meson_test.py') - test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') - cmd_templ = '''setlocal -"%s" "%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''' - ET.SubElement(postbuild, 'Command').text = cmd_templ % (sys.executable, test_script, test_data) - ET.SubElement(root, 'Import', Project='$(VCTargetsPath)\Microsoft.Cpp.targets') - tree = ET.ElementTree(root) - tree.write(ofname, encoding='utf-8', xml_declaration=True) - datafile = open(test_data, 'wb') - self.serialise_tests() - datafile.close() - # ElementTree can not do prettyprinting so do it manually - #doc = xml.dom.minidom.parse(ofname) - #open(ofname, 'w').write(doc.toprettyxml()) diff --git a/meson/wrap/wrap.py b/meson/wrap/wrap.py deleted file mode 100644 index 2818fa0..0000000 --- a/meson/wrap/wrap.py +++ /dev/null @@ -1,212 +0,0 @@ -# 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 urllib.request, os, hashlib, shutil -import subprocess -import sys - -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/' - -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 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 = {} - ifile = open(fname) - first = ifile.readline().strip() - - if first == '[wrap-file]': - self.type = 'file' - elif first == '[wrap-git]': - self.type = 'git' - 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): - self.subdir_root = subdir_root - self.cachedir = os.path.join(self.subdir_root, 'packagecache') - - def resolve(self, packagename): - fname = os.path.join(self.subdir_root, packagename + '.wrap') - dirname = os.path.join(self.subdir_root, packagename) - if not os.path.isfile(fname): - if os.path.isdir(dirname): - # No wrap file but dir exists -> user put it there manually. - return packagename - return None - 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) - else: - raise RuntimeError('Unreachable code.') - return p.get('directory') - - 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: - if revno.lower() == 'head': - subprocess.check_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) - - - 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) - dlsize = int(resp.info()['Content-Length']) - 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('') - resp.close() - 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)) - open(ofname, 'wb').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)) - open(os.path.join(self.cachedir, p.get('patch_filename')), 'wb').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) diff --git a/meson/wrap/wraptool.py b/meson/wrap/wraptool.py deleted file mode 100755 index d2f0a28..0000000 --- a/meson/wrap/wraptool.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env python3 - -# 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 <command> [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() - open(wrapfile, 'wb').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 - open(wrapfile, 'wb').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(sys.argv) < 1 or sys.argv[0] == '-h' or sys.argv[1] == '--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:])) diff --git a/meson/xcodebackend.py b/meson/xcodebackend.py deleted file mode 100644 index 8ac3f67..0000000 --- a/meson/xcodebackend.py +++ /dev/null @@ -1,775 +0,0 @@ -# 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. - -from . import backends, build -from . import mesonlib -import uuid, os, sys - -from .coredata import MesonException - -class XCodeBackend(backends.Backend): - def __init__(self, build): - super().__init__(build) - 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 - self.serialise_tests() - 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') - self.ofile = open(self.proj_file, 'w') - 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() - 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, 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 = t.get_filename() - elif isinstance(t, build.SharedLibrary): - # OSX has a completely different shared library - # naming scheme so do this manually. - typestr = self.get_xcodetype('dummy.dylib') - path = t.get_osx_filename() - 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 = "<group>";') - 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 = "<group>";') - 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 = "<group>";') - 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 = "<group>";') - 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 = "<group>";') - 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 = "<group>";') - 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_basename()] - 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): - 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') - test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') - 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 = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk";') - 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_osx_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_name + '.' + dylib_version - else: - product_name = target_name - 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') |