diff --git a/clang/docs/Multilib.rst b/clang/docs/Multilib.rst new file mode 100644 --- /dev/null +++ b/clang/docs/Multilib.rst @@ -0,0 +1,170 @@ +======== +Multilib +======== + +Introduction +============ + +This document describes how multilib is implemented in Clang. + +What is multilib and why might you care? +If you're :doc:`cross compiling` then you can't use native +system headers and libraries. To address this, you can use a combination of +``--sysroot``, ``-isystem`` and ``-L`` options to point clang at suitable +directories for your target. +However, when there are many possible directories to choose from, it's not +necessarily obvious which one to pick. +Multilib allows a toolchain designer to imbue the toolchain with the ability to +pick a suitable directory automatically, based on the options the user provides +to clang. For example, if the user specifies +``--target=arm-none-eabi -mcpu=cortex-m4`` the toolchain can choose a directory +containing headers and libraries suitable for Armv7E-M, because it knows that's +a suitable architecture for Arm Cortex-M4. +Multilib can also choose between libraries for the same architecture based on +other options. For example if the user specifies ``-fno-exceptions`` then a +toolchain could select libraries built without exception support, thereby +reducing the size of the resulting binary. + +Design +====== + +Clang supports GCC's ``-print-multi-lib`` and ``-print-multi-directory`` +options. These are described in +`GCC Developer Options `_. + +There are two ways to configure multilib in Clang: hard-coded or via a +configuration file. + +Hard-coded Multilib +=================== + +The available libraries can be hard-coded in clang. Typically this is done +using the ``MultilibBuilder`` interface. There are many examples of this in +``Gnu.cpp``. +The remainder of this document will not focus on this type of multilib. + +Multilib via configuration file +=============================== + +Some clang toolchains support loading multilib configuration from a +``multilib.yaml`` configuration file. + +A ``multilib.yaml`` configuration file specifies which multilib variants are +available, their relative location, what compilation options were used to build +them, and the criteria by which they are selected. + +Multilib processing +=================== + +Clang goes through the following steps to use multilib from a configuration +file: +#. Convert command line arguments to flags. Clang can accept the same + information via different arguments - for example, + ``--target=arm-none-eabi -march=armv7-m`` and + ``--target=armv7m-none-eabi`` are equivalent. Clang can also accept many + independent pieces of information within a single flag - for example + ``-march=armv8.1m.main+fp+mve`` specifies the architecture and two + extensions in a single command line argument. + To make it easier for the multilib system, clang converts the command line + arguments into a standard set of simpler "flags". In many cases these flags + will look like a command line argument with the leading ``-`` stripped off, + but where a suitable form for the flag doesn't exist in command line + arguments then its form will be different. For example, an Arm architecture + extension is represented like ``march=+mve`` since there's no way to specify + it in isolation in a command line argument. + To see what flags are emitted for a given set of command line arguments, use + the ``-print-multi-selection-flags-experimental`` command line argument + along with the rest of the arguments you want to use. +#. Load ``multilib.yaml`` from sysroot. +#. Generate additional flags. ``multilib.yaml`` contains a ``flagMap`` section, + which specifies how to generate additional flags based on the flags derived + from command line arguments. Flags are matched using regular expressions. + These regular expressions shall use the POSIX extended regular expression + syntax. +#. Match flags against multilib variants. If the generated flags are a superset + of the flags specified for a multilib variant then the variant is considered + a match. + If more than one variant matches then a toolchain may opt to either use only + the *last* matching multilib variant, or may use all matching variants, + thereby layering them. +#. Generate ``-isystem`` and ``-L`` arguments. Iterate in reverse order over + the matching multilib variants, and generate ``-isystem`` and ``-L`` + arguments based on each multilib variant directory. + +Stability +========= + +Multilib via configuration file shall be considered an experimental feature +until LLVM 18, at which point ``-print-multi-selection-flags-experimental`` +should be renamed to ``-print-multi-selection-flags``. Once stability is +reached, flags emitted by ``-print-multi-selection-flags`` should not be +removed or changed, although new flags may be added. + +Restrictions +============ + +Despite the name, multilib is used to locate both ``include`` and ``lib`` +directories. Therefore it is important that consistent options are passed to +the clang driver when both compiling and linking. Otherwise inconsistent +``include`` and ``lib`` directories may be used, and the results will be +undefined. + +Example multilib.yaml +===================== + +The below example is intended to be a minimal example of a possible multilib. +For a more comprehensive example see +``clang/test/Driver/Inputs/baremetal_multilib/multilib.yaml`` in the +``llvm-project`` sources. + +.. code-block:: yaml + # multilib.yaml + + # This file is in two parts: + # 1. A list of multilib variants. + # 2. A mapping from flags generated from command line arguments to further + # flags. + + variants: + + # Example of a multilib variant targeting Arm v6-M. + # dir is the relative location of the directory containing the headers + # and/or libraries. + - dir: thumb/v6-m + # If the flags generated by clang from the command line arguments and the + # flagMap below are a superset of {V6} then this multilib variant will be + # considered a match. + flags: [V6] + # If a user invokes clang with -print-multi-lib then the arguments it + # prints will be derived from this. For example: + # thumb/v6-m;@-target=thumbv6m-none-eabi + printArgs: [--target=thumbv6m-none-eabi] + + # Similarly, a multilib variant targeting Arm v7-M with an FPU (floating + # point unit). + - dir: thumb/v7-m + # Here, the flags generated by clang must be a superset of + # {V7orLater, hasFPU} for this multilib variant to be a match. + flags: [V7orLater, hasFPU] + printArgs: [--target=thumbv7m-none-eabi, -mfpu=fpv4-sp-d16] + + # The second section of the file is a map from auto-detected flags + # to custom flags. + # The regex must match a whole flag string. + # "matchFlags" flags will be added if an argument matches, while + # "noMatchFlags" flags will be added otherwise. + flagMap: + + # Set a "V6" flag if the regular expression matches any of the flags + # generated from the command line arguments. + - regex: target=thumbv6m-.* + matchFlags: [V6] + + # Set a "V7orLater" flag if the regular expression matches any of the flags + # generated from the command line arguments. + - regex: target=thumbv[7-9].* + matchFlags: [V7orLater] + + # Example of noMatchFlags - set hasFPU if mfpu=none *doesn't* match. + - regex: mfpu=none + noMatchFlags: [hasFPU] diff --git a/clang/docs/index.rst b/clang/docs/index.rst --- a/clang/docs/index.rst +++ b/clang/docs/index.rst @@ -100,6 +100,7 @@ CodeOwners InternalsManual DriverInternals + Multilib OffloadingDesign PCHInternals ItaniumMangleAbiTags