# Copyright 2012-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import re
import shlex
import pickle
import subprocess
from collections import OrderedDict
import itertools
from pathlib import PurePath
from functools import lru_cache

from . import backends
from .. import modules
from .. import environment, mesonlib
from ..dependencies import base
from .. import build
from .. import mlog
from .. import dependencies
from .. import compilers
from ..compilers import CompilerArgs, CCompiler, VisualStudioCCompiler
from ..linkers import ArLinker
from ..mesonlib import File, MesonException, OrderedSet
from ..mesonlib import get_compiler_for_source, has_path_sep
from .backends import CleanTrees
from ..build import InvalidArguments


class GnBackend(backends.Backend):
    def __init__(self, build):
        super().__init__(build)
        self.name = 'ninja'
        self.gn_filename = 'BUILD.gn'

    def generate(self, interp):
        self.interpreter = interp
        #self.ninja_command = environment.detect_ninja(log=True)
        #if self.ninja_command is None:
        #    raise MesonException('Could not detect Ninja v1.5 or newer')
        outfilename = os.path.join(self.environment.get_build_dir(),
                                   self.gn_filename)
        tempfilename = outfilename + '~'
        with open(tempfilename, 'w', encoding='utf-8') as outfile:
            outfile.write('# This is the build file for project "%s"\n' %
                          self.build.get_project())
            outfile.write('# It is autogenerated by the Meson build system.\n')
            outfile.write('# Do not edit by hand.\n\n')
            outfile.write('import("../meson_templates.gni")\n\n')
            outfile.write('config("common_config") {\n')
            outfile.write('}\n\n')

            #outfile.write('ninja_required_version = 1.5.1\n\n')
            for t in self.build.get_targets().values():
                self.generate_target(t, outfile)
        # Only overwrite the old build file after the new one has been
        # fully created.
        os.replace(tempfilename, outfilename)

    def get_target_sources(self, target):
        srcs = OrderedDict()
        for s in target.get_sources():
            # BuildTarget sources are always mesonlib.File files which are
            # either in the source root, or generated with configure_file and
            # in the build root
            if not isinstance(s, File):
                raise InvalidArguments(
                    'All sources in target {!r} must be of type mesonlib.File'.
                    format(s))
            f = s.rel_to_builddir(self.build_to_src)
            srcs[f] = s
        return srcs

    def generate_custom_target(self, target, outfile):
        target.absolute_paths = True
        (srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
        for i in target.depend_files:
            outfile.write('### depend_files %s")\n' % i)
        if 'python' in target.command[0]:
            outfile.write('meson_action("%s") {\n' % (target.name))
            outfile.write('  capture = %s\n' % str(target.capture).lower())
            outfile.write('  script = rebase_path("%s")\n' % cmd[1])

            outfile.write('  outputs = [\n')
            for output in ofilenames:
                outfile.write('    "$target_gen_dir/%s",\n' % output)
            outfile.write('  ]\n')

            outfile.write('  inputs = [\n')
            for src in target.sources:
                outfile.write('    "%s",\n' %
                              src.rel_to_builddir(self.build_to_src))
            outfile.write("  ]\n")

            outfile.write('  args = [\n')
            next_is_outdir = False
            for arg in cmd[2:]:
                if arg in ofilenames:
                    outfile.write('    rebase_path("$target_gen_dir/%s"),\n' %
                                  arg)
                elif arg == '--outdir':
                    outfile.write('    "%s",\n' % arg)
                    next_is_outdir = True
                elif next_is_outdir:
                    outdir = os.path.relpath(arg,
                                             self.environment.get_build_dir())
                    outfile.write('    rebase_path("$target_gen_dir/%s"),\n' %
                                  outdir)
                    next_is_outdir = False
                else:
                    outfile.write('    "%s",\n' % arg)
            outfile.write("  ]\n")
            outfile.write('}\n\n')
        else:
            outfile.write('###meson_action("%s.%s") {\n' %
                          (target.name, target.get_id()))

    def generate_target(self, target, outfile):
        if isinstance(target, build.CustomTarget):
            self.generate_custom_target(target, outfile)
            return

        #if isinstance(target, build.RunTarget):
        #    self.generate_run_target(target, outfile)

        name = target.get_id()
        if name in self.processed_targets:
            return

        self.processed_targets[name] = True
        # Generate rules for all dependency targets
        self.process_target_dependencies(target, outfile)

        # For those who depend on our generated files
        outfile.write('config("%s.%s-config") {\n' %
                      (target.name, target.get_id()))
        outfile.write('  include_dirs = [\n')
        for gensrc in target.get_generated_sources():
            outfile.write('    "$target_gen_dir/%s",\n' %
                          self.get_target_dir(gensrc))
        outfile.write("  ]\n")
        outfile.write('}\n\n')

        outfile.write('meson_source_set("%s.%s") {\n' %
                      (target.name, target.get_id()))
        outfile.write('  public_configs = [ ":%s.%s-config" ]\n' %
                      (target.name, target.get_id()))

        outfile.write('  sources = [\n')
        target_sources = self.get_target_sources(target)
        for src in target_sources:
            outfile.write("    \"%s\",\n" % src)
        outfile.write("  ]\n")

        outfile.write("  deps = [\n")
        for dep in target.get_dependencies():
            outfile.write("    \":%s.%s\",\n" % (dep.name, dep.get_id()))
        outfile.write("  ]\n")

        if isinstance(target, build.BuildTarget):
            outfile.write('  include_dirs = [\n')
            for i in reversed(target.get_include_dirs()):
                basedir = i.get_curdir()
                # We should iterate include dirs in reversed orders because
                # -Ipath will add to begin of array. And without reverse
                # flags will be added in reversed order.
                for d in reversed(i.get_incdirs()):
                    # Avoid superfluous '/.' at the end of paths when d is '.'
                    if d not in ('', '.'):
                        expdir = os.path.join(basedir, d)
                    else:
                        expdir = basedir
                    srctreedir = os.path.join(self.build_to_src, expdir)
                    outfile.write('    "%s",\n' % srctreedir)
            # For generated files:
            outfile.write('    "%s",\n' %
                          os.path.join(self.build_to_src, target.get_subdir()))
            outfile.write('  ]\n')

            if 'c' in target.compilers:
                compiler = target.compilers['c']
                outfile.write('  cflags_c = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.build.get_project_args(compiler, target.subproject,
                                                   target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.escape_extra_args(
                    compiler, target.get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')

            if 'cpp' in target.compilers:
                compiler = target.compilers['cpp']
                outfile.write('  cflags_cc = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.build.get_project_args(compiler, target.subproject,
                                                   target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.escape_extra_args(
                    compiler, target.get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')

            outfile.write('  deps += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write('    ":%s",\n' % (gensrc.name))
            outfile.write("  ]\n")

            outfile.write('  sources += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write(
                        '    "$target_gen_dir/%s",\n' %
                        self.get_target_generated_dir(target, gensrc, s))
            outfile.write("  ]\n")

            outfile.write('  ### external deps\n')
            outfile.write('  deps += [\n')
            for extdep in target.get_external_deps():
                if isinstance(extdep, base.PkgConfigDependency):
                    for arg in extdep.get_link_args():
                        outfile.write('    "%s",\n' % arg)
            outfile.write("  ]\n")

        outfile.write('}\n\n')

    def process_target_dependencies(self, target, outfile):
        for t in target.get_dependencies():
            if t.get_id() not in self.processed_targets:
                self.generate_target(t, outfile)

bee00282b1a42dddd82fd43c2adbaa8c29bc8e04
<mask token>


class GnBackend(backends.Backend):
    <mask token>

    def generate(self, interp):
        self.interpreter = interp
        outfilename = os.path.join(self.environment.get_build_dir(), self.
            gn_filename)
        tempfilename = outfilename + '~'
        with open(tempfilename, 'w', encoding='utf-8') as outfile:
            outfile.write('# This is the build file for project "%s"\n' %
                self.build.get_project())
            outfile.write('# It is autogenerated by the Meson build system.\n')
            outfile.write('# Do not edit by hand.\n\n')
            outfile.write('import("../meson_templates.gni")\n\n')
            outfile.write('config("common_config") {\n')
            outfile.write('}\n\n')
            for t in self.build.get_targets().values():
                self.generate_target(t, outfile)
        os.replace(tempfilename, outfilename)
    <mask token>

    def generate_custom_target(self, target, outfile):
        target.absolute_paths = True
        srcs, ofilenames, cmd = self.eval_custom_target_command(target)
        for i in target.depend_files:
            outfile.write('### depend_files %s")\n' % i)
        if 'python' in target.command[0]:
            outfile.write('meson_action("%s") {\n' % target.name)
            outfile.write('  capture = %s\n' % str(target.capture).lower())
            outfile.write('  script = rebase_path("%s")\n' % cmd[1])
            outfile.write('  outputs = [\n')
            for output in ofilenames:
                outfile.write('    "$target_gen_dir/%s",\n' % output)
            outfile.write('  ]\n')
            outfile.write('  inputs = [\n')
            for src in target.sources:
                outfile.write('    "%s",\n' % src.rel_to_builddir(self.
                    build_to_src))
            outfile.write('  ]\n')
            outfile.write('  args = [\n')
            next_is_outdir = False
            for arg in cmd[2:]:
                if arg in ofilenames:
                    outfile.write(
                        '    rebase_path("$target_gen_dir/%s"),\n' % arg)
                elif arg == '--outdir':
                    outfile.write('    "%s",\n' % arg)
                    next_is_outdir = True
                elif next_is_outdir:
                    outdir = os.path.relpath(arg, self.environment.
                        get_build_dir())
                    outfile.write(
                        '    rebase_path("$target_gen_dir/%s"),\n' % outdir)
                    next_is_outdir = False
                else:
                    outfile.write('    "%s",\n' % arg)
            outfile.write('  ]\n')
            outfile.write('}\n\n')
        else:
            outfile.write('###meson_action("%s.%s") {\n' % (target.name,
                target.get_id()))
    <mask token>
    <mask token>

<mask token>


class GnBackend(backends.Backend):
    <mask token>

    def generate(self, interp):
        self.interpreter = interp
        outfilename = os.path.join(self.environment.get_build_dir(), self.
            gn_filename)
        tempfilename = outfilename + '~'
        with open(tempfilename, 'w', encoding='utf-8') as outfile:
            outfile.write('# This is the build file for project "%s"\n' %
                self.build.get_project())
            outfile.write('# It is autogenerated by the Meson build system.\n')
            outfile.write('# Do not edit by hand.\n\n')
            outfile.write('import("../meson_templates.gni")\n\n')
            outfile.write('config("common_config") {\n')
            outfile.write('}\n\n')
            for t in self.build.get_targets().values():
                self.generate_target(t, outfile)
        os.replace(tempfilename, outfilename)

    def get_target_sources(self, target):
        srcs = OrderedDict()
        for s in target.get_sources():
            if not isinstance(s, File):
                raise InvalidArguments(
                    'All sources in target {!r} must be of type mesonlib.File'
                    .format(s))
            f = s.rel_to_builddir(self.build_to_src)
            srcs[f] = s
        return srcs

    def generate_custom_target(self, target, outfile):
        target.absolute_paths = True
        srcs, ofilenames, cmd = self.eval_custom_target_command(target)
        for i in target.depend_files:
            outfile.write('### depend_files %s")\n' % i)
        if 'python' in target.command[0]:
            outfile.write('meson_action("%s") {\n' % target.name)
            outfile.write('  capture = %s\n' % str(target.capture).lower())
            outfile.write('  script = rebase_path("%s")\n' % cmd[1])
            outfile.write('  outputs = [\n')
            for output in ofilenames:
                outfile.write('    "$target_gen_dir/%s",\n' % output)
            outfile.write('  ]\n')
            outfile.write('  inputs = [\n')
            for src in target.sources:
                outfile.write('    "%s",\n' % src.rel_to_builddir(self.
                    build_to_src))
            outfile.write('  ]\n')
            outfile.write('  args = [\n')
            next_is_outdir = False
            for arg in cmd[2:]:
                if arg in ofilenames:
                    outfile.write(
                        '    rebase_path("$target_gen_dir/%s"),\n' % arg)
                elif arg == '--outdir':
                    outfile.write('    "%s",\n' % arg)
                    next_is_outdir = True
                elif next_is_outdir:
                    outdir = os.path.relpath(arg, self.environment.
                        get_build_dir())
                    outfile.write(
                        '    rebase_path("$target_gen_dir/%s"),\n' % outdir)
                    next_is_outdir = False
                else:
                    outfile.write('    "%s",\n' % arg)
            outfile.write('  ]\n')
            outfile.write('}\n\n')
        else:
            outfile.write('###meson_action("%s.%s") {\n' % (target.name,
                target.get_id()))

    def generate_target(self, target, outfile):
        if isinstance(target, build.CustomTarget):
            self.generate_custom_target(target, outfile)
            return
        name = target.get_id()
        if name in self.processed_targets:
            return
        self.processed_targets[name] = True
        self.process_target_dependencies(target, outfile)
        outfile.write('config("%s.%s-config") {\n' % (target.name, target.
            get_id()))
        outfile.write('  include_dirs = [\n')
        for gensrc in target.get_generated_sources():
            outfile.write('    "$target_gen_dir/%s",\n' % self.
                get_target_dir(gensrc))
        outfile.write('  ]\n')
        outfile.write('}\n\n')
        outfile.write('meson_source_set("%s.%s") {\n' % (target.name,
            target.get_id()))
        outfile.write('  public_configs = [ ":%s.%s-config" ]\n' % (target.
            name, target.get_id()))
        outfile.write('  sources = [\n')
        target_sources = self.get_target_sources(target)
        for src in target_sources:
            outfile.write('    "%s",\n' % src)
        outfile.write('  ]\n')
        outfile.write('  deps = [\n')
        for dep in target.get_dependencies():
            outfile.write('    ":%s.%s",\n' % (dep.name, dep.get_id()))
        outfile.write('  ]\n')
        if isinstance(target, build.BuildTarget):
            outfile.write('  include_dirs = [\n')
            for i in reversed(target.get_include_dirs()):
                basedir = i.get_curdir()
                for d in reversed(i.get_incdirs()):
                    if d not in ('', '.'):
                        expdir = os.path.join(basedir, d)
                    else:
                        expdir = basedir
                    srctreedir = os.path.join(self.build_to_src, expdir)
                    outfile.write('    "%s",\n' % srctreedir)
            outfile.write('    "%s",\n' % os.path.join(self.build_to_src,
                target.get_subdir()))
            outfile.write('  ]\n')
            if 'c' in target.compilers:
                compiler = target.compilers['c']
                outfile.write('  cflags_c = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.build.get_project_args(compiler, target.
                    subproject, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.escape_extra_args(compiler, target.
                    get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
            if 'cpp' in target.compilers:
                compiler = target.compilers['cpp']
                outfile.write('  cflags_cc = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.build.get_project_args(compiler, target.
                    subproject, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.escape_extra_args(compiler, target.
                    get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
            outfile.write('  deps += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write('    ":%s",\n' % gensrc.name)
            outfile.write('  ]\n')
            outfile.write('  sources += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write('    "$target_gen_dir/%s",\n' % self.
                        get_target_generated_dir(target, gensrc, s))
            outfile.write('  ]\n')
            outfile.write('  ### external deps\n')
            outfile.write('  deps += [\n')
            for extdep in target.get_external_deps():
                if isinstance(extdep, base.PkgConfigDependency):
                    for arg in extdep.get_link_args():
                        outfile.write('    "%s",\n' % arg)
            outfile.write('  ]\n')
        outfile.write('}\n\n')

    def process_target_dependencies(self, target, outfile):
        for t in target.get_dependencies():
            if t.get_id() not in self.processed_targets:
                self.generate_target(t, outfile)

<mask token>


class GnBackend(backends.Backend):

    def __init__(self, build):
        super().__init__(build)
        self.name = 'ninja'
        self.gn_filename = 'BUILD.gn'

    def generate(self, interp):
        self.interpreter = interp
        outfilename = os.path.join(self.environment.get_build_dir(), self.
            gn_filename)
        tempfilename = outfilename + '~'
        with open(tempfilename, 'w', encoding='utf-8') as outfile:
            outfile.write('# This is the build file for project "%s"\n' %
                self.build.get_project())
            outfile.write('# It is autogenerated by the Meson build system.\n')
            outfile.write('# Do not edit by hand.\n\n')
            outfile.write('import("../meson_templates.gni")\n\n')
            outfile.write('config("common_config") {\n')
            outfile.write('}\n\n')
            for t in self.build.get_targets().values():
                self.generate_target(t, outfile)
        os.replace(tempfilename, outfilename)

    def get_target_sources(self, target):
        srcs = OrderedDict()
        for s in target.get_sources():
            if not isinstance(s, File):
                raise InvalidArguments(
                    'All sources in target {!r} must be of type mesonlib.File'
                    .format(s))
            f = s.rel_to_builddir(self.build_to_src)
            srcs[f] = s
        return srcs

    def generate_custom_target(self, target, outfile):
        target.absolute_paths = True
        srcs, ofilenames, cmd = self.eval_custom_target_command(target)
        for i in target.depend_files:
            outfile.write('### depend_files %s")\n' % i)
        if 'python' in target.command[0]:
            outfile.write('meson_action("%s") {\n' % target.name)
            outfile.write('  capture = %s\n' % str(target.capture).lower())
            outfile.write('  script = rebase_path("%s")\n' % cmd[1])
            outfile.write('  outputs = [\n')
            for output in ofilenames:
                outfile.write('    "$target_gen_dir/%s",\n' % output)
            outfile.write('  ]\n')
            outfile.write('  inputs = [\n')
            for src in target.sources:
                outfile.write('    "%s",\n' % src.rel_to_builddir(self.
                    build_to_src))
            outfile.write('  ]\n')
            outfile.write('  args = [\n')
            next_is_outdir = False
            for arg in cmd[2:]:
                if arg in ofilenames:
                    outfile.write(
                        '    rebase_path("$target_gen_dir/%s"),\n' % arg)
                elif arg == '--outdir':
                    outfile.write('    "%s",\n' % arg)
                    next_is_outdir = True
                elif next_is_outdir:
                    outdir = os.path.relpath(arg, self.environment.
                        get_build_dir())
                    outfile.write(
                        '    rebase_path("$target_gen_dir/%s"),\n' % outdir)
                    next_is_outdir = False
                else:
                    outfile.write('    "%s",\n' % arg)
            outfile.write('  ]\n')
            outfile.write('}\n\n')
        else:
            outfile.write('###meson_action("%s.%s") {\n' % (target.name,
                target.get_id()))

    def generate_target(self, target, outfile):
        if isinstance(target, build.CustomTarget):
            self.generate_custom_target(target, outfile)
            return
        name = target.get_id()
        if name in self.processed_targets:
            return
        self.processed_targets[name] = True
        self.process_target_dependencies(target, outfile)
        outfile.write('config("%s.%s-config") {\n' % (target.name, target.
            get_id()))
        outfile.write('  include_dirs = [\n')
        for gensrc in target.get_generated_sources():
            outfile.write('    "$target_gen_dir/%s",\n' % self.
                get_target_dir(gensrc))
        outfile.write('  ]\n')
        outfile.write('}\n\n')
        outfile.write('meson_source_set("%s.%s") {\n' % (target.name,
            target.get_id()))
        outfile.write('  public_configs = [ ":%s.%s-config" ]\n' % (target.
            name, target.get_id()))
        outfile.write('  sources = [\n')
        target_sources = self.get_target_sources(target)
        for src in target_sources:
            outfile.write('    "%s",\n' % src)
        outfile.write('  ]\n')
        outfile.write('  deps = [\n')
        for dep in target.get_dependencies():
            outfile.write('    ":%s.%s",\n' % (dep.name, dep.get_id()))
        outfile.write('  ]\n')
        if isinstance(target, build.BuildTarget):
            outfile.write('  include_dirs = [\n')
            for i in reversed(target.get_include_dirs()):
                basedir = i.get_curdir()
                for d in reversed(i.get_incdirs()):
                    if d not in ('', '.'):
                        expdir = os.path.join(basedir, d)
                    else:
                        expdir = basedir
                    srctreedir = os.path.join(self.build_to_src, expdir)
                    outfile.write('    "%s",\n' % srctreedir)
            outfile.write('    "%s",\n' % os.path.join(self.build_to_src,
                target.get_subdir()))
            outfile.write('  ]\n')
            if 'c' in target.compilers:
                compiler = target.compilers['c']
                outfile.write('  cflags_c = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.build.get_project_args(compiler, target.
                    subproject, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.escape_extra_args(compiler, target.
                    get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
            if 'cpp' in target.compilers:
                compiler = target.compilers['cpp']
                outfile.write('  cflags_cc = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.build.get_project_args(compiler, target.
                    subproject, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.escape_extra_args(compiler, target.
                    get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
            outfile.write('  deps += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write('    ":%s",\n' % gensrc.name)
            outfile.write('  ]\n')
            outfile.write('  sources += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write('    "$target_gen_dir/%s",\n' % self.
                        get_target_generated_dir(target, gensrc, s))
            outfile.write('  ]\n')
            outfile.write('  ### external deps\n')
            outfile.write('  deps += [\n')
            for extdep in target.get_external_deps():
                if isinstance(extdep, base.PkgConfigDependency):
                    for arg in extdep.get_link_args():
                        outfile.write('    "%s",\n' % arg)
            outfile.write('  ]\n')
        outfile.write('}\n\n')

    def process_target_dependencies(self, target, outfile):
        for t in target.get_dependencies():
            if t.get_id() not in self.processed_targets:
                self.generate_target(t, outfile)

import os
import re
import shlex
import pickle
import subprocess
from collections import OrderedDict
import itertools
from pathlib import PurePath
from functools import lru_cache
from . import backends
from .. import modules
from .. import environment, mesonlib
from ..dependencies import base
from .. import build
from .. import mlog
from .. import dependencies
from .. import compilers
from ..compilers import CompilerArgs, CCompiler, VisualStudioCCompiler
from ..linkers import ArLinker
from ..mesonlib import File, MesonException, OrderedSet
from ..mesonlib import get_compiler_for_source, has_path_sep
from .backends import CleanTrees
from ..build import InvalidArguments


class GnBackend(backends.Backend):

    def __init__(self, build):
        super().__init__(build)
        self.name = 'ninja'
        self.gn_filename = 'BUILD.gn'

    def generate(self, interp):
        self.interpreter = interp
        outfilename = os.path.join(self.environment.get_build_dir(), self.
            gn_filename)
        tempfilename = outfilename + '~'
        with open(tempfilename, 'w', encoding='utf-8') as outfile:
            outfile.write('# This is the build file for project "%s"\n' %
                self.build.get_project())
            outfile.write('# It is autogenerated by the Meson build system.\n')
            outfile.write('# Do not edit by hand.\n\n')
            outfile.write('import("../meson_templates.gni")\n\n')
            outfile.write('config("common_config") {\n')
            outfile.write('}\n\n')
            for t in self.build.get_targets().values():
                self.generate_target(t, outfile)
        os.replace(tempfilename, outfilename)

    def get_target_sources(self, target):
        srcs = OrderedDict()
        for s in target.get_sources():
            if not isinstance(s, File):
                raise InvalidArguments(
                    'All sources in target {!r} must be of type mesonlib.File'
                    .format(s))
            f = s.rel_to_builddir(self.build_to_src)
            srcs[f] = s
        return srcs

    def generate_custom_target(self, target, outfile):
        target.absolute_paths = True
        srcs, ofilenames, cmd = self.eval_custom_target_command(target)
        for i in target.depend_files:
            outfile.write('### depend_files %s")\n' % i)
        if 'python' in target.command[0]:
            outfile.write('meson_action("%s") {\n' % target.name)
            outfile.write('  capture = %s\n' % str(target.capture).lower())
            outfile.write('  script = rebase_path("%s")\n' % cmd[1])
            outfile.write('  outputs = [\n')
            for output in ofilenames:
                outfile.write('    "$target_gen_dir/%s",\n' % output)
            outfile.write('  ]\n')
            outfile.write('  inputs = [\n')
            for src in target.sources:
                outfile.write('    "%s",\n' % src.rel_to_builddir(self.
                    build_to_src))
            outfile.write('  ]\n')
            outfile.write('  args = [\n')
            next_is_outdir = False
            for arg in cmd[2:]:
                if arg in ofilenames:
                    outfile.write(
                        '    rebase_path("$target_gen_dir/%s"),\n' % arg)
                elif arg == '--outdir':
                    outfile.write('    "%s",\n' % arg)
                    next_is_outdir = True
                elif next_is_outdir:
                    outdir = os.path.relpath(arg, self.environment.
                        get_build_dir())
                    outfile.write(
                        '    rebase_path("$target_gen_dir/%s"),\n' % outdir)
                    next_is_outdir = False
                else:
                    outfile.write('    "%s",\n' % arg)
            outfile.write('  ]\n')
            outfile.write('}\n\n')
        else:
            outfile.write('###meson_action("%s.%s") {\n' % (target.name,
                target.get_id()))

    def generate_target(self, target, outfile):
        if isinstance(target, build.CustomTarget):
            self.generate_custom_target(target, outfile)
            return
        name = target.get_id()
        if name in self.processed_targets:
            return
        self.processed_targets[name] = True
        self.process_target_dependencies(target, outfile)
        outfile.write('config("%s.%s-config") {\n' % (target.name, target.
            get_id()))
        outfile.write('  include_dirs = [\n')
        for gensrc in target.get_generated_sources():
            outfile.write('    "$target_gen_dir/%s",\n' % self.
                get_target_dir(gensrc))
        outfile.write('  ]\n')
        outfile.write('}\n\n')
        outfile.write('meson_source_set("%s.%s") {\n' % (target.name,
            target.get_id()))
        outfile.write('  public_configs = [ ":%s.%s-config" ]\n' % (target.
            name, target.get_id()))
        outfile.write('  sources = [\n')
        target_sources = self.get_target_sources(target)
        for src in target_sources:
            outfile.write('    "%s",\n' % src)
        outfile.write('  ]\n')
        outfile.write('  deps = [\n')
        for dep in target.get_dependencies():
            outfile.write('    ":%s.%s",\n' % (dep.name, dep.get_id()))
        outfile.write('  ]\n')
        if isinstance(target, build.BuildTarget):
            outfile.write('  include_dirs = [\n')
            for i in reversed(target.get_include_dirs()):
                basedir = i.get_curdir()
                for d in reversed(i.get_incdirs()):
                    if d not in ('', '.'):
                        expdir = os.path.join(basedir, d)
                    else:
                        expdir = basedir
                    srctreedir = os.path.join(self.build_to_src, expdir)
                    outfile.write('    "%s",\n' % srctreedir)
            outfile.write('    "%s",\n' % os.path.join(self.build_to_src,
                target.get_subdir()))
            outfile.write('  ]\n')
            if 'c' in target.compilers:
                compiler = target.compilers['c']
                outfile.write('  cflags_c = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.build.get_project_args(compiler, target.
                    subproject, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.escape_extra_args(compiler, target.
                    get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
            if 'cpp' in target.compilers:
                compiler = target.compilers['cpp']
                outfile.write('  cflags_cc = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.build.get_project_args(compiler, target.
                    subproject, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.escape_extra_args(compiler, target.
                    get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
            outfile.write('  deps += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write('    ":%s",\n' % gensrc.name)
            outfile.write('  ]\n')
            outfile.write('  sources += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write('    "$target_gen_dir/%s",\n' % self.
                        get_target_generated_dir(target, gensrc, s))
            outfile.write('  ]\n')
            outfile.write('  ### external deps\n')
            outfile.write('  deps += [\n')
            for extdep in target.get_external_deps():
                if isinstance(extdep, base.PkgConfigDependency):
                    for arg in extdep.get_link_args():
                        outfile.write('    "%s",\n' % arg)
            outfile.write('  ]\n')
        outfile.write('}\n\n')

    def process_target_dependencies(self, target, outfile):
        for t in target.get_dependencies():
            if t.get_id() not in self.processed_targets:
                self.generate_target(t, outfile)

# Copyright 2012-2017 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import re
import shlex
import pickle
import subprocess
from collections import OrderedDict
import itertools
from pathlib import PurePath
from functools import lru_cache

from . import backends
from .. import modules
from .. import environment, mesonlib
from ..dependencies import base
from .. import build
from .. import mlog
from .. import dependencies
from .. import compilers
from ..compilers import CompilerArgs, CCompiler, VisualStudioCCompiler
from ..linkers import ArLinker
from ..mesonlib import File, MesonException, OrderedSet
from ..mesonlib import get_compiler_for_source, has_path_sep
from .backends import CleanTrees
from ..build import InvalidArguments


class GnBackend(backends.Backend):
    def __init__(self, build):
        super().__init__(build)
        self.name = 'ninja'
        self.gn_filename = 'BUILD.gn'

    def generate(self, interp):
        self.interpreter = interp
        #self.ninja_command = environment.detect_ninja(log=True)
        #if self.ninja_command is None:
        #    raise MesonException('Could not detect Ninja v1.5 or newer')
        outfilename = os.path.join(self.environment.get_build_dir(),
                                   self.gn_filename)
        tempfilename = outfilename + '~'
        with open(tempfilename, 'w', encoding='utf-8') as outfile:
            outfile.write('# This is the build file for project "%s"\n' %
                          self.build.get_project())
            outfile.write('# It is autogenerated by the Meson build system.\n')
            outfile.write('# Do not edit by hand.\n\n')
            outfile.write('import("../meson_templates.gni")\n\n')
            outfile.write('config("common_config") {\n')
            outfile.write('}\n\n')

            #outfile.write('ninja_required_version = 1.5.1\n\n')
            for t in self.build.get_targets().values():
                self.generate_target(t, outfile)
        # Only overwrite the old build file after the new one has been
        # fully created.
        os.replace(tempfilename, outfilename)

    def get_target_sources(self, target):
        srcs = OrderedDict()
        for s in target.get_sources():
            # BuildTarget sources are always mesonlib.File files which are
            # either in the source root, or generated with configure_file and
            # in the build root
            if not isinstance(s, File):
                raise InvalidArguments(
                    'All sources in target {!r} must be of type mesonlib.File'.
                    format(s))
            f = s.rel_to_builddir(self.build_to_src)
            srcs[f] = s
        return srcs

    def generate_custom_target(self, target, outfile):
        target.absolute_paths = True
        (srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
        for i in target.depend_files:
            outfile.write('### depend_files %s")\n' % i)
        if 'python' in target.command[0]:
            outfile.write('meson_action("%s") {\n' % (target.name))
            outfile.write('  capture = %s\n' % str(target.capture).lower())
            outfile.write('  script = rebase_path("%s")\n' % cmd[1])

            outfile.write('  outputs = [\n')
            for output in ofilenames:
                outfile.write('    "$target_gen_dir/%s",\n' % output)
            outfile.write('  ]\n')

            outfile.write('  inputs = [\n')
            for src in target.sources:
                outfile.write('    "%s",\n' %
                              src.rel_to_builddir(self.build_to_src))
            outfile.write("  ]\n")

            outfile.write('  args = [\n')
            next_is_outdir = False
            for arg in cmd[2:]:
                if arg in ofilenames:
                    outfile.write('    rebase_path("$target_gen_dir/%s"),\n' %
                                  arg)
                elif arg == '--outdir':
                    outfile.write('    "%s",\n' % arg)
                    next_is_outdir = True
                elif next_is_outdir:
                    outdir = os.path.relpath(arg,
                                             self.environment.get_build_dir())
                    outfile.write('    rebase_path("$target_gen_dir/%s"),\n' %
                                  outdir)
                    next_is_outdir = False
                else:
                    outfile.write('    "%s",\n' % arg)
            outfile.write("  ]\n")
            outfile.write('}\n\n')
        else:
            outfile.write('###meson_action("%s.%s") {\n' %
                          (target.name, target.get_id()))

    def generate_target(self, target, outfile):
        if isinstance(target, build.CustomTarget):
            self.generate_custom_target(target, outfile)
            return

        #if isinstance(target, build.RunTarget):
        #    self.generate_run_target(target, outfile)

        name = target.get_id()
        if name in self.processed_targets:
            return

        self.processed_targets[name] = True
        # Generate rules for all dependency targets
        self.process_target_dependencies(target, outfile)

        # For those who depend on our generated files
        outfile.write('config("%s.%s-config") {\n' %
                      (target.name, target.get_id()))
        outfile.write('  include_dirs = [\n')
        for gensrc in target.get_generated_sources():
            outfile.write('    "$target_gen_dir/%s",\n' %
                          self.get_target_dir(gensrc))
        outfile.write("  ]\n")
        outfile.write('}\n\n')

        outfile.write('meson_source_set("%s.%s") {\n' %
                      (target.name, target.get_id()))
        outfile.write('  public_configs = [ ":%s.%s-config" ]\n' %
                      (target.name, target.get_id()))

        outfile.write('  sources = [\n')
        target_sources = self.get_target_sources(target)
        for src in target_sources:
            outfile.write("    \"%s\",\n" % src)
        outfile.write("  ]\n")

        outfile.write("  deps = [\n")
        for dep in target.get_dependencies():
            outfile.write("    \":%s.%s\",\n" % (dep.name, dep.get_id()))
        outfile.write("  ]\n")

        if isinstance(target, build.BuildTarget):
            outfile.write('  include_dirs = [\n')
            for i in reversed(target.get_include_dirs()):
                basedir = i.get_curdir()
                # We should iterate include dirs in reversed orders because
                # -Ipath will add to begin of array. And without reverse
                # flags will be added in reversed order.
                for d in reversed(i.get_incdirs()):
                    # Avoid superfluous '/.' at the end of paths when d is '.'
                    if d not in ('', '.'):
                        expdir = os.path.join(basedir, d)
                    else:
                        expdir = basedir
                    srctreedir = os.path.join(self.build_to_src, expdir)
                    outfile.write('    "%s",\n' % srctreedir)
            # For generated files:
            outfile.write('    "%s",\n' %
                          os.path.join(self.build_to_src, target.get_subdir()))
            outfile.write('  ]\n')

            if 'c' in target.compilers:
                compiler = target.compilers['c']
                outfile.write('  cflags_c = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.build.get_project_args(compiler, target.subproject,
                                                   target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_c += [\n')
                args = self.escape_extra_args(
                    compiler, target.get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')

            if 'cpp' in target.compilers:
                compiler = target.compilers['cpp']
                outfile.write('  cflags_cc = [\n')
                args = self.build.get_global_args(compiler, target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.build.get_project_args(compiler, target.subproject,
                                                   target.is_cross)
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')
                outfile.write('  cflags_cc += [\n')
                args = self.escape_extra_args(
                    compiler, target.get_extra_args(compiler.get_language()))
                for arg in args:
                    outfile.write('    "%s",\n' % arg.replace('"', '\\"'))
                outfile.write('  ]\n')

            outfile.write('  deps += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write('    ":%s",\n' % (gensrc.name))
            outfile.write("  ]\n")

            outfile.write('  sources += [\n')
            for gensrc in target.get_generated_sources():
                for s in gensrc.get_outputs():
                    outfile.write(
                        '    "$target_gen_dir/%s",\n' %
                        self.get_target_generated_dir(target, gensrc, s))
            outfile.write("  ]\n")

            outfile.write('  ### external deps\n')
            outfile.write('  deps += [\n')
            for extdep in target.get_external_deps():
                if isinstance(extdep, base.PkgConfigDependency):
                    for arg in extdep.get_link_args():
                        outfile.write('    "%s",\n' % arg)
            outfile.write("  ]\n")

        outfile.write('}\n\n')

    def process_target_dependencies(self, target, outfile):
        for t in target.get_dependencies():
            if t.get_id() not in self.processed_targets:
                self.generate_target(t, outfile)
