[Buildroot] [PATCH 1/5] support/scripts/bl-toolchain-gen: add new script to support Bootlin toolchains

Titouan Christophe titouan.christophe at railnova.eu
Thu May 14 14:33:28 UTC 2020


Hello Thomas and all,

First of all, thank you a lot for integrating these toolchains directly 
into Buildroot !

I left some comments below, mostly for cosmetic reasons in Python.

On 14/05/20 14:52, Thomas Petazzoni wrote:

[--SNIP--]

> ---
>   support/scripts/bl-toolchains-gen | 472 ++++++++++++++++++++++++++++++

Most of the other scripts in support/scripts have a name in the form 
<verb>-<details> (ex: check-bin-arch). As a matter of consistency, I 
would rename this one to gen-bootlin-toolchains.

>   1 file changed, 472 insertions(+)
>   create mode 100755 support/scripts/bl-toolchains-gen

[--SNIP--]

> +
> +class Toolchain:
> +    def __init__(self, arch, libc, variant, version):
> +        self.arch = arch
> +        self.libc = libc
> +        self.variant = variant
> +        self.version = version
> +        self.fname_prefix = "%s--%s--%s-%s" % (self.arch, self.libc, self.variant, self.version)
> +        self.option_name = "BR2_TOOLCHAIN_EXTERNAL_BOOTLIN_%s_%s_%s" % \
> +            (self.arch.replace("-", "_").upper(), self.libc.upper(), self.variant.replace("-", "_").upper())
> +        self.fragment = requests.get(self.fragment_url()).text.split("\n")
> +        self.sha256 = requests.get(self.hash_url()).text.split(" ")[0]
> +
> +    def tarball_url(self):
> +        return os.path.join(BASE_URL, self.arch, "tarballs",
> +                            self.fname_prefix + ".tar.bz2")
> +
> +    def hash_url(self):
> +        return os.path.join(BASE_URL, self.arch, "tarballs",
> +                            self.fname_prefix + ".sha256")
> +
> +    def fragment_url(self):
> +        return os.path.join(BASE_URL, self.arch, "fragments",
> +                            self.fname_prefix + ".frag")

It's nicer if you mark the 3 above methods as properties 
(https://docs.python.org/3/library/functions.html#property), and you can 
then use them as "attributes":

class Toolchain:
     # ...
     @property
     def fragment_url(self):
         return ...

print(toolchain.fragment_url)

> +
> +    def gen_config_in_options(self, f):
> +        f.write("config %s\n" % self.option_name)
> +        f.write("\tbool \"%s %s %s %s\"\n" %
> +                (self.arch, self.libc, self.variant, self.version))
> +        for c in arches[self.arch]['conditions']:
> +            f.write("\tdepends on %s\n" % c)
> +        selects = []
> +        for frag in self.fragment:
> +            # libc type
> +            if frag.startswith("BR2_TOOLCHAIN_EXTERNAL_CUSTOM_UCLIBC"):
> +                selects.append("BR2_TOOLCHAIN_EXTERNAL_UCLIBC")
> +            elif frag.startswith("BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC"):
> +                selects.append("BR2_TOOLCHAIN_EXTERNAL_GLIBC")
> +                # all glibc toolchains have RPC support
> +                selects.append("BR2_TOOLCHAIN_HAS_NATIVE_RPC")
> +            elif frag.startswith("BR2_TOOLCHAIN_EXTERNAL_CUSTOM_MUSL"):
> +                selects.append("BR2_TOOLCHAIN_EXTERNAL_MUSL")
> +
> +            # gcc version
> +            if frag.startswith("BR2_TOOLCHAIN_EXTERNAL_GCC_"):
> +                m = re.match("^BR2_TOOLCHAIN_EXTERNAL_GCC_([0-9_]*)=y$", frag)
> +                if m is None:
> +                    print("ERROR: cannot get gcc version for toolchain %s" % self.fname_prefix)
> +                    sys.exit(1)
> +                selects.append("BR2_TOOLCHAIN_GCC_AT_LEAST_%s" % m[1])

Shorter (and removes the need to import sys):

assert m, "Cannot get gcc version for toolchain %s" % self.fname_prefix

> +
> +            # kernel headers version
> +            if frag.startswith("BR2_TOOLCHAIN_EXTERNAL_HEADERS_"):
> +                m = re.match("^BR2_TOOLCHAIN_EXTERNAL_HEADERS_([0-9_]*)=y$", frag)
> +                if m is None:
> +                    print("ERROR: cannot get kernel headers version for toolchain %s" % self.fname_prefix)
> +                    sys.exit(1)
Same

[--SNIP--]

> +
> +        f.write("\thelp\n")
> +
> +        desc = "Bootlin toolchain for the %s architecture, using the %s C library" % \
> +            (self.arch, self.libc)

Maybe add a little description about bleeding-edge/stable here ?

> +
> +        f.write(textwrap.fill(desc, width=62, initial_indent="\t  ", subsequent_indent="\t  ") + "\n")
> +        f.write("\n")
> +        f.write("\t  https://toolchains.bootlin.com/\n")

[--SNIP--]

> +def get_toolchains():
> +    toolchains = list()
> +    for arch, details in arches.items():
> +        print(arch)
> +        url = os.path.join(BASE_URL, arch, "available_toolchains")
> +        cwd, listing = htmllistparse.fetch_listing(url)
> +        fnames = [f.name for f in listing]
> +        # Sorting the list so we have the most recent version last
> +        fnames.sort()
> +        # This dict will allow us to keep only the latest version for
> +        # each toolchain.
> +        tmp = dict()
> +        for fname in fnames:
> +            parts = fname.split('--')
> +            if parts[0] != arch:
> +                print("FATAL: arch does not match: %s vs. %s" % (parts[0], arch))
> +                sys.exit(1)

Again:
assert parts[0] == arch, "Arch does not match: %s vs %s" % (parts[0], arch)

> +            libc = parts[1]
> +            if parts[2].startswith("stable-"):
> +                variant = "stable"
> +                version = parts[2][len("stable-"):]
> +            elif parts[2].startswith("bleeding-edge-"):
> +                variant = "bleeding-edge"
> +                version = parts[2][len("bleeding-edge-"):]
> +            tmp[(arch, libc, variant)] = version
> +
> +        for k, v in tmp.items():
> +            t = Toolchain(k[0], k[1], k[2], v)
> +            toolchains.append(t)
> +
> +    return toolchains

return [Toolchain(k[0], k[1], k[2], v) for k, v in tmp.items()]

[--SNIP--]

> +def gen_hash(toolchains, fpath):
> +    with open(fpath, "w") as f:
> +        for toolchain in toolchains:
> +            toolchain.gen_hash(f)
> +


Could you also add the comment stating that this file is auto-generated 
here ?

By the way, since all the files having this comment use the "# comment" 
syntax, you could even have this defined in a global variable at the top 
of the script. I would also add the time of generation in this comment:

AUTO_GENERATED_COMMENT = """# This file is auto-generated by ... on %s
# Do not edit

""" % datetime.now().isoformat()

> +
> +def gen_runtime_test(toolchains, fpath):
> +    with open(fpath, "w") as f:
> +        f.write("from tests.toolchain.test_external import TestExternalToolchain\n")
> +        for toolchain in toolchains:
> +            toolchain.gen_test(f)
> +

Same here

> +
> +def gen_toolchains(toolchains):
> +    maindir = "toolchain/toolchain-external/toolchain-external-bootlin"
> +    gen_config_in_options(toolchains, os.path.join(maindir, "Config.in.options"))
> +    gen_mk(toolchains, os.path.join(maindir, "toolchain-external-bootlin.mk"))
> +    gen_hash(toolchains, os.path.join(maindir, "toolchain-external-bootlin.hash"))
> +    gen_runtime_test(toolchains,
> +                     os.path.join("support", "testing", "tests", "toolchain", "test_external_bootlin.py"))
> +
> +
> +toolchains = get_toolchains()
> +gen_toolchains(toolchains)
> 

Kind regards,

Titouan



More information about the buildroot mailing list