aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/backends.py
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2016-01-23 20:02:52 +0200
committerJussi Pakkanen <jpakkane@gmail.com>2016-01-23 20:02:52 +0200
commit7435df8399a9580441f3940b35543ee2933a7b12 (patch)
treed34e467b180deb2622f75f2fcc182b405bcc3af5 /mesonbuild/backends.py
parentd6b205314618052e154901fa89579dc04a114011 (diff)
downloadmeson-7435df8399a9580441f3940b35543ee2933a7b12.zip
meson-7435df8399a9580441f3940b35543ee2933a7b12.tar.gz
meson-7435df8399a9580441f3940b35543ee2933a7b12.tar.bz2
Moved backends to their own module.
Diffstat (limited to 'mesonbuild/backends.py')
-rw-r--r--mesonbuild/backends.py423
1 files changed, 0 insertions, 423 deletions
diff --git a/mesonbuild/backends.py b/mesonbuild/backends.py
deleted file mode 100644
index c583a7b..0000000
--- a/mesonbuild/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)