summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasahiro Yamada <yamada.masahiro@socionext.com>2018-05-28 05:21:40 -0400
committerMasahiro Yamada <yamada.masahiro@socionext.com>2018-05-28 14:28:58 -0400
commit104daea149c45cc84842ce77a9bd6436d19f3dd8 (patch)
tree7f0aaa24e9fa03154a74b2bd7bcb93f24d678ea4
parentf1089c92da791034af73478159626007cba7f092 (diff)
kconfig: reference environment variables directly and remove 'option env='
To get access to environment variables, Kconfig needs to define a symbol using "option env=" syntax. It is tedious to add a symbol entry for each environment variable given that we need to define much more such as 'CC', 'AS', 'srctree' etc. to evaluate the compiler capability in Kconfig. Adding '$' for symbol references is grammatically inconsistent. Looking at the code, the symbols prefixed with 'S' are expanded by: - conf_expand_value() This is used to expand 'arch/$ARCH/defconfig' and 'defconfig_list' - sym_expand_string_value() This is used to expand strings in 'source' and 'mainmenu' All of them are fixed values independent of user configuration. So, they can be changed into the direct expansion instead of symbols. This change makes the code much cleaner. The bounce symbols 'SRCARCH', 'ARCH', 'SUBARCH', 'KERNELVERSION' are gone. sym_init() hard-coding 'UNAME_RELEASE' is also gone. 'UNAME_RELEASE' should be replaced with an environment variable. ARCH_DEFCONFIG is a normal symbol, so it should be simply referenced without '$' prefix. The new syntax is addicted by Make. The variable reference needs parentheses, like $(FOO), but you can omit them for single-letter variables, like $F. Yet, in Makefiles, people tend to use the parenthetical form for consistency / clarification. At this moment, only the environment variable is supported, but I will extend the concept of 'variable' later on. The variables are expanded in the lexer so we can simplify the token handling on the parser side. For example, the following code works. [Example code] config MY_TOOLCHAIN_LIST string default "My tools: CC=$(CC), AS=$(AS), CPP=$(CPP)" [Result] $ make -s alldefconfig && tail -n 1 .config CONFIG_MY_TOOLCHAIN_LIST="My tools: CC=gcc, AS=as, CPP=gcc -E" Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Reviewed-by: Kees Cook <keescook@chromium.org>
-rw-r--r--Documentation/kbuild/kconfig-language.txt8
-rw-r--r--Kconfig8
-rw-r--r--Makefile3
-rw-r--r--arch/sh/Kconfig4
-rw-r--r--arch/sparc/Kconfig4
-rw-r--r--arch/um/Kconfig.common4
-rw-r--r--arch/x86/Kconfig4
-rw-r--r--arch/x86/um/Kconfig6
-rw-r--r--init/Kconfig16
-rw-r--r--scripts/kconfig/confdata.c33
-rw-r--r--scripts/kconfig/kconf_id.c1
-rw-r--r--scripts/kconfig/lkc.h5
-rw-r--r--scripts/kconfig/lkc_proto.h6
-rw-r--r--scripts/kconfig/menu.c3
-rw-r--r--scripts/kconfig/preprocess.c238
-rw-r--r--scripts/kconfig/symbol.c56
-rw-r--r--scripts/kconfig/util.c29
-rw-r--r--scripts/kconfig/zconf.l67
-rw-r--r--scripts/kconfig/zconf.y2
19 files changed, 343 insertions, 154 deletions
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
index f5b9493f04ad..0e966e8f9ec7 100644
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -198,14 +198,6 @@ applicable everywhere (see syntax).
198 enables the third modular state for all config symbols. 198 enables the third modular state for all config symbols.
199 At most one symbol may have the "modules" option set. 199 At most one symbol may have the "modules" option set.
200 200
201 - "env"=<value>
202 This imports the environment variable into Kconfig. It behaves like
203 a default, except that the value comes from the environment, this
204 also means that the behaviour when mixing it with normal defaults is
205 undefined at this point. The symbol is currently not exported back
206 to the build environment (if this is desired, it can be done via
207 another symbol).
208
209 - "allnoconfig_y" 201 - "allnoconfig_y"
210 This declares the symbol as one that should have the value y when 202 This declares the symbol as one that should have the value y when
211 using "allnoconfig". Used for symbols that hide other symbols. 203 using "allnoconfig". Used for symbols that hide other symbols.
diff --git a/Kconfig b/Kconfig
index 8c4c1cb0f9cd..4af1b42ef62e 100644
--- a/Kconfig
+++ b/Kconfig
@@ -3,10 +3,6 @@
3# For a description of the syntax of this configuration file, 3# For a description of the syntax of this configuration file,
4# see Documentation/kbuild/kconfig-language.txt. 4# see Documentation/kbuild/kconfig-language.txt.
5# 5#
6mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration" 6mainmenu "Linux/$(ARCH) $(KERNELVERSION) Kernel Configuration"
7 7
8config SRCARCH 8source "arch/$(SRCARCH)/Kconfig"
9 string
10 option env="SRCARCH"
11
12source "arch/$SRCARCH/Kconfig"
diff --git a/Makefile b/Makefile
index 58afa07bdf40..59b86543da65 100644
--- a/Makefile
+++ b/Makefile
@@ -284,7 +284,8 @@ include scripts/Kbuild.include
284# Read KERNELRELEASE from include/config/kernel.release (if it exists) 284# Read KERNELRELEASE from include/config/kernel.release (if it exists)
285KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) 285KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
286KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION) 286KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
287export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION 287UNAME_RELEASE := $(shell uname --release)
288export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION UNAME_RELEASE
288 289
289# SUBARCH tells the usermode build what the underlying arch is. That is set 290# SUBARCH tells the usermode build what the underlying arch is. That is set
290# first, and if a usermode build is happening, the "ARCH=um" on the command 291# first, and if a usermode build is happening, the "ARCH=um" on the command
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 1851eaeee131..c8400e34e255 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -58,7 +58,7 @@ config SUPERH
58 <http://www.linux-sh.org/>. 58 <http://www.linux-sh.org/>.
59 59
60config SUPERH32 60config SUPERH32
61 def_bool ARCH = "sh" 61 def_bool "$(ARCH)" = "sh"
62 select HAVE_KPROBES 62 select HAVE_KPROBES
63 select HAVE_KRETPROBES 63 select HAVE_KRETPROBES
64 select HAVE_IOREMAP_PROT if MMU && !X2TLB 64 select HAVE_IOREMAP_PROT if MMU && !X2TLB
@@ -77,7 +77,7 @@ config SUPERH32
77 select HAVE_CC_STACKPROTECTOR 77 select HAVE_CC_STACKPROTECTOR
78 78
79config SUPERH64 79config SUPERH64
80 def_bool ARCH = "sh64" 80 def_bool "$(ARCH)" = "sh64"
81 select HAVE_EXIT_THREAD 81 select HAVE_EXIT_THREAD
82 select KALLSYMS 82 select KALLSYMS
83 83
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 8767e45f1b2b..df7410cb1608 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -1,6 +1,6 @@
1config 64BIT 1config 64BIT
2 bool "64-bit kernel" if ARCH = "sparc" 2 bool "64-bit kernel" if "$(ARCH)" = "sparc"
3 default ARCH = "sparc64" 3 default "$(ARCH)" = "sparc64"
4 help 4 help
5 SPARC is a family of RISC microprocessors designed and marketed by 5 SPARC is a family of RISC microprocessors designed and marketed by
6 Sun Microsystems, incorporated. They are very widely found in Sun 6 Sun Microsystems, incorporated. They are very widely found in Sun
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common
index c68add8df3ae..07f84c842cc3 100644
--- a/arch/um/Kconfig.common
+++ b/arch/um/Kconfig.common
@@ -54,10 +54,6 @@ config HZ
54 int 54 int
55 default 100 55 default 100
56 56
57config SUBARCH
58 string
59 option env="SUBARCH"
60
61config NR_CPUS 57config NR_CPUS
62 int 58 int
63 range 1 1 59 range 1 1
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c07f492b871a..22365050ef5e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1,8 +1,8 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2# Select 32 or 64 bit 2# Select 32 or 64 bit
3config 64BIT 3config 64BIT
4 bool "64-bit kernel" if ARCH = "x86" 4 bool "64-bit kernel" if "$(ARCH)" = "x86"
5 default ARCH != "i386" 5 default "$(ARCH)" != "i386"
6 ---help--- 6 ---help---
7 Say yes to build a 64-bit kernel - formerly known as x86_64 7 Say yes to build a 64-bit kernel - formerly known as x86_64
8 Say no to build a 32-bit kernel - formerly known as i386 8 Say no to build a 32-bit kernel - formerly known as i386
diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig
index 13ed827c7c66..6a15c4dcc746 100644
--- a/arch/x86/um/Kconfig
+++ b/arch/x86/um/Kconfig
@@ -1,5 +1,5 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2mainmenu "User Mode Linux/$SUBARCH $KERNELVERSION Kernel Configuration" 2mainmenu "User Mode Linux/$(SUBARCH) $(KERNELVERSION) Kernel Configuration"
3 3
4source "arch/um/Kconfig.common" 4source "arch/um/Kconfig.common"
5 5
@@ -16,8 +16,8 @@ config UML_X86
16 select GENERIC_FIND_FIRST_BIT 16 select GENERIC_FIND_FIRST_BIT
17 17
18config 64BIT 18config 64BIT
19 bool "64-bit kernel" if SUBARCH = "x86" 19 bool "64-bit kernel" if "$(SUBARCH)" = "x86"
20 default SUBARCH != "i386" 20 default "$(SUBARCH)" != "i386"
21 21
22config X86_32 22config X86_32
23 def_bool !64BIT 23 def_bool !64BIT
diff --git a/init/Kconfig b/init/Kconfig
index 15aae32e0719..1217fc62ca61 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1,20 +1,12 @@
1config ARCH
2 string
3 option env="ARCH"
4
5config KERNELVERSION
6 string
7 option env="KERNELVERSION"
8
9config DEFCONFIG_LIST 1config DEFCONFIG_LIST
10 string 2 string
11 depends on !UML 3 depends on !UML
12 option defconfig_list 4 option defconfig_list
13 default "/lib/modules/$UNAME_RELEASE/.config" 5 default "/lib/modules/$(UNAME_RELEASE)/.config"
14 default "/etc/kernel-config" 6 default "/etc/kernel-config"
15 default "/boot/config-$UNAME_RELEASE" 7 default "/boot/config-$(UNAME_RELEASE)"
16 default "$ARCH_DEFCONFIG" 8 default ARCH_DEFCONFIG
17 default "arch/$ARCH/defconfig" 9 default "arch/$(ARCH)/defconfig"
18 10
19config CONSTRUCTORS 11config CONSTRUCTORS
20 bool 12 bool
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 569217168e96..5f87ad561b08 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -30,7 +30,7 @@ static void conf_message(const char *fmt, ...)
30static const char *conf_filename; 30static const char *conf_filename;
31static int conf_lineno, conf_warnings; 31static int conf_lineno, conf_warnings;
32 32
33const char conf_defname[] = "arch/$ARCH/defconfig"; 33const char conf_defname[] = "arch/$(ARCH)/defconfig";
34 34
35static void conf_warning(const char *fmt, ...) 35static void conf_warning(const char *fmt, ...)
36{ 36{
@@ -81,39 +81,13 @@ const char *conf_get_autoconfig_name(void)
81 return name ? name : "include/config/auto.conf"; 81 return name ? name : "include/config/auto.conf";
82} 82}
83 83
84static char *conf_expand_value(const char *in)
85{
86 struct symbol *sym;
87 const char *src;
88 static char res_value[SYMBOL_MAXLENGTH];
89 char *dst, name[SYMBOL_MAXLENGTH];
90
91 res_value[0] = 0;
92 dst = name;
93 while ((src = strchr(in, '$'))) {
94 strncat(res_value, in, src - in);
95 src++;
96 dst = name;
97 while (isalnum(*src) || *src == '_')
98 *dst++ = *src++;
99 *dst = 0;
100 sym = sym_lookup(name, 0);
101 sym_calc_value(sym);
102 strcat(res_value, sym_get_string_value(sym));
103 in = src;
104 }
105 strcat(res_value, in);
106
107 return res_value;
108}
109
110char *conf_get_default_confname(void) 84char *conf_get_default_confname(void)
111{ 85{
112 struct stat buf; 86 struct stat buf;
113 static char fullname[PATH_MAX+1]; 87 static char fullname[PATH_MAX+1];
114 char *env, *name; 88 char *env, *name;
115 89
116 name = conf_expand_value(conf_defname); 90 name = expand_string(conf_defname);
117 env = getenv(SRCTREE); 91 env = getenv(SRCTREE);
118 if (env) { 92 if (env) {
119 sprintf(fullname, "%s/%s", env, name); 93 sprintf(fullname, "%s/%s", env, name);
@@ -274,7 +248,8 @@ int conf_read_simple(const char *name, int def)
274 if (expr_calc_value(prop->visible.expr) == no || 248 if (expr_calc_value(prop->visible.expr) == no ||
275 prop->expr->type != E_SYMBOL) 249 prop->expr->type != E_SYMBOL)
276 continue; 250 continue;
277 name = conf_expand_value(prop->expr->left.sym->name); 251 sym_calc_value(prop->expr->left.sym);
252 name = sym_get_string_value(prop->expr->left.sym);
278 in = zconf_fopen(name); 253 in = zconf_fopen(name);
279 if (in) { 254 if (in) {
280 conf_message("using defaults found in %s", 255 conf_message("using defaults found in %s",
diff --git a/scripts/kconfig/kconf_id.c b/scripts/kconfig/kconf_id.c
index 3ea9c5f9f730..b3e0ea0ac732 100644
--- a/scripts/kconfig/kconf_id.c
+++ b/scripts/kconfig/kconf_id.c
@@ -32,7 +32,6 @@ static struct kconf_id kconf_id_array[] = {
32 { "on", T_ON, TF_PARAM }, 32 { "on", T_ON, TF_PARAM },
33 { "modules", T_OPT_MODULES, TF_OPTION }, 33 { "modules", T_OPT_MODULES, TF_OPTION },
34 { "defconfig_list", T_OPT_DEFCONFIG_LIST, TF_OPTION }, 34 { "defconfig_list", T_OPT_DEFCONFIG_LIST, TF_OPTION },
35 { "env", T_OPT_ENV, TF_OPTION },
36 { "allnoconfig_y", T_OPT_ALLNOCONFIG_Y, TF_OPTION }, 35 { "allnoconfig_y", T_OPT_ALLNOCONFIG_Y, TF_OPTION },
37}; 36};
38 37
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 2628bc6a2141..ed3ff88e60ba 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -44,7 +44,6 @@ enum conf_def_mode {
44 44
45#define T_OPT_MODULES 1 45#define T_OPT_MODULES 1
46#define T_OPT_DEFCONFIG_LIST 2 46#define T_OPT_DEFCONFIG_LIST 2
47#define T_OPT_ENV 3
48#define T_OPT_ALLNOCONFIG_Y 4 47#define T_OPT_ALLNOCONFIG_Y 4
49 48
50struct kconf_id { 49struct kconf_id {
@@ -103,6 +102,7 @@ void *xmalloc(size_t size);
103void *xcalloc(size_t nmemb, size_t size); 102void *xcalloc(size_t nmemb, size_t size);
104void *xrealloc(void *p, size_t size); 103void *xrealloc(void *p, size_t size);
105char *xstrdup(const char *s); 104char *xstrdup(const char *s);
105char *xstrndup(const char *s, size_t n);
106 106
107struct gstr { 107struct gstr {
108 size_t len; 108 size_t len;
@@ -120,9 +120,6 @@ void str_printf(struct gstr *gs, const char *fmt, ...);
120const char *str_get(struct gstr *gs); 120const char *str_get(struct gstr *gs);
121 121
122/* symbol.c */ 122/* symbol.c */
123extern struct expr *sym_env_list;
124
125void sym_init(void);
126void sym_clear_all_valid(void); 123void sym_clear_all_valid(void);
127struct symbol *sym_choice_default(struct symbol *sym); 124struct symbol *sym_choice_default(struct symbol *sym);
128const char *sym_get_string_default(struct symbol *sym); 125const char *sym_get_string_default(struct symbol *sym);
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 9dc8abfb1dc3..9f465fe1ca85 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -49,5 +49,11 @@ const char * sym_get_string_value(struct symbol *sym);
49 49
50const char * prop_get_type_name(enum prop_type type); 50const char * prop_get_type_name(enum prop_type type);
51 51
52/* preprocess.c */
53void env_write_dep(FILE *f, const char *auto_conf_name);
54char *expand_string(const char *in);
55char *expand_dollar(const char **str);
56char *expand_one_token(const char **str);
57
52/* expr.c */ 58/* expr.c */
53void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); 59void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 068a4e4db20a..379a119dcd1e 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -214,9 +214,6 @@ void menu_add_option(int token, char *arg)
214 zconf_error("trying to redefine defconfig symbol"); 214 zconf_error("trying to redefine defconfig symbol");
215 sym_defconfig_list->flags |= SYMBOL_AUTO; 215 sym_defconfig_list->flags |= SYMBOL_AUTO;
216 break; 216 break;
217 case T_OPT_ENV:
218 prop_add_env(arg);
219 break;
220 case T_OPT_ALLNOCONFIG_Y: 217 case T_OPT_ALLNOCONFIG_Y:
221 current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; 218 current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
222 break; 219 break;
diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c
new file mode 100644
index 000000000000..a2eb2eb02929
--- /dev/null
+++ b/scripts/kconfig/preprocess.c
@@ -0,0 +1,238 @@
1// SPDX-License-Identifier: GPL-2.0
2//
3// Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
4
5#include <stdarg.h>
6#include <stdbool.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include "list.h"
12
13static void __attribute__((noreturn)) pperror(const char *format, ...)
14{
15 va_list ap;
16
17 fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
18 va_start(ap, format);
19 vfprintf(stderr, format, ap);
20 va_end(ap);
21 fprintf(stderr, "\n");
22
23 exit(1);
24}
25
26/*
27 * Environment variables
28 */
29static LIST_HEAD(env_list);
30
31struct env {
32 char *name;
33 char *value;
34 struct list_head node;
35};
36
37static void env_add(const char *name, const char *value)
38{
39 struct env *e;
40
41 e = xmalloc(sizeof(*e));
42 e->name = xstrdup(name);
43 e->value = xstrdup(value);
44
45 list_add_tail(&e->node, &env_list);
46}
47
48static void env_del(struct env *e)
49{
50 list_del(&e->node);
51 free(e->name);
52 free(e->value);
53 free(e);
54}
55
56/* The returned pointer must be freed when done */
57static char *env_expand(const char *name)
58{
59 struct env *e;
60 const char *value;
61
62 if (!*name)
63 return NULL;
64
65 list_for_each_entry(e, &env_list, node) {
66 if (!strcmp(name, e->name))
67 return xstrdup(e->value);
68 }
69
70 value = getenv(name);
71 if (!value)
72 return NULL;
73
74 /*
75 * We need to remember all referenced environment variables.
76 * They will be written out to include/config/auto.conf.cmd
77 */
78 env_add(name, value);
79
80 return xstrdup(value);
81}
82
83void env_write_dep(FILE *f, const char *autoconfig_name)
84{
85 struct env *e, *tmp;
86
87 list_for_each_entry_safe(e, tmp, &env_list, node) {
88 fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value);
89 fprintf(f, "%s: FORCE\n", autoconfig_name);
90 fprintf(f, "endif\n");
91 env_del(e);
92 }
93}
94
95static char *eval_clause(const char *str, size_t len)
96{
97 char *tmp, *name, *res;
98
99 tmp = xstrndup(str, len);
100
101 name = expand_string(tmp);
102
103 res = env_expand(name);
104 if (res)
105 goto free;
106
107 res = xstrdup("");
108free:
109 free(name);
110 free(tmp);
111
112 return res;
113}
114
115/*
116 * Expand a string that follows '$'
117 *
118 * For example, if the input string is
119 * ($(FOO)$($(BAR)))$(BAZ)
120 * this helper evaluates
121 * $($(FOO)$($(BAR)))
122 * and returns a new string containing the expansion (note that the string is
123 * recursively expanded), also advancing 'str' to point to the next character
124 * after the corresponding closing parenthesis, in this case, *str will be
125 * $(BAR)
126 */
127char *expand_dollar(const char **str)
128{
129 const char *p = *str;
130 const char *q;
131 int nest = 0;
132
133 /*
134 * In Kconfig, variable references always start with "$(".
135 * Neither single-letter variables as in $A nor curly braces as in ${CC}
136 * are supported. '$' not followed by '(' loses its special meaning.
137 */
138 if (*p != '(') {
139 *str = p;
140 return xstrdup("$");
141 }
142
143 p++;
144 q = p;
145 while (*q) {
146 if (*q == '(') {
147 nest++;
148 } else if (*q == ')') {
149 if (nest-- == 0)
150 break;
151 }
152 q++;
153 }
154
155 if (!*q)
156 pperror("unterminated reference to '%s': missing ')'", p);
157
158 /* Advance 'str' to after the expanded initial portion of the string */
159 *str = q + 1;
160
161 return eval_clause(p, q - p);
162}
163
164static char *__expand_string(const char **str, bool (*is_end)(char c))
165{
166 const char *in, *p;
167 char *expansion, *out;
168 size_t in_len, out_len;
169
170 out = xmalloc(1);
171 *out = 0;
172 out_len = 1;
173
174 p = in = *str;
175
176 while (1) {
177 if (*p == '$') {
178 in_len = p - in;
179 p++;
180 expansion = expand_dollar(&p);
181 out_len += in_len + strlen(expansion);
182 out = xrealloc(out, out_len);
183 strncat(out, in, in_len);
184 strcat(out, expansion);
185 free(expansion);
186 in = p;
187 continue;
188 }
189
190 if (is_end(*p))
191 break;
192
193 p++;
194 }
195
196 in_len = p - in;
197 out_len += in_len;
198 out = xrealloc(out, out_len);
199 strncat(out, in, in_len);
200
201 /* Advance 'str' to the end character */
202 *str = p;
203
204 return out;
205}
206
207static bool is_end_of_str(char c)
208{
209 return !c;
210}
211
212/*
213 * Expand variables in the given string. Undefined variables
214 * expand to an empty string.
215 * The returned string must be freed when done.
216 */
217char *expand_string(const char *in)
218{
219 return __expand_string(&in, is_end_of_str);
220}
221
222static bool is_end_of_token(char c)
223{
224 /* Why are '.' and '/' valid characters for symbols? */
225 return !(isalnum(c) || c == '_' || c == '-' || c == '.' || c == '/');
226}
227
228/*
229 * Expand variables in a token. The parsing stops when a token separater
230 * (in most cases, it is a whitespace) is encountered. 'str' is updated to
231 * point to the next character.
232 *
233 * The returned string must be freed when done.
234 */
235char *expand_one_token(const char **str)
236{
237 return __expand_string(str, is_end_of_token);
238}
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index f0b2e3b3102d..2460648a581a 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -33,33 +33,6 @@ struct symbol *sym_defconfig_list;
33struct symbol *modules_sym; 33struct symbol *modules_sym;
34tristate modules_val; 34tristate modules_val;
35 35
36struct expr *sym_env_list;
37
38static void sym_add_default(struct symbol *sym, const char *def)
39{
40 struct property *prop = prop_alloc(P_DEFAULT, sym);
41
42 prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
43}
44
45void sym_init(void)
46{
47 struct symbol *sym;
48 struct utsname uts;
49 static bool inited = false;
50
51 if (inited)
52 return;
53 inited = true;
54
55 uname(&uts);
56
57 sym = sym_lookup("UNAME_RELEASE", 0);
58 sym->type = S_STRING;
59 sym->flags |= SYMBOL_AUTO;
60 sym_add_default(sym, uts.release);
61}
62
63enum symbol_type sym_get_type(struct symbol *sym) 36enum symbol_type sym_get_type(struct symbol *sym)
64{ 37{
65 enum symbol_type type = sym->type; 38 enum symbol_type type = sym->type;
@@ -1401,32 +1374,3 @@ const char *prop_get_type_name(enum prop_type type)
1401 } 1374 }
1402 return "unknown"; 1375 return "unknown";
1403} 1376}
1404
1405static void prop_add_env(const char *env)
1406{
1407 struct symbol *sym, *sym2;
1408 struct property *prop;
1409 char *p;
1410
1411 sym = current_entry->sym;
1412 sym->flags |= SYMBOL_AUTO;
1413 for_all_properties(sym, prop, P_ENV) {
1414 sym2 = prop_get_symbol(prop);
1415 if (strcmp(sym2->name, env))
1416 menu_warn(current_entry, "redefining environment symbol from %s",
1417 sym2->name);
1418 return;
1419 }
1420
1421 prop = prop_alloc(P_ENV, sym);
1422 prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
1423
1424 sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
1425 sym_env_list->right.sym = sym;
1426
1427 p = getenv(env);
1428 if (p)
1429 sym_add_default(sym, p);
1430 else
1431 menu_warn(current_entry, "environment variable %s undefined", env);
1432}
diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c
index c6f6e21b809f..703ee4904613 100644
--- a/scripts/kconfig/util.c
+++ b/scripts/kconfig/util.c
@@ -34,8 +34,6 @@ struct file *file_lookup(const char *name)
34/* write a dependency file as used by kbuild to track dependencies */ 34/* write a dependency file as used by kbuild to track dependencies */
35int file_write_dep(const char *name) 35int file_write_dep(const char *name)
36{ 36{
37 struct symbol *sym, *env_sym;
38 struct expr *e;
39 struct file *file; 37 struct file *file;
40 FILE *out; 38 FILE *out;
41 39
@@ -54,21 +52,7 @@ int file_write_dep(const char *name)
54 fprintf(out, "\n%s: \\\n" 52 fprintf(out, "\n%s: \\\n"
55 "\t$(deps_config)\n\n", conf_get_autoconfig_name()); 53 "\t$(deps_config)\n\n", conf_get_autoconfig_name());
56 54
57 expr_list_for_each_sym(sym_env_list, e, sym) { 55 env_write_dep(out, conf_get_autoconfig_name());
58 struct property *prop;
59 const char *value;
60
61 prop = sym_get_env_prop(sym);
62 env_sym = prop_get_symbol(prop);
63 if (!env_sym)
64 continue;
65 value = getenv(env_sym->name);
66 if (!value)
67 value = "";
68 fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
69 fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
70 fprintf(out, "endif\n");
71 }
72 56
73 fprintf(out, "\n$(deps_config): ;\n"); 57 fprintf(out, "\n$(deps_config): ;\n");
74 fclose(out); 58 fclose(out);
@@ -165,3 +149,14 @@ char *xstrdup(const char *s)
165 fprintf(stderr, "Out of memory.\n"); 149 fprintf(stderr, "Out of memory.\n");
166 exit(1); 150 exit(1);
167} 151}
152
153char *xstrndup(const char *s, size_t n)
154{
155 char *p;
156
157 p = strndup(s, n);
158 if (p)
159 return p;
160 fprintf(stderr, "Out of memory.\n");
161 exit(1);
162}
diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l
index 045093d827e1..b3855909913c 100644
--- a/scripts/kconfig/zconf.l
+++ b/scripts/kconfig/zconf.l
@@ -1,6 +1,5 @@
1%option nostdinit noyywrap never-interactive full ecs 1%option nostdinit noyywrap never-interactive full ecs
2%option 8bit nodefault yylineno 2%option 8bit nodefault yylineno
3%option noinput
4%x COMMAND HELP STRING PARAM 3%x COMMAND HELP STRING PARAM
5%{ 4%{
6/* 5/*
@@ -35,6 +34,8 @@ struct buffer *current_buf;
35 34
36static int last_ts, first_ts; 35static int last_ts, first_ts;
37 36
37static char *expand_token(const char *in, size_t n);
38static void append_expanded_string(const char *in);
38static void zconf_endhelp(void); 39static void zconf_endhelp(void);
39static void zconf_endfile(void); 40static void zconf_endfile(void);
40 41
@@ -147,6 +148,13 @@ n [A-Za-z0-9_-]
147 yylval.string = text; 148 yylval.string = text;
148 return T_WORD; 149 return T_WORD;
149 } 150 }
151 ({n}|[/.$])+ {
152 /* this token includes at least one '$' */
153 yylval.string = expand_token(yytext, yyleng);
154 if (strlen(yylval.string))
155 return T_WORD;
156 free(yylval.string);
157 }
150 #.* /* comment */ 158 #.* /* comment */
151 \\\n ; 159 \\\n ;
152 [[:blank:]]+ 160 [[:blank:]]+
@@ -157,12 +165,13 @@ n [A-Za-z0-9_-]
157} 165}
158 166
159<STRING>{ 167<STRING>{
160 [^'"\\\n]+/\n { 168 "$".* append_expanded_string(yytext);
169 [^$'"\\\n]+/\n {
161 append_string(yytext, yyleng); 170 append_string(yytext, yyleng);
162 yylval.string = text; 171 yylval.string = text;
163 return T_WORD_QUOTE; 172 return T_WORD_QUOTE;
164 } 173 }
165 [^'"\\\n]+ { 174 [^$'"\\\n]+ {
166 append_string(yytext, yyleng); 175 append_string(yytext, yyleng);
167 } 176 }
168 \\.?/\n { 177 \\.?/\n {
@@ -249,6 +258,58 @@ n [A-Za-z0-9_-]
249} 258}
250 259
251%% 260%%
261static char *expand_token(const char *in, size_t n)
262{
263 char *out;
264 int c;
265 char c2;
266 const char *rest, *end;
267
268 new_string();
269 append_string(in, n);
270
271 /* get the whole line because we do not know the end of token. */
272 while ((c = input()) != EOF) {
273 if (c == '\n') {
274 unput(c);
275 break;
276 }
277 c2 = c;
278 append_string(&c2, 1);
279 }
280
281 rest = text;
282 out = expand_one_token(&rest);
283
284 /* push back unused characters to the input stream */
285 end = rest + strlen(rest);
286 while (end > rest)
287 unput(*--end);
288
289 free(text);
290
291 return out;
292}
293
294static void append_expanded_string(const char *str)
295{
296 const char *end;
297 char *res;
298
299 str++;
300
301 res = expand_dollar(&str);
302
303 /* push back unused characters to the input stream */
304 end = str + strlen(str);
305 while (end > str)
306 unput(*--end);
307
308 append_string(res, strlen(res));
309
310 free(res);
311}
312
252void zconf_starthelp(void) 313void zconf_starthelp(void)
253{ 314{
254 new_string(); 315 new_string();
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index 8bfaaf853d23..031b2e24ae00 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -534,7 +534,6 @@ void conf_parse(const char *name)
534 534
535 zconf_initscan(name); 535 zconf_initscan(name);
536 536
537 sym_init();
538 _menu_init(); 537 _menu_init();
539 538
540 if (getenv("ZCONF_DEBUG")) 539 if (getenv("ZCONF_DEBUG"))
@@ -780,3 +779,4 @@ void zconfdump(FILE *out)
780#include "expr.c" 779#include "expr.c"
781#include "symbol.c" 780#include "symbol.c"
782#include "menu.c" 781#include "menu.c"
782#include "preprocess.c"