Skip to contentSkip to conversation

kbuild: move cc_c_o logic to a shell script

RFC PATCH In review Sam Ravnborg 2 participants 2 messages Jun 9, 2014 – Jul 3, 2014 Kbuild

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 kbuild: move cc_c_o logic to a shell script

From b92cb72f08908a718da05318975545e988bfdaf9 Mon Sep 17 00:00:00 2001
From: Sam Ravnborg <[email protected]>
Date: Mon, 9 Jun 2014 18:03:22 +0200
Subject: [PATCH] kbuild: move cc_c_o logic to a shell script

The amount of makefile magic required when building a .o file from a .c file had grown far too much.
Move all the logic to a shell script where it is much easier to follow the sequence and thus easier to debug/enhance.

This transition has following impact on the current functionality:
- We no longer rebuild the kernel if the source for recordmount is changed The source filehas not changed for a couple of years
- A shortcut to build symtypes files is lost. It was never supported by the top-level Makefile anyway

---

The final link of vmlinux was moved out to a shell script resulting in some much more readable code.
Try to do the same for .c => .o rule.

I would like someone with more shell-foo than me to review the shell script.

Sam

 scripts/Makefile.build | 115 ++++--------------------------
 scripts/kcc.sh         | 187 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 202 insertions(+), 100 deletions(-)
 create mode 100644 scripts/kcc.sh
scripts/Makefile.build +15 -100
index 003bc26..3497a7c 100644
@@ -158,14 +158,9 @@ __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
 	@:
 
 # Linus' kernel sanity checking tool
-ifneq ($(KBUILD_CHECKSRC),0)
-  ifeq ($(KBUILD_CHECKSRC),2)
-    quiet_cmd_force_checksrc = CHECK   $<
-          cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
-  else
-      quiet_cmd_checksrc     = CHECK   $<
-            cmd_checksrc     = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
-  endif
+ifeq ($(KBUILD_CHECKSRC),2)
+quiet_cmd_force_checksrc = CHECK   $<
+      cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
 endif
 
 # Do section mismatch analysis for each module/built-in.o
@@ -219,108 +214,28 @@ cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<
 $(obj)/%.i: $(src)/%.c FORCE
 	$(call if_changed_dep,cc_i_c)
 
-cmd_gensymtypes =                                                           \
-    $(CPP) -D__GENKSYMS__ $(c_flags) $< |                                   \
-    $(GENKSYMS) $(if $(1), -T $(2))                                         \
-     $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX))             \
-     $(if $(KBUILD_PRESERVE),-p)                                            \
-     -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
-
-quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
-cmd_cc_symtypes_c =                                                         \
-    set -e;                                                                 \
-    $(call cmd_gensymtypes,true,$@) >/dev/null;                             \
-    test -s $@ || rm -f $@
-
-$(obj)/%.symtypes : $(src)/%.c FORCE
-	$(call cmd,cc_symtypes_c)
-
-# C (.c) files
-# The C file is compiled and updated dependency information is generated.
-# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
-
-quiet_cmd_cc_o_c = CC $(quiet_modtag)  $@
-
-ifndef CONFIG_MODVERSIONS
-cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
-
-else
-# When module versioning is enabled the following steps are executed:
-# o compile a .tmp_<file>.o from <file>.c
-# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does
-#   not export symbols, we just rename .tmp_<file>.o to <file>.o and
-#   are done.
-# o otherwise, we calculate symbol versions using the good old
-#   genksyms on the preprocessed source and postprocess them in a way
-#   that they are usable as a linker script
-# o generate <file>.o from .tmp_<file>.o using the linker to
-#   replace the unresolved symbols __crc_exported_symbol with
-#   the actual value of the checksum generated by genksyms
-
-cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
-cmd_modversions =								\
-	if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then		\
-		$(call cmd_gensymtypes,$(KBUILD_SYMTYPES),$(@:.o=.symtypes))	\
-		    > $(@D)/.tmp_$(@F:.o=.ver);					\
-										\
-		$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) 			\
-			-T $(@D)/.tmp_$(@F:.o=.ver);				\
-		rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);		\
-	else									\
-		mv -f $(@D)/.tmp_$(@F) $@;					\
-	fi;
-endif
-
-ifdef CONFIG_FTRACE_MCOUNT_RECORD
-ifdef BUILD_C_RECORDMCOUNT
-ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
-  RECORDMCOUNT_FLAGS = -w
-endif
-# Due to recursion, we must skip empty.o.
-# The empty.o file is created in the make process in order to determine
-#  the target endianness and word size. It is made before all other C
-#  files, including recordmcount.
-sub_cmd_record_mcount =					\
-	if [ $(@) != "scripts/mod/empty.o" ]; then	\
-		$(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)";	\
-	fi;
-recordmcount_source := $(srctree)/scripts/recordmcount.c \
-		    $(srctree)/scripts/recordmcount.h
-else
-sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
-	"$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
-	"$(if $(CONFIG_64BIT),64,32)" \
-	"$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \
-	"$(LD)" "$(NM)" "$(RM)" "$(MV)" \
-	"$(if $(part-of-module),1,0)" "$(@)";
-recordmcount_source := $(srctree)/scripts/recordmcount.pl
-endif
-cmd_record_mcount = 						\
-	if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then	\
-		$(sub_cmd_record_mcount)			\
-	fi;
-endif
-
 define rule_cc_o_c
-	$(call echo-cmd,checksrc) $(cmd_checksrc)			  \
-	$(call echo-cmd,cc_o_c) $(cmd_cc_o_c);				  \
-	$(cmd_modversions)						  \
-	$(call echo-cmd,record_mcount)					  \
-	$(cmd_record_mcount)						  \
-	scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' >    \
-	                                              $(dot-target).tmp;  \
-	rm -f $(depfile);						  \
+	$(CONFIG_SHELL) $(srctree)/scripts/kcc.sh			\
+	    $< $@ $(depfile)						\
+	    $(if $(part-of-module),m,b)					\
+	    "$(echo-why)"						\
+	    $(c_flags);							\
+	scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' >	\
+	                                           $(dot-target).tmp;	\
+	rm -f $(depfile);						\
 	mv -f $(dot-target).tmp $(dot-target).cmd
 endef
+# cmd_cc_o_c is required by if_changed_rule to detect changes in options
+cmd_cc_o_c = $(CC) $(c_flags)
 
 # Built-in and composite module parts
-$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
+$(obj)/%.o: $(src)/%.c FORCE
 	$(call cmd,force_checksrc)
 	$(call if_changed_rule,cc_o_c)
 
 # Single-part modules are special since we need to mark them in $(MODVERDIR)
 
-$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
+$(single-used-m): $(obj)/%.o: $(src)/%.c FORCE
 	$(call cmd,force_checksrc)
 	$(call if_changed_rule,cc_o_c)
 	@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
scripts/kcc.sh new file +187 -0

187 lines not on this page · raw message

Signature · 1 line
1.9.3
#1 lore raw

Dne 9.6.2014 18:23, Sam Ravnborg napsal(a):

Quoted 9 lines

From b92cb72f08908a718da05318975545e988bfdaf9 Mon Sep 17 00:00:00 2001
From: Sam Ravnborg <[email protected]>
Date: Mon, 9 Jun 2014 18:03:22 +0200
Subject: [PATCH] kbuild: move cc_c_o logic to a shell script

The amount of makefile magic required when building a .o file from a .c file had grown far too much.
Move all the logic to a shell script where it is much easier to follow the sequence and thus easier to debug/enhance.

That's a nice cleanup! Some review below, but I'll have to do one more pass.

Quoted 3 lines

This transition has following impact on the current functionality:
- We no longer rebuild the kernel if the source for recordmount is changed The source filehas not changed for a couple of years

Yeah, that should not be an issue.

Quoted 2 lines

- A shortcut to build symtypes files is lost. It was never supported by the top-level Makefile anyway

There is a rule for that:
%.symtypes: %.c prepare scripts FORCE

        $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)

But it could be added to the script, e.g. if $outfile ends in .symtypes, do just the genksyms run.

Quoted 21 lines
scripts/kcc.sh new file +15 -0
new file mode 100644
index 0000000..2b0bad6
@@ -0,0 +1,187 @@
+#!/bin/sh
+# kernel wrapper for cc
+# In the simple case we just call cc with the supplied arguments.
+# But we may check the source with sparse before we call cc.
+# And we may postprocess the source or the .o file to support
+# module versioning and function tracing.
+
+# Error out on error
+set -e
+
+# Print command and execute
+# ${quiet} determine which command to print (if any)
+run()
+{
+	case "${quiet}" in

scripts/kcc.sh line 25

Quoted 10 lines
scripts/kcc.sh new file +10 -0
+		"silent_")
+			shift
+			;;
+		"quiet_")
+			printf "  %s \n" "$1 ${why}"
+			shift
+			;;
+		*)
+			shift
+			echo "$*"

While there is no -n or -e option to gcc, I'd use printf just to be on the safe side:

                        printf '%s\n' "$*"
Quoted 16 lines
scripts/kcc.sh new file +16 -0
+	esac
+
+	# Run the command
+	$*
+}
+
+# Calculate symbol versions on the preprocessed source
+# using genksyms and postprocess the output in a way
+# that it is usable as a linker script.
+# Then generate the .o file with the __crc_exported_symbol replaced.
+gen_sym_types()
+{
+	if [ "${KBUILD_SYMTYPES}" = "y" ]; then
+		dump_types="-T $1.symtypes"
+	fi
+

scripts/kcc.sh line 51

Quoted 10 lines
scripts/kcc.sh new file +10 -0
+	if [ "${CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX}" = "y" ]; then
+		mod_prefix="-s _"
+	fi
+
+	if [ "${KBUILD_PRESERVE}" != "" ]; then
+		preserve="-p";
+		if [ -f $1.symref ]; then
+			reference="-r $1.symref"
+		fi
+	fi

The -r <file>.symref should not depend on KBUILD_PRESERVE

Quoted 18 lines
scripts/kcc.sh new file +18 -0
+
+	out=$1.ver
+	shift
+
+	${CPP} -D__GENKSYMS__ $* ${infile} | \
+	    ${GENKSYMS} ${dump_types} ${mod_prefix} ${preserve} ${reference} > ${out}
+
+	# Generate <file>.o from .tmp_<file>.o using the linker to
+	# replace the unresolved symbols __crc_exported_symbol with
+	# the actual value of the checksum generated by genksyms
+	${LD} ${LDFLAGS} -r -o ${outfile} ${tmpfile}.o -T ${out}
+	rm -f ${tmpfile}.o ${out}
+}
+
+# Create __mcount_loc section with pointers to all calls to mcount
+record_mcount()
+{
+	# Due to recursion, we must skip empty.o.

scripts/kcc.sh line 79

Quoted 10 lines
scripts/kcc.sh new file +10 -0
+	# The empty.o file is created in the make process in order to determine
+	# the target endianness and word size. It is made before all other C
+	# files, including recordmcount.
+
+	if [ "$(basename ${outfile})" = "empty.o" ]; then
+		return
+	fi
+
+	if [ "${BUILD_C_RECORDMCOUNT}" != "" ]; then
+		if [ "${RECORDMCOUNT_WARN}" != "" ]; then

In the Makefile, there was a check for RECORDMCOUNT_WARN coming from the make command line, but that's not a big deal. Just document it in the changelog.

scripts/kcc.sh line 184

Quoted 3 lines
scripts/kcc.sh new file +3 -0
+# Do we have to run record_mcount?
+if [ "${CONFIG_FTRACE_MCOUNT_RECORD}" != "" ]; then
+	if [ $(echo $* | grep -c -e "-pg") -gt 0 ]; then

case " $* " in
" -pg ")
record_mcount
esac

This has the advantage over the Makefile version that it checks a whole word "-pg". Also, it saves some forking.

Michal