Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kbuild: simplify dependency generation for CONFIG_TRIM_UNUSED_KSYMS

My main motivation of this commit is to clean up scripts/Kbuild.include
and scripts/Makefile.build.

Currently, CONFIG_TRIM_UNUSED_KSYMS works with a tricky gimmick;
possibly exported symbols are detected by letting $(CPP) replace
EXPORT_SYMBOL* with a special string '=== __KSYM_*===', which is
post-processed by sed, and passed to fixdep. The extra preprocessing
is costly, and hacking cmd_and_fixdep is ugly.

I came up with a new way to find exported symbols; insert a dummy
symbol __ksym_marker_* to each potentially exported symbol. Those
dummy symbols are picked up by $(NM), post-processed by sed, then
appended to .*.cmd files. I collected the post-process part to a
new shell script scripts/gen_ksymdeps.sh for readability. The dummy
symbols are put into the .discard.* section so that the linker
script rips them off the final vmlinux or modules.

A nice side-effect is building with CONFIG_TRIM_UNUSED_KSYMS will
be much faster.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Reviewed-by: Nicolas Pitre <nico@linaro.org>

+55 -71
+8 -5
include/asm-generic/export.h
··· 59 59 .endm 60 60 #undef __put 61 61 62 - #if defined(__KSYM_DEPS__) 63 - 64 - #define __EXPORT_SYMBOL(sym, val, sec) === __KSYM_##sym === 65 - 66 - #elif defined(CONFIG_TRIM_UNUSED_KSYMS) 62 + #if defined(CONFIG_TRIM_UNUSED_KSYMS) 67 63 68 64 #include <linux/kconfig.h> 69 65 #include <generated/autoksyms.h> 70 66 67 + .macro __ksym_marker sym 68 + .section ".discard.ksym","a" 69 + __ksym_marker_\sym: 70 + .previous 71 + .endm 72 + 71 73 #define __EXPORT_SYMBOL(sym, val, sec) \ 74 + __ksym_marker sym; \ 72 75 __cond_export_sym(sym, val, sec, __is_defined(__KSYM_##sym)) 73 76 #define __cond_export_sym(sym, val, sec, conf) \ 74 77 ___cond_export_sym(sym, val, sec, conf)
+11 -11
include/linux/export.h
··· 92 92 */ 93 93 #define __EXPORT_SYMBOL(sym, sec) 94 94 95 - #elif defined(__KSYM_DEPS__) 96 - 97 - /* 98 - * For fine grained build dependencies, we want to tell the build system 99 - * about each possible exported symbol even if they're not actually exported. 100 - * We use a string pattern that is unlikely to be valid code that the build 101 - * system filters out from the preprocessor output (see ksym_dep_filter 102 - * in scripts/Kbuild.include). 103 - */ 104 - #define __EXPORT_SYMBOL(sym, sec) === __KSYM_##sym === 105 - 106 95 #elif defined(CONFIG_TRIM_UNUSED_KSYMS) 107 96 108 97 #include <generated/autoksyms.h> 109 98 99 + /* 100 + * For fine grained build dependencies, we want to tell the build system 101 + * about each possible exported symbol even if they're not actually exported. 102 + * We use a symbol pattern __ksym_marker_<symbol> that the build system filters 103 + * from the $(NM) output (see scripts/gen_ksymdeps.sh). These symbols are 104 + * discarded in the final link stage. 105 + */ 106 + #define __ksym_marker(sym) \ 107 + static int __ksym_marker_##sym[0] __section(".discard.ksym") __used 108 + 110 109 #define __EXPORT_SYMBOL(sym, sec) \ 110 + __ksym_marker(sym); \ 111 111 __cond_export_sym(sym, sec, __is_defined(__KSYM_##sym)) 112 112 #define __cond_export_sym(sym, sec, conf) \ 113 113 ___cond_export_sym(sym, sec, conf)
-28
scripts/Kbuild.include
··· 260 260 @set -e; \ 261 261 $(cmd_and_fixdep), @:) 262 262 263 - ifndef CONFIG_TRIM_UNUSED_KSYMS 264 - 265 263 cmd_and_fixdep = \ 266 264 $(echo-cmd) $(cmd_$(1)); \ 267 265 scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\ 268 266 rm -f $(depfile); 269 - 270 - else 271 - 272 - # Filter out exported kernel symbol names from the preprocessor output. 273 - # See also __KSYM_DEPS__ in include/linux/export.h. 274 - # We disable the depfile generation here, so as not to overwrite the existing 275 - # depfile while fixdep is parsing it. 276 - flags_nodeps = $(filter-out -Wp$(comma)-M%, $($(1))) 277 - ksym_dep_filter = \ 278 - case "$(1)" in \ 279 - cc_*_c|cpp_i_c) \ 280 - $(CPP) $(call flags_nodeps,c_flags) -D__KSYM_DEPS__ $< ;; \ 281 - as_*_S|cpp_s_S) \ 282 - $(CPP) $(call flags_nodeps,a_flags) -D__KSYM_DEPS__ $< ;; \ 283 - boot*|build*|cpp_its_S|*cpp_lds_S|dtc|host*|vdso*) : ;; \ 284 - *) echo "Don't know how to preprocess $(1)" >&2; false ;; \ 285 - esac | tr ";" "\n" | sed -n 's/^.*=== __KSYM_\(.*\) ===.*$$/_\1/p' 286 - 287 - cmd_and_fixdep = \ 288 - $(echo-cmd) $(cmd_$(1)); \ 289 - $(ksym_dep_filter) | \ 290 - scripts/basic/fixdep -e $(depfile) $@ '$(make-cmd)' \ 291 - > $(dot-target).cmd; \ 292 - rm -f $(depfile); 293 - 294 - endif 295 267 296 268 # Usage: $(call if_changed_rule,foo) 297 269 # Will check if $(cmd_foo) or any of the prerequisites changed,
+7
scripts/Makefile.build
··· 254 254 $(wildcard include/config/orc/unwinder.h \ 255 255 include/config/stack/validation.h) 256 256 257 + ifdef CONFIG_TRIM_UNUSED_KSYMS 258 + cmd_gen_ksymdeps = \ 259 + $(CONFIG_SHELL) $(srctree)/scripts/gen_ksymdeps.sh $@ >> $(dot-target).cmd; 260 + endif 261 + 257 262 define rule_cc_o_c 258 263 $(call echo-cmd,checksrc) $(cmd_checksrc) \ 259 264 $(call cmd_and_fixdep,cc_o_c) \ 265 + $(cmd_gen_ksymdeps) \ 260 266 $(cmd_checkdoc) \ 261 267 $(call echo-cmd,objtool) $(cmd_objtool) \ 262 268 $(cmd_modversions_c) \ ··· 271 265 272 266 define rule_as_o_S 273 267 $(call cmd_and_fixdep,as_o_S) \ 268 + $(cmd_gen_ksymdeps) \ 274 269 $(call echo-cmd,objtool) $(cmd_objtool) \ 275 270 $(cmd_modversions_S) 276 271 endef
+4 -27
scripts/basic/fixdep.c
··· 105 105 106 106 static void usage(void) 107 107 { 108 - fprintf(stderr, "Usage: fixdep [-e] <depfile> <target> <cmdline>\n"); 109 - fprintf(stderr, " -e insert extra dependencies given on stdin\n"); 108 + fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n"); 110 109 exit(1); 111 110 } 112 111 ··· 128 129 prev_c = c; 129 130 } 130 131 printf(".h) \\\n"); 131 - } 132 - 133 - static void do_extra_deps(void) 134 - { 135 - char buf[80]; 136 - 137 - while (fgets(buf, sizeof(buf), stdin)) { 138 - int len = strlen(buf); 139 - 140 - if (len < 2 || buf[len - 1] != '\n') { 141 - fprintf(stderr, "fixdep: bad data on stdin\n"); 142 - exit(1); 143 - } 144 - print_dep(buf, len - 1, "include/ksym"); 145 - } 146 132 } 147 133 148 134 struct item { ··· 277 293 * assignments are parsed not only by make, but also by the rather simple 278 294 * parser in scripts/mod/sumversion.c. 279 295 */ 280 - static void parse_dep_file(char *m, const char *target, int insert_extra_deps) 296 + static void parse_dep_file(char *m, const char *target) 281 297 { 282 298 char *p; 283 299 int is_last, is_target; ··· 353 369 exit(1); 354 370 } 355 371 356 - if (insert_extra_deps) 357 - do_extra_deps(); 358 - 359 372 printf("\n%s: $(deps_%s)\n\n", target, target); 360 373 printf("$(deps_%s):\n", target); 361 374 } ··· 360 379 int main(int argc, char *argv[]) 361 380 { 362 381 const char *depfile, *target, *cmdline; 363 - int insert_extra_deps = 0; 364 382 void *buf; 365 383 366 - if (argc == 5 && !strcmp(argv[1], "-e")) { 367 - insert_extra_deps = 1; 368 - argv++; 369 - } else if (argc != 4) 384 + if (argc != 4) 370 385 usage(); 371 386 372 387 depfile = argv[1]; ··· 372 395 printf("cmd_%s := %s\n\n", target, cmdline); 373 396 374 397 buf = read_file(depfile); 375 - parse_dep_file(buf, target, insert_extra_deps); 398 + parse_dep_file(buf, target); 376 399 free(buf); 377 400 378 401 return 0;
+25
scripts/gen_ksymdeps.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + set -e 5 + 6 + # List of exported symbols 7 + ksyms=$($NM $1 | sed -n 's/.*__ksym_marker_\(.*\)/\1/p' | tr A-Z a-z) 8 + 9 + if [ -z "$ksyms" ]; then 10 + exit 0 11 + fi 12 + 13 + echo 14 + echo "ksymdeps_$1 := \\" 15 + 16 + for s in $ksyms 17 + do 18 + echo $s | sed -e 's:^_*: $(wildcard include/ksym/:' \ 19 + -e 's:__*:/:g' -e 's/$/.h) \\/' 20 + done 21 + 22 + echo 23 + echo "$1: \$(ksymdeps_$1)" 24 + echo 25 + echo "\$(ksymdeps_$1):"