mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/4] add first LLVM/clang support
@ 2024-11-25 15:09 Ahmad Fatoum
  2024-11-25 15:09 ` [PATCH 1/4] sandbox: use host system's UBSan library Ahmad Fatoum
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2024-11-25 15:09 UTC (permalink / raw)
  To: barebox

We can't compile all of barebox with clang yet, because we use
GCC-specific extensions, especially C-code in naked functions, which we
is judiciously used on 32-bit ARM platforms.

Nevertheless, sandbox can already be used with clang and it's useful for
incoming support for libfuzzer, so let's add support to Kbuild.

Ahmad Fatoum (4):
  sandbox: use host system's UBSan library
  common: implement CC_IS_GCC and CC_IS_CLANG symbols
  fixdep: sync with Linux
  Makefile: add LLVM/clang support

 Makefile                 |  45 ++++--
 arch/arm/Kconfig         |   3 +-
 arch/sandbox/Makefile    |   4 +
 common/Kconfig           |  16 +++
 lib/Kconfig.ubsan        |   3 +
 lib/Makefile             |   2 +-
 scripts/Kbuild.include   |  31 ++--
 scripts/Kconfig.include  |   6 +
 scripts/Makefile.build   |   8 +-
 scripts/Makefile.clang   |   9 ++
 scripts/Makefile.ubsan   |  33 +++--
 scripts/basic/Makefile   |   2 +
 scripts/basic/fixdep.c   | 297 ++++++++++++++++++++++++---------------
 scripts/cc-version.sh    |  52 +++++++
 scripts/compiler.h       |  20 +--
 scripts/include/xalloc.h |  34 +++++
 scripts/mod/sumversion.c |  19 ++-
 17 files changed, 411 insertions(+), 173 deletions(-)
 create mode 100644 scripts/Makefile.clang
 create mode 100755 scripts/cc-version.sh
 create mode 100644 scripts/include/xalloc.h

-- 
2.39.5




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] sandbox: use host system's UBSan library
  2024-11-25 15:09 [PATCH 0/4] add first LLVM/clang support Ahmad Fatoum
@ 2024-11-25 15:09 ` Ahmad Fatoum
  2024-11-25 15:09 ` [PATCH 2/4] common: implement CC_IS_GCC and CC_IS_CLANG symbols Ahmad Fatoum
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2024-11-25 15:09 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

The host system's libubsan is more extensive than what we have and when
building with libfuzzer later, having the functions defined again leads
to linker error due to repeated definitions.

Therefore, let's only use our ubsan functions when we are outside
sandbox.

While at it, we restructure the Makefile a bit to look more like Linux'
and to allow easier extension in future.  CFLAGS_UBSAN will now
unconditionally have the enabled options, but this is ok as we only
make use of it when UBSAN is actually enabled.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 lib/Kconfig.ubsan      |  3 +++
 lib/Makefile           |  2 +-
 scripts/Makefile.ubsan | 33 ++++++++++++++++++---------------
 3 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan
index 22958f48011e..c04ff3cbb6fd 100644
--- a/lib/Kconfig.ubsan
+++ b/lib/Kconfig.ubsan
@@ -31,6 +31,9 @@ config UBSAN_NO_ALIGNMENT
 	  Disabling this option on architectures that support unaligned
 	  accesses may produce a lot of false positives.
 
+config UBSAN_STANDALONE
+	def_bool !SANDBOX
+
 config UBSAN_ALIGNMENT
 	def_bool !UBSAN_NO_ALIGNMENT
 
diff --git a/lib/Makefile b/lib/Makefile
index 41aed121267c..1cf311ebcdb8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -82,7 +82,7 @@ obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
 obj-$(CONFIG_CRC8)	+= crc8.o
 obj-$(CONFIG_NLS)	+= nls_base.o
 obj-$(CONFIG_FSL_QE_FIRMWARE) += fsl-qe-firmware.o
-obj-$(CONFIG_UBSAN)	+= ubsan.o
+obj-$(CONFIG_UBSAN_STANDALONE)	+= ubsan.o
 obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
 
 # GCC library routines
diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan
index 019771b845c5..4fb30a6c3768 100644
--- a/scripts/Makefile.ubsan
+++ b/scripts/Makefile.ubsan
@@ -1,19 +1,22 @@
 # SPDX-License-Identifier: GPL-2.0
-ifdef CONFIG_UBSAN
-      CFLAGS_UBSAN += $(call cc-option, -fsanitize=shift)
-      CFLAGS_UBSAN += $(call cc-option, -fsanitize=integer-divide-by-zero)
-      CFLAGS_UBSAN += $(call cc-option, -fsanitize=unreachable)
-      CFLAGS_UBSAN += $(call cc-option, -fsanitize=signed-integer-overflow)
-      CFLAGS_UBSAN += $(call cc-option, -fsanitize=bounds)
-      CFLAGS_UBSAN += $(call cc-option, -fsanitize=object-size)
-      CFLAGS_UBSAN += $(call cc-option, -fsanitize=bool)
-      CFLAGS_UBSAN += $(call cc-option, -fsanitize=enum)
+ifdef CONFIG_UBSAN_STANDALONE
+      ubsan-cflags-y += $(call cc-option, -fsanitize=shift)
+      ubsan-cflags-y += $(call cc-option, -fsanitize=integer-divide-by-zero)
+      ubsan-cflags-y += $(call cc-option, -fsanitize=unreachable)
+      ubsan-cflags-y += $(call cc-option, -fsanitize=signed-integer-overflow)
+      ubsan-cflags-y += $(call cc-option, -fsanitize=bounds)
+      ubsan-cflags-y += $(call cc-option, -fsanitize=object-size)
+      ubsan-cflags-y += $(call cc-option, -fsanitize=bool)
+      ubsan-cflags-y += $(call cc-option, -fsanitize=enum)
 
-ifdef CONFIG_UBSAN_ALIGNMENT
-      CFLAGS_UBSAN += $(call cc-option, -fsanitize=alignment)
+      ubsan-cflags-$(CONFIG_UBSAN_ALIGNMENT) += $(call cc-option, -fsanitize=alignment)
+else
+      ubsan-cflags-y += -fsanitize=undefined
+      ubsan-cflags-$(if $(CONFIG_UBSAN_ALIGNMENT),,y) += $(call cc-option, -fno-sanitize=alignment)
 endif
 
-      # -fsanitize=* options makes GCC less smart than usual and
-      # increase number of 'maybe-uninitialized false-positives
-      CFLAGS_UBSAN += $(call cc-option, -Wno-maybe-uninitialized)
-endif
+# -fsanitize=* options makes GCC less smart than usual and
+# increase number of 'maybe-uninitialized false-positives
+ubsan-cflags-y += $(call cc-option, -Wno-maybe-uninitialized)
+
+export CFLAGS_UBSAN := $(ubsan-cflags-y)
-- 
2.39.5




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/4] common: implement CC_IS_GCC and CC_IS_CLANG symbols
  2024-11-25 15:09 [PATCH 0/4] add first LLVM/clang support Ahmad Fatoum
  2024-11-25 15:09 ` [PATCH 1/4] sandbox: use host system's UBSan library Ahmad Fatoum
@ 2024-11-25 15:09 ` Ahmad Fatoum
  2024-11-25 15:09 ` [PATCH 3/4] fixdep: sync with Linux Ahmad Fatoum
  2024-11-25 15:09 ` [PATCH 4/4] Makefile: add LLVM/clang support Ahmad Fatoum
  3 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2024-11-25 15:09 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

As preparation for support LLVM+clang, we need barebox to be able to
detect what compiler is being used and its version.

Import the necessary infrastructure from Linux.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 common/Kconfig          | 16 +++++++++++++
 scripts/Kconfig.include |  6 +++++
 scripts/cc-version.sh   | 52 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 74 insertions(+)
 create mode 100755 scripts/cc-version.sh

diff --git a/common/Kconfig b/common/Kconfig
index 859356038386..498d219b4de3 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -2,6 +2,22 @@
 
 source "common/boards/Kconfig"
 
+config CC_IS_GCC
+	def_bool $(success,test "$(cc-name)" = GCC)
+
+config GCC_VERSION
+	int
+	default $(cc-version) if CC_IS_GCC
+	default 0
+
+config CC_IS_CLANG
+	def_bool $(success,test "$(cc-name)" = Clang)
+
+config CLANG_VERSION
+	int
+	default $(cc-version) if CC_IS_CLANG
+	default 0
+
 config GREGORIAN_CALENDER
 	bool
 
diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include
index a5fe72c504ff..55ec8737d0db 100644
--- a/scripts/Kconfig.include
+++ b/scripts/Kconfig.include
@@ -23,6 +23,12 @@ success = $(if-success,$(1),y,n)
 # Return n if <command> exits with 0, y otherwise
 failure = $(if-success,$(1),n,y)
 
+# Get the C compiler name, version, and error out if it is not supported.
+cc-info := $(shell,$(srctree)/scripts/cc-version.sh $(CC))
+$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this C compiler is not supported.)
+cc-name := $(shell,set -- $(cc-info) && echo $1)
+cc-version := $(shell,set -- $(cc-info) && echo $2)
+
 # $(cc-option,<flag>)
 # Return y if the compiler supports <flag>, n otherwise
 cc-option = $(success,mkdir .tmp_$$$$; trap "rm -rf .tmp_$$$$" EXIT; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$$$/tmp.o)
diff --git a/scripts/cc-version.sh b/scripts/cc-version.sh
new file mode 100755
index 000000000000..65d8a2805d2e
--- /dev/null
+++ b/scripts/cc-version.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Print the C compiler name and its version in a 5 or 6-digit form.
+# Also, perform the minimum version check.
+
+set -e
+
+# Print the C compiler name and some version components.
+get_c_compiler_info()
+{
+	cat <<- EOF | "$@" -E -P -x c - 2>/dev/null
+	#if defined(__clang__)
+	Clang	__clang_major__  __clang_minor__  __clang_patchlevel__
+	#elif defined(__GNUC__)
+	GCC	__GNUC__  __GNUC_MINOR__  __GNUC_PATCHLEVEL__
+	#else
+	unknown
+	#endif
+	EOF
+}
+
+# Convert the version string x.y.z to a canonical 5 or 6-digit form.
+get_canonical_version()
+{
+	IFS=.
+	set -- $1
+	echo $((10000 * $1 + 100 * $2 + $3))
+}
+
+# $@ instead of $1 because multiple words might be given, e.g. CC="ccache gcc".
+orig_args="$@"
+set -- $(get_c_compiler_info "$@")
+
+name=$1
+
+case "$name" in
+GCC)
+	version=$2.$3.$4
+	;;
+Clang)
+	version=$2.$3.$4
+	;;
+*)
+	echo "$orig_args: unknown C compiler" >&2
+	exit 1
+	;;
+esac
+
+cversion=$(get_canonical_version $version)
+
+echo $name $cversion
-- 
2.39.5




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/4] fixdep: sync with Linux
  2024-11-25 15:09 [PATCH 0/4] add first LLVM/clang support Ahmad Fatoum
  2024-11-25 15:09 ` [PATCH 1/4] sandbox: use host system's UBSan library Ahmad Fatoum
  2024-11-25 15:09 ` [PATCH 2/4] common: implement CC_IS_GCC and CC_IS_CLANG symbols Ahmad Fatoum
@ 2024-11-25 15:09 ` Ahmad Fatoum
  2024-11-25 15:09 ` [PATCH 4/4] Makefile: add LLVM/clang support Ahmad Fatoum
  3 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2024-11-25 15:09 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

It's been quite a while since we updated fixdep, but we don't have any
barebox-specifics in fixdep, so let's sync now with Linux.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 Makefile                 |   4 +-
 scripts/Kbuild.include   |  31 ++--
 scripts/Makefile.build   |   8 +-
 scripts/basic/Makefile   |   2 +
 scripts/basic/fixdep.c   | 297 ++++++++++++++++++++++++---------------
 scripts/compiler.h       |  20 +--
 scripts/include/xalloc.h |  34 +++++
 scripts/mod/sumversion.c |  19 ++-
 8 files changed, 265 insertions(+), 150 deletions(-)
 create mode 100644 scripts/include/xalloc.h

diff --git a/Makefile b/Makefile
index 991e11bd0dee..b17452ed2cb1 100644
--- a/Makefile
+++ b/Makefile
@@ -846,7 +846,7 @@ quiet_cmd_sysmap = SYSMAP  System.map
 define rule_barebox__
 	$(if $(CONFIG_KALLSYMS),,+$(call cmd,barebox_version))
 	$(call cmd,barebox__)
-	$(Q)echo 'cmd_$@ := $(cmd_barebox__)' > $(@D)/.$(@F).cmd
+	$(Q)echo 'savedcmd_$@ := $(cmd_barebox__)' > $(@D)/.$(@F).cmd
 	$(call cmd,prelink__)
 	$(call cmd,sysmap)
 endef
@@ -893,7 +893,7 @@ cmd_ksym_ld = $(cmd_barebox__)
 define rule_ksym_ld
 	+$(call cmd,barebox_version)
 	$(call cmd,barebox__)
-	$(Q)echo 'cmd_$@ := $(cmd_barebox__)' > $(@D)/.$(@F).cmd
+	$(Q)echo 'savedcmd_$@ := $(cmd_barebox__)' > $(@D)/.$(@F).cmd
 endef
 
 # Generate .S file with all kernel symbols
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index eeb459f8fad3..315e50a2f709 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -183,10 +183,14 @@ cmd = @set -e; $(echo-cmd) $(cmd_$(1))
 ifneq ($(KBUILD_NOCMDDEP),1)
 # Check if both commands are the same including their order. Result is empty
 # string if equal. User may override this check using make KBUILD_NOCMDDEP=1
-cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \
+# If the target does not exist, the *.cmd file should not be included so
+# $(savedcmd_$@) gets empty. Then, target will be built even if $(newer-prereqs)
+# happens to become empty.
+cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(savedcmd_$@))), \
                          $(subst $(space),$(space_escape),$(strip $(cmd_$1))))
 else
-cmd-check = $(if $(strip $(cmd_$@)),,1)
+# We still need to detect missing targets.
+cmd-check = $(if $(strip $(savedcmd_$@)),,1)
 endif
 
 # Replace >$< with >$$< to preserve $ when reloading the .cmd file
@@ -198,19 +202,26 @@ endif
 make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1)))))
 
 # Find any prerequisites that are newer than target or that do not exist.
-# (This is not true for now; $? should contain any non-existent prerequisites,
-# but it does not work as expected when .SECONDARY is present. This seems a bug
-# of GNU Make.)
 # PHONY targets skipped in both cases.
+# If there is no prerequisite other than phony targets, $(newer-prereqs) becomes
+# empty even if the target does not exist. cmd-check saves this corner case.
 newer-prereqs = $(filter-out $(PHONY),$?)
 
+# It is a typical mistake to forget the FORCE prerequisite. Check it here so
+# no more breakage will slip in.
+check-FORCE = $(if $(filter FORCE, $^),,$(warning FORCE prerequisite is missing))
+
+if-changed-cond = $(newer-prereqs)$(cmd-check)$(check-FORCE)
+
 # Execute command if command has changed or prerequisite(s) are updated.
-if_changed = $(if $(newer-prereqs)$(cmd-check),                              \
+if_changed = $(if $(if-changed-cond),$(cmd_and_savecmd),@:)
+
+cmd_and_savecmd =                                                            \
 	$(cmd);                                                              \
-	printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
+	printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd
 
 # Execute the command and also postprocess generated .d dependencies file.
-if_changed_dep = $(if $(newer-prereqs)$(cmd-check),$(cmd_and_fixdep),@:)
+if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:)
 
 cmd_and_fixdep =                                                             \
 	$(cmd);                                                              \
@@ -220,7 +231,7 @@ cmd_and_fixdep =                                                             \
 # Usage: $(call if_changed_rule,foo)
 # Will check if $(cmd_foo) or any of the prerequisites changed,
 # and if so will execute $(rule_foo).
-if_changed_rule = $(if $(newer-prereqs)$(cmd-check),$(rule_$(1)),@:)
+if_changed_rule = $(if $(if-changed-cond),$(rule_$(1)),@:)
 
 ###
 # why - tell why a target got built
@@ -247,7 +258,7 @@ why =                                                                        \
         $(if $(wildcard $@),                                                 \
             $(if $(newer-prereqs),- due to: $(newer-prereqs),                \
                 $(if $(cmd-check),                                           \
-                    $(if $(cmd_$@),- due to command line change,             \
+                    $(if $(savedcmd_$@),- due to command line change,        \
                         $(if $(filter $@, $(targets)),                       \
                             - due to missing .cmd file,                      \
                             - due to $(notdir $@) not in $$(targets)         \
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 25347eee0108..6b67ad17634b 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -130,6 +130,10 @@ define rule_cc_o_c
 	$(call cmd_and_fixdep,cc_o_c)
 endef
 
+define rule_as_o_S
+	$(call cmd_and_fixdep,as_o_S)
+endef
+
 # Built-in and composite module parts
 
 %.pbl.o: %.c FORCE
@@ -168,10 +172,10 @@ quiet_cmd_as_o_S = AS $(quiet_modtag)  $@
 cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<
 
 %.pbl.o: %.S FORCE
-	$(call if_changed_dep,as_o_S)
+	$(call if_changed_rule,as_o_S)
 
 %.o: %.S FORCE
-	$(call if_changed_dep,as_o_S)
+	$(call if_changed_rule,as_o_S)
 
 targets += $(filter-out $(subdir-obj-y), $(real-obj-y)) $(real-obj-m) $(lib-y)
 targets += $(pbl-y)
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index eeb6a38c5551..e48754e29924 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -3,3 +3,5 @@
 # fixdep: used to generate dependency information during build process
 
 hostprogs-always-y	+= fixdep
+
+KBUILD_HOSTCFLAGS += -I$(srctree)/scripts/include/
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 44e887cff49b..cdd5da7e009b 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -70,7 +70,7 @@
  *
  * It first generates a line
  *
- *   cmd_<target> = <cmdline>
+ *   savedcmd_<target> = <cmdline>
  *
  * and then basically copies the .<target>.d file to stdout, in the
  * process filtering out the dependency on autoconf.h and adding
@@ -94,36 +94,19 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <string.h>
-#include <stdarg.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
 
+#include <xalloc.h>
+
 static void usage(void)
 {
 	fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
 	exit(1);
 }
 
-/*
- * In the intended usage of this program, the stdout is redirected to .*.cmd
- * files. The return value of printf() must be checked to catch any error,
- * e.g. "No space left on device".
- */
-static void xprintf(const char *format, ...)
-{
-	va_list ap;
-	int ret;
-
-	va_start(ap, format);
-	ret = vprintf(format, ap);
-	if (ret < 0) {
-		perror("fixdep");
-		exit(1);
-	}
-	va_end(ap);
-}
-
 struct item {
 	struct item	*next;
 	unsigned int	len;
@@ -132,7 +115,7 @@ struct item {
 };
 
 #define HASHSZ 256
-static struct item *hashtab[HASHSZ];
+static struct item *config_hashtab[HASHSZ], *file_hashtab[HASHSZ];
 
 static unsigned int strhash(const char *str, unsigned int sz)
 {
@@ -145,31 +128,14 @@ static unsigned int strhash(const char *str, unsigned int sz)
 }
 
 /*
- * Lookup a value in the configuration string.
+ * Add a new value to the configuration string.
  */
-static int is_defined_config(const char *name, int len, unsigned int hash)
+static void add_to_hashtable(const char *name, int len, unsigned int hash,
+			     struct item *hashtab[])
 {
 	struct item *aux;
 
-	for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
-		if (aux->hash == hash && aux->len == len &&
-		    memcmp(aux->name, name, len) == 0)
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * Add a new value to the configuration string.
- */
-static void define_config(const char *name, int len, unsigned int hash)
-{
-	struct item *aux = malloc(sizeof(*aux) + len);
-
-	if (!aux) {
-		perror("fixdep:malloc");
-		exit(1);
-	}
+	aux = xmalloc(sizeof(*aux) + len);
 	memcpy(aux->name, name, len);
 	aux->len = len;
 	aux->hash = hash;
@@ -177,19 +143,36 @@ static void define_config(const char *name, int len, unsigned int hash)
 	hashtab[hash % HASHSZ] = aux;
 }
 
+/*
+ * Lookup a string in the hash table. If found, just return true.
+ * If not, add it to the hashtable and return false.
+ */
+static bool in_hashtable(const char *name, int len, struct item *hashtab[])
+{
+	struct item *aux;
+	unsigned int hash = strhash(name, len);
+
+	for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
+		if (aux->hash == hash && aux->len == len &&
+		    memcmp(aux->name, name, len) == 0)
+			return true;
+	}
+
+	add_to_hashtable(name, len, hash, hashtab);
+
+	return false;
+}
+
 /*
  * Record the use of a CONFIG_* word.
  */
 static void use_config(const char *m, int slen)
 {
-	unsigned int hash = strhash(m, slen);
+	if (in_hashtable(m, slen, config_hashtab))
+		return;
 
-	if (is_defined_config(m, slen, hash))
-	    return;
-
-	define_config(m, slen, hash);
 	/* Print out a dependency path from a symbol name. */
-	xprintf("    $(wildcard include/config/%.*s) \\\n", slen, m);
+	printf("    $(wildcard include/config/%.*s) \\\n", slen, m);
 }
 
 /* test if s ends in sub */
@@ -244,11 +227,7 @@ static void *read_file(const char *filename)
 		perror(filename);
 		exit(2);
 	}
-	buf = malloc(st.st_size + 1);
-	if (!buf) {
-		perror("fixdep: malloc");
-		exit(2);
-	}
+	buf = xmalloc(st.st_size + 1);
 	if (read(fd, buf, st.st_size) != st.st_size) {
 		perror("fixdep: read");
 		exit(2);
@@ -262,8 +241,16 @@ static void *read_file(const char *filename)
 /* Ignore certain dependencies */
 static int is_ignored_file(const char *s, int len)
 {
-	return str_ends_with(s, len, "include/generated/autoconf.h") ||
-	       str_ends_with(s, len, "include/generated/autoksyms.h");
+	return str_ends_with(s, len, "include/generated/autoconf.h");
+}
+
+/* Do not parse these files */
+static int is_no_parse_file(const char *s, int len)
+{
+	/* rustc may list binary files in dep-info */
+	return str_ends_with(s, len, ".rlib") ||
+	       str_ends_with(s, len, ".rmeta") ||
+	       str_ends_with(s, len, ".so");
 }
 
 /*
@@ -271,75 +258,144 @@ static int is_ignored_file(const char *s, int len)
  * assignments are parsed not only by make, but also by the rather simple
  * parser in scripts/mod/sumversion.c.
  */
-static void parse_dep_file(char *m, const char *target)
+static void parse_dep_file(char *p, const char *target)
 {
-	char *p;
-	int is_last, is_target;
-	int saw_any_target = 0;
-	int is_first_dep = 0;
-	void *buf;
-
-	while (1) {
-		/* Skip any "white space" */
-		while (*m == ' ' || *m == '\\' || *m == '\n')
-			m++;
-
-		if (!*m)
-			break;
-
-		/* Find next "white space" */
-		p = m;
-		while (*p && *p != ' ' && *p != '\\' && *p != '\n')
-			p++;
-		is_last = (*p == '\0');
-		/* Is the token we found a target name? */
-		is_target = (*(p-1) == ':');
-		/* Don't write any target names into the dependency file */
-		if (is_target) {
-			/* The /next/ file is the first dependency */
-			is_first_dep = 1;
-		} else if (!is_ignored_file(m, p - m)) {
-			*p = '\0';
+	bool saw_any_target = false;
+	bool is_target = true;
+	bool is_source = false;
+	bool need_parse;
+	char *q, saved_c;
 
+	while (*p) {
+		/* handle some special characters first. */
+		switch (*p) {
+		case '#':
 			/*
-			 * Do not list the source file as dependency, so that
-			 * kbuild is not confused if a .c file is rewritten
-			 * into .S or vice versa. Storing it in source_* is
-			 * needed for modpost to compute srcversions.
+			 * skip comments.
+			 * rustc may emit comments to dep-info.
 			 */
-			if (is_first_dep) {
+			p++;
+			while (*p != '\0' && *p != '\n') {
 				/*
-				 * If processing the concatenation of multiple
-				 * dependency files, only process the first
-				 * target name, which will be the original
-				 * source name, and ignore any other target
-				 * names, which will be intermediate temporary
-				 * files.
+				 * escaped newlines continue the comment across
+				 * multiple lines.
 				 */
-				if (!saw_any_target) {
-					saw_any_target = 1;
-					xprintf("source_%s := %s\n\n",
-						target, m);
-					xprintf("deps_%s := \\\n", target);
+				if (*p == '\\')
+					p++;
+				p++;
+			}
+			continue;
+		case ' ':
+		case '\t':
+			/* skip whitespaces */
+			p++;
+			continue;
+		case '\\':
+			/*
+			 * backslash/newline combinations continue the
+			 * statement. Skip it just like a whitespace.
+			 */
+			if (*(p + 1) == '\n') {
+				p += 2;
+				continue;
+			}
+			break;
+		case '\n':
+			/*
+			 * Makefiles use a line-based syntax, where the newline
+			 * is the end of a statement. After seeing a newline,
+			 * we expect the next token is a target.
+			 */
+			p++;
+			is_target = true;
+			continue;
+		case ':':
+			/*
+			 * assume the first dependency after a colon as the
+			 * source file.
+			 */
+			p++;
+			is_target = false;
+			is_source = true;
+			continue;
+		}
+
+		/* find the end of the token */
+		q = p;
+		while (*q != ' ' && *q != '\t' && *q != '\n' && *q != '#' && *q != ':') {
+			if (*q == '\\') {
+				/*
+				 * backslash/newline combinations work like as
+				 * a whitespace, so this is the end of token.
+				 */
+				if (*(q + 1) == '\n')
+					break;
+
+				/* escaped special characters */
+				if (*(q + 1) == '#' || *(q + 1) == ':') {
+					memmove(p + 1, p, q - p);
+					p++;
 				}
-				is_first_dep = 0;
-			} else {
-				xprintf("  %s \\\n", m);
+
+				q++;
 			}
 
-			buf = read_file(m);
+			if (*q == '\0')
+				break;
+			q++;
+		}
+
+		/* Just discard the target */
+		if (is_target) {
+			p = q;
+			continue;
+		}
+
+		saved_c = *q;
+		*q = '\0';
+		need_parse = false;
+
+		/*
+		 * Do not list the source file as dependency, so that kbuild is
+		 * not confused if a .c file is rewritten into .S or vice versa.
+		 * Storing it in source_* is needed for modpost to compute
+		 * srcversions.
+		 */
+		if (is_source) {
+			/*
+			 * The DT build rule concatenates multiple dep files.
+			 * When processing them, only process the first source
+			 * name, which will be the original one, and ignore any
+			 * other source names, which will be intermediate
+			 * temporary files.
+			 *
+			 * rustc emits the same dependency list for each
+			 * emission type. It is enough to list the source name
+			 * just once.
+			 */
+			if (!saw_any_target) {
+				saw_any_target = true;
+				printf("source_%s := %s\n\n", target, p);
+				printf("deps_%s := \\\n", target);
+				need_parse = true;
+			}
+		} else if (!is_ignored_file(p, q - p) &&
+			   !in_hashtable(p, q - p, file_hashtab)) {
+			printf("  %s \\\n", p);
+			need_parse = true;
+		}
+
+		if (need_parse && !is_no_parse_file(p, q - p)) {
+			void *buf;
+
+			buf = read_file(p);
 			parse_config_file(buf);
 			free(buf);
 		}
 
-		if (is_last)
-			break;
-
-		/*
-		 * Start searching for next token immediately after the first
-		 * "whitespace" character that follows this token.
-		 */
-		m = p + 1;
+		is_source = false;
+		*q = saved_c;
+		p = q;
 	}
 
 	if (!saw_any_target) {
@@ -347,8 +403,8 @@ static void parse_dep_file(char *m, const char *target)
 		exit(1);
 	}
 
-	xprintf("\n%s: $(deps_%s)\n\n", target, target);
-	xprintf("$(deps_%s):\n", target);
+	printf("\n%s: $(deps_%s)\n\n", target, target);
+	printf("$(deps_%s):\n", target);
 }
 
 int main(int argc, char *argv[])
@@ -363,11 +419,22 @@ int main(int argc, char *argv[])
 	target = argv[2];
 	cmdline = argv[3];
 
-	xprintf("cmd_%s := %s\n\n", target, cmdline);
+	printf("savedcmd_%s := %s\n\n", target, cmdline);
 
 	buf = read_file(depfile);
 	parse_dep_file(buf, target);
 	free(buf);
 
+	fflush(stdout);
+
+	/*
+	 * In the intended usage, the stdout is redirected to .*.cmd files.
+	 * Call ferror() to catch errors such as "No space left on device".
+	 */
+	if (ferror(stdout)) {
+		fprintf(stderr, "fixdep: not all data was written to the output\n");
+		exit(1);
+	}
+
 	return 0;
 }
diff --git a/scripts/compiler.h b/scripts/compiler.h
index 925cad21b6cf..d8d0e1b906df 100644
--- a/scripts/compiler.h
+++ b/scripts/compiler.h
@@ -6,6 +6,7 @@
 #define __COMPILER_H__
 
 #include <stddef.h>
+#include <xalloc.h>
 
 #if defined(__BEOS__)	 || \
     defined(__NetBSD__)  || \
@@ -167,23 +168,4 @@ typedef uint32_t __u32;
 	_min1 < _min2 ? _min1 : _min2; })
 #endif
 
-static inline void *xmalloc(size_t size)
-{
-	void *p = NULL;
-
-	if (!(p = malloc(size))) {
-		printf("ERROR: out of memory\n");
-		exit(1);
-	}
-
-	return p;
-}
-
-static inline void *xzalloc(size_t size)
-{
-	void *p = xmalloc(size);
-	memset(p, 0, size);
-	return p;
-}
-
 #endif
diff --git a/scripts/include/xalloc.h b/scripts/include/xalloc.h
new file mode 100644
index 000000000000..597d81ee2f6f
--- /dev/null
+++ b/scripts/include/xalloc.h
@@ -0,0 +1,34 @@
+/*
+ * Keep all the ugly #ifdef for system stuff here
+ */
+
+#ifndef __XALLOC_H__
+#define __XALLOC_H__
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+__attribute__ ((__returns_nonnull__))
+static inline void *xmalloc(size_t size)
+{
+	void *p = NULL;
+
+	if (!(p = malloc(size))) {
+		printf("ERROR: out of memory\n");
+		exit(1);
+	}
+
+	return p;
+}
+
+__attribute__ ((__returns_nonnull__))
+static inline void *xzalloc(size_t size)
+{
+	void *p = xmalloc(size);
+	memset(p, 0, size);
+	return p;
+}
+
+#endif
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
index b5f1824a6934..20b6ee2aefe6 100644
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -287,8 +287,8 @@ static int parse_file(const char *fname, struct md4_ctx *md)
 	return 1;
 }
 
-/* We have dir/file.o.  Open dir/.file.o.cmd, look for deps_ line to
- * figure out source file. */
+/* We have dir/file.o.  Open dir/.file.o.cmd, look for source_ and deps_ line
+ * to figure out source file. */
 static int parse_source_files(const char *objfile, struct md4_ctx *md)
 {
 	char *cmd, *file, *line, *dir;
@@ -329,6 +329,21 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
 	*/
 	while ((line = get_next_line(&pos, file, flen)) != NULL) {
 		char* p = line;
+
+		if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
+			p = strrchr(line, ' ');
+			if (!p) {
+				warn("malformed line: %s\n", line);
+				goto out_file;
+			}
+			p++;
+			if (!parse_file(p, md)) {
+				warn("could not open %s: %s\n",
+				     p, strerror(errno));
+				goto out_file;
+			}
+			continue;
+		}
 		if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
 			check_files = 1;
 			continue;
-- 
2.39.5




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/4] Makefile: add LLVM/clang support
  2024-11-25 15:09 [PATCH 0/4] add first LLVM/clang support Ahmad Fatoum
                   ` (2 preceding siblings ...)
  2024-11-25 15:09 ` [PATCH 3/4] fixdep: sync with Linux Ahmad Fatoum
@ 2024-11-25 15:09 ` Ahmad Fatoum
  3 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2024-11-25 15:09 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

We can't compile all of barebox with clang yet, because we use
GCC-specific extensions, especially C-code in naked functions, which we
is judiciously used on 32-bit ARM platforms.

Nevertheless, sandbox can already be used with clang and it's useful for
incoming support for libfuzzer, so let's add support to Kbuild.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 Makefile               | 41 +++++++++++++++++++++++++++++++++++------
 arch/arm/Kconfig       |  3 ++-
 arch/sandbox/Makefile  |  4 ++++
 scripts/Makefile.clang |  9 +++++++++
 4 files changed, 50 insertions(+), 7 deletions(-)
 create mode 100644 scripts/Makefile.clang

diff --git a/Makefile b/Makefile
index b17452ed2cb1..7f7dde9e6bc9 100644
--- a/Makefile
+++ b/Makefile
@@ -383,8 +383,19 @@ HOST_LFS_CFLAGS := $(shell getconf LFS_CFLAGS 2>/dev/null)
 HOST_LFS_LDFLAGS := $(shell getconf LFS_LDFLAGS 2>/dev/null)
 HOST_LFS_LIBS := $(shell getconf LFS_LIBS 2>/dev/null)
 
-HOSTCC       = gcc
-HOSTCXX      = g++
+ifneq ($(LLVM),)
+ifneq ($(filter %/,$(LLVM)),)
+LLVM_PREFIX := $(LLVM)
+else ifneq ($(filter -%,$(LLVM)),)
+LLVM_SUFFIX := $(LLVM)
+endif
+
+HOSTCC	= $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
+HOSTCXX	= $(LLVM_PREFIX)clang++$(LLVM_SUFFIX)
+else
+HOSTCC	= gcc
+HOSTCXX	= g++
+endif
 
 KBUILD_USERHOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \
 			      -O2 -fomit-frame-pointer -std=gnu11
@@ -397,15 +408,26 @@ KBUILD_HOSTLDFLAGS  := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS)
 KBUILD_HOSTLDLIBS   := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
 
 # Make variables (CC, etc...)
-
-LD		= $(CROSS_COMPILE)ld
-CC		= $(CROSS_COMPILE)gcc
 CPP		= $(CC) -E
+ifneq ($(LLVM),)
+CC		= $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
+LD		= $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX)
+AR		= $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)
+NM		= $(LLVM_PREFIX)llvm-nm$(LLVM_SUFFIX)
+OBJCOPY		= $(LLVM_PREFIX)llvm-objcopy$(LLVM_SUFFIX)
+OBJDUMP		= $(LLVM_PREFIX)llvm-objdump$(LLVM_SUFFIX)
+READELF		= $(LLVM_PREFIX)llvm-readelf$(LLVM_SUFFIX)
+STRIP		= $(LLVM_PREFIX)llvm-strip$(LLVM_SUFFIX)
+else
+CC		= $(CROSS_COMPILE)gcc
+LD		= $(CROSS_COMPILE)ld
 AR		= $(CROSS_COMPILE)ar
 NM		= $(CROSS_COMPILE)nm
-STRIP		= $(CROSS_COMPILE)strip
 OBJCOPY		= $(CROSS_COMPILE)objcopy
 OBJDUMP		= $(CROSS_COMPILE)objdump
+READELF		= $(CROSS_COMPILE)readelf
+STRIP		= $(CROSS_COMPILE)strip
+endif
 LEX		= flex
 YACC		= bison
 AWK		= awk
@@ -459,6 +481,7 @@ KBUILD_AFLAGS_KERNEL :=
 KBUILD_CFLAGS_KERNEL :=
 KBUILD_AFLAGS_MODULE := -DMODULE
 KBUILD_CFLAGS_MODULE := -DMODULE
+CLANG_FLAGS :=
 
 LDFLAGS_barebox	:= -Map barebox.map
 
@@ -530,6 +553,10 @@ ifdef building_out_of_srctree
 	{ echo "# this is build directory, ignore it"; echo "*"; } > .gitignore
 endif
 
+ifeq ($(CONFIG_CC_IS_CLANG),y)
+include $(srctree)/scripts/Makefile.clang
+endif
+
 ifdef config-build
 # ===========================================================================
 # *config targets only - make sure prerequisites are updated, and descend
@@ -660,6 +687,8 @@ KBUILD_CFLAGS	+= -fno-omit-frame-pointer -fno-optimize-sibling-calls
 KBUILD_CFLAGS	+= $(call cc-disable-warning,frame-address,)
 endif
 
+KBUILD_CFLAGS-$(CONFIG_CC_IS_CLANG) += -Wno-gnu
+
 KBUILD_CFLAGS-$(CONFIG_WERROR) += -Werror
 
 # This warning generated too much noise in a regular build.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0251f2dcef62..516cc721a5f6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -287,8 +287,9 @@ config BOARD_ARM_GENERIC_DT_AARCH64
 	default y
 
 config AEABI
-	bool "Use the ARM EABI to compile barebox"
+	bool "Use the ARM EABI to compile barebox" if !CC_IS_CLANG
 	depends on !CPU_V8
+	default CC_IS_CLANG
 	help
 	  This option allows for barebox to be compiled using the latest
 	  ARM ABI (aka EABI).
diff --git a/arch/sandbox/Makefile b/arch/sandbox/Makefile
index 5c51f2de38b3..5d434bcbf19b 100644
--- a/arch/sandbox/Makefile
+++ b/arch/sandbox/Makefile
@@ -62,6 +62,10 @@ endif
 ifeq ($(CONFIG_ASAN),y)
 KBUILD_CPPFLAGS += -fsanitize=address
 SANITIZER_LIBS += -fsanitize=address
+ifeq ($(CONFIG_CC_IS_CLANG),y)
+KBUILD_CPPFLAGS += -fno-sanitize-address-globals-dead-stripping
+BAREBOX_LDFLAGS += -fno-sanitize-address-globals-dead-stripping
+endif
 endif
 
 ifeq ($(CONFIG_UBSAN),y)
diff --git a/scripts/Makefile.clang b/scripts/Makefile.clang
new file mode 100644
index 000000000000..c0302ff82670
--- /dev/null
+++ b/scripts/Makefile.clang
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+CLANG_FLAGS	+= -Wno-typdef-redefinition
+CLANG_FLAGS	+= -Werror=unknown-warning-option
+CLANG_FLAGS	+= -Werror=ignored-optimization-argument
+CLANG_FLAGS	+= -Werror=option-ignored
+CLANG_FLAGS	+= -Werror=unused-command-line-argument
+KBUILD_CPPFLAGS	+= $(CLANG_FLAGS)
+KBUILD_USERHOSTCFLAGS += $(CLANG_FLAGS)
+export CLANG_FLAGS
-- 
2.39.5




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-11-25 15:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-11-25 15:09 [PATCH 0/4] add first LLVM/clang support Ahmad Fatoum
2024-11-25 15:09 ` [PATCH 1/4] sandbox: use host system's UBSan library Ahmad Fatoum
2024-11-25 15:09 ` [PATCH 2/4] common: implement CC_IS_GCC and CC_IS_CLANG symbols Ahmad Fatoum
2024-11-25 15:09 ` [PATCH 3/4] fixdep: sync with Linux Ahmad Fatoum
2024-11-25 15:09 ` [PATCH 4/4] Makefile: add LLVM/clang support Ahmad Fatoum

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox