diff mbox series

[1/2] package/gcc/gcc-bpf: add BPF target support

Message ID 20220809094109.2279598-1-james.hilliard1@gmail.com
State Changes Requested
Headers show
Series [1/2] package/gcc/gcc-bpf: add BPF target support | expand

Commit Message

James Hilliard Aug. 9, 2022, 9:41 a.m. UTC
This adds GCC BPF target support, however unlike traditional targets
the BPF target is effectively used by packages such as systemd as
a separate language rather than an entirely separate architecture.

As such we need to build what is effectively a multi-arch toolchain
for GCC BPF support, as the BPF target is effectively a bare metal
target this isn't the same as a multi-lib toolchain and generally
avoids library conflict issues as the BPF target does not have
userspace libraries.

This adds an additional gcc build stage which is similar to gcc-final
and added as a toolchain dependency when BPF target support is
enabled.

Similar to our gcc toolchain we also need a toolchain wrapper, this
is separate from our normal toolchain wrapper.

Cc: Jose E. Marchesi <jose.marchesi@oracle.com>
Cc: David Faust <david.faust@oracle.com>
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
 package/Makefile.in                           |   3 +
 package/gcc/Config.in.host                    |  12 ++
 package/gcc/gcc-bpf/gcc-bpf.hash              |   1 +
 package/gcc/gcc-bpf/gcc-bpf.mk                | 116 ++++++++++++++++++
 .../toolchain-buildroot.mk                    |   4 +
 5 files changed, 136 insertions(+)
 create mode 120000 package/gcc/gcc-bpf/gcc-bpf.hash
 create mode 100644 package/gcc/gcc-bpf/gcc-bpf.mk

Comments

Arnout Vandecappelle Sept. 30, 2023, 3:06 p.m. UTC | #1
Hi James,

  After more than a year we're finally getting back to this patch...

On 09/08/2022 11:41, James Hilliard wrote:
> This adds GCC BPF target support, however unlike traditional targets
> the BPF target is effectively used by packages such as systemd as
> a separate language rather than an entirely separate architecture.

  I looked at the systemd mesonfile and it looks like it unconditionally uses 
gcc-bpf if it can find bpf-none-gcc in PATH. That's annoying, because it means 
that currently, it'll already use it if it is installed in /usr/bin... Ideally 
we should enable/disable it in systemd dependin on whether gcc-bpf is enabled or 
not.

> As such we need to build what is effectively a multi-arch toolchain

  It's not really a toolchain because there's no libc, just the compiler itself...

> for GCC BPF support, as the BPF target is effectively a bare metal
> target this isn't the same as a multi-lib toolchain and generally
> avoids library conflict issues as the BPF target does not have
> userspace libraries.

  ... which you already say here :-)


> This adds an additional gcc build stage which is similar to gcc-final
> and added as a toolchain dependency when BPF target support is
> enabled.

  I don't see why this is an additional gcc build stage. It seems to me that 
gcc-bpf shouldn't need a dependency on libc or on host-gcc-initial. It probably 
_does_ have a dependency on kernel headers though...


> Similar to our gcc toolchain we also need a toolchain wrapper, this
> is separate from our normal toolchain wrapper.

  Are you sure this toolchain wrapper is needed? Most of the fixups that are 
applied by the wrapper relate to the target architecture options - -march, 
-mtune, etc. I would expect that those would simply break gcc-bpf entirely... 
Other options are for optimisation, debugging, hardening, etc. I'm not sure if 
it's a good idea to apply those when compiling to BPF either. Then there's 
pointing to the sysroot - given that this is a bare metal toolchain, it 
shouldn't be needed. And finally there is ccache, which I'm also not sure of if 
it's going to work well with BPF code generation.

  So I'm thinking that the wrapper should perhaps be skipped here.


> Cc: Jose E. Marchesi <jose.marchesi@oracle.com>
> Cc: David Faust <david.faust@oracle.com>
> Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
> ---
>   package/Makefile.in                           |   3 +
>   package/gcc/Config.in.host                    |  12 ++
>   package/gcc/gcc-bpf/gcc-bpf.hash              |   1 +
>   package/gcc/gcc-bpf/gcc-bpf.mk                | 116 ++++++++++++++++++
>   .../toolchain-buildroot.mk                    |   4 +
>   5 files changed, 136 insertions(+)
>   create mode 120000 package/gcc/gcc-bpf/gcc-bpf.hash
>   create mode 100644 package/gcc/gcc-bpf/gcc-bpf.mk
> 
> diff --git a/package/Makefile.in b/package/Makefile.in
> index ff60f85092..a6f5292903 100644
> --- a/package/Makefile.in
> +++ b/package/Makefile.in
> @@ -39,6 +39,9 @@ endif
>   # Compute GNU_TARGET_NAME
>   GNU_TARGET_NAME = $(ARCH)-$(TARGET_VENDOR)-$(TARGET_OS)-$(LIBC)$(ABI)
>   
> +# Compute BPF_TARGET_NAME
> +BPF_TARGET_NAME = bpf-$(TARGET_VENDOR)-none
> +
>   # FLAT binary format needs uclinux, except RISC-V 64-bits which needs
>   # the regular linux name.
>   ifeq ($(BR2_BINFMT_FLAT):$(BR2_RISCV_64),y:)
> diff --git a/package/gcc/Config.in.host b/package/gcc/Config.in.host
> index ba2a2ee072..c49f6e6b26 100644
> --- a/package/gcc/Config.in.host
> +++ b/package/gcc/Config.in.host
> @@ -60,6 +60,10 @@ config BR2_GCC_VERSION_12_X
>   
>   endchoice
>   
> +config BR2_GCC_SUPPORTS_BPF
> +	bool
> +	default y if BR2_TOOLCHAIN_GCC_AT_LEAST_12
> +
>   # libcilkrts was introduced in gcc 4.9 and removed in gcc 8.x
>   config BR2_GCC_SUPPORTS_LIBCILKRTS
>   	bool
> @@ -94,6 +98,14 @@ config BR2_EXTRA_GCC_CONFIG_OPTIONS
>   	  include. Those options are applied for all of the gcc
>   	  initial, gcc intermediate and gcc final passes.
>   
> +config BR2_TOOLCHAIN_BUILDROOT_BPF
> +	bool "Enable bpf support"
> +	depends on BR2_GCC_SUPPORTS_BPF
> +	depends on BR2_PACKAGE_HOST_BINUTILS_SUPPORTS_BPF
> +	help
> +	  Enable this option if you want your toolchain to support BPF
> +	  targets.

  This only allows us to use gcc-bpf with an internal toolchain. In general, we 
want that any feature exposed by the internal toolchain is also available in a 
(custom) external toolchain.

  However, for gcc-bpf, I don't think it needs to be tied to the internal 
toolchain at all. For me, it makes more sense to have it as a seperate package, 
unrelated to gcc, with a fixed version. Having these selectable versions is 
anyway a pain :-). And I don't think there's any reason to need to link the 
version of gcc-bpf with gcc-target.

  So I would propose to make gcc-bpf a completely new package with no 
relationship with gcc at all.

> +
>   config BR2_TOOLCHAIN_BUILDROOT_CXX
>   	bool "Enable C++ support"
>   	select BR2_INSTALL_LIBSTDCPP
> diff --git a/package/gcc/gcc-bpf/gcc-bpf.hash b/package/gcc/gcc-bpf/gcc-bpf.hash
> new file mode 120000
> index 0000000000..7ac9361ab2
> --- /dev/null
> +++ b/package/gcc/gcc-bpf/gcc-bpf.hash
> @@ -0,0 +1 @@
> +../gcc.hash
> \ No newline at end of file
> diff --git a/package/gcc/gcc-bpf/gcc-bpf.mk b/package/gcc/gcc-bpf/gcc-bpf.mk
> new file mode 100644
> index 0000000000..b12d27ad00
> --- /dev/null
> +++ b/package/gcc/gcc-bpf/gcc-bpf.mk
> @@ -0,0 +1,116 @@
> +################################################################################
> +#
> +# gcc-bpf
> +#
> +################################################################################
> +
> +GCC_BPF_VERSION = $(GCC_VERSION)
> +GCC_BPF_SITE = $(GCC_SITE)
> +GCC_BPF_SOURCE = $(GCC_SOURCE)
> +
> +HOST_GCC_BPF_DL_SUBDIR = gcc
> +
> +HOST_GCC_BPF_DEPENDENCIES = \
> +	$(HOST_GCC_COMMON_DEPENDENCIES) \

  I don't think all of those dependencies apply. For sure host-binutils 
shouldn't be needed for gcc-bpf, only host-binutils-bpf, no? And even on a FLAT 
target I don't think elf2flt should be needed.

> +	$(BR_LIBC)

  As I wrote earlier, I don't see why it should depend on libc.

> +
> +HOST_GCC_BPF_EXCLUDES = $(HOST_GCC_EXCLUDES)
> +
> +HOST_GCC_BPF_POST_PATCH_HOOKS += HOST_GCC_APPLY_PATCHES

  If it's a separate package with a different version, this isn't needed either.

> +
> +# gcc doesn't support in-tree build, so we create a 'build'
> +# subdirectory in the gcc sources, and build from there.
> +HOST_GCC_BPF_SUBDIR = build
> +
> +HOST_GCC_BPF_PRE_CONFIGURE_HOOKS += HOST_GCC_CONFIGURE_SYMLINK
> +
> +HOST_GCC_BPF_CONF_OPTS = \
> +	--target=$(BPF_TARGET_NAME) \
> +	--prefix="$(HOST_DIR)" \
> +	--sysconfdir="$(HOST_DIR)/etc" \
> +	--enable-languages=c \
> +	--with-gnu-ld \
> +	--enable-static \
> +	--disable-decimal-float \
> +	--disable-gcov \
> +	--disable-libssp \
> +	--disable-multilib \
> +	--disable-shared \
> +	--with-gmp=$(HOST_DIR) \
> +	--with-mpc=$(HOST_DIR) \
> +	--with-mpfr=$(HOST_DIR) \
> +	--with-pkgversion="Buildroot $(BR2_VERSION_FULL)" \
> +	--with-bugurl="http://bugs.buildroot.net/" \
> +	--without-zstd \
> +	$(call qstrip,$(BR2_EXTRA_GCC_CONFIG_OPTIONS))
> +
> +ifeq ($(BR2_GCC_ENABLE_GRAPHITE),y)
> +HOST_GCC_BPF_DEPENDENCIES += host-isl
> +HOST_GCC_BPF_CONF_OPTS += --with-isl=$(HOST_DIR)
> +else
> +HOST_GCC_BPF_CONF_OPTS += --without-isl --without-cloog
> +endif

  I think it's very unlikely that it's worth enabling graphite for BPF code 
generation... I wouldn't bother with this.


> +# Don't build documentation. It takes up extra space / build time,
> +# and sometimes needs specific makeinfo versions to work
> +HOST_GCC_BPF_CONF_ENV = \
> +	MAKEINFO=missing
> +
> +# Make sure we have 'cc'
> +define HOST_GCC_BPF_CREATE_CC_SYMLINKS
> +	if [ ! -e $(HOST_DIR)/bin/$(BPF_TARGET_NAME)-cc ]; then \
> +		ln -f $(HOST_DIR)/bin/$(BPF_TARGET_NAME)-gcc \
> +			$(HOST_DIR)/bin/$(BPF_TARGET_NAME)-cc; \

  I don't think there's anything that actually needs or uses the bpf-none-cc 
symlink. At least in systemd, there's explicit logic for clang and for gcc, 
there's no use of -cc.

> +	fi
> +endef
> +
> +HOST_GCC_BPF_POST_INSTALL_HOOKS += HOST_GCC_BPF_CREATE_CC_SYMLINKS
> +
> +HOST_GCC_BPF_MAKE_OPTS = $(HOST_GCC_COMMON_MAKE_OPTS) all-gcc all-target-libgcc

  The common opts are just gcc_cv_libc_provides_ssp=yes/no. Again, I don't think 
we should necessarily apply the global SSP option to BPF. SSP for BPF sounds 
slightly ridiculous...

> +HOST_GCC_BPF_INSTALL_OPTS = install-gcc install-target-libgcc
> +
> +HOST_GCC_BPF_TOOLCHAIN_WRAPPER_ARGS = -DBR_SYSROOT='"$(STAGING_SUBDIR)"'
> +HOST_GCC_BPF_TOOLCHAIN_WRAPPER_ARGS += $(HOST_GCC_COMMON_TOOLCHAIN_WRAPPER_ARGS)
> +
> +define HOST_GCC_BPF_TOOLCHAIN_WRAPPER_BUILD
> +	$(HOSTCC) $(HOST_CFLAGS) $(HOST_GCC_BPF_TOOLCHAIN_WRAPPER_ARGS) \
> +		-s -Wl,--hash-style=$(TOOLCHAIN_WRAPPER_HASH_STYLE) \
> +		toolchain/toolchain-wrapper.c \
> +		-o $(@D)/toolchain-wrapper-bpf
> +endef
> +
> +define HOST_GCC_BPF_TOOLCHAIN_WRAPPER_INSTALL
> +	$(INSTALL) -D -m 0755 $(@D)/toolchain-wrapper-bpf \
> +		$(HOST_DIR)/bin/toolchain-wrapper-bpf
> +endef
> +
> +HOST_GCC_BPF_POST_BUILD_HOOKS += HOST_GCC_BPF_TOOLCHAIN_WRAPPER_BUILD
> +HOST_GCC_BPF_POST_INSTALL_HOOKS += HOST_GCC_BPF_TOOLCHAIN_WRAPPER_INSTALL
> +
> +define HOST_GCC_BPF_INSTALL_WRAPPER_AND_SIMPLE_SYMLINKS
> +	$(Q)cd $(HOST_DIR)/bin; \
> +	for i in $(BPF_TARGET_NAME)-*; do \
> +		case "$$i" in \
> +		*.br_real) \
> +			;; \
> +		*-ar|*-ranlib|*-nm) \
> +			ln -snf $$i bpf$${i##$(BPF_TARGET_NAME)}; \
> +			;; \
> +		*cc|*cc-*|*++|*++-*|*cpp|*-gfortran|*-gdc) \
> +			rm -f $$i.br_real; \
> +			mv $$i $$i.br_real; \
> +			ln -sf toolchain-wrapper-bpf $$i; \
> +			ln -sf toolchain-wrapper-bpf bpf$${i##$(BPF_TARGET_NAME)}; \
> +			ln -snf $$i.br_real bpf$${i##$(BPF_TARGET_NAME)}.br_real; \
> +			;; \
> +		*) \
> +			ln -snf $$i bpf$${i##$(BPF_TARGET_NAME)}; \
> +			;; \
> +		esac; \
> +	done
> +
> +endef
> +
> +HOST_GCC_BPF_POST_INSTALL_HOOKS += HOST_GCC_BPF_INSTALL_WRAPPER_AND_SIMPLE_SYMLINKS
> +
> +$(eval $(host-autotools-package))
> diff --git a/toolchain/toolchain-buildroot/toolchain-buildroot.mk b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
> index b30cc332d2..34e7e49a5f 100644
> --- a/toolchain/toolchain-buildroot/toolchain-buildroot.mk
> +++ b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
> @@ -12,6 +12,10 @@ BR_LIBC = $(call qstrip,$(BR2_TOOLCHAIN_BUILDROOT_LIBC))
>   
>   TOOLCHAIN_BUILDROOT_DEPENDENCIES = host-gcc-final
>   
> +ifeq ($(BR2_TOOLCHAIN_BUILDROOT_BPF),y)
> +TOOLCHAIN_BUILDROOT_DEPENDENCIES += host-gcc-bpf

  I don't think it's appropriate at all to build this as a dependency of the 
toolchain. Nothing is going to use it unless it has specific handling for it - 
like systemd. So the proper approach is to add it as a dependency to systemd.

  I also don't really think it should be an option. An option in systemd maybe, 
but not a buildroot-level option.

  Regards,
  Arnout

> +endif
> +
>   TOOLCHAIN_BUILDROOT_ADD_TOOLCHAIN_DEPENDENCY = NO
>   
>   $(eval $(virtual-package))
James Hilliard Sept. 30, 2023, 3:56 p.m. UTC | #2
On Sat, Sep 30, 2023 at 9:06 AM Arnout Vandecappelle <arnout@mind.be> wrote:
>
>   Hi James,
>
>   After more than a year we're finally getting back to this patch...
>
> On 09/08/2022 11:41, James Hilliard wrote:
> > This adds GCC BPF target support, however unlike traditional targets
> > the BPF target is effectively used by packages such as systemd as
> > a separate language rather than an entirely separate architecture.
>
>   I looked at the systemd mesonfile and it looks like it unconditionally uses
> gcc-bpf if it can find bpf-none-gcc in PATH. That's annoying, because it means
> that currently, it'll already use it if it is installed in /usr/bin... Ideally
> we should enable/disable it in systemd dependin on whether gcc-bpf is enabled or
> not.

Actually it won't since it will only try to use clang unless you set
-Dbpf-compiler=gcc,
https://github.com/systemd/systemd/blob/v254/meson.build#L1093

Probably a good idea to explicitly disable for now with -Dbpf-framework=false as
that could actually be an issue with clang.

>
> > As such we need to build what is effectively a multi-arch toolchain
>
>   It's not really a toolchain because there's no libc, just the compiler itself...

I recall it does make use of a static libgcc.a or something like that,
not a full
libc AFAIU but there are some issues with handling linking still.

>
> > for GCC BPF support, as the BPF target is effectively a bare metal
> > target this isn't the same as a multi-lib toolchain and generally
> > avoids library conflict issues as the BPF target does not have
> > userspace libraries.
>
>   ... which you already say here :-)
>
>
> > This adds an additional gcc build stage which is similar to gcc-final
> > and added as a toolchain dependency when BPF target support is
> > enabled.
>
>   I don't see why this is an additional gcc build stage. It seems to me that
> gcc-bpf shouldn't need a dependency on libc or on host-gcc-initial. It probably
> _does_ have a dependency on kernel headers though...

Hmm, not entirely sure on the libc dependency, I think I have it depending on
host-gcc-initial so that it's built similar to host-gcc-final.

>
>
> > Similar to our gcc toolchain we also need a toolchain wrapper, this
> > is separate from our normal toolchain wrapper.
>
>   Are you sure this toolchain wrapper is needed? Most of the fixups that are
> applied by the wrapper relate to the target architecture options - -march,
> -mtune, etc. I would expect that those would simply break gcc-bpf entirely...
> Other options are for optimisation, debugging, hardening, etc. I'm not sure if
> it's a good idea to apply those when compiling to BPF either. Then there's
> pointing to the sysroot - given that this is a bare metal toolchain, it
> shouldn't be needed. And finally there is ccache, which I'm also not sure of if
> it's going to work well with BPF code generation.

Isn't the toolchain wrapper needed to make sure it work when bundled as part
of an external toolchain?

>
>   So I'm thinking that the wrapper should perhaps be skipped here.
>
>
> > Cc: Jose E. Marchesi <jose.marchesi@oracle.com>
> > Cc: David Faust <david.faust@oracle.com>
> > Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
> > ---
> >   package/Makefile.in                           |   3 +
> >   package/gcc/Config.in.host                    |  12 ++
> >   package/gcc/gcc-bpf/gcc-bpf.hash              |   1 +
> >   package/gcc/gcc-bpf/gcc-bpf.mk                | 116 ++++++++++++++++++
> >   .../toolchain-buildroot.mk                    |   4 +
> >   5 files changed, 136 insertions(+)
> >   create mode 120000 package/gcc/gcc-bpf/gcc-bpf.hash
> >   create mode 100644 package/gcc/gcc-bpf/gcc-bpf.mk
> >
> > diff --git a/package/Makefile.in b/package/Makefile.in
> > index ff60f85092..a6f5292903 100644
> > --- a/package/Makefile.in
> > +++ b/package/Makefile.in
> > @@ -39,6 +39,9 @@ endif
> >   # Compute GNU_TARGET_NAME
> >   GNU_TARGET_NAME = $(ARCH)-$(TARGET_VENDOR)-$(TARGET_OS)-$(LIBC)$(ABI)
> >
> > +# Compute BPF_TARGET_NAME
> > +BPF_TARGET_NAME = bpf-$(TARGET_VENDOR)-none
> > +
> >   # FLAT binary format needs uclinux, except RISC-V 64-bits which needs
> >   # the regular linux name.
> >   ifeq ($(BR2_BINFMT_FLAT):$(BR2_RISCV_64),y:)
> > diff --git a/package/gcc/Config.in.host b/package/gcc/Config.in.host
> > index ba2a2ee072..c49f6e6b26 100644
> > --- a/package/gcc/Config.in.host
> > +++ b/package/gcc/Config.in.host
> > @@ -60,6 +60,10 @@ config BR2_GCC_VERSION_12_X
> >
> >   endchoice
> >
> > +config BR2_GCC_SUPPORTS_BPF
> > +     bool
> > +     default y if BR2_TOOLCHAIN_GCC_AT_LEAST_12
> > +
> >   # libcilkrts was introduced in gcc 4.9 and removed in gcc 8.x
> >   config BR2_GCC_SUPPORTS_LIBCILKRTS
> >       bool
> > @@ -94,6 +98,14 @@ config BR2_EXTRA_GCC_CONFIG_OPTIONS
> >         include. Those options are applied for all of the gcc
> >         initial, gcc intermediate and gcc final passes.
> >
> > +config BR2_TOOLCHAIN_BUILDROOT_BPF
> > +     bool "Enable bpf support"
> > +     depends on BR2_GCC_SUPPORTS_BPF
> > +     depends on BR2_PACKAGE_HOST_BINUTILS_SUPPORTS_BPF
> > +     help
> > +       Enable this option if you want your toolchain to support BPF
> > +       targets.
>
>   This only allows us to use gcc-bpf with an internal toolchain. In general, we
> want that any feature exposed by the internal toolchain is also available in a
> (custom) external toolchain.

Yeah, I hadn't looked at exactly how it would work as part of an
external toolchain
but one reason I was having it part of the toolchain build is so that
it can be used
to build a toolchain with bpf support.

>
>   However, for gcc-bpf, I don't think it needs to be tied to the internal
> toolchain at all. For me, it makes more sense to have it as a seperate package,
> unrelated to gcc, with a fixed version. Having these selectable versions is
> anyway a pain :-). And I don't think there's any reason to need to link the
> version of gcc-bpf with gcc-target.

I think I did it this way mostly for consistency, I mean if you're downloading
an external toolchain with a specific gcc version it would be a bit unexpected
if say the gcc-bpf compiler was a different version from the rest of the gcc
toolchain.

>
>   So I would propose to make gcc-bpf a completely new package with no
> relationship with gcc at all.

Would that approach still allow us to generate toolchains with gcc-bpf?

>
> > +
> >   config BR2_TOOLCHAIN_BUILDROOT_CXX
> >       bool "Enable C++ support"
> >       select BR2_INSTALL_LIBSTDCPP
> > diff --git a/package/gcc/gcc-bpf/gcc-bpf.hash b/package/gcc/gcc-bpf/gcc-bpf.hash
> > new file mode 120000
> > index 0000000000..7ac9361ab2
> > --- /dev/null
> > +++ b/package/gcc/gcc-bpf/gcc-bpf.hash
> > @@ -0,0 +1 @@
> > +../gcc.hash
> > \ No newline at end of file
> > diff --git a/package/gcc/gcc-bpf/gcc-bpf.mk b/package/gcc/gcc-bpf/gcc-bpf.mk
> > new file mode 100644
> > index 0000000000..b12d27ad00
> > --- /dev/null
> > +++ b/package/gcc/gcc-bpf/gcc-bpf.mk
> > @@ -0,0 +1,116 @@
> > +################################################################################
> > +#
> > +# gcc-bpf
> > +#
> > +################################################################################
> > +
> > +GCC_BPF_VERSION = $(GCC_VERSION)
> > +GCC_BPF_SITE = $(GCC_SITE)
> > +GCC_BPF_SOURCE = $(GCC_SOURCE)
> > +
> > +HOST_GCC_BPF_DL_SUBDIR = gcc
> > +
> > +HOST_GCC_BPF_DEPENDENCIES = \
> > +     $(HOST_GCC_COMMON_DEPENDENCIES) \
>
>   I don't think all of those dependencies apply. For sure host-binutils
> shouldn't be needed for gcc-bpf, only host-binutils-bpf, no? And even on a FLAT
> target I don't think elf2flt should be needed.
>
> > +     $(BR_LIBC)
>
>   As I wrote earlier, I don't see why it should depend on libc.
>
> > +
> > +HOST_GCC_BPF_EXCLUDES = $(HOST_GCC_EXCLUDES)
> > +
> > +HOST_GCC_BPF_POST_PATCH_HOOKS += HOST_GCC_APPLY_PATCHES
>
>   If it's a separate package with a different version, this isn't needed either.
>
> > +
> > +# gcc doesn't support in-tree build, so we create a 'build'
> > +# subdirectory in the gcc sources, and build from there.
> > +HOST_GCC_BPF_SUBDIR = build
> > +
> > +HOST_GCC_BPF_PRE_CONFIGURE_HOOKS += HOST_GCC_CONFIGURE_SYMLINK
> > +
> > +HOST_GCC_BPF_CONF_OPTS = \
> > +     --target=$(BPF_TARGET_NAME) \
> > +     --prefix="$(HOST_DIR)" \
> > +     --sysconfdir="$(HOST_DIR)/etc" \
> > +     --enable-languages=c \
> > +     --with-gnu-ld \
> > +     --enable-static \
> > +     --disable-decimal-float \
> > +     --disable-gcov \
> > +     --disable-libssp \
> > +     --disable-multilib \
> > +     --disable-shared \
> > +     --with-gmp=$(HOST_DIR) \
> > +     --with-mpc=$(HOST_DIR) \
> > +     --with-mpfr=$(HOST_DIR) \
> > +     --with-pkgversion="Buildroot $(BR2_VERSION_FULL)" \
> > +     --with-bugurl="http://bugs.buildroot.net/" \
> > +     --without-zstd \
> > +     $(call qstrip,$(BR2_EXTRA_GCC_CONFIG_OPTIONS))
> > +
> > +ifeq ($(BR2_GCC_ENABLE_GRAPHITE),y)
> > +HOST_GCC_BPF_DEPENDENCIES += host-isl
> > +HOST_GCC_BPF_CONF_OPTS += --with-isl=$(HOST_DIR)
> > +else
> > +HOST_GCC_BPF_CONF_OPTS += --without-isl --without-cloog
> > +endif
>
>   I think it's very unlikely that it's worth enabling graphite for BPF code
> generation... I wouldn't bother with this.
>
>
> > +# Don't build documentation. It takes up extra space / build time,
> > +# and sometimes needs specific makeinfo versions to work
> > +HOST_GCC_BPF_CONF_ENV = \
> > +     MAKEINFO=missing
> > +
> > +# Make sure we have 'cc'
> > +define HOST_GCC_BPF_CREATE_CC_SYMLINKS
> > +     if [ ! -e $(HOST_DIR)/bin/$(BPF_TARGET_NAME)-cc ]; then \
> > +             ln -f $(HOST_DIR)/bin/$(BPF_TARGET_NAME)-gcc \
> > +                     $(HOST_DIR)/bin/$(BPF_TARGET_NAME)-cc; \
>
>   I don't think there's anything that actually needs or uses the bpf-none-cc
> symlink. At least in systemd, there's explicit logic for clang and for gcc,
> there's no use of -cc.

I recall I did this just for consistency.

>
> > +     fi
> > +endef
> > +
> > +HOST_GCC_BPF_POST_INSTALL_HOOKS += HOST_GCC_BPF_CREATE_CC_SYMLINKS
> > +
> > +HOST_GCC_BPF_MAKE_OPTS = $(HOST_GCC_COMMON_MAKE_OPTS) all-gcc all-target-libgcc
>
>   The common opts are just gcc_cv_libc_provides_ssp=yes/no. Again, I don't think
> we should necessarily apply the global SSP option to BPF. SSP for BPF sounds
> slightly ridiculous...
>
> > +HOST_GCC_BPF_INSTALL_OPTS = install-gcc install-target-libgcc
> > +
> > +HOST_GCC_BPF_TOOLCHAIN_WRAPPER_ARGS = -DBR_SYSROOT='"$(STAGING_SUBDIR)"'
> > +HOST_GCC_BPF_TOOLCHAIN_WRAPPER_ARGS += $(HOST_GCC_COMMON_TOOLCHAIN_WRAPPER_ARGS)
> > +
> > +define HOST_GCC_BPF_TOOLCHAIN_WRAPPER_BUILD
> > +     $(HOSTCC) $(HOST_CFLAGS) $(HOST_GCC_BPF_TOOLCHAIN_WRAPPER_ARGS) \
> > +             -s -Wl,--hash-style=$(TOOLCHAIN_WRAPPER_HASH_STYLE) \
> > +             toolchain/toolchain-wrapper.c \
> > +             -o $(@D)/toolchain-wrapper-bpf
> > +endef
> > +
> > +define HOST_GCC_BPF_TOOLCHAIN_WRAPPER_INSTALL
> > +     $(INSTALL) -D -m 0755 $(@D)/toolchain-wrapper-bpf \
> > +             $(HOST_DIR)/bin/toolchain-wrapper-bpf
> > +endef
> > +
> > +HOST_GCC_BPF_POST_BUILD_HOOKS += HOST_GCC_BPF_TOOLCHAIN_WRAPPER_BUILD
> > +HOST_GCC_BPF_POST_INSTALL_HOOKS += HOST_GCC_BPF_TOOLCHAIN_WRAPPER_INSTALL
> > +
> > +define HOST_GCC_BPF_INSTALL_WRAPPER_AND_SIMPLE_SYMLINKS
> > +     $(Q)cd $(HOST_DIR)/bin; \
> > +     for i in $(BPF_TARGET_NAME)-*; do \
> > +             case "$$i" in \
> > +             *.br_real) \
> > +                     ;; \
> > +             *-ar|*-ranlib|*-nm) \
> > +                     ln -snf $$i bpf$${i##$(BPF_TARGET_NAME)}; \
> > +                     ;; \
> > +             *cc|*cc-*|*++|*++-*|*cpp|*-gfortran|*-gdc) \
> > +                     rm -f $$i.br_real; \
> > +                     mv $$i $$i.br_real; \
> > +                     ln -sf toolchain-wrapper-bpf $$i; \
> > +                     ln -sf toolchain-wrapper-bpf bpf$${i##$(BPF_TARGET_NAME)}; \
> > +                     ln -snf $$i.br_real bpf$${i##$(BPF_TARGET_NAME)}.br_real; \
> > +                     ;; \
> > +             *) \
> > +                     ln -snf $$i bpf$${i##$(BPF_TARGET_NAME)}; \
> > +                     ;; \
> > +             esac; \
> > +     done
> > +
> > +endef
> > +
> > +HOST_GCC_BPF_POST_INSTALL_HOOKS += HOST_GCC_BPF_INSTALL_WRAPPER_AND_SIMPLE_SYMLINKS
> > +
> > +$(eval $(host-autotools-package))
> > diff --git a/toolchain/toolchain-buildroot/toolchain-buildroot.mk b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
> > index b30cc332d2..34e7e49a5f 100644
> > --- a/toolchain/toolchain-buildroot/toolchain-buildroot.mk
> > +++ b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
> > @@ -12,6 +12,10 @@ BR_LIBC = $(call qstrip,$(BR2_TOOLCHAIN_BUILDROOT_LIBC))
> >
> >   TOOLCHAIN_BUILDROOT_DEPENDENCIES = host-gcc-final
> >
> > +ifeq ($(BR2_TOOLCHAIN_BUILDROOT_BPF),y)
> > +TOOLCHAIN_BUILDROOT_DEPENDENCIES += host-gcc-bpf
>
>   I don't think it's appropriate at all to build this as a dependency of the
> toolchain. Nothing is going to use it unless it has specific handling for it -
> like systemd. So the proper approach is to add it as a dependency to systemd.
>
>   I also don't really think it should be an option. An option in systemd maybe,
> but not a buildroot-level option.

Don't we need it as an option for building toolchains with gcc-bpf support?

>
>   Regards,
>   Arnout
>
> > +endif
> > +
> >   TOOLCHAIN_BUILDROOT_ADD_TOOLCHAIN_DEPENDENCY = NO
> >
> >   $(eval $(virtual-package))
Arnout Vandecappelle Sept. 30, 2023, 4:26 p.m. UTC | #3
Hi James,

On 30/09/2023 17:56, James Hilliard wrote:
> On Sat, Sep 30, 2023 at 9:06 AM Arnout Vandecappelle <arnout@mind.be> wrote:
>>
>>    Hi James,
>>
>>    After more than a year we're finally getting back to this patch...
>>
>> On 09/08/2022 11:41, James Hilliard wrote:
>>> This adds GCC BPF target support, however unlike traditional targets
>>> the BPF target is effectively used by packages such as systemd as
>>> a separate language rather than an entirely separate architecture.
>>
>>    I looked at the systemd mesonfile and it looks like it unconditionally uses
>> gcc-bpf if it can find bpf-none-gcc in PATH. That's annoying, because it means
>> that currently, it'll already use it if it is installed in /usr/bin... Ideally
>> we should enable/disable it in systemd dependin on whether gcc-bpf is enabled or
>> not.
> 
> Actually it won't since it will only try to use clang unless you set
> -Dbpf-compiler=gcc,
> https://github.com/systemd/systemd/blob/v254/meson.build#L1093

  Yes indeed, it seems to default to clang, I had missed that.


> Probably a good idea to explicitly disable for now with -Dbpf-framework=false as
> that could actually be an issue with clang.

  Indeed.


>>> As such we need to build what is effectively a multi-arch toolchain
>>
>>    It's not really a toolchain because there's no libc, just the compiler itself...
> 
> I recall it does make use of a static libgcc.a or something like that,
> not a full
> libc AFAIU but there are some issues with handling linking still.

  libgcc is part of gcc (obviously).

  libc isn't built for BPF so there would be no point depending on it.


>>> for GCC BPF support, as the BPF target is effectively a bare metal
>>> target this isn't the same as a multi-lib toolchain and generally
>>> avoids library conflict issues as the BPF target does not have
>>> userspace libraries.
>>
>>    ... which you already say here :-)
>>
>>
>>> This adds an additional gcc build stage which is similar to gcc-final
>>> and added as a toolchain dependency when BPF target support is
>>> enabled.
>>
>>    I don't see why this is an additional gcc build stage. It seems to me that
>> gcc-bpf shouldn't need a dependency on libc or on host-gcc-initial. It probably
>> _does_ have a dependency on kernel headers though...
> 
> Hmm, not entirely sure on the libc dependency, I think I have it depending on
> host-gcc-initial so that it's built similar to host-gcc-final.
> 
>>
>>
>>> Similar to our gcc toolchain we also need a toolchain wrapper, this
>>> is separate from our normal toolchain wrapper.
>>
>>    Are you sure this toolchain wrapper is needed? Most of the fixups that are
>> applied by the wrapper relate to the target architecture options - -march,
>> -mtune, etc. I would expect that those would simply break gcc-bpf entirely...
>> Other options are for optimisation, debugging, hardening, etc. I'm not sure if
>> it's a good idea to apply those when compiling to BPF either. Then there's
>> pointing to the sysroot - given that this is a bare metal toolchain, it
>> shouldn't be needed. And finally there is ccache, which I'm also not sure of if
>> it's going to work well with BPF code generation.
> 
> Isn't the toolchain wrapper needed to make sure it work when bundled as part
> of an external toolchain?

  No, not at all. In fact, the wrapper is in the way when you use it as an 
external toolchain, and we have special handling for that case.

[snip]
>>    However, for gcc-bpf, I don't think it needs to be tied to the internal
>> toolchain at all. For me, it makes more sense to have it as a seperate package,
>> unrelated to gcc, with a fixed version. Having these selectable versions is
>> anyway a pain :-). And I don't think there's any reason to need to link the
>> version of gcc-bpf with gcc-target.
> 
> I think I did it this way mostly for consistency, I mean if you're downloading
> an external toolchain with a specific gcc version it would be a bit unexpected
> if say the gcc-bpf compiler was a different version from the rest of the gcc
> toolchain.

  I think it's a mistake to think of gcc-bpf as part of the toolchain. Even if 
you build systemd with gcc, you can still easily use clang-bpf to build the BPF 
stuff. This already indicates that the bpf compiler is not part of the 
toolchain. You could also compare it to the ti-cgt-pru compiler for the PRU 
controller: it's just a compiler for something else than our target, so it has 
no real relationship with the toolchain.


  Regards,
  Arnout


[snip]
James Hilliard Sept. 30, 2023, 5:57 p.m. UTC | #4
On Sat, Sep 30, 2023 at 10:26 AM Arnout Vandecappelle <arnout@mind.be> wrote:
>
>   Hi James,
>
> On 30/09/2023 17:56, James Hilliard wrote:
> > On Sat, Sep 30, 2023 at 9:06 AM Arnout Vandecappelle <arnout@mind.be> wrote:
> >>
> >>    Hi James,
> >>
> >>    After more than a year we're finally getting back to this patch...
> >>
> >> On 09/08/2022 11:41, James Hilliard wrote:
> >>> This adds GCC BPF target support, however unlike traditional targets
> >>> the BPF target is effectively used by packages such as systemd as
> >>> a separate language rather than an entirely separate architecture.
> >>
> >>    I looked at the systemd mesonfile and it looks like it unconditionally uses
> >> gcc-bpf if it can find bpf-none-gcc in PATH. That's annoying, because it means
> >> that currently, it'll already use it if it is installed in /usr/bin... Ideally
> >> we should enable/disable it in systemd dependin on whether gcc-bpf is enabled or
> >> not.
> >
> > Actually it won't since it will only try to use clang unless you set
> > -Dbpf-compiler=gcc,
> > https://github.com/systemd/systemd/blob/v254/meson.build#L1093
>
>   Yes indeed, it seems to default to clang, I had missed that.
>
>
> > Probably a good idea to explicitly disable for now with -Dbpf-framework=false as
> > that could actually be an issue with clang.
>
>   Indeed.
>
>
> >>> As such we need to build what is effectively a multi-arch toolchain
> >>
> >>    It's not really a toolchain because there's no libc, just the compiler itself...
> >
> > I recall it does make use of a static libgcc.a or something like that,
> > not a full
> > libc AFAIU but there are some issues with handling linking still.
>
>   libgcc is part of gcc (obviously).
>
>   libc isn't built for BPF so there would be no point depending on it.

Isn't libc needed by gcc itself?

>
>
> >>> for GCC BPF support, as the BPF target is effectively a bare metal
> >>> target this isn't the same as a multi-lib toolchain and generally
> >>> avoids library conflict issues as the BPF target does not have
> >>> userspace libraries.
> >>
> >>    ... which you already say here :-)
> >>
> >>
> >>> This adds an additional gcc build stage which is similar to gcc-final
> >>> and added as a toolchain dependency when BPF target support is
> >>> enabled.
> >>
> >>    I don't see why this is an additional gcc build stage. It seems to me that
> >> gcc-bpf shouldn't need a dependency on libc or on host-gcc-initial. It probably
> >> _does_ have a dependency on kernel headers though...
> >
> > Hmm, not entirely sure on the libc dependency, I think I have it depending on
> > host-gcc-initial so that it's built similar to host-gcc-final.
> >
> >>
> >>
> >>> Similar to our gcc toolchain we also need a toolchain wrapper, this
> >>> is separate from our normal toolchain wrapper.
> >>
> >>    Are you sure this toolchain wrapper is needed? Most of the fixups that are
> >> applied by the wrapper relate to the target architecture options - -march,
> >> -mtune, etc. I would expect that those would simply break gcc-bpf entirely...
> >> Other options are for optimisation, debugging, hardening, etc. I'm not sure if
> >> it's a good idea to apply those when compiling to BPF either. Then there's
> >> pointing to the sysroot - given that this is a bare metal toolchain, it
> >> shouldn't be needed. And finally there is ccache, which I'm also not sure of if
> >> it's going to work well with BPF code generation.
> >
> > Isn't the toolchain wrapper needed to make sure it work when bundled as part
> > of an external toolchain?
>
>   No, not at all. In fact, the wrapper is in the way when you use it as an
> external toolchain, and we have special handling for that case.
>
> [snip]
> >>    However, for gcc-bpf, I don't think it needs to be tied to the internal
> >> toolchain at all. For me, it makes more sense to have it as a seperate package,
> >> unrelated to gcc, with a fixed version. Having these selectable versions is
> >> anyway a pain :-). And I don't think there's any reason to need to link the
> >> version of gcc-bpf with gcc-target.
> >
> > I think I did it this way mostly for consistency, I mean if you're downloading
> > an external toolchain with a specific gcc version it would be a bit unexpected
> > if say the gcc-bpf compiler was a different version from the rest of the gcc
> > toolchain.
>
>   I think it's a mistake to think of gcc-bpf as part of the toolchain. Even if
> you build systemd with gcc, you can still easily use clang-bpf to build the BPF
> stuff. This already indicates that the bpf compiler is not part of the
> toolchain. You could also compare it to the ti-cgt-pru compiler for the PRU
> controller: it's just a compiler for something else than our target, so it has
> no real relationship with the toolchain.

Hmm, so host-clang also has a toolchain wrapper from the looks of it,
I'm confused
why that would need one and this wouldn't.

I'm not sure how ti-cgt-pru compares in this case since gcc-bpf is
compiling code
to run on our target CPU. A clang/llvm toolchain can target both bpf and our
primary CPU architecture within the same toolchain as well.

>
>
>   Regards,
>   Arnout
>
>
> [snip]
Arnout Vandecappelle Sept. 30, 2023, 7:51 p.m. UTC | #5
On 30/09/2023 19:57, James Hilliard wrote:
> On Sat, Sep 30, 2023 at 10:26 AM Arnout Vandecappelle <arnout@mind.be> wrote:
>>
>>    Hi James,
>>
>> On 30/09/2023 17:56, James Hilliard wrote:
>>> On Sat, Sep 30, 2023 at 9:06 AM Arnout Vandecappelle <arnout@mind.be> wrote:

[snip]
>>    libc isn't built for BPF so there would be no point depending on it.
> 
> Isn't libc needed by gcc itself?

  Not really. host-gcc-final depends on libc because it defaults to linking with 
libc so it needs to "see" it. But it's not really used by gcc.

  The "-none" part of the tuple bpf-buildroot-none indicates that its a 
freestanding compiler, without libc.

[snip]
>>    I think it's a mistake to think of gcc-bpf as part of the toolchain. Even if
>> you build systemd with gcc, you can still easily use clang-bpf to build the BPF
>> stuff. This already indicates that the bpf compiler is not part of the
>> toolchain. You could also compare it to the ti-cgt-pru compiler for the PRU
>> controller: it's just a compiler for something else than our target, so it has
>> no real relationship with the toolchain.
> 
> Hmm, so host-clang also has a toolchain wrapper from the looks of it,

  Yes, because host-clang builds for the target. Now, clang of course always 
includes all its backends, so you can actually use it to build for any target. 
If you use it for a different target than the buildroot target, it's very well 
possible that some of the options injected by the toolchain wrapper would create 
conflicts or other problems.

> I'm confused
> why that would need one and this wouldn't.

  Because host-clang builds for the same target as host-gcc-final (for 
buildroot's main target). If we start using host-clang to build for BPF, we 
ideally shouldn't use the wrapper. At least, I think so.


> I'm not sure how ti-cgt-pru compares in this case since gcc-bpf is
> compiling code
> to run on our target CPU.

  No it doesn't. It compiles code to BPF, which is bytecode. That bytecode is 
architecture-independent. It gets interpreted by the kernel (and JIT-compiled to 
machine code). It's comparable with, say, WebAssembly.

> A clang/llvm toolchain can target both bpf and our
> primary CPU architecture within the same toolchain as well.

  Yes, I agree that the fact that clang can target all architectures with the 
same build makes things a bit confusing.

  Regards,
  Arnout
diff mbox series

Patch

diff --git a/package/Makefile.in b/package/Makefile.in
index ff60f85092..a6f5292903 100644
--- a/package/Makefile.in
+++ b/package/Makefile.in
@@ -39,6 +39,9 @@  endif
 # Compute GNU_TARGET_NAME
 GNU_TARGET_NAME = $(ARCH)-$(TARGET_VENDOR)-$(TARGET_OS)-$(LIBC)$(ABI)
 
+# Compute BPF_TARGET_NAME
+BPF_TARGET_NAME = bpf-$(TARGET_VENDOR)-none
+
 # FLAT binary format needs uclinux, except RISC-V 64-bits which needs
 # the regular linux name.
 ifeq ($(BR2_BINFMT_FLAT):$(BR2_RISCV_64),y:)
diff --git a/package/gcc/Config.in.host b/package/gcc/Config.in.host
index ba2a2ee072..c49f6e6b26 100644
--- a/package/gcc/Config.in.host
+++ b/package/gcc/Config.in.host
@@ -60,6 +60,10 @@  config BR2_GCC_VERSION_12_X
 
 endchoice
 
+config BR2_GCC_SUPPORTS_BPF
+	bool
+	default y if BR2_TOOLCHAIN_GCC_AT_LEAST_12
+
 # libcilkrts was introduced in gcc 4.9 and removed in gcc 8.x
 config BR2_GCC_SUPPORTS_LIBCILKRTS
 	bool
@@ -94,6 +98,14 @@  config BR2_EXTRA_GCC_CONFIG_OPTIONS
 	  include. Those options are applied for all of the gcc
 	  initial, gcc intermediate and gcc final passes.
 
+config BR2_TOOLCHAIN_BUILDROOT_BPF
+	bool "Enable bpf support"
+	depends on BR2_GCC_SUPPORTS_BPF
+	depends on BR2_PACKAGE_HOST_BINUTILS_SUPPORTS_BPF
+	help
+	  Enable this option if you want your toolchain to support BPF
+	  targets.
+
 config BR2_TOOLCHAIN_BUILDROOT_CXX
 	bool "Enable C++ support"
 	select BR2_INSTALL_LIBSTDCPP
diff --git a/package/gcc/gcc-bpf/gcc-bpf.hash b/package/gcc/gcc-bpf/gcc-bpf.hash
new file mode 120000
index 0000000000..7ac9361ab2
--- /dev/null
+++ b/package/gcc/gcc-bpf/gcc-bpf.hash
@@ -0,0 +1 @@ 
+../gcc.hash
\ No newline at end of file
diff --git a/package/gcc/gcc-bpf/gcc-bpf.mk b/package/gcc/gcc-bpf/gcc-bpf.mk
new file mode 100644
index 0000000000..b12d27ad00
--- /dev/null
+++ b/package/gcc/gcc-bpf/gcc-bpf.mk
@@ -0,0 +1,116 @@ 
+################################################################################
+#
+# gcc-bpf
+#
+################################################################################
+
+GCC_BPF_VERSION = $(GCC_VERSION)
+GCC_BPF_SITE = $(GCC_SITE)
+GCC_BPF_SOURCE = $(GCC_SOURCE)
+
+HOST_GCC_BPF_DL_SUBDIR = gcc
+
+HOST_GCC_BPF_DEPENDENCIES = \
+	$(HOST_GCC_COMMON_DEPENDENCIES) \
+	$(BR_LIBC)
+
+HOST_GCC_BPF_EXCLUDES = $(HOST_GCC_EXCLUDES)
+
+HOST_GCC_BPF_POST_PATCH_HOOKS += HOST_GCC_APPLY_PATCHES
+
+# gcc doesn't support in-tree build, so we create a 'build'
+# subdirectory in the gcc sources, and build from there.
+HOST_GCC_BPF_SUBDIR = build
+
+HOST_GCC_BPF_PRE_CONFIGURE_HOOKS += HOST_GCC_CONFIGURE_SYMLINK
+
+HOST_GCC_BPF_CONF_OPTS = \
+	--target=$(BPF_TARGET_NAME) \
+	--prefix="$(HOST_DIR)" \
+	--sysconfdir="$(HOST_DIR)/etc" \
+	--enable-languages=c \
+	--with-gnu-ld \
+	--enable-static \
+	--disable-decimal-float \
+	--disable-gcov \
+	--disable-libssp \
+	--disable-multilib \
+	--disable-shared \
+	--with-gmp=$(HOST_DIR) \
+	--with-mpc=$(HOST_DIR) \
+	--with-mpfr=$(HOST_DIR) \
+	--with-pkgversion="Buildroot $(BR2_VERSION_FULL)" \
+	--with-bugurl="http://bugs.buildroot.net/" \
+	--without-zstd \
+	$(call qstrip,$(BR2_EXTRA_GCC_CONFIG_OPTIONS))
+
+ifeq ($(BR2_GCC_ENABLE_GRAPHITE),y)
+HOST_GCC_BPF_DEPENDENCIES += host-isl
+HOST_GCC_BPF_CONF_OPTS += --with-isl=$(HOST_DIR)
+else
+HOST_GCC_BPF_CONF_OPTS += --without-isl --without-cloog
+endif
+
+# Don't build documentation. It takes up extra space / build time,
+# and sometimes needs specific makeinfo versions to work
+HOST_GCC_BPF_CONF_ENV = \
+	MAKEINFO=missing
+
+# Make sure we have 'cc'
+define HOST_GCC_BPF_CREATE_CC_SYMLINKS
+	if [ ! -e $(HOST_DIR)/bin/$(BPF_TARGET_NAME)-cc ]; then \
+		ln -f $(HOST_DIR)/bin/$(BPF_TARGET_NAME)-gcc \
+			$(HOST_DIR)/bin/$(BPF_TARGET_NAME)-cc; \
+	fi
+endef
+
+HOST_GCC_BPF_POST_INSTALL_HOOKS += HOST_GCC_BPF_CREATE_CC_SYMLINKS
+
+HOST_GCC_BPF_MAKE_OPTS = $(HOST_GCC_COMMON_MAKE_OPTS) all-gcc all-target-libgcc
+HOST_GCC_BPF_INSTALL_OPTS = install-gcc install-target-libgcc
+
+HOST_GCC_BPF_TOOLCHAIN_WRAPPER_ARGS = -DBR_SYSROOT='"$(STAGING_SUBDIR)"'
+HOST_GCC_BPF_TOOLCHAIN_WRAPPER_ARGS += $(HOST_GCC_COMMON_TOOLCHAIN_WRAPPER_ARGS)
+
+define HOST_GCC_BPF_TOOLCHAIN_WRAPPER_BUILD
+	$(HOSTCC) $(HOST_CFLAGS) $(HOST_GCC_BPF_TOOLCHAIN_WRAPPER_ARGS) \
+		-s -Wl,--hash-style=$(TOOLCHAIN_WRAPPER_HASH_STYLE) \
+		toolchain/toolchain-wrapper.c \
+		-o $(@D)/toolchain-wrapper-bpf
+endef
+
+define HOST_GCC_BPF_TOOLCHAIN_WRAPPER_INSTALL
+	$(INSTALL) -D -m 0755 $(@D)/toolchain-wrapper-bpf \
+		$(HOST_DIR)/bin/toolchain-wrapper-bpf
+endef
+
+HOST_GCC_BPF_POST_BUILD_HOOKS += HOST_GCC_BPF_TOOLCHAIN_WRAPPER_BUILD
+HOST_GCC_BPF_POST_INSTALL_HOOKS += HOST_GCC_BPF_TOOLCHAIN_WRAPPER_INSTALL
+
+define HOST_GCC_BPF_INSTALL_WRAPPER_AND_SIMPLE_SYMLINKS
+	$(Q)cd $(HOST_DIR)/bin; \
+	for i in $(BPF_TARGET_NAME)-*; do \
+		case "$$i" in \
+		*.br_real) \
+			;; \
+		*-ar|*-ranlib|*-nm) \
+			ln -snf $$i bpf$${i##$(BPF_TARGET_NAME)}; \
+			;; \
+		*cc|*cc-*|*++|*++-*|*cpp|*-gfortran|*-gdc) \
+			rm -f $$i.br_real; \
+			mv $$i $$i.br_real; \
+			ln -sf toolchain-wrapper-bpf $$i; \
+			ln -sf toolchain-wrapper-bpf bpf$${i##$(BPF_TARGET_NAME)}; \
+			ln -snf $$i.br_real bpf$${i##$(BPF_TARGET_NAME)}.br_real; \
+			;; \
+		*) \
+			ln -snf $$i bpf$${i##$(BPF_TARGET_NAME)}; \
+			;; \
+		esac; \
+	done
+
+endef
+
+HOST_GCC_BPF_POST_INSTALL_HOOKS += HOST_GCC_BPF_INSTALL_WRAPPER_AND_SIMPLE_SYMLINKS
+
+$(eval $(host-autotools-package))
diff --git a/toolchain/toolchain-buildroot/toolchain-buildroot.mk b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
index b30cc332d2..34e7e49a5f 100644
--- a/toolchain/toolchain-buildroot/toolchain-buildroot.mk
+++ b/toolchain/toolchain-buildroot/toolchain-buildroot.mk
@@ -12,6 +12,10 @@  BR_LIBC = $(call qstrip,$(BR2_TOOLCHAIN_BUILDROOT_LIBC))
 
 TOOLCHAIN_BUILDROOT_DEPENDENCIES = host-gcc-final
 
+ifeq ($(BR2_TOOLCHAIN_BUILDROOT_BPF),y)
+TOOLCHAIN_BUILDROOT_DEPENDENCIES += host-gcc-bpf
+endif
+
 TOOLCHAIN_BUILDROOT_ADD_TOOLCHAIN_DEPENDENCY = NO
 
 $(eval $(virtual-package))