# Buggy code
def generate_single_compile(
    self, target, outfile, src, is_generated=False, header_deps=[], order_deps=[]
):
    """
    Compiles C/C++, ObjC/ObjC++, Fortran, and D sources
    """
    if isinstance(src, str) and src.endswith(".h"):
        raise AssertionError("BUG: sources should not contain headers {!r}".format(src))
    if isinstance(src, RawFilename) and src.fname.endswith(".h"):
        raise AssertionError(
            "BUG: sources should not contain headers {!r}".format(src.fname)
        )
    extra_orderdeps = []
    compiler = get_compiler_for_source(target.compilers.values(), src)

    # Create an empty commands list, and start adding arguments from
    # various sources in the order in which they must override each other
    commands = CompilerArgs(compiler)
    # Add compiler args for compiling this target derived from 'base' build
    # options passed on the command-line, in default_options, etc.
    # These have the lowest priority.
    commands += compilers.get_base_compile_args(
        self.environment.coredata.base_options, compiler
    )
    # The code generated by valac is usually crap and has tons of unused
    # variables and such, so disable warnings for Vala C sources.
    no_warn_args = is_generated == "vala"
    # Add compiler args and include paths from several sources; defaults,
    # build options, external dependencies, etc.
    commands += self.generate_basic_compiler_args(target, compiler, no_warn_args)
    # Add include dirs from the `include_directories:` kwarg on the target
    # and from `include_directories:` of internal deps of the target.
    #
    # Target include dirs should override internal deps include dirs.
    #
    # Include dirs from internal deps should override include dirs from
    # external deps.
    for i in target.get_include_dirs():
        basedir = i.get_curdir()
        for d in i.get_incdirs():
            # Avoid superfluous '/.' at the end of paths when d is '.'
            if d not in ("", "."):
                expdir = os.path.join(basedir, d)
            else:
                expdir = basedir
            srctreedir = os.path.join(self.build_to_src, expdir)
            # Add source subdir first so that the build subdir overrides it
            sargs = compiler.get_include_args(srctreedir, i.is_system)
            commands += sargs
            # There may be include dirs where a build directory has not been
            # created for some source dir. For example if someone does this:
            #
            # inc = include_directories('foo/bar/baz')
            #
            # But never subdir()s into the actual dir.
            if os.path.isdir(os.path.join(self.environment.get_build_dir(), expdir)):
                bargs = compiler.get_include_args(expdir, i.is_system)
            else:
                bargs = []
            commands += bargs
        for d in i.get_extra_build_dirs():
            commands += compiler.get_include_args(d, i.is_system)
    # Add per-target compile args, f.ex, `c_args : ['-DFOO']`. We set these
    # near the end since these are supposed to override everything else.
    commands += self.escape_extra_args(
        compiler, target.get_extra_args(compiler.get_language())
    )
    # Add source dir and build dir. Project-specific and target-specific
    # include paths must override per-target compile args, include paths
    # from external dependencies, internal dependencies, and from
    # per-target `include_directories:`
    #
    # We prefer headers in the build dir and the custom target dir over the
    # source dir since, for instance, the user might have an
    # srcdir == builddir Autotools build in their source tree. Many
    # projects that are moving to Meson have both Meson and Autotools in
    # parallel as part of the transition.
    commands += self.get_source_dir_include_args(target, compiler)
    commands += self.get_custom_target_dir_include_args(target, compiler)
    commands += self.get_build_dir_include_args(target, compiler)
    # Finally add the private dir for the target to the include path. This
    # must override everything else and must be the final path added.
    commands += compiler.get_include_args(self.get_target_private_dir(target), False)

    # FIXME: This file handling is atrocious and broken. We need to
    # replace it with File objects used consistently everywhere.
    if isinstance(src, RawFilename):
        rel_src = src.fname
        if os.path.isabs(src.fname):
            abs_src = src.fname
        else:
            abs_src = os.path.join(self.environment.get_build_dir(), src.fname)
    elif is_generated:
        raise AssertionError(
            "BUG: broken generated source file handling for {!r}".format(src)
        )
    else:
        if isinstance(src, File):
            rel_src = src.rel_to_builddir(self.build_to_src)
        else:
            raise InvalidArguments("Invalid source type: {!r}".format(src))
        abs_src = os.path.join(self.environment.get_build_dir(), rel_src)
    if isinstance(src, (RawFilename, File)):
        src_filename = src.fname
    elif os.path.isabs(src):
        src_filename = os.path.basename(src)
    else:
        src_filename = src
    obj_basename = src_filename.replace("/", "_").replace("\\", "_")
    rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename)
    rel_obj += "." + self.environment.get_object_suffix()
    dep_file = compiler.depfile_for_object(rel_obj)

    # Add MSVC debug file generation compile flags: /Fd /FS
    commands += self.get_compile_debugfile_args(compiler, target, rel_obj)

    # PCH handling
    if self.environment.coredata.base_options.get("b_pch", False):
        commands += self.get_pch_include_args(compiler, target)
        pchlist = target.get_pch(compiler.language)
    else:
        pchlist = []
    if len(pchlist) == 0:
        pch_dep = []
    elif compiler.id == "intel":
        pch_dep = []
    else:
        arr = []
        i = os.path.join(
            self.get_target_private_dir(target), compiler.get_pch_name(pchlist[0])
        )
        arr.append(i)
        pch_dep = arr

    crstr = ""
    if target.is_cross:
        crstr = "_CROSS"
    compiler_name = "%s%s_COMPILER" % (compiler.get_language(), crstr)
    extra_deps = []
    if compiler.get_language() == "fortran":
        extra_deps += self.get_fortran_deps(compiler, abs_src, target)
        # Dependency hack. Remove once multiple outputs in Ninja is fixed:
        # https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8
        for modname, srcfile in self.fortran_deps[target.get_basename()].items():
            modfile = os.path.join(
                self.get_target_private_dir(target),
                compiler.module_name_to_filename(modname),
            )
            if srcfile == src:
                depelem = NinjaBuildElement(
                    self.all_outputs, modfile, "FORTRAN_DEP_HACK", rel_obj
                )
                depelem.write(outfile)
        commands += compiler.get_module_outdir_args(self.get_target_private_dir(target))

    element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
    for d in header_deps:
        if isinstance(d, RawFilename):
            d = d.fname
        elif not self.has_dir_part(d):
            d = os.path.join(self.get_target_private_dir(target), d)
        element.add_dep(d)
    for d in extra_deps:
        element.add_dep(d)
    for d in order_deps:
        if isinstance(d, RawFilename):
            d = d.fname
        elif not self.has_dir_part(d):
            d = os.path.join(self.get_target_private_dir(target), d)
        element.add_orderdep(d)
    element.add_orderdep(pch_dep)
    element.add_orderdep(extra_orderdeps)
    # Convert from GCC-style link argument naming to the naming used by the
    # current compiler.
    commands = commands.to_native()
    for i in self.get_fortran_orderdeps(target, compiler):
        element.add_orderdep(i)
    element.add_item("DEPFILE", dep_file)
    element.add_item("ARGS", commands)
    element.write(outfile)
    return rel_obj


# Traceback (FileNotFoundError)
The Meson build system
Version: 0.38.0
Source dir: /home/Adama-docs/Adam/MyDocs/praca/IMGW/dev/meson_bug
Build dir: /home/Adama-docs/Adam/MyDocs/praca/IMGW/dev/meson_bug/build
Build type: native build
Project name: simple fortran
Native fortran compiler: gfortran (gcc 5.4.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Program pp_ser.py found: YES (/usr/bin/env python /home/adam/meson_bug/pp_ser.py)
Build targets in project: 1
Traceback (most recent call last):
File "/home/adam/.local/lib/python3.5/site-packages/mesonbuild/mesonmain.py", line 286, in run
app.generate()
File "/home/adam/.local/lib/python3.5/site-packages/mesonbuild/mesonmain.py", line 170, in generate
g.generate(intr)
File "/home/adam/.local/lib/python3.5/site-packages/mesonbuild/backend/ninjabackend.py", line 191, in generate
self.generate_target(t, outfile)
File "/home/adam/.local/lib/python3.5/site-packages/mesonbuild/backend/ninjabackend.py", line 386, in generate_target
header_deps=header_deps)
File "/home/adam/.local/lib/python3.5/site-packages/mesonbuild/backend/ninjabackend.py", line 1916, in generate_single_compile
extra_deps += self.get_fortran_deps(compiler, abs_src, target)
File "/home/adam/.local/lib/python3.5/site-packages/mesonbuild/backend/ninjabackend.py", line 1632, in get_fortran_deps
with open(src) as f:
FileNotFoundError: [Errno 2] No such file or directory: '/home/adam/meson_bug/build/dwarf@exe/src1.f90'

# Fixed code
def generate_single_compile(
    self, target, outfile, src, is_generated=False, header_deps=[], order_deps=[]
):
    """
    Compiles C/C++, ObjC/ObjC++, Fortran, and D sources
    """
    if isinstance(src, str) and src.endswith(".h"):
        raise AssertionError("BUG: sources should not contain headers {!r}".format(src))
    if isinstance(src, RawFilename) and src.fname.endswith(".h"):
        raise AssertionError(
            "BUG: sources should not contain headers {!r}".format(src.fname)
        )
    extra_orderdeps = []
    compiler = get_compiler_for_source(target.compilers.values(), src)

    # Create an empty commands list, and start adding arguments from
    # various sources in the order in which they must override each other
    commands = CompilerArgs(compiler)
    # Add compiler args for compiling this target derived from 'base' build
    # options passed on the command-line, in default_options, etc.
    # These have the lowest priority.
    commands += compilers.get_base_compile_args(
        self.environment.coredata.base_options, compiler
    )
    # The code generated by valac is usually crap and has tons of unused
    # variables and such, so disable warnings for Vala C sources.
    no_warn_args = is_generated == "vala"
    # Add compiler args and include paths from several sources; defaults,
    # build options, external dependencies, etc.
    commands += self.generate_basic_compiler_args(target, compiler, no_warn_args)
    # Add include dirs from the `include_directories:` kwarg on the target
    # and from `include_directories:` of internal deps of the target.
    #
    # Target include dirs should override internal deps include dirs.
    #
    # Include dirs from internal deps should override include dirs from
    # external deps.
    for i in target.get_include_dirs():
        basedir = i.get_curdir()
        for d in i.get_incdirs():
            # Avoid superfluous '/.' at the end of paths when d is '.'
            if d not in ("", "."):
                expdir = os.path.join(basedir, d)
            else:
                expdir = basedir
            srctreedir = os.path.join(self.build_to_src, expdir)
            # Add source subdir first so that the build subdir overrides it
            sargs = compiler.get_include_args(srctreedir, i.is_system)
            commands += sargs
            # There may be include dirs where a build directory has not been
            # created for some source dir. For example if someone does this:
            #
            # inc = include_directories('foo/bar/baz')
            #
            # But never subdir()s into the actual dir.
            if os.path.isdir(os.path.join(self.environment.get_build_dir(), expdir)):
                bargs = compiler.get_include_args(expdir, i.is_system)
            else:
                bargs = []
            commands += bargs
        for d in i.get_extra_build_dirs():
            commands += compiler.get_include_args(d, i.is_system)
    # Add per-target compile args, f.ex, `c_args : ['-DFOO']`. We set these
    # near the end since these are supposed to override everything else.
    commands += self.escape_extra_args(
        compiler, target.get_extra_args(compiler.get_language())
    )
    # Add source dir and build dir. Project-specific and target-specific
    # include paths must override per-target compile args, include paths
    # from external dependencies, internal dependencies, and from
    # per-target `include_directories:`
    #
    # We prefer headers in the build dir and the custom target dir over the
    # source dir since, for instance, the user might have an
    # srcdir == builddir Autotools build in their source tree. Many
    # projects that are moving to Meson have both Meson and Autotools in
    # parallel as part of the transition.
    commands += self.get_source_dir_include_args(target, compiler)
    commands += self.get_custom_target_dir_include_args(target, compiler)
    commands += self.get_build_dir_include_args(target, compiler)
    # Finally add the private dir for the target to the include path. This
    # must override everything else and must be the final path added.
    commands += compiler.get_include_args(self.get_target_private_dir(target), False)

    # FIXME: This file handling is atrocious and broken. We need to
    # replace it with File objects used consistently everywhere.
    if isinstance(src, RawFilename):
        rel_src = src.fname
        if os.path.isabs(src.fname):
            abs_src = src.fname
        else:
            abs_src = os.path.join(self.environment.get_build_dir(), src.fname)
    elif is_generated:
        raise AssertionError(
            "BUG: broken generated source file handling for {!r}".format(src)
        )
    else:
        if isinstance(src, File):
            rel_src = src.rel_to_builddir(self.build_to_src)
        else:
            raise InvalidArguments("Invalid source type: {!r}".format(src))
        abs_src = os.path.join(self.environment.get_build_dir(), rel_src)
    if isinstance(src, (RawFilename, File)):
        src_filename = src.fname
    elif os.path.isabs(src):
        src_filename = os.path.basename(src)
    else:
        src_filename = src
    obj_basename = src_filename.replace("/", "_").replace("\\", "_")
    rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename)
    rel_obj += "." + self.environment.get_object_suffix()
    dep_file = compiler.depfile_for_object(rel_obj)

    # Add MSVC debug file generation compile flags: /Fd /FS
    commands += self.get_compile_debugfile_args(compiler, target, rel_obj)

    # PCH handling
    if self.environment.coredata.base_options.get("b_pch", False):
        commands += self.get_pch_include_args(compiler, target)
        pchlist = target.get_pch(compiler.language)
    else:
        pchlist = []
    if len(pchlist) == 0:
        pch_dep = []
    elif compiler.id == "intel":
        pch_dep = []
    else:
        arr = []
        i = os.path.join(
            self.get_target_private_dir(target), compiler.get_pch_name(pchlist[0])
        )
        arr.append(i)
        pch_dep = arr

    crstr = ""
    if target.is_cross:
        crstr = "_CROSS"
    compiler_name = "%s%s_COMPILER" % (compiler.get_language(), crstr)
    extra_deps = []
    if compiler.get_language() == "fortran":
        # Can't read source file to scan for deps if it's generated later
        # at build-time. Skip scanning for deps, and just set the module
        # outdir argument instead.
        # https://github.com/mesonbuild/meson/issues/1348
        if not is_generated:
            extra_deps += self.get_fortran_deps(compiler, abs_src, target)
        # Dependency hack. Remove once multiple outputs in Ninja is fixed:
        # https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8
        for modname, srcfile in self.fortran_deps[target.get_basename()].items():
            modfile = os.path.join(
                self.get_target_private_dir(target),
                compiler.module_name_to_filename(modname),
            )
            if srcfile == src:
                depelem = NinjaBuildElement(
                    self.all_outputs, modfile, "FORTRAN_DEP_HACK", rel_obj
                )
                depelem.write(outfile)
        commands += compiler.get_module_outdir_args(self.get_target_private_dir(target))

    element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
    for d in header_deps:
        if isinstance(d, RawFilename):
            d = d.fname
        elif not self.has_dir_part(d):
            d = os.path.join(self.get_target_private_dir(target), d)
        element.add_dep(d)
    for d in extra_deps:
        element.add_dep(d)
    for d in order_deps:
        if isinstance(d, RawFilename):
            d = d.fname
        elif not self.has_dir_part(d):
            d = os.path.join(self.get_target_private_dir(target), d)
        element.add_orderdep(d)
    element.add_orderdep(pch_dep)
    element.add_orderdep(extra_orderdeps)
    # Convert from GCC-style link argument naming to the naming used by the
    # current compiler.
    commands = commands.to_native()
    for i in self.get_fortran_orderdeps(target, compiler):
        element.add_orderdep(i)
    element.add_item("DEPFILE", dep_file)
    element.add_item("ARGS", commands)
    element.write(outfile)
    return rel_obj