From 7435df8399a9580441f3940b35543ee2933a7b12 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 23 Jan 2016 20:02:52 +0200 Subject: Moved backends to their own module. --- mesonbuild/backend/__init__.py | 0 mesonbuild/backend/backends.py | 423 ++++++++ mesonbuild/backend/ninjabackend.py | 1828 +++++++++++++++++++++++++++++++++++ mesonbuild/backend/vs2010backend.py | 646 +++++++++++++ mesonbuild/backend/xcodebackend.py | 776 +++++++++++++++ mesonbuild/backends.py | 423 -------- mesonbuild/mesonmain.py | 6 +- mesonbuild/ninjabackend.py | 1828 ----------------------------------- mesonbuild/vs2010backend.py | 645 ------------ mesonbuild/xcodebackend.py | 775 --------------- 10 files changed, 3676 insertions(+), 3674 deletions(-) create mode 100644 mesonbuild/backend/__init__.py create mode 100644 mesonbuild/backend/backends.py create mode 100644 mesonbuild/backend/ninjabackend.py create mode 100644 mesonbuild/backend/vs2010backend.py create mode 100644 mesonbuild/backend/xcodebackend.py delete mode 100644 mesonbuild/backends.py delete mode 100644 mesonbuild/ninjabackend.py delete mode 100644 mesonbuild/vs2010backend.py delete mode 100644 mesonbuild/xcodebackend.py diff --git a/mesonbuild/backend/__init__.py b/mesonbuild/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py new file mode 100644 index 0000000..cab3b8f --- /dev/null +++ b/mesonbuild/backend/backends.py @@ -0,0 +1,423 @@ +# Copyright 2012-2016 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os, pickle, re +from .. import build +from .. import dependencies +from .. import mesonlib +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/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py new file mode 100644 index 0000000..e748def --- /dev/null +++ b/mesonbuild/backend/ninjabackend.py @@ -0,0 +1,1828 @@ +# 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 +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): + vala_output_files = self.generate_vala_compile(target, outfile) + gen_src_deps += vala_output_files + 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. + if self.environment.is_header(src): + header_deps.append(src) + else: + 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 = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner'] + 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 = 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 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 determine_dep_vapis(self, target): + result = [] + for dep in target.link_targets: + for i in dep.sources: + if hasattr(i, 'fname'): + i = i.fname + if i.endswith('vala'): + vapiname = os.path.splitext(os.path.split(i)[1])[0] + '.vapi' + fullname = os.path.join(self.get_target_dir(dep), vapiname) + result.append(fullname) + break + return result + + 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'] + (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 = [] + vala_input_files = [] + for s in src: + if s.endswith('.vala'): + vala_input_files.append(s.rel_to_builddir(self.build_to_src)) + if len(src) == 0: + raise InvalidArguments('Vala library has no Vala source files.') + namebase = os.path.splitext(os.path.split(src[0].fname)[1])[0] + base_h = namebase + '.h' + base_vapi = namebase + '.vapi' + hname = os.path.normpath(os.path.join(self.get_target_dir(target), base_h)) + vapiname = os.path.normpath(os.path.join(self.get_target_dir(target), base_vapi)) + + generated_c_files = [] + outputs = [vapiname] + args = ['-d', self.get_target_private_dir(target)] + args += ['-C']#, '-o', cname] + if not isinstance(target, build.Executable): + outputs.append(hname) + args += ['-H', hname] + args += ['--library=' + target.name] + args += ['--vapi=' + os.path.join('..', base_vapi)] + for src in vala_input_files: + namebase = os.path.splitext(os.path.split(src)[1])[0] + '.c' + full_c = os.path.join(self.get_target_private_dir(target), namebase) + generated_c_files.append(full_c) + outputs.append(full_c) + 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] + extra_args = [] + + for a in target.extra_args.get('vala', []): + if isinstance(a, File): + relname = a.rel_to_builddir(self.build_to_src) + extra_dep_files.append(relname) + extra_args.append(relname) + else: + extra_args.append(a) + dependency_vapis = self.determine_dep_vapis(target) + extra_dep_files += dependency_vapis + args += extra_args + args += dependency_vapis + element = NinjaBuildElement(outputs, + valac.get_language() + '_COMPILER', + vala_input_files + vapi_src) + element.add_item('ARGS', args) + element.add_dep(extra_dep_files) + element.write(outfile) + self.check_outputs(element) + return generated_c_files + + 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. + outfile.write(rule) + outfile.write(command) + outfile.write(description) + outfile.write(restat) + outfile.write('\n') + + def generate_rust_compile_rules(self, compiler, outfile): + rule = 'rule %s_COMPILER\n' % compiler.get_language() + invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) + command = ' command = %s $ARGS $in\n' % invoc + description = ' description = Compiling Rust source $in.\n' + depfile = ' depfile = $targetdep\n' + + depstyle = ' deps = gcc\n' + outfile.write(rule) + outfile.write(command) + outfile.write(description) + outfile.write(depfile) + outfile.write(depstyle) + outfile.write('\n') + + def generate_swift_compile_rules(self, compiler, outfile): + rule = 'rule %s_COMPILER\n' % compiler.get_language() + full_exe = [sys.executable, + self.environment.get_build_command(), + '--internal', + 'dirchanger', + '$RUNDIR'] + compiler.get_exelist() + invoc = ' '.join([ninja_quote(i) for i in full_exe]) + command = ' command = %s $ARGS $in\n' % invoc + description = ' description = Compiling Swift source $in.\n' + outfile.write(rule) + outfile.write(command) + outfile.write(description) + outfile.write('\n') + + def generate_fortran_dep_hack(self, outfile): + if mesonlib.is_windows(): + cmd = 'cmd /C ""' + else: + cmd = 'true' + template = '''# Workaround for these issues: +# https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485 +rule FORTRAN_DEP_HACK + command = %s + description = Dep hack + restat = 1 + +''' + outfile.write(template % cmd) + + def generate_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/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py new file mode 100644 index 0000000..c9fe09f --- /dev/null +++ b/mesonbuild/backend/vs2010backend.py @@ -0,0 +1,646 @@ +# Copyright 2014-2016 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os, sys +import pickle +from . import backends +from .. import 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' + regen_command = [sys.executable, + self.environment.get_build_command(), + '--internal', + 'regencheck'] + private_dir = self.environment.get_scratch_dir() + cmd_templ = '''setlocal +"%s" "%s" +if %%errorlevel%% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone +:cmErrorLevel +exit /b %%1 +:cmDone +if %%errorlevel%% neq 0 goto :VCEnd''' + igroup = ET.SubElement(root, 'ItemGroup') + 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 % \ + ('" "'.join(regen_command), 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') + test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') + test_command = [sys.executable, + self.environment.get_build_command(), + '--internal', + 'test'] + cmd_templ = '''setlocal +"%s" "%s" +if %%errorlevel%% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone +:cmErrorLevel +exit /b %%1 +:cmDone +if %%errorlevel%% neq 0 goto :VCEnd''' + ET.SubElement(postbuild, 'Command').text =\ + cmd_templ % ('" "'.join(test_command), 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/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py new file mode 100644 index 0000000..d874be9 --- /dev/null +++ b/mesonbuild/backend/xcodebackend.py @@ -0,0 +1,776 @@ +# Copyright 2014-2016 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from . import backends +from .. import build +from .. import mesonlib +import uuid, os, sys + +from ..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 = "";') + self.indent_level -= 1 + self.write_line('};') + + # Sources + self.write_line('%s /* Sources */ = {' % sources_id) + self.indent_level+=1 + self.write_line('isa = PBXGroup;') + self.write_line('children = (') + self.indent_level+=1 + for t in self.build.targets: + self.write_line('%s /* %s */,' % (groupmap[t], t)) + self.indent_level-=1 + self.write_line(');') + self.write_line('name = Sources;') + self.write_line('sourcetree = "";') + self.indent_level-=1 + self.write_line('};') + + self.write_line('%s /* Resources */ = {' % resources_id) + self.indent_level+=1 + self.write_line('isa = PBXGroup;') + self.write_line('children = (') + self.write_line(');') + self.write_line('name = Resources;') + self.write_line('sourceTree = "";') + self.indent_level-=1 + self.write_line('};') + + # Targets + for t in self.build.targets: + self.write_line('%s /* %s */ = {' % (groupmap[t], t)) + self.indent_level+=1 + self.write_line('isa = PBXGroup;') + self.write_line('children = (') + self.indent_level+=1 + self.write_line('%s /* Source files */,' % target_src_map[t]) + self.indent_level-=1 + self.write_line(');') + self.write_line('name = %s;' % t) + self.write_line('sourceTree = "";') + self.indent_level-=1 + self.write_line('};') + self.write_line('%s /* Source files */ = {' % target_src_map[t]) + self.indent_level+=1 + self.write_line('isa = PBXGroup;') + self.write_line('children = (') + self.indent_level+=1 + for s in self.build.targets[t].sources: + s = os.path.join(s.subdir, s.fname) + if isinstance(s, str): + self.write_line('%s /* %s */,' % (self.filemap[s], s)) + for o in self.build.targets[t].objects: + o = os.path.join(self.build.targets[t].subdir, o) + self.write_line('%s /* %s */,' % (self.filemap[o], o)) + self.indent_level-=1 + self.write_line(');') + self.write_line('name = "Source files";') + self.write_line('sourceTree = "";') + self.indent_level-=1 + self.write_line('};') + + # And finally products + self.write_line('%s /* Products */ = {' % products_id) + self.indent_level+=1 + self.write_line('isa = PBXGroup;') + self.write_line('children = (') + self.indent_level+=1 + for t in self.build.targets: + self.write_line('%s /* %s */,' % (self.target_filemap[t], t)) + self.indent_level-=1 + self.write_line(');') + self.write_line('name = Products;') + self.write_line('sourceTree = "";') + self.indent_level-=1 + self.write_line('};') + self.ofile.write('/* End PBXGroup section */\n') + + def generate_pbx_native_target(self): + self.ofile.write('\n/* Begin PBXNativeTarget section */\n') + for tname, idval in self.native_targets.items(): + t = self.build.targets[tname] + self.write_line('%s /* %s */ = {' % (idval, tname)) + self.indent_level+=1 + self.write_line('isa = PBXNativeTarget;') + self.write_line('buildConfigurationList = %s /* Build configuration list for PBXNativeTarget "%s" */;'\ + % (self.buildconflistmap[tname], tname)) + self.write_line('buildPhases = (') + self.indent_level+=1 + self.write_line('%s /* Sources */,' % self.buildphasemap[tname]) + self.indent_level-=1 + self.write_line(');') + self.write_line('buildRules = (') + self.write_line(');') + self.write_line('dependencies = (') + self.indent_level+=1 + for lt in self.build.targets[tname].link_targets: + # NOT DOCUMENTED, may need to make different links + # to same target have different targetdependency item. + idval = self.pbx_dep_map[lt.get_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') 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) diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 6317c95..5cca0a5 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -138,13 +138,13 @@ itself as required.''' mlog.log('Build type:', mlog.bold('native build')) b = build.Build(env) if self.options.backend == 'ninja': - from . import ninjabackend + from .backend import ninjabackend g = ninjabackend.NinjaBackend(b) elif self.options.backend == 'vs2010': - from . import vs2010backend + from .backend import vs2010backend g = vs2010backend.Vs2010Backend(b) elif self.options.backend == 'xcode': - from . import xcodebackend + from .backend import xcodebackend g = xcodebackend.XCodeBackend(b) else: raise RuntimeError('Unknown backend "%s".' % self.options.backend) diff --git a/mesonbuild/ninjabackend.py b/mesonbuild/ninjabackend.py deleted file mode 100644 index a15ac68..0000000 --- a/mesonbuild/ninjabackend.py +++ /dev/null @@ -1,1828 +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 -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): - vala_output_files = self.generate_vala_compile(target, outfile) - gen_src_deps += vala_output_files - 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. - if self.environment.is_header(src): - header_deps.append(src) - else: - 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 = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner'] - 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 = 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 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 determine_dep_vapis(self, target): - result = [] - for dep in target.link_targets: - for i in dep.sources: - if hasattr(i, 'fname'): - i = i.fname - if i.endswith('vala'): - vapiname = os.path.splitext(os.path.split(i)[1])[0] + '.vapi' - fullname = os.path.join(self.get_target_dir(dep), vapiname) - result.append(fullname) - break - return result - - 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'] - (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 = [] - vala_input_files = [] - for s in src: - if s.endswith('.vala'): - vala_input_files.append(s.rel_to_builddir(self.build_to_src)) - if len(src) == 0: - raise InvalidArguments('Vala library has no Vala source files.') - namebase = os.path.splitext(os.path.split(src[0].fname)[1])[0] - base_h = namebase + '.h' - base_vapi = namebase + '.vapi' - hname = os.path.normpath(os.path.join(self.get_target_dir(target), base_h)) - vapiname = os.path.normpath(os.path.join(self.get_target_dir(target), base_vapi)) - - generated_c_files = [] - outputs = [vapiname] - args = ['-d', self.get_target_private_dir(target)] - args += ['-C']#, '-o', cname] - if not isinstance(target, build.Executable): - outputs.append(hname) - args += ['-H', hname] - args += ['--library=' + target.name] - args += ['--vapi=' + os.path.join('..', base_vapi)] - for src in vala_input_files: - namebase = os.path.splitext(os.path.split(src)[1])[0] + '.c' - full_c = os.path.join(self.get_target_private_dir(target), namebase) - generated_c_files.append(full_c) - outputs.append(full_c) - 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] - extra_args = [] - - for a in target.extra_args.get('vala', []): - if isinstance(a, File): - relname = a.rel_to_builddir(self.build_to_src) - extra_dep_files.append(relname) - extra_args.append(relname) - else: - extra_args.append(a) - dependency_vapis = self.determine_dep_vapis(target) - extra_dep_files += dependency_vapis - args += extra_args - args += dependency_vapis - element = NinjaBuildElement(outputs, - valac.get_language() + '_COMPILER', - vala_input_files + vapi_src) - element.add_item('ARGS', args) - element.add_dep(extra_dep_files) - element.write(outfile) - self.check_outputs(element) - return generated_c_files - - 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. - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write(restat) - outfile.write('\n') - - def generate_rust_compile_rules(self, compiler, outfile): - rule = 'rule %s_COMPILER\n' % compiler.get_language() - invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()]) - command = ' command = %s $ARGS $in\n' % invoc - description = ' description = Compiling Rust source $in.\n' - depfile = ' depfile = $targetdep\n' - - depstyle = ' deps = gcc\n' - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write(depfile) - outfile.write(depstyle) - outfile.write('\n') - - def generate_swift_compile_rules(self, compiler, outfile): - rule = 'rule %s_COMPILER\n' % compiler.get_language() - full_exe = [sys.executable, - self.environment.get_build_command(), - '--internal', - 'dirchanger', - '$RUNDIR'] + compiler.get_exelist() - invoc = ' '.join([ninja_quote(i) for i in full_exe]) - command = ' command = %s $ARGS $in\n' % invoc - description = ' description = Compiling Swift source $in.\n' - outfile.write(rule) - outfile.write(command) - outfile.write(description) - outfile.write('\n') - - def generate_fortran_dep_hack(self, outfile): - if mesonlib.is_windows(): - cmd = 'cmd /C ""' - else: - cmd = 'true' - template = '''# Workaround for these issues: -# https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 -# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485 -rule FORTRAN_DEP_HACK - command = %s - description = Dep hack - restat = 1 - -''' - outfile.write(template % cmd) - - def generate_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/mesonbuild/vs2010backend.py b/mesonbuild/vs2010backend.py deleted file mode 100644 index 84bad40..0000000 --- a/mesonbuild/vs2010backend.py +++ /dev/null @@ -1,645 +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' - regen_command = [sys.executable, - self.environment.get_build_command(), - '--internal', - 'regencheck'] - private_dir = self.environment.get_scratch_dir() - cmd_templ = '''setlocal -"%s" "%s" -if %%errorlevel%% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone -:cmErrorLevel -exit /b %%1 -:cmDone -if %%errorlevel%% neq 0 goto :VCEnd''' - igroup = ET.SubElement(root, 'ItemGroup') - 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 % \ - ('" "'.join(regen_command), 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') - test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat') - test_command = [sys.executable, - self.environment.get_build_command(), - '--internal', - 'test'] - cmd_templ = '''setlocal -"%s" "%s" -if %%errorlevel%% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %%errorlevel%% & goto :cmDone -:cmErrorLevel -exit /b %%1 -:cmDone -if %%errorlevel%% neq 0 goto :VCEnd''' - ET.SubElement(postbuild, 'Command').text =\ - cmd_templ % ('" "'.join(test_command), 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/mesonbuild/xcodebackend.py b/mesonbuild/xcodebackend.py deleted file mode 100644 index 8ac3f67..0000000 --- a/mesonbuild/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 = "";') - self.indent_level -= 1 - self.write_line('};') - - # Sources - self.write_line('%s /* Sources */ = {' % sources_id) - self.indent_level+=1 - self.write_line('isa = PBXGroup;') - self.write_line('children = (') - self.indent_level+=1 - for t in self.build.targets: - self.write_line('%s /* %s */,' % (groupmap[t], t)) - self.indent_level-=1 - self.write_line(');') - self.write_line('name = Sources;') - self.write_line('sourcetree = "";') - self.indent_level-=1 - self.write_line('};') - - self.write_line('%s /* Resources */ = {' % resources_id) - self.indent_level+=1 - self.write_line('isa = PBXGroup;') - self.write_line('children = (') - self.write_line(');') - self.write_line('name = Resources;') - self.write_line('sourceTree = "";') - self.indent_level-=1 - self.write_line('};') - - # Targets - for t in self.build.targets: - self.write_line('%s /* %s */ = {' % (groupmap[t], t)) - self.indent_level+=1 - self.write_line('isa = PBXGroup;') - self.write_line('children = (') - self.indent_level+=1 - self.write_line('%s /* Source files */,' % target_src_map[t]) - self.indent_level-=1 - self.write_line(');') - self.write_line('name = %s;' % t) - self.write_line('sourceTree = "";') - self.indent_level-=1 - self.write_line('};') - self.write_line('%s /* Source files */ = {' % target_src_map[t]) - self.indent_level+=1 - self.write_line('isa = PBXGroup;') - self.write_line('children = (') - self.indent_level+=1 - for s in self.build.targets[t].sources: - s = os.path.join(s.subdir, s.fname) - if isinstance(s, str): - self.write_line('%s /* %s */,' % (self.filemap[s], s)) - for o in self.build.targets[t].objects: - o = os.path.join(self.build.targets[t].subdir, o) - self.write_line('%s /* %s */,' % (self.filemap[o], o)) - self.indent_level-=1 - self.write_line(');') - self.write_line('name = "Source files";') - self.write_line('sourceTree = "";') - self.indent_level-=1 - self.write_line('};') - - # And finally products - self.write_line('%s /* Products */ = {' % products_id) - self.indent_level+=1 - self.write_line('isa = PBXGroup;') - self.write_line('children = (') - self.indent_level+=1 - for t in self.build.targets: - self.write_line('%s /* %s */,' % (self.target_filemap[t], t)) - self.indent_level-=1 - self.write_line(');') - self.write_line('name = Products;') - self.write_line('sourceTree = "";') - self.indent_level-=1 - self.write_line('};') - self.ofile.write('/* End PBXGroup section */\n') - - def generate_pbx_native_target(self): - self.ofile.write('\n/* Begin PBXNativeTarget section */\n') - for tname, idval in self.native_targets.items(): - t = self.build.targets[tname] - self.write_line('%s /* %s */ = {' % (idval, tname)) - self.indent_level+=1 - self.write_line('isa = PBXNativeTarget;') - self.write_line('buildConfigurationList = %s /* Build configuration list for PBXNativeTarget "%s" */;'\ - % (self.buildconflistmap[tname], tname)) - self.write_line('buildPhases = (') - self.indent_level+=1 - self.write_line('%s /* Sources */,' % self.buildphasemap[tname]) - self.indent_level-=1 - self.write_line(');') - self.write_line('buildRules = (') - self.write_line(');') - self.write_line('dependencies = (') - self.indent_level+=1 - for lt in self.build.targets[tname].link_targets: - # NOT DOCUMENTED, may need to make different links - # to same target have different targetdependency item. - idval = self.pbx_dep_map[lt.get_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') -- cgit v1.1