kbuild: add infrastructure to build userspace programs

Kbuild supports the infrastructure to build host programs, but there
was no support to build userspace programs for the target architecture
(i.e. the same architecture as the kernel).

Sam Ravnborg worked on this in 2014 (https://lkml.org/lkml/2014/7/13/154),
but it was not merged. One problem at that time was, there was no good way
to know whether $(CC) can link standalone programs. In fact, pre-built
kernel.org toolchains [1] are often used for building the kernel, but they
do not provide libc.

Now, we can handle this cleanly because the compiler capability is
evaluated at the Kconfig time. If $(CC) cannot link standalone programs,
the relevant options are hidden by 'depends on CC_CAN_LINK'.

The implementation just mimics scripts/Makefile.host

The userspace programs are compiled with the same flags as the host
programs. In addition, it uses -m32 or -m64 if it is found in
$(KBUILD_CFLAGS).

This new syntax has two usecases.

- Sample programs

  Several userspace programs under samples/ include UAPI headers
  installed in usr/include. Most of them were previously built for
  the host architecture just to use the 'hostprogs' syntax.

  However, 'make headers' always works for the target architecture.
  This caused the arch mismatch in cross-compiling. To fix this
  distortion, sample code should be built for the target architecture.

- Bpfilter

  net/bpfilter/Makefile compiles bpfilter_umh as the user mode helper,
  and embeds it into the kernel. Currently, it overrides HOSTCC with
  CC to use the 'hostprogs' syntax. This hack should go away.

[1]: https://mirrors.edge.kernel.org/pub/tools/crosstool/
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
This commit is contained in:
Masahiro Yamada 2020-04-29 12:45:14 +09:00
parent b1183b6dca
commit 7f3a59db27
4 changed files with 62 additions and 4 deletions

View File

@ -406,9 +406,12 @@ else
HOSTCC = gcc
HOSTCXX = g++
endif
KBUILD_HOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 \
-fomit-frame-pointer -std=gnu89 $(HOST_LFS_CFLAGS) \
$(HOSTCFLAGS)
export KBUILD_USERCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \
-O2 -fomit-frame-pointer -std=gnu89
export KBUILD_USERLDFLAGS :=
KBUILD_HOSTCFLAGS := $(KBUILD_USERCFLAGS) $(HOST_LFS_CFLAGS) $(HOSTCFLAGS)
KBUILD_HOSTCXXFLAGS := -Wall -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS)
KBUILD_HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS)
KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
@ -944,6 +947,10 @@ ifeq ($(CONFIG_RELR),y)
LDFLAGS_vmlinux += --pack-dyn-relocs=relr
endif
# Align the bit size of userspace programs with the kernel
KBUILD_USERCFLAGS += $(filter -m32 -m64, $(KBUILD_CFLAGS))
KBUILD_USERLDFLAGS += $(filter -m32 -m64, $(KBUILD_CFLAGS))
# make the checker run with the right architecture
CHECKFLAGS += --arch=$(ARCH)

View File

@ -50,6 +50,12 @@ ifneq ($(hostprogs)$(hostcxxlibs-y)$(hostcxxlibs-m),)
include scripts/Makefile.host
endif
# Do not include userprogs rules unless needed.
userprogs := $(sort $(userprogs))
ifneq ($(userprogs),)
include scripts/Makefile.userprogs
endif
ifndef obj
$(warning kbuild: Makefile.build is included improperly)
endif

View File

@ -29,7 +29,7 @@ subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn))
__clean-files := $(extra-y) $(extra-m) $(extra-) \
$(always) $(always-y) $(always-m) $(always-) $(targets) $(clean-files) \
$(hostprogs) $(hostprogs-y) $(hostprogs-m) $(hostprogs-) \
$(hostprogs) $(hostprogs-y) $(hostprogs-m) $(hostprogs-) $(userprogs) \
$(hostcxxlibs-y) $(hostcxxlibs-m)
__clean-files := $(filter-out $(no-clean-files), $(__clean-files))

View File

@ -0,0 +1,45 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Build userspace programs for the target system
#
# Executables compiled from a single .c file
user-csingle := $(foreach m, $(userprogs), $(if $($(m)-objs),,$(m)))
# Executables linked based on several .o files
user-cmulti := $(foreach m, $(userprogs), $(if $($(m)-objs),$(m)))
# Objects compiled from .c files
user-cobjs := $(sort $(foreach m, $(userprogs), $($(m)-objs)))
user-csingle := $(addprefix $(obj)/, $(user-csingle))
user-cmulti := $(addprefix $(obj)/, $(user-cmulti))
user-cobjs := $(addprefix $(obj)/, $(user-cobjs))
user_ccflags = -Wp,-MMD,$(depfile) $(KBUILD_USERCFLAGS) $(userccflags) \
$($(target-stem)-userccflags)
user_ldflags = $(KBUILD_USERLDFLAGS) $(userldflags) $($(target-stem)-userldflags)
# Create an executable from a single .c file
quiet_cmd_user_cc_c = CC [U] $@
cmd_user_cc_c = $(CC) $(user_ccflags) $(user_ldflags) -o $@ $< \
$($(target-stem)-userldlibs)
$(user-csingle): $(obj)/%: $(src)/%.c FORCE
$(call if_changed_dep,user_cc_c)
# Link an executable based on list of .o files
quiet_cmd_user_ld = LD [U] $@
cmd_user_ld = $(CC) $(user_ldflags) -o $@ \
$(addprefix $(obj)/, $($(target-stem)-objs)) \
$($(target-stem)-userldlibs)
$(user-cmulti): FORCE
$(call if_changed,user_ld)
$(call multi_depend, $(user-cmulti), , -objs)
# Create .o file from a .c file
quiet_cmd_user_cc_o_c = CC [U] $@
cmd_user_cc_o_c = $(CC) $(user_ccflags) -c -o $@ $<
$(user-cobjs): $(obj)/%.o: $(src)/%.c FORCE
$(call if_changed_dep,user_cc_o_c)
targets += $(user-csingle) $(user-cmulti) $(user-cobjs)