From nobody Mon Feb 9 12:26:59 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1625149316; cv=none; d=zohomail.com; s=zohoarc; b=mYY7G6ik2F1qoSdmNG+heE100TPw/vX7gpXJcZYuFWCvCqK0IsMrVSJW+fNvxpkV3EKdMEYaWBrJzrfSUttgY9MQ+vlzpK+NkQvC/6cICJ7TAosQi7tTYDvogUzGfIt6xwKvcnfSEfgeWLCdqKaAWQ/mMrjqaxbfN3La/OrPlrg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1625149316; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=3hpnDlnZloPTdPWMxCtLEQbl5GzNsNSc5c7pn5Byb7E=; b=ItXr+fdhVaZpSexISOWWAYaTL7eUIasWqZd2abUfiUyc+GOMxjjzs5jT1y+oO9ND9V2iOWTndm9PdQpvcsytfTVzjPJYDU9t99xOe94FAubqOalr7E6ORENK1MbjsbvjrwrSbZrAeKjnkGGE5vNJUAfrMpoJAOTt+zaE/xrx3uw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1625149316336458.07160910828554; Thu, 1 Jul 2021 07:21:56 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.148775.275042 (Exim 4.92) (envelope-from ) id 1lyxZV-00024m-6j; Thu, 01 Jul 2021 14:21:41 +0000 Received: by outflank-mailman (output) from mailman id 148775.275042; Thu, 01 Jul 2021 14:21:41 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1lyxZV-00023H-1Y; Thu, 01 Jul 2021 14:21:41 +0000 Received: by outflank-mailman (input) for mailman id 148775; Thu, 01 Jul 2021 14:21:39 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1lyxQZ-0005F9-M3 for xen-devel@lists.xenproject.org; Thu, 01 Jul 2021 14:12:27 +0000 Received: from esa5.hc3370-68.iphmx.com (unknown [216.71.155.168]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 309bf640-da76-11eb-8328-12813bfff9fa; Thu, 01 Jul 2021 14:11:12 +0000 (UTC) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 309bf640-da76-11eb-8328-12813bfff9fa DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1625148672; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=APF1/u5jPnrWo/5Fqte+sYKklT316xDw+oribOSGvg8=; b=Ge6JnMP34vCiOXZ5Txyu4meDPNMNAynK3t9TiXzuMm2lShhXr17ahCV0 EvGodJ6a+OOxrvKi7uBl+5WIxADfht6XdlXfZgo1aw71cUnDL5vTHzlfC 9gyQaO3QWP/cu30I9Oxv/6NemNkZoFjZbN853zlsrBeRALg1TbFFQ3Km9 k=; Authentication-Results: esa5.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none IronPort-SDR: DPse08MoYbUEHN87mCBV8I3seFbD0iRz6VH/LPSxzcuPuQZQjOtYLAmTnXANpYULIIjcgv/Px1 Sp8OkTpY2yODr15n27DBnTkPKjJAuOP/poJnHJYFkXpneEmop0a2vGCerd0fNZxzJ5Bpr0/OAx /bnaBSfuzwAbVrgLqW7FtuEKTszwqufSVO4Oab/tDf/0NSuC5rOa8tT/uHSDaHfSQMsB94SMhP 0YHBhgI51ECOkvrmJsOaDm4UH+uUu2VnVFOUd6nz1UJXNGjNJYdjKSrlVdWOtmVuku3Egi8Fay vd8= X-SBRS: 5.1 X-MesageID: 47093441 X-Ironport-Server: esa5.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED IronPort-HdrOrdr: A9a23:qrnDPqpWRqPpvhTp/nkAj0waV5rveYIsimQD101hICG9Evb0qy nOpoV/6faQslwssR4b9uxoVJPvfZq+z+8W3WByB9eftWDd0QPFEGgL1+DfKlbbak7DH4BmtJ uJc8JFeafN5VoRt7eG3OFveexQvOVu88qT9JjjJ28Gd3APV0n5hT0JcjpyFCdNNW57LKt8Lr WwzOxdqQGtfHwGB/7LfUXsD4D41rv2fIuNW29+OyIa X-IronPort-AV: E=Sophos;i="5.83,314,1616472000"; d="scan'208";a="47093441" From: Anthony PERARD To: CC: Anthony PERARD , Andrew Cooper , George Dunlap , "Ian Jackson" , Jan Beulich , Julien Grall , Stefano Stabellini , Wei Liu , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Subject: [XEN PATCH v6 30/31] build: introduce if_changed_deps Date: Thu, 1 Jul 2021 15:10:10 +0100 Message-ID: <20210701141011.785641-31-anthony.perard@citrix.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210701141011.785641-1-anthony.perard@citrix.com> References: <20210701141011.785641-1-anthony.perard@citrix.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @citrix.com) Content-Type: text/plain; charset="utf-8" This macro does compare command line like if_changed, but it also rewrite the dependencies generated by $(CC) in order to depend on a CONFIG_* as generated by kconfig instead of depending on autoconf.h. This allow to make a change in kconfig options and only rebuild the object that uses that CONFIG_* option. cmd_and_record isn't needed anymore as it is replace by cmd_and_fixdep. There's only one .*.d dependency file left which is explicitly included as a workound, all the other are been absorb into the .*.cmd dependency files via `fixdep`. So including .*.d can be removed from the makefile. This imports fixdep.c and if_changed_deps macro from Linux v5.12. Signed-off-by: Anthony PERARD --- .gitignore | 1 + xen/Makefile | 16 +- xen/Rules.mk | 17 +- xen/arch/x86/Makefile | 8 +- xen/scripts/Kbuild.include | 17 +- xen/tools/Makefile | 7 +- xen/tools/fixdep.c | 404 +++++++++++++++++++++++++++++++++++++ 7 files changed, 441 insertions(+), 29 deletions(-) create mode 100644 xen/tools/fixdep.c diff --git a/.gitignore b/.gitignore index 91ae22ae9216..1c9c8a47aac6 100644 --- a/.gitignore +++ b/.gitignore @@ -341,6 +341,7 @@ xen/include/xen/lib/x86/cpuid-autogen.h xen/test/livepatch/config.h xen/test/livepatch/expect_config.h xen/test/livepatch/*.livepatch +xen/tools/fixdep xen/tools/kconfig/.tmp_gtkcheck xen/tools/kconfig/.tmp_qtcheck xen/tools/symbols diff --git a/xen/Makefile b/xen/Makefile index 71f098cd6374..d8dedca206a1 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -185,6 +185,13 @@ endif export root-make-done :=3D y endif # root-make-done =20 +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D +# Rules shared between *config targets and build targets + +PHONY +=3D tools_fixdep +tools_fixdep: + $(MAKE) -C tools fixdep + # Shorthand for kconfig kconfig =3D -f $(BASEDIR)/tools/kconfig/Makefile.kconfig ARCH=3D$(ARCH) SR= CARCH=3D$(SRCARCH) HOSTCC=3D"$(HOSTCC)" HOSTCXX=3D"$(HOSTCXX)" =20 @@ -397,7 +404,7 @@ $(TARGET).gz: $(TARGET) mv $@.new $@ =20 PHONY +=3D prepare -prepare: +prepare: tools_fixdep $(MAKE) -C tools $(MAKE) $(build)=3D. include/xen/compile.h [ -e arch/$(TARGET_ARCH)/efi ] && for f in $$(cd common/efi; echo *.[ch])= ; \ @@ -476,6 +483,7 @@ include/xen/compile.h: include/xen/compile.h.in .banner= FORCE @cat .banner $(call filechk,compile.h) =20 +-include $(wildcard .asm-offsets.s.d) asm-offsets.s: arch/$(TARGET_ARCH)/$(TARGET_SUBARCH)/asm-offsets.c $(CC) $(filter-out -Wa$(comma)% -flto,$(c_flags)) -S -g0 -o $@.new -MQ $@= $< $(call move-if-changed,$@.new,$@) @@ -542,13 +550,13 @@ _MAP: =20 # Avoid those single target rules when Makefile is included by Rules.mk ifndef obj -%.o %.i %.s: %.c FORCE +%.o %.i %.s: %.c tools_fixdep FORCE $(MAKE) $(build)=3D$(*D) $(*D)/$(@F) =20 -%.o %.s: %.S FORCE +%.o %.s: %.S tools_fixdep FORCE $(MAKE) $(build)=3D$(*D) $(*D)/$(@F) =20 -%/: FORCE +%/: tools_fixdep FORCE $(MAKE) $(build)=3D$* need-builtin=3D1 endif =20 diff --git a/xen/Rules.mk b/xen/Rules.mk index 4b3abf0ea880..f2af4a6e0644 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -139,8 +139,8 @@ cpp_flags =3D $(filter-out -Wa$(comma)%,$(1)) # Calculation of flags, first the generic flags, then the arch specific fl= ags, # and last the flags modified for a target or a directory. =20 -c_flags =3D -MMD -MP -MF $(@D)/.$(@F).d $(XEN_CFLAGS) -a_flags =3D -MMD -MP -MF $(@D)/.$(@F).d $(XEN_AFLAGS) +c_flags =3D -MMD -MP -MF $(depfile) $(XEN_CFLAGS) +a_flags =3D -MMD -MP -MF $(depfile) $(XEN_AFLAGS) =20 include $(BASEDIR)/arch/$(TARGET_ARCH)/Rules.mk =20 @@ -197,7 +197,7 @@ else endif =20 define rule_cc_o_c - $(call cmd_and_record,cc_o_c) + $(call cmd_and_fixdep,cc_o_c) $(call cmd,objcopy_fix_sym) endef =20 @@ -208,7 +208,7 @@ quiet_cmd_cc_o_S =3D CC $@ cmd_cc_o_S =3D $(CC) $(a_flags) -c $< -o $@ =20 $(obj)/%.o: $(src)/%.S FORCE - $(call if_changed,cc_o_S) + $(call if_changed_dep,cc_o_S) =20 =20 quiet_cmd_obj_init_o =3D INIT_O $@ @@ -238,13 +238,13 @@ quiet_cmd_cpp_s_S =3D CPP $@ cmd_cpp_s_S =3D $(CPP) $(call cpp_flags,$(a_flags)) -MQ $@ -o $@ $< =20 $(obj)/%.i: $(src)/%.c FORCE - $(call if_changed,cpp_i_c) + $(call if_changed_dep,cpp_i_c) =20 $(obj)/%.s: $(src)/%.c FORCE - $(call if_changed,cc_s_c) + $(call if_changed_dep,cc_s_c) =20 $(obj)/%.s: $(src)/%.S FORCE - $(call if_changed,cpp_s_S) + $(call if_changed_dep,cpp_s_S) =20 # Linker scripts, .lds.S -> .lds quiet_cmd_cpp_lds_S =3D LDS $@ @@ -283,9 +283,6 @@ existing-targets :=3D $(wildcard $(sort $(targets))) =20 -include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd) =20 -DEPS:=3D $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).d) --include $(DEPS_INCLUDE) - # Declare the contents of the PHONY variable as phony. We keep that # information in a variable so we can use it in if_changed and friends. .PHONY: $(PHONY) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index c5e87f3db35b..bcb140756b98 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -280,7 +280,7 @@ $(BASEDIR)/include/arch-x86/asm/asm-macros.h: $(obj)/as= m-macros.i $(src)/Makefil =20 $(obj)/efi.lds: AFLAGS-y +=3D -DEFI $(obj)/xen.lds $(obj)/efi.lds: $(src)/xen.lds.S FORCE - $(call if_changed,cpp_lds_S) + $(call if_changed_dep,cpp_lds_S) =20 $(obj)/boot/mkelf32: $(src)/boot/mkelf32.c $(HOSTCC) $(HOSTCFLAGS) -o $@ $< @@ -296,9 +296,3 @@ clean:: rm -f $(BASEDIR)/.xen.efi.[0-9]* efi/*.efi efi/mkreloc rm -f boot/cmdline.S boot/reloc.S boot/*.lnk boot/*.bin rm -f note.o - -# Suppress loading of DEPS files for internal, temporary target files. Th= is -# then also suppresses re-generation of the respective .*.d2 files. -ifeq ($(filter-out .xen%.o,$(notdir $(MAKECMDGOALS))),) -DEPS_INCLUDE:=3D -endif diff --git a/xen/scripts/Kbuild.include b/xen/scripts/Kbuild.include index 788929cdca38..b56bbc4300f0 100644 --- a/xen/scripts/Kbuild.include +++ b/xen/scripts/Kbuild.include @@ -15,8 +15,7 @@ dot-target =3D $(@D)/.$(@F) =20 ### # dependencies -DEPS =3D .*.d -DEPS_INCLUDE =3D $(addsuffix .d2, $(basename $(wildcard $(DEPS)))) +depfile =3D $(dot-target).d =20 ### # real prerequisites without phony targets @@ -129,6 +128,8 @@ cmd =3D @set -e; $(echo-cmd) $(cmd_$(1)) ### # if_changed - execute command if any prerequisite is newer than # target, or command line has changed +# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies +# including used config symbols # if_changed_rule - as if_changed but execute rule instead =20 ifneq ($(KBUILD_NOCMDDEP),1) @@ -157,15 +158,19 @@ if_changed =3D $(if $(any-prereq)$(cmd-check), = \ $(cmd); = \ printf '%s\n' 'cmd_$@ :=3D $(make-cmd)' > $(dot-target).cmd, @:) =20 +# Execute the command and also postprocess generated .d dependencies file. +if_changed_dep =3D $(if $(any-prereq)$(cmd-check),$(cmd_and_fixdep),@:) + +cmd_and_fixdep =3D = \ + $(cmd); = \ + tools/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd; = \ + rm -f $(depfile) + # 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 =3D $(if $(any-prereq)$(cmd-check),$(rule_$(1)),@:) =20 -cmd_and_record =3D = \ - $(cmd); = \ - printf '%s\n' 'cmd_$@ :=3D $(make-cmd)' > $(dot-target).cmd - ### # why - tell why a target got built # enabled by make V=3D2 diff --git a/xen/tools/Makefile b/xen/tools/Makefile index 4e42163f981c..722f3664549d 100644 --- a/xen/tools/Makefile +++ b/xen/tools/Makefile @@ -2,11 +2,14 @@ include $(XEN_ROOT)/Config.mk =20 .PHONY: default -default: symbols +default: symbols fixdep =20 .PHONY: clean clean: - rm -f *.o symbols + rm -f *.o symbols fixdep =20 symbols: symbols.c $(HOSTCC) $(HOSTCFLAGS) -o $@ $< + +fixdep: fixdep.c + $(HOSTCC) $(HOSTCFLAGS) -o $@ $< diff --git a/xen/tools/fixdep.c b/xen/tools/fixdep.c new file mode 100644 index 000000000000..d98540552941 --- /dev/null +++ b/xen/tools/fixdep.c @@ -0,0 +1,404 @@ +/* + * "Optimize" a list of dependencies as spit out by gcc -MD + * for the kernel build + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + * + * Author Kai Germaschewski + * Copyright 2002 by Kai Germaschewski + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * + * Introduction: + * + * gcc produces a very nice and correct list of dependencies which + * tells make when to remake a file. + * + * To use this list as-is however has the drawback that virtually + * every file in the kernel includes autoconf.h. + * + * If the user re-runs make *config, autoconf.h will be + * regenerated. make notices that and will rebuild every file which + * includes autoconf.h, i.e. basically all files. This is extremely + * annoying if the user just changed CONFIG_HIS_DRIVER from n to m. + * + * So we play the same trick that "mkdep" played before. We replace + * the dependency on autoconf.h by a dependency on every config + * option which is mentioned in any of the listed prerequisites. + * + * kconfig populates a tree in include/config/ with an empty file + * for each config symbol and when the configuration is updated + * the files representing changed config options are touched + * which then let make pick up the changes and the files that use + * the config symbols are rebuilt. + * + * So if the user changes his CONFIG_HIS_DRIVER option, only the objects + * which depend on "include/config/his/driver.h" will be rebuilt, + * so most likely only his driver ;-) + * + * The idea above dates, by the way, back to Michael E Chastain, AFAIK. + * + * So to get dependencies right, there are two issues: + * o if any of the files the compiler read changed, we need to rebuild + * o if the command line given to the compile the file changed, we + * better rebuild as well. + * + * The former is handled by using the -MD output, the later by saving + * the command line used to compile the old object and comparing it + * to the one we would now use. + * + * Again, also this idea is pretty old and has been discussed on + * kbuild-devel a long time ago. I don't have a sensibly working + * internet connection right now, so I rather don't mention names + * without double checking. + * + * This code here has been based partially based on mkdep.c, which + * says the following about its history: + * + * Copyright abandoned, Michael Chastain, . + * This is a C version of syncdep.pl by Werner Almesberger. + * + * + * It is invoked as + * + * fixdep + * + * and will read the dependency file + * + * The transformed dependency snipped is written to stdout. + * + * It first generates a line + * + * cmd_ =3D + * + * and then basically copies the ..d file to stdout, in the + * process filtering out the dependency on autoconf.h and adding + * dependencies on include/config/my/option.h for every + * CONFIG_MY_OPTION encountered in any of the prerequisites. + * + * We don't even try to really parse the header files, but + * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will + * be picked up as well. It's not a problem with respect to + * correctness, since that can only give too many dependencies, thus + * we cannot miss a rebuild. Since people tend to not mention totally + * unrelated CONFIG_ options all over the place, it's not an + * efficiency problem either. + * + * (Note: it'd be easy to port over the complete mkdep state machine, + * but I don't think the added complexity is worth it) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void usage(void) +{ + fprintf(stderr, "Usage: fixdep \n"); + exit(1); +} + +/* + * In the intended usage of this program, the stdout is redirected to .*.c= md + * files. The return value of printf() and putchar() must be checked to ca= tch + * 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 =3D vprintf(format, ap); + if (ret < 0) { + perror("fixdep"); + exit(1); + } + va_end(ap); +} + +static void xputchar(int c) +{ + int ret; + + ret =3D putchar(c); + if (ret =3D=3D EOF) { + perror("fixdep"); + exit(1); + } +} + +/* + * Print out a dependency path from a symbol name + */ +static void print_dep(const char *m, int slen, const char *dir) +{ + int c, prev_c =3D '/', i; + + xprintf(" $(wildcard %s/", dir); + for (i =3D 0; i < slen; i++) { + c =3D m[i]; + if (c =3D=3D '_') + c =3D '/'; + else + c =3D tolower(c); + if (c !=3D '/' || prev_c !=3D '/') + xputchar(c); + prev_c =3D c; + } + xprintf(".h) \\\n"); +} + +struct item { + struct item *next; + unsigned int len; + unsigned int hash; + char name[]; +}; + +#define HASHSZ 256 +static struct item *hashtab[HASHSZ]; + +static unsigned int strhash(const char *str, unsigned int sz) +{ + /* fnv32 hash */ + unsigned int i, hash =3D 2166136261U; + + for (i =3D 0; i < sz; i++) + hash =3D (hash ^ str[i]) * 0x01000193; + return hash; +} + +/* + * Lookup a value in the configuration string. + */ +static int is_defined_config(const char *name, int len, unsigned int hash) +{ + struct item *aux; + + for (aux =3D hashtab[hash % HASHSZ]; aux; aux =3D aux->next) { + if (aux->hash =3D=3D hash && aux->len =3D=3D len && + memcmp(aux->name, name, len) =3D=3D 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 =3D malloc(sizeof(*aux) + len); + + if (!aux) { + perror("fixdep:malloc"); + exit(1); + } + memcpy(aux->name, name, len); + aux->len =3D len; + aux->hash =3D hash; + aux->next =3D hashtab[hash % HASHSZ]; + hashtab[hash % HASHSZ] =3D aux; +} + +/* + * Record the use of a CONFIG_* word. + */ +static void use_config(const char *m, int slen) +{ + unsigned int hash =3D strhash(m, slen); + + if (is_defined_config(m, slen, hash)) + return; + + define_config(m, slen, hash); + print_dep(m, slen, "include/config"); +} + +/* test if s ends in sub */ +static int str_ends_with(const char *s, int slen, const char *sub) +{ + int sublen =3D strlen(sub); + + if (sublen > slen) + return 0; + + return !memcmp(s + slen - sublen, sub, sublen); +} + +static void parse_config_file(const char *p) +{ + const char *q, *r; + const char *start =3D p; + + while ((p =3D strstr(p, "CONFIG_"))) { + if (p > start && (isalnum(p[-1]) || p[-1] =3D=3D '_')) { + p +=3D 7; + continue; + } + p +=3D 7; + q =3D p; + while (isalnum(*q) || *q =3D=3D '_') + q++; + if (str_ends_with(p, q - p, "_MODULE")) + r =3D q - 7; + else + r =3D q; + if (r > p) + use_config(p, r - p); + p =3D q; + } +} + +static void *read_file(const char *filename) +{ + struct stat st; + int fd; + char *buf; + + fd =3D open(filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "fixdep: error opening file: "); + perror(filename); + exit(2); + } + if (fstat(fd, &st) < 0) { + fprintf(stderr, "fixdep: error fstat'ing file: "); + perror(filename); + exit(2); + } + buf =3D malloc(st.st_size + 1); + if (!buf) { + perror("fixdep: malloc"); + exit(2); + } + if (read(fd, buf, st.st_size) !=3D st.st_size) { + perror("fixdep: read"); + exit(2); + } + buf[st.st_size] =3D '\0'; + close(fd); + + return buf; +} + +/* 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"); +} + +/* + * Important: The below generated source_foo.o and deps_foo.o variable + * 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) +{ + char *p; + int is_last, is_target; + int saw_any_target =3D 0; + int is_first_dep =3D 0; + void *buf; + + while (1) { + /* Skip any "white space" */ + while (*m =3D=3D ' ' || *m =3D=3D '\\' || *m =3D=3D '\n') + m++; + + if (!*m) + break; + + /* Find next "white space" */ + p =3D m; + while (*p && *p !=3D ' ' && *p !=3D '\\' && *p !=3D '\n') + p++; + is_last =3D (*p =3D=3D '\0'); + /* Is the token we found a target name? */ + is_target =3D (*(p-1) =3D=3D ':'); + /* Don't write any target names into the dependency file */ + if (is_target) { + /* The /next/ file is the first dependency */ + is_first_dep =3D 1; + } else if (!is_ignored_file(m, p - m)) { + *p =3D '\0'; + + /* + * 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_first_dep) { + /* + * 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. + */ + if (!saw_any_target) { + saw_any_target =3D 1; + xprintf("source_%s :=3D %s\n\n", + target, m); + xprintf("deps_%s :=3D \\\n", target); + } + is_first_dep =3D 0; + } else { + xprintf(" %s \\\n", m); + } + + buf =3D read_file(m); + 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 =3D p + 1; + } + + if (!saw_any_target) { + fprintf(stderr, "fixdep: parse error; no targets found\n"); + exit(1); + } + + xprintf("\n%s: $(deps_%s)\n\n", target, target); + xprintf("$(deps_%s):\n", target); +} + +int main(int argc, char *argv[]) +{ + const char *depfile, *target, *cmdline; + void *buf; + + if (argc !=3D 4) + usage(); + + depfile =3D argv[1]; + target =3D argv[2]; + cmdline =3D argv[3]; + + xprintf("cmd_%s :=3D %s\n\n", target, cmdline); + + buf =3D read_file(depfile); + parse_dep_file(buf, target); + free(buf); + + return 0; +} --=20 Anthony PERARD