bazelbuild / platforms

Constraint values for specifying platforms and toolchains
Apache License 2.0
108 stars 71 forks source link

Processors and Environments #9

Open wpieterse2825 opened 4 years ago

wpieterse2825 commented 4 years ago

Hi all, trust all is well!

I want to ask you're help with something. Have been googling around for a related set of problems, but can't seem to find a solution for the problem. I don't know if this is the correct place to post this, if not, kindly provide me a location where I can.

I'm in the process of developing a small OS. While doing the programming tasks have been progressing quite nicely, I'm having a problem with doing the cross-platform stuff inside Bazel.

The idea I have is, that the OS can be compiled for a specific device, say, the Pixel phone. The device has a very specific set of features, such as an ARM processor, it's 64-bit, and the CPU also has bi-endian.

No the problem comes in when specifying the toolchains. I understand that I can specify constraints for all things (CPU Architecture, CPU Sub-Architecture, Bit Size, Endianess). It's just the explosion of variations that comes with it. For the CPU architecture, you have possibly x86 and ARM, and then for the sub-architectures you have on the x86 side Sandy Bridge, Knights Landing, etc.

Bit sizes and endianess aside, there's also different "environments", like the firmware (UEFI, BIOS, etc.), kernel-mode code, driver code, user-mode code, etc.

So basically, is there a way to use the platforms workspace for this, can it be cleanly mapped? I know I will have to define a few constraints for the extra features.

Also, how would I manage the various combinations of these items, like UEFI on x86 Sandy Bridge, and U-Boot on ARM Corext-A53 for example? I've been looking at possible ways of doing inheritance inside Starlark for the C++ toolchain rules, but can't seem to find a nice solution, always ending up with a lot of duplication.

silvergasp commented 4 years ago

I would also like to explore this further. I am interested in cortex-m targets. There are a number of optional extensions to the instruction set on cortex-m devices. See here. In particular, DSP and FPU instruction sets. Would the desired method be to add different sub-directories containing constraint values for 'fpu', 'dsp' or 'arbitrary_instruction_set_extension'.

silvergasp commented 4 years ago

Just for reference here is an example of a build file that I have been working on. I understand that there is some interest in centralising these constraints into one repository. What is the intention when it comes to dealing with each subtle difference in architectures. Is there perhaps somewhere this discussion is more active?

constraint_value(
    name = "armv6-m",
    constraint_setting = "@platforms//cpu:cpu",
)

constraint_value(
    name = "armv7-m",
    constraint_setting = "@platforms//cpu:cpu",
)

constraint_value(
    name = "armv7-m-fpu",
    constraint_setting = "@platforms//cpu:cpu",
)

constraint_value(
    name = "armv7e-m",
    constraint_setting = "@platforms//cpu:cpu",
)

constraint_value(
    name = "armv7e-m-fpu",
    constraint_setting = "@platforms//cpu:cpu",
)
yicm commented 4 years ago

As the official document says here : https://docs.bazel.build/versions/3.4.0/platforms.html#generally-useful-constraints-and-platforms .

@silvergasp The goal of this warehouse is to ensure ecological consistency. In addition, with so many non-uniform CPU types, is there a better solution?

Another example is that there are many compiler versions under Linux. Do I need to add another constraint set? How to choose the corresponding compiler version based only on the platform? eg:

constraint_setting(name = "glibc_version")

constraint_value(
    name = "glibc_2_25",
    constraint_setting = ":glibc_version",
)

constraint_value(
    name = "glibc_2_26",
    constraint_setting = ":glibc_version",
)

toolchain(
    name = "barc_linux_toolchain_glibc225",
    exec_compatible_with = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        "glibc_version:glibc_2_25"
    ],
    target_compatible_with = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        "glibc_version:glibc_2_25"
    ],
    toolchain = ":barc_linux",
    toolchain_type = ":toolchain_type",
)

toolchain(
    name = "barc_linux_toolchain_glibc226",
    exec_compatible_with = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        "glibc_version:glibc_2_26"
    ],
    target_compatible_with = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        "glibc_version:glibc_2_26"
    ],
    toolchain = ":barc_linux",
    toolchain_type = ":toolchain_type",
)
wpieterse2825 commented 4 years ago

Hi @yicm and @silvergasp , that's basically what I've ended up with but instead of typing all that out, I made a Starlark macro that iterates over a dictionary of platforms to build those constraint settings and toolchains.

If you need, I can extract the necessary items out of my repository and put it up on GitHub?

yicm commented 4 years ago

@wpieterse2825 If possible, you can provide it, thank you very much!

wpieterse2825 commented 4 years ago

Hi @yicm, I've uploaded it here, have a look.

Also, regarding the strange is_host target in the build folder that only points to Linux and not other platforms, I develop inside a container using the VS Code remote containers extension, this also goes for the usage of the LLVM/Clang tools inside the C++ toolchain scripts.

yicm commented 4 years ago

Hi @wpieterse2825, I have read your code. Your idea is to define the configuration structure DEVICE_CONFIGRATIONS of different CPU architectures, and then realize the automatic generation of constraint sets and tool chains. Here I have a problem. Now that the automated tool chain generation has been realized, the tool chain suite can be generated, and the way of using the platform is more complicated. Because the platform seems to only correspond to one tool chain, it is not very friendly when there are multiple tool chains for one platform. So, do you have any views on the use of the platform under what circumstances?

wpieterse2825 commented 4 years ago

Hi @yicm, that's exactly where I've also hit a speed bump with this solution. I tried creating a macro that will generate transitions for each of the available constraint settings, where I start of the top loop with creating transitions to the architecture, then these sub-targets start a new loop depending on the bit-size, etc. but that turned out to be too unwieldy. I'm really hoping the Bazel team can give us the vision of bazel build //:all and everything works as stated in the configuration road map. I've been following the design docs posted on their proposal repo, and it seems the work is being done, it's just taking time.

As for handling this solution more easily at the moment, I'm also quite stumped, if you have any ideas on how to do this differently, please, share with me, and I'll try to implement a solution, as I'm busy with a type of OS that I want to develop for multiple platforms from the start, using QEmu emulators to test the system on each supported platform.

yicm commented 4 years ago

Hi @wpieterse2825 , I think Bazel itself is not very suitable for compiling C++ projects. For example, the concept of platform, its target level is the platform, and a C++ project has multiple tool chains under the same platform, and sometimes you only need to use a certain tool chain under the platform, and sometimes you need to choose the all tool chains under the platform build project at the same time. Therefore, even if Bazel's platform function can use command bazel build //:all to compile all platforms, it is not very good in some cases.

I have just used Bazel not long ago. This is my opinion. I don't know if it is correct. I hope we can discuss it together ^_^.