diff mbox

[v4,5/8] kbuild: add fine grained build dependencies for exported symbols

Message ID 1456717691-28298-6-git-send-email-nicolas.pitre@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Nicolas Pitre Feb. 29, 2016, 3:48 a.m. UTC
Like with kconfig options, we now have the ability to compile in and
out individual EXPORT_SYMBOL() declarations based on the content of
include/generated/autoksyms.h.  However we don't want the entire
world to be rebuilt whenever that file is touched.

Let's apply the same build dependency trick used for CONFIG_* symbols
where the time stamp of empty files whose paths matching those symbols
is used to trigger fine grained rebuilds. In our case the key is the
symbol name passed to EXPORT_SYMBOL().

However, unlike config options, we cannot just use fixdep to parse
the source code for EXPORT_SYMBOL(ksym) because several variants exist
and parsing them all in a separate tool, and keeping it in synch, is
not trivially maintainable.  Furthermore, there are variants such as

	EXPORT_SYMBOL_GPL(pci_user_read_config_##size);

that are instanciated via a macro for which we can't easily determine
the actual exported symbol name(s) short of actually running the
preprocessor on them.

Storing the symbol name string in a special ELF section doesn't work
for targets that output assembly or preprocessed source.

So the best way is really to leverage the preprocessor by having it emit
a warning for each EXPORT_SYMBOL() instance and filtering those apart
from stderr by the build system. Then the list of symbols is simply fed
to fixdep to be merged with the other dependencies.

Because of the lowercasing performed by fixdep, there might be name
collisions triggering spurious rebuilds for similar symbols. But this
shouldn't be a big issue in practice. (This is the case for CONFIG_*
symbols and I didn't want to be different here, whatever the original
reason for doing so.)

To avoid needless build overhead, the exported symbol name gathering is
performed only when CONFIG_TRIM_UNUSED_KSYMS is selected.

Signed-off-by: Nicolas Pitre <nico@linaro.org>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
---
 include/linux/export.h | 16 ++++++++++++++--
 scripts/Kbuild.include | 28 ++++++++++++++++++++++++++++
 scripts/basic/fixdep.c |  1 +
 3 files changed, 43 insertions(+), 2 deletions(-)

Comments

Michal Marek March 3, 2016, 10:57 p.m. UTC | #1
Dne 29.2.2016 v 04:48 Nicolas Pitre napsal(a):
> +# Filter out exported kernel symbol names advertised as warning pragmas
> +# by the preprocessor and write them to $(1). We must consider continuation
> +# lines as well: they start with a blank, or the preceeding line ends with
> +# a ':'. Anything else is passed through as is.
> +# See also __KSYM_DEP() in include/linux/export.h.
> +ksym_dep_filter = sed -n \
> +	-e '1 {x; $$!d}' \
> +	-e '/^ / {H; $$!d}' \
> +	-e 'x; /:$$/ {x; H; $$!d; s/^/ /; x}' \
> +	-e ':filter; /^.*KBUILD_AUTOKSYM_DEP: /! {p; b next}' \
> +	-e 's//KSYM_/; s/\n.*//; w $(1)' \
> +	-e ':next; $$!d' \
> +	-e '1 q; s/^/ /; x; /^ /! b filter'

This is unreadable and it does not work with my gcc version. I get
dependencies like

    $(wildcard include/config/ksym/simple/strtoull [enabled by default].h) \

Please use some other way, which does not require parsing the compiler
diagnostic messages. A straightforward solution is to do something
similar to genksyms: A separate preprocessor pass with -Dsomething that
leaves the EXPORT_SYMBOL statements alone and just collect their occurences.

Thanks,
Michal
--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nicolas Pitre March 4, 2016, 2:46 a.m. UTC | #2
On Thu, 3 Mar 2016, Michal Marek wrote:

> Dne 29.2.2016 v 04:48 Nicolas Pitre napsal(a):
> > +# Filter out exported kernel symbol names advertised as warning pragmas
> > +# by the preprocessor and write them to $(1). We must consider continuation
> > +# lines as well: they start with a blank, or the preceeding line ends with
> > +# a ':'. Anything else is passed through as is.
> > +# See also __KSYM_DEP() in include/linux/export.h.
> > +ksym_dep_filter = sed -n \
> > +	-e '1 {x; $$!d}' \
> > +	-e '/^ / {H; $$!d}' \
> > +	-e 'x; /:$$/ {x; H; $$!d; s/^/ /; x}' \
> > +	-e ':filter; /^.*KBUILD_AUTOKSYM_DEP: /! {p; b next}' \
> > +	-e 's//KSYM_/; s/\n.*//; w $(1)' \
> > +	-e ':next; $$!d' \
> > +	-e '1 q; s/^/ /; x; /^ /! b filter'
> 
> This is unreadable and it does not work with my gcc version. I get
> dependencies like
> 
>     $(wildcard include/config/ksym/simple/strtoull [enabled by default].h) \

That's too bad.  This had almost zero overhead as the preprocessor 
didn't have to be executed twice.

Probably adding s/ .*//; before w $(1) would fix that.  But I agree this 
is fragile.  What gcc version is this?

> Please use some other way, which does not require parsing the compiler
> diagnostic messages. A straightforward solution is to do something
> similar to genksyms: A separate preprocessor pass with -Dsomething that
> leaves the EXPORT_SYMBOL statements alone and just collect their occurences.

I went that route at some point. But here I need to extract those 
EXPORT_SYMBOL() instances for all if_changed_dep uses.  That includes 
cc_o_c, cc_s_c, cc_i_c, cc_lst_c, as_s_S, as_o_S, etc. etc.  I need the 
corresponding preprocessor flags without the usual target flags.  Let's 
see what I can do that is more readable than a sed script.

Oh and who said that a sed script had to, or could be readable?  ;-)


Nicolas
--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Michal Marek March 4, 2016, 10:10 a.m. UTC | #3
On 2016-03-04 03:46, Nicolas Pitre wrote:
> On Thu, 3 Mar 2016, Michal Marek wrote:
> 
>> Dne 29.2.2016 v 04:48 Nicolas Pitre napsal(a):
>>> +# Filter out exported kernel symbol names advertised as warning pragmas
>>> +# by the preprocessor and write them to $(1). We must consider continuation
>>> +# lines as well: they start with a blank, or the preceeding line ends with
>>> +# a ':'. Anything else is passed through as is.
>>> +# See also __KSYM_DEP() in include/linux/export.h.
>>> +ksym_dep_filter = sed -n \
>>> +	-e '1 {x; $$!d}' \
>>> +	-e '/^ / {H; $$!d}' \
>>> +	-e 'x; /:$$/ {x; H; $$!d; s/^/ /; x}' \
>>> +	-e ':filter; /^.*KBUILD_AUTOKSYM_DEP: /! {p; b next}' \
>>> +	-e 's//KSYM_/; s/\n.*//; w $(1)' \
>>> +	-e ':next; $$!d' \
>>> +	-e '1 q; s/^/ /; x; /^ /! b filter'
>>
>> This is unreadable and it does not work with my gcc version. I get
>> dependencies like
>>
>>     $(wildcard include/config/ksym/simple/strtoull [enabled by default].h) \
> 
> That's too bad.  This had almost zero overhead as the preprocessor 
> didn't have to be executed twice.

I know you are trying to collect the exports in a single pass, but
parsing the compiler warnings is really fragile.


> Probably adding s/ .*//; before w $(1) would fix that.  But I agree this 
> is fragile.  What gcc version is this?

$ gcc --version
gcc (SUSE Linux) 4.8.3 20140627 [gcc-4_8-branch revision 212064]
...

The output looks like this:
$ echo '_Pragma("GCC warning \"KBUILD_AUTOKSYM_DEP: test\"")' | gcc
-Wall -c -xc -
<stdin>:1:13: warning: KBUILD_AUTOKSYM_DEP: test [enabled by default]

Clang output is similar, except that the text appears twice in the output:
$ echo '_Pragma("GCC warning \"KBUILD_AUTOKSYM_DEP: test\"")' | clang
-Wall -c -xc -
<stdin>:1:1: warning: KBUILD_AUTOKSYM_DEP: test [-W#pragma-messages]
_Pragma("GCC warning \"KBUILD_AUTOKSYM_DEP: test\"")
^
<scratch space>:2:6: note: expanded from here
 GCC warning "KBUILD_AUTOKSYM_DEP: test"
     ^

What is worse, older gccs do not support the GCC warning pragma:
$ gcc --version
gcc (GCC) 4.1.2 20070115 (SUSE Linux)
...
$ echo '_Pragma("GCC warning \"KBUILD_AUTOKSYM_DEP: test\"")' | gcc
-Wall -c -xc  -
<stdin>:1: warning: ignoring #pragma GCC warning


> Oh and who said that a sed script had to, or could be readable?  ;-)

I guess I could live with a non-redable sed script embedded in a
Makefile, if I knew that it won't need updating for each new compiler
release :).

Michal

--
To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/export.h b/include/linux/export.h
index 77afdb2a25..794392102d 100644
--- a/include/linux/export.h
+++ b/include/linux/export.h
@@ -76,8 +76,20 @@  extern struct module __this_module;
 	___cond_export_sym(sym, sec, conf)
 #define ___cond_export_sym(sym, sec, enabled)			\
 	__cond_export_sym_##enabled(sym, sec)
-#define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec)
-#define __cond_export_sym_0(sym, sec) /* nothing */
+#define __cond_export_sym_1(sym, sec)				\
+	__KSYM_DEP(sym) ___EXPORT_SYMBOL(sym, sec)
+#define __cond_export_sym_0(sym, sec)				\
+	__KSYM_DEP(sym) /* nothing */
+
+/*
+ * For fine grained build dependencies, we want to tell the build system
+ * about each possible exported symbol even if they're not actually exported.
+ * This is accomplished with a preprocessor warning that gets captured by
+ * the make rule (see ksym_dep_filter in scripts/Kbuild.include).
+ */
+#define __KSYM_DEP(sym) __pragma_string( KBUILD_AUTOKSYM_DEP: sym )
+#define __pragma_string(x) __emit_pragma( GCC warning #x )
+#define __emit_pragma(x) _Pragma(#x)
 
 #else
 #define __EXPORT_SYMBOL ___EXPORT_SYMBOL
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 8a257fa663..0b69479310 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -258,12 +258,40 @@  if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ),                  \
 	@set -e;                                                             \
 	$(cmd_and_fixdep))
 
+ifndef CONFIG_TRIM_UNUSED_KSYMS
+
 cmd_and_fixdep =                                                             \
 	$(echo-cmd) $(cmd_$(1));                                             \
 	scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
 	rm -f $(depfile);                                                    \
 	mv -f $(dot-target).tmp $(dot-target).cmd;
 
+else
+
+# Filter out exported kernel symbol names advertised as warning pragmas
+# by the preprocessor and write them to $(1). We must consider continuation
+# lines as well: they start with a blank, or the preceeding line ends with
+# a ':'. Anything else is passed through as is.
+# See also __KSYM_DEP() in include/linux/export.h.
+ksym_dep_filter = sed -n \
+	-e '1 {x; $$!d}' \
+	-e '/^ / {H; $$!d}' \
+	-e 'x; /:$$/ {x; H; $$!d; s/^/ /; x}' \
+	-e ':filter; /^.*KBUILD_AUTOKSYM_DEP: /! {p; b next}' \
+	-e 's//KSYM_/; s/\n.*//; w $(1)' \
+	-e ':next; $$!d' \
+	-e '1 q; s/^/ /; x; /^ /! b filter'
+
+cmd_and_fixdep =                                                             \
+	$(echo-cmd)                                                          \
+	$(cmd_$(1)) 2>&1 | $(call ksym_dep_filter,$(dot-target).ksym.tmp) >&2;\
+	scripts/basic/fixdep -e $(depfile) $@ '$(make-cmd)'                  \
+	    < $(dot-target).ksym.tmp > $(dot-target).tmp;	             \
+	rm -f $(dot-target).ksym.tmp $(depfile);                             \
+	mv -f $(dot-target).tmp $(dot-target).cmd;
+
+endif
+
 # Usage: $(call if_changed_rule,foo)
 # Will check if $(cmd_foo) or any of the prerequisites changed,
 # and if so will execute $(rule_foo).
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index d984deb120..2dc6bf754a 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -354,6 +354,7 @@  static void parse_dep_file(void *map, size_t len)
 
 			/* Ignore certain dependencies */
 			if (strrcmp(s, "include/generated/autoconf.h") &&
+			    strrcmp(s, "include/generated/autoksyms.h") &&
 			    strrcmp(s, "arch/um/include/uml-config.h") &&
 			    strrcmp(s, "include/linux/kconfig.h") &&
 			    strrcmp(s, ".ver")) {