Exemple #1
0
    def lang(self: ArgsProtocol) -> Lang:
        """
        Returns:
            A `blight.enums.Lang` value representing the tool's language
        """
        x_lang_map = {
            "c": Lang.C,
            "c-header": Lang.C,
            "c++": Lang.Cxx,
            "c++-header": Lang.Cxx
        }

        # First, check for `-x lang`. This overrides the language determined by
        # the frontend's binary name (e.g. `g++`).
        x_flag_index = rindex_prefix(self.args, "-x")
        if x_flag_index is not None:
            if self.args[x_flag_index] == "-x":
                # TODO(ww): Maybe bounds check.
                x_lang = self.args[x_flag_index + 1]
            else:
                # NOTE(ww): -xc and -xc++ both work, at least on GCC.
                x_lang = self.args[x_flag_index][2:]
            return x_lang_map.get(x_lang, Lang.Unknown)

        # No `-x lang` means that we're operating in the frontend's default mode.
        if self.__class__ == CC:
            return Lang.C
        elif self.__class__ == CXX:
            return Lang.Cxx
        else:
            logger.debug(
                f"unknown default language mode for {self.__class__.__name__}")
            return Lang.Unknown
Exemple #2
0
    def outputs(self) -> List[str]:
        """
        Specializes `Tool.outputs` for the linker.
        """

        outputs = super().outputs
        if outputs != []:
            return outputs

        # The GNU linker additionally supports --output=OUTFILE and
        # --output OUTFILE. Handle them here.
        output_flag_index = rindex_prefix(self.args, "--output")
        if output_flag_index is None:
            return ["a.out"]

        # Split option form.
        if self.args[output_flag_index] == "--output":
            return [self.args[output_flag_index + 1]]

        # Assignment form.
        return [self.args[output_flag_index].split("=")[1]]
Exemple #3
0
    def outputs(self) -> List[str]:
        """
        Returns all "outputs" produced by the tool. "Outputs" is subjectively
        defined to be the "main" products of a tool, i.e. results of a particular
        stage or invocation and **not** any incidental or metadata files that
        might otherwise be created in the process.

        Tools may further refine the behavior of this mixin-supplied property
        by overriding it with their own, more specific behavior.

        Returns:
            A list of `str`, each of which is an output
        """

        o_flag_index = rindex_prefix(self.args, "-o")
        if o_flag_index is None:
            return []

        if self.args[o_flag_index] == "-o":
            return [self.args[o_flag_index + 1]]

        # NOTE(ww): Outputs like -ofoo. Gross, but valid according to GCC.
        return [self.args[o_flag_index][2:]]
Exemple #4
0
    def std(self: LangProtocol) -> Std:
        """
        Returns:
            A `blight.enums.Std` value representing the tool's standard
        """

        # First, a special case: if -ansi is present, we're in
        # C89 mode for C code and C++03 mode for C++ code.
        if "-ansi" in self.args:
            if self.lang == Lang.C:
                return Std.C89
            elif self.lang == Lang.Cxx:
                return Std.Cxx03
            else:
                logger.debug(f"-ansi passed but unknown language: {self.lang}")
                return Std.Unknown

        # Experimentally, both GCC and clang respect the last -std=XXX flag passed.
        # See: https://stackoverflow.com/questions/40563269/passing-multiple-std-switches-to-g
        std_flag_index = rindex_prefix(self.args, "-std=")

        # No -std=XXX flags? The tool is operating in its default standard mode,
        # which is determined by its language.
        if std_flag_index is None:
            if self.lang == Lang.C:
                return Std.GnuUnknown
            elif self.lang == Lang.Cxx:
                return Std.GnuxxUnknown
            else:
                logger.debug(
                    f"no -std= flag and unknown language: {self.lang}")
                return Std.Unknown

        last_std_flag = self.args[std_flag_index]
        std_flag_map = {
            # C89 flags.
            "-std=c89": Std.C89,
            "-std=c90": Std.C89,
            "-std=iso9899:1990": Std.C89,
            # C94 flags.
            "-std=iso9899:199409": Std.C94,
            # C99 flags.
            "-std=c99": Std.C99,
            "-std=c9x": Std.C99,
            "-std=iso9899:1999": Std.C99,
            "-std=iso9899:199x": Std.C99,
            # C11 flags.
            "-std=c11": Std.C11,
            "-std=c1x": Std.C11,
            "-std=iso9899:2011": Std.C11,
            # C17 flags.
            "-std=c17": Std.C17,
            "-std=c18": Std.C17,
            "-std=iso9899:2017": Std.C17,
            "-std=iso9899:2018": Std.C17,
            # C20 (presumptive) flags.
            "-std=c2x": Std.C2x,
            # GNU89 flags.
            "-std=gnu89": Std.Gnu89,
            "-std=gnu90": Std.Gnu89,
            # GNU99 flags.
            "-std=gnu99": Std.Gnu99,
            "-std=gnu9x": Std.Gnu99,
            # GNU11 flags.
            "-std=gnu11": Std.Gnu11,
            "-std=gnu1x": Std.Gnu11,
            # GNU17 flags.
            "-std=gnu17": Std.Gnu17,
            "-std=gnu18": Std.Gnu17,
            # GNU20 (presumptive) flags.
            "-std=gnu2x": Std.Gnu2x,
            # C++03 flags.
            # NOTE(ww): Both gcc and clang treat C++98 mode as C++03 mode.
            "-std=c++98": Std.Cxx03,
            "-std=c++03": Std.Cxx03,
            # C++11 flags.
            "-std=c++11": Std.Cxx11,
            "-std=c++0x": Std.Cxx11,
            # C++14 flags.
            "-std=c++14": Std.Cxx14,
            "-std=c++1y": Std.Cxx14,
            # C++17 flags.
            "-std=c++17": Std.Cxx17,
            "-std=c++1z": Std.Cxx17,
            # C++20 (presumptive) flags.
            "-std=c++2a": Std.Cxx2a,
            # GNU++03 flags.
            "-std=gnu++98": Std.Gnuxx03,
            "-std=gnu++03": Std.Gnuxx03,
            # GNU++11 flags.
            "-std=gnu++11": Std.Gnuxx11,
            "-std=gnu++0x": Std.Gnuxx11,
            # GNU++14 flags.
            "-std=gnu++14": Std.Gnuxx14,
            "-std=gnu++1y": Std.Gnuxx14,
            # GNU++17 flags.
            "-std=gnu++17": Std.Gnuxx17,
            "-std=gnu++1z": Std.Gnuxx17,
            # GNU++20 (presumptive) flags.
            "-std=gnu++2a": Std.Gnuxx2a,
        }

        std = std_flag_map.get(last_std_flag)
        if std is not None:
            return std

        # If we've made it here, then we've reached a -std=XXX flag that we
        # don't know yet. Make an effort to guess at it.
        std_name = last_std_flag.split("=")[1]
        if std_name.startswith("c++"):
            logger.debug(f"partially unrecognized c++ std: {last_std_flag}")
            return Std.CxxUnknown
        elif std_name.startswith("gnu++"):
            logger.debug(f"partially unrecognized gnu++ std: {last_std_flag}")
            return Std.GnuxxUnknown
        elif std_name.startswith("gnu"):
            logger.debug(f"partially unrecognized gnu c std: {last_std_flag}")
            return Std.GnuUnknown
        elif std_name.startswith("c") or std_name.startswith("iso9899"):
            logger.debug(f"partially unrecognized c std: {last_std_flag}")
            return Std.CUnknown

        logger.debug(f"completely unrecognized -std= flag: {last_std_flag}")
        return Std.Unknown