Esempio n. 1
0
    def expand_macro(self, name, path, condition, already_expanded, parser, maxdepth=3):
        """ Expand a macro named @name. Preconditions to the folder are given
        in @condition. The input file is @path and to avoid endless
        recursion processing is aborted if the current name is already present
        in @already_expanded. To save the results, the local variables are
        accessed via the @parser parameter."""

        if maxdepth == 0:
            return

        if name in already_expanded:
            return
        else:
            already_expanded.add(name)

        basepath = os.path.dirname(name)
        filename = os.path.basename(name)

        basename = ""

        # Extract base name from macro name
        match = self.regex_base.match(filename)
        if not match:
            return

        if match.group(1) is None:  # we have a macro
            basename = match.group(2)
            if basename.endswith("y"):
                basename = basename[:-1]
        elif match.group(2) is None:  # we have a file
            basename = match.group(1)

        scan_regex_string = ""
        if match.group(1) is None:
            scan_regex_string = r"\s*" + basename + r"(|y|\$\(" + \
                                CONFIG_FORMAT + r"\))\s*(:=|\+=|=)\s*(.*)"
        else:
            scan_regex_string = r"\s*" + basename + r"(|-y|-objs|-\$\(" + \
                                CONFIG_FORMAT + r"\))\s*(:=|\+=|=)\s*(.*)"

        scan_regex = re.compile(scan_regex_string)

        if not path in parser.file_content_cache:
            parser.read_whole_file(path)

        inputs = parser.file_content_cache[path]

        for line in inputs:
            if line.invalid:
                continue

            ifdef_condition = line.condition
            line = line.processed_line

            match = scan_regex.match(line)
            if not match:
                continue

            config_in_composite = match.group(2)
            condition_comp = ""
            if config_in_composite:
                condition_comp = Helper.get_config_string(config_in_composite,
                                                         self.model)

            rhs = match.group(4)

            matches = [x for x in re.split("\t| ", rhs) if x]
            for item in matches:
                fullpath = basepath + "/" + item
                passdown_condition = condition[:]
                if config_in_composite:
                    passdown_condition.append(condition_comp)

                if os.path.isdir(fullpath):
                    parser.local_vars["dir_cond_collection"]\
                        [fullpath].add_alternative(passdown_condition[:])
                else:
                    sourcefile = Helper.guess_source_for_target(fullpath)
                    if not sourcefile:
                        self.expand_macro(fullpath, path,passdown_condition,
                                          already_expanded, parser, maxdepth-1)
                    else:
                        full_condition = DataStructures.Precondition()
                        if len(condition) > 0:
                            full_condition = condition[:]
                        if config_in_composite:
                            full_condition.append(condition_comp)
                        if len(ifdef_condition) > 0:
                            full_condition.extend(ifdef_condition)

                        parser.local_vars["file_features"][sourcefile].\
                            add_alternative(full_condition[:])

        already_expanded.discard(name)
    def expand_macro(self, name, path, condition, already_expanded, parser):
        """ Expand the macro @name. Preconditions to the folder are given
        in @condition. The path to the input file is @path and to avoid endless
        recursion processing is aborted if the current name is already present
        in @already_expanded. To save the results, the local variables are
        accessed via the @parser parameter."""

        if name in already_expanded:
            return

        already_expanded.add(name)

        ifdef_condition = DataStructures.Precondition()
        basepath = os.path.dirname(name)
        filename = os.path.basename(name)

        basename = ""

        match = re.match(self.regex_base, filename)
        if not match:
            return

        if match.group(1) is None:  # we have a macro
            basename = match.group(2)
            if basename.endswith("y"):
                basename = basename[:-1]
        elif match.group(2) is None:  # we have a file
            basename = match.group(1)

        # Hacky bit for archival/libarchive/
        if "all_configs" in parser.local_vars and basename == "COMMON_FILES":
            ifdef_condition.add_condition(" || ".join(
                parser.local_vars["all_configs"]))

        scan_regex_string = ""
        if match.group(1) is None:
            scan_regex_string = r"\s*" + basename + r"(|y|\$\(" + \
                                CONFIG_FORMAT + r"\))\s*(:=|\+=|=)\s*(.*)"
        else:
            scan_regex_string = r"\s*" + basename + r"(|-y|-objs|-\$\(" + \
                                CONFIG_FORMAT + r"\))\s*(:=|\+=|=)\s*(.*)"

        if not path in parser.file_content_cache:
            parser.read_whole_file(path)

        inputs = parser.file_content_cache[path]

        for line in inputs:

            line = line.processed_line

            match = re.match(scan_regex_string, line)
            if not match:
                continue

            config_in_composite = match.group(2)
            condition_comp = ""
            if config_in_composite:
                condition_comp = \
                    Tools.get_config_string(config_in_composite,
                                            self.model)

            rhs = match.group(4)

            matches = [x for x in re.split("\t| ", rhs) if x]
            for item in matches:
                fullpath = basepath + "/" + item
                passdown_condition = condition[:]
                if config_in_composite:
                    passdown_condition.append(condition_comp)

                if os.path.isdir(fullpath):
                    parser.local_vars["dir_cond_collection"]\
                        [fullpath].add_alternative(passdown_condition[:])
                else:
                    sourcefile = Kbuild.guess_source_for_target(fullpath)
                    if not sourcefile:
                        self.expand_macro(fullpath, path, passdown_condition,
                                          already_expanded, parser)
                    else:
                        full_condition = DataStructures.Precondition()
                        if len(condition) > 0:
                            full_condition = condition[:]
                        if config_in_composite:
                            full_condition.append(condition_comp)
                        if len(ifdef_condition) > 0:
                            for ifdef_cond in ifdef_condition:
                                full_condition.append(ifdef_cond)

                        parser.local_vars["file_features"][sourcefile].\
                            add_alternative(full_condition[:])

        already_expanded.discard(name)
Esempio n. 3
0
    def expand_macro(self, name, path, condition, already_expanded, parser):
        """ Expand a macro named @name. Preconditions to the folder are given
        in @condition. The path to the input file is @path and to avoid endless
        recursion processing is aborted if the current name is already present
        in @already_expanded. To save the results, the local variables are
        accessed via the @parser parameter."""

        if name in already_expanded:
            return

        already_expanded.add(name)

        basepath = os.path.dirname(name)
        filename = os.path.basename(name)

        match = re.match(self.regex_base, filename)
        if not match:
            return

        basename = match.group(1)

        scan_regex_string = r"\s*" + basename + r"\s*(:=|\+=|=)\s*(.*)"

        if not path in parser.file_content_cache:
            parser.read_whole_file(path)

        inputs = parser.file_content_cache[path]

        for line in inputs:

            if line.invalid:
                continue

            ifdef_condition = line.condition
            line = line.processed_line

            match = re.match(scan_regex_string, line)
            if not match:
                continue

            rhs = match.group(2)

            matches = [x for x in re.split("\t| ", rhs) if x]
            for item in matches:
                fullpath = basepath + "/" + item
                passdown_condition = condition[:]

                sourcefile = Kbuild.guess_source_for_target(fullpath)
                if not sourcefile:
                    self.expand_macro(fullpath, path, passdown_condition,
                                      already_expanded, parser)
                else:
                    full_condition = DataStructures.Precondition()
                    if len(condition) > 0:
                        full_condition = condition[:]
                    if len(ifdef_condition) > 0:
                        full_condition.extend(ifdef_condition)

                    parser.global_vars["file_features"][sourcefile].\
                        add_alternative(full_condition[:])

        already_expanded.discard(name)
Esempio n. 4
0
    def process(self, parser, args, dirs_to_process):
        """ Initialize the global variables and find the subdirectories which
        we need to descend into by parsing the toplevel Makefile, looking for
        the classes-y and subdirs-y definitions."""

        # nesting unparseable expressions:
        parser.global_vars.create_variable("no_config_nesting", 0)

        # directory preconditions
        parser.global_vars.create_variable(
            "dir_cond_collection",
            collections.defaultdict(DataStructures.Alternatives))

        parser.global_vars.create_variable("mainboard_dirs", [])

        for vendor in os.listdir("src/mainboard"):
            directory = "src/mainboard/" + vendor
            if not os.path.isdir(directory):
                continue
            for mainboard in os.listdir(directory):
                f = directory + "/" + mainboard
                if not os.path.isdir(f):
                    continue

                parser.global_vars["mainboard_dirs"].append(vendor + "/" + \
                                                            mainboard)

        with open(self.get_file_for_subdirectory("."), 'r') as mainfile:
            while True:
                (good, line) = Tools.get_multiline_from_file(mainfile)
                if not good:
                    break

                # evaluate classes-y
                match = re.match(r"^classes-y\s*:=\s*(.*)", line)
                if match:
                    classes = [
                        x for x in re.split("\t| ", match.group(1)) if x
                    ]
                    parser.global_vars.create_variable("classes", classes)
                    continue

                # look for subdirs
                match = re.match(r"^subdirs-y\s*[:\+]=\s*(.*)", line)
                if not match:
                    continue

                subdirs = [x for x in re.split("\t| ", match.group(1)) if x]
                for item in subdirs:
                    if r"$(MAINBOARDDIR)" in item:
                        for mainboard_dir in parser.global_vars[
                                "mainboard_dirs"]:
                            subdir = re.sub(r"\$\(MAINBOARDDIR\)",
                                            mainboard_dir, item)
                            if os.path.isdir(subdir):
                                dirs_to_process[
                                    subdir] = DataStructures.Precondition()

                    elif r"$(ARCHDIR-y)" in line:
                        # FIXME: x86 hardcoded for testing tree
                        item = re.sub(r"\$\(ARCHDIR-y\)", r"x86", item)
                        precond = DataStructures.Precondition()
                        precond.add_condition("CONFIG_ARCH_X86")
                        parser.global_vars["dir_cond_collection"][item].\
                            add_alternative(precond)
                        dirs_to_process[item] = precond

                    elif os.path.isdir(item):
                        dirs_to_process[item] = DataStructures.Precondition()

        # User provided directories have no precondition
        for item in args.directory:
            dirs_to_process[item] = DataStructures.Precondition()

        # Initialize global data structure
        parser.global_vars.create_variable(
            "file_features",
            collections.defaultdict(DataStructures.Alternatives))
Esempio n. 5
0
    def process(self, parser, line, basepath):
        line = line.processed_line

        subdir = re.match(r"\s*subdirs-(y|\$[\{\(]" + CONFIG_FORMAT + \
                          r"[\}\)])\s*(:=|\+=|=)\s*(.*)", line)
        if subdir:
            matches = [x for x in re.split("\t| ", subdir.group(4)) if x]
            for match in matches:
                fullpath = os.path.relpath(basepath + "/" + match)
                tmp_condition = DataStructures.Precondition()

                if not subdir.group(1) == "y":
                    tmp_condition.add_condition("CONFIG_" + subdir.group(2))

                if os.path.isdir(fullpath):
                    additional_condition = []
                    # See below, this is not really Kbuild, but approximation to
                    # golem formulae
                    if basepath.startswith("src/mainboard/"):
                        (vendor_option, board_option) = \
                                self.get_vendor_and_board_options_from(basepath)

                        additional_condition = parser.local_vars[
                            "ifdef_condition"][:]
                        additional_condition.append(vendor_option)
                        additional_condition.append(board_option)

                    cond = Helper.build_precondition(
                        [tmp_condition],
                        Helper.build_precondition(
                            parser.global_vars["dir_cond_collection"]
                            [basepath], additional_condition))

                    parser.global_vars["dir_cond_collection"][fullpath].\
                        add_alternative(cond)
                    if not fullpath in parser.local_vars["dir_cond_collection"]:
                        parser.local_vars["dir_cond_collection"].append(
                            fullpath)

            return True

        cls = re.match(r"\s*classes-y\s*\+=\s*(.*)", line)
        if cls:
            parser.global_vars["classes"].extend(cls.group(1).split())

        for cls in parser.global_vars["classes"]:
            cls_match = re.match(
                cls + r"-(y|\$[\(\{]" + CONFIG_FORMAT +
                r"[\}\)]|srcs)\s*(:=|\+=|=)\s*(.*)", line)
            if not cls_match:
                continue

            matches = [x for x in re.split("\t| ", cls_match.group(4)) if x]
            for match in matches:
                fullpath = os.path.relpath(basepath + "/" + match)
                additional_condition = []

                if not cls_match.group(1) == "y" and not cls_match.group(
                        1) == "srcs":
                    additional_condition.append("CONFIG_" + cls_match.group(2))

                # SONDERFALL: src/arch/x86/Makefile.inc
                if basepath == "src/arch/x86" and \
                        cls_match.group(1) == "srcs" and \
                        "$(MAINBOARDDIR)" in match:
                    for mbdir in parser.global_vars["mainboard_dirs"]:
                        cur_fullpath = re.sub(r"\$\(MAINBOARDDIR\)", mbdir,
                                              match)
                        sourcefile = Kbuild.guess_source_for_target(
                            cur_fullpath)
                        if sourcefile:
                            # Information from directory can be converted
                            # into conditions. This is NOT in the Kbuild
                            # system but yields higher equivalence with
                            # golem.
                            (vendor_option, board_option) = \
                                    self.get_vendor_and_board_options_from(cur_fullpath)
                            condition = parser.local_vars["ifdef_condition"][:]
                            condition.append(vendor_option)
                            condition.append(board_option)

                            cond = Helper.build_precondition(
                                parser.global_vars["dir_cond_collection"]
                                [basepath], condition)

                            new_alt = DataStructures.Alternatives()
                            new_alt.add_alternative(cond)
                            parser.global_vars["file_features"][
                                cur_fullpath] = new_alt

                # Normalfall:
                additional_condition.extend(
                    parser.local_vars["ifdef_condition"][:])

                # src/mainboard has conditions we know from the path...
                # Usually this is not in the build system, but can be used
                # for higher equivalence ratings against golem
                if basepath.startswith("src/mainboard/"):
                    (vendor_option, board_option) = \
                        self.get_vendor_and_board_options_from(fullpath)

                    additional_condition.append(vendor_option)
                    additional_condition.append(board_option)

                cond = Helper.build_precondition(
                    parser.global_vars["dir_cond_collection"][basepath],
                    additional_condition)

                sourcefile = Kbuild.guess_source_for_target(fullpath)
                if sourcefile:
                    new_alt = DataStructures.Alternatives()
                    new_alt.add_alternative(cond)
                    parser.global_vars["file_features"][fullpath] = new_alt
                else:
                    parser.local_vars["composite_map"][
                        fullpath].add_alternative(cond)

            return True

        return False