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>
This commit is contained in:
parent
f1089c92da
commit
104daea149
|
@ -198,14 +198,6 @@ applicable everywhere (see syntax).
|
|||
enables the third modular state for all config symbols.
|
||||
At most one symbol may have the "modules" option set.
|
||||
|
||||
- "env"=<value>
|
||||
This imports the environment variable into Kconfig. It behaves like
|
||||
a default, except that the value comes from the environment, this
|
||||
also means that the behaviour when mixing it with normal defaults is
|
||||
undefined at this point. The symbol is currently not exported back
|
||||
to the build environment (if this is desired, it can be done via
|
||||
another symbol).
|
||||
|
||||
- "allnoconfig_y"
|
||||
This declares the symbol as one that should have the value y when
|
||||
using "allnoconfig". Used for symbols that hide other symbols.
|
||||
|
|
8
Kconfig
8
Kconfig
|
@ -3,10 +3,6 @@
|
|||
# For a description of the syntax of this configuration file,
|
||||
# see Documentation/kbuild/kconfig-language.txt.
|
||||
#
|
||||
mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration"
|
||||
mainmenu "Linux/$(ARCH) $(KERNELVERSION) Kernel Configuration"
|
||||
|
||||
config SRCARCH
|
||||
string
|
||||
option env="SRCARCH"
|
||||
|
||||
source "arch/$SRCARCH/Kconfig"
|
||||
source "arch/$(SRCARCH)/Kconfig"
|
||||
|
|
3
Makefile
3
Makefile
|
@ -284,7 +284,8 @@ include scripts/Kbuild.include
|
|||
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
|
||||
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
|
||||
KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
|
||||
export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
|
||||
UNAME_RELEASE := $(shell uname --release)
|
||||
export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION UNAME_RELEASE
|
||||
|
||||
# SUBARCH tells the usermode build what the underlying arch is. That is set
|
||||
# first, and if a usermode build is happening, the "ARCH=um" on the command
|
||||
|
|
|
@ -58,7 +58,7 @@ config SUPERH
|
|||
<http://www.linux-sh.org/>.
|
||||
|
||||
config SUPERH32
|
||||
def_bool ARCH = "sh"
|
||||
def_bool "$(ARCH)" = "sh"
|
||||
select HAVE_KPROBES
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_IOREMAP_PROT if MMU && !X2TLB
|
||||
|
@ -77,7 +77,7 @@ config SUPERH32
|
|||
select HAVE_CC_STACKPROTECTOR
|
||||
|
||||
config SUPERH64
|
||||
def_bool ARCH = "sh64"
|
||||
def_bool "$(ARCH)" = "sh64"
|
||||
select HAVE_EXIT_THREAD
|
||||
select KALLSYMS
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config 64BIT
|
||||
bool "64-bit kernel" if ARCH = "sparc"
|
||||
default ARCH = "sparc64"
|
||||
bool "64-bit kernel" if "$(ARCH)" = "sparc"
|
||||
default "$(ARCH)" = "sparc64"
|
||||
help
|
||||
SPARC is a family of RISC microprocessors designed and marketed by
|
||||
Sun Microsystems, incorporated. They are very widely found in Sun
|
||||
|
|
|
@ -54,10 +54,6 @@ config HZ
|
|||
int
|
||||
default 100
|
||||
|
||||
config SUBARCH
|
||||
string
|
||||
option env="SUBARCH"
|
||||
|
||||
config NR_CPUS
|
||||
int
|
||||
range 1 1
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Select 32 or 64 bit
|
||||
config 64BIT
|
||||
bool "64-bit kernel" if ARCH = "x86"
|
||||
default ARCH != "i386"
|
||||
bool "64-bit kernel" if "$(ARCH)" = "x86"
|
||||
default "$(ARCH)" != "i386"
|
||||
---help---
|
||||
Say yes to build a 64-bit kernel - formerly known as x86_64
|
||||
Say no to build a 32-bit kernel - formerly known as i386
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
mainmenu "User Mode Linux/$SUBARCH $KERNELVERSION Kernel Configuration"
|
||||
mainmenu "User Mode Linux/$(SUBARCH) $(KERNELVERSION) Kernel Configuration"
|
||||
|
||||
source "arch/um/Kconfig.common"
|
||||
|
||||
|
@ -16,8 +16,8 @@ config UML_X86
|
|||
select GENERIC_FIND_FIRST_BIT
|
||||
|
||||
config 64BIT
|
||||
bool "64-bit kernel" if SUBARCH = "x86"
|
||||
default SUBARCH != "i386"
|
||||
bool "64-bit kernel" if "$(SUBARCH)" = "x86"
|
||||
default "$(SUBARCH)" != "i386"
|
||||
|
||||
config X86_32
|
||||
def_bool !64BIT
|
||||
|
|
16
init/Kconfig
16
init/Kconfig
|
@ -1,20 +1,12 @@
|
|||
config ARCH
|
||||
string
|
||||
option env="ARCH"
|
||||
|
||||
config KERNELVERSION
|
||||
string
|
||||
option env="KERNELVERSION"
|
||||
|
||||
config DEFCONFIG_LIST
|
||||
string
|
||||
depends on !UML
|
||||
option defconfig_list
|
||||
default "/lib/modules/$UNAME_RELEASE/.config"
|
||||
default "/lib/modules/$(UNAME_RELEASE)/.config"
|
||||
default "/etc/kernel-config"
|
||||
default "/boot/config-$UNAME_RELEASE"
|
||||
default "$ARCH_DEFCONFIG"
|
||||
default "arch/$ARCH/defconfig"
|
||||
default "/boot/config-$(UNAME_RELEASE)"
|
||||
default ARCH_DEFCONFIG
|
||||
default "arch/$(ARCH)/defconfig"
|
||||
|
||||
config CONSTRUCTORS
|
||||
bool
|
||||
|
|
|
@ -30,7 +30,7 @@ static void conf_message(const char *fmt, ...)
|
|||
static const char *conf_filename;
|
||||
static int conf_lineno, conf_warnings;
|
||||
|
||||
const char conf_defname[] = "arch/$ARCH/defconfig";
|
||||
const char conf_defname[] = "arch/$(ARCH)/defconfig";
|
||||
|
||||
static void conf_warning(const char *fmt, ...)
|
||||
{
|
||||
|
@ -81,39 +81,13 @@ const char *conf_get_autoconfig_name(void)
|
|||
return name ? name : "include/config/auto.conf";
|
||||
}
|
||||
|
||||
static char *conf_expand_value(const char *in)
|
||||
{
|
||||
struct symbol *sym;
|
||||
const char *src;
|
||||
static char res_value[SYMBOL_MAXLENGTH];
|
||||
char *dst, name[SYMBOL_MAXLENGTH];
|
||||
|
||||
res_value[0] = 0;
|
||||
dst = name;
|
||||
while ((src = strchr(in, '$'))) {
|
||||
strncat(res_value, in, src - in);
|
||||
src++;
|
||||
dst = name;
|
||||
while (isalnum(*src) || *src == '_')
|
||||
*dst++ = *src++;
|
||||
*dst = 0;
|
||||
sym = sym_lookup(name, 0);
|
||||
sym_calc_value(sym);
|
||||
strcat(res_value, sym_get_string_value(sym));
|
||||
in = src;
|
||||
}
|
||||
strcat(res_value, in);
|
||||
|
||||
return res_value;
|
||||
}
|
||||
|
||||
char *conf_get_default_confname(void)
|
||||
{
|
||||
struct stat buf;
|
||||
static char fullname[PATH_MAX+1];
|
||||
char *env, *name;
|
||||
|
||||
name = conf_expand_value(conf_defname);
|
||||
name = expand_string(conf_defname);
|
||||
env = getenv(SRCTREE);
|
||||
if (env) {
|
||||
sprintf(fullname, "%s/%s", env, name);
|
||||
|
@ -274,7 +248,8 @@ int conf_read_simple(const char *name, int def)
|
|||
if (expr_calc_value(prop->visible.expr) == no ||
|
||||
prop->expr->type != E_SYMBOL)
|
||||
continue;
|
||||
name = conf_expand_value(prop->expr->left.sym->name);
|
||||
sym_calc_value(prop->expr->left.sym);
|
||||
name = sym_get_string_value(prop->expr->left.sym);
|
||||
in = zconf_fopen(name);
|
||||
if (in) {
|
||||
conf_message("using defaults found in %s",
|
||||
|
|
|
@ -32,7 +32,6 @@ static struct kconf_id kconf_id_array[] = {
|
|||
{ "on", T_ON, TF_PARAM },
|
||||
{ "modules", T_OPT_MODULES, TF_OPTION },
|
||||
{ "defconfig_list", T_OPT_DEFCONFIG_LIST, TF_OPTION },
|
||||
{ "env", T_OPT_ENV, TF_OPTION },
|
||||
{ "allnoconfig_y", T_OPT_ALLNOCONFIG_Y, TF_OPTION },
|
||||
};
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ enum conf_def_mode {
|
|||
|
||||
#define T_OPT_MODULES 1
|
||||
#define T_OPT_DEFCONFIG_LIST 2
|
||||
#define T_OPT_ENV 3
|
||||
#define T_OPT_ALLNOCONFIG_Y 4
|
||||
|
||||
struct kconf_id {
|
||||
|
@ -103,6 +102,7 @@ void *xmalloc(size_t size);
|
|||
void *xcalloc(size_t nmemb, size_t size);
|
||||
void *xrealloc(void *p, size_t size);
|
||||
char *xstrdup(const char *s);
|
||||
char *xstrndup(const char *s, size_t n);
|
||||
|
||||
struct gstr {
|
||||
size_t len;
|
||||
|
@ -120,9 +120,6 @@ void str_printf(struct gstr *gs, const char *fmt, ...);
|
|||
const char *str_get(struct gstr *gs);
|
||||
|
||||
/* symbol.c */
|
||||
extern struct expr *sym_env_list;
|
||||
|
||||
void sym_init(void);
|
||||
void sym_clear_all_valid(void);
|
||||
struct symbol *sym_choice_default(struct symbol *sym);
|
||||
const char *sym_get_string_default(struct symbol *sym);
|
||||
|
|
|
@ -49,5 +49,11 @@ const char * sym_get_string_value(struct symbol *sym);
|
|||
|
||||
const char * prop_get_type_name(enum prop_type type);
|
||||
|
||||
/* preprocess.c */
|
||||
void env_write_dep(FILE *f, const char *auto_conf_name);
|
||||
char *expand_string(const char *in);
|
||||
char *expand_dollar(const char **str);
|
||||
char *expand_one_token(const char **str);
|
||||
|
||||
/* expr.c */
|
||||
void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken);
|
||||
|
|
|
@ -214,9 +214,6 @@ void menu_add_option(int token, char *arg)
|
|||
zconf_error("trying to redefine defconfig symbol");
|
||||
sym_defconfig_list->flags |= SYMBOL_AUTO;
|
||||
break;
|
||||
case T_OPT_ENV:
|
||||
prop_add_env(arg);
|
||||
break;
|
||||
case T_OPT_ALLNOCONFIG_Y:
|
||||
current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
|
||||
break;
|
||||
|
|
238
scripts/kconfig/preprocess.c
Normal file
238
scripts/kconfig/preprocess.c
Normal file
|
@ -0,0 +1,238 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "list.h"
|
||||
|
||||
static void __attribute__((noreturn)) pperror(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Environment variables
|
||||
*/
|
||||
static LIST_HEAD(env_list);
|
||||
|
||||
struct env {
|
||||
char *name;
|
||||
char *value;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static void env_add(const char *name, const char *value)
|
||||
{
|
||||
struct env *e;
|
||||
|
||||
e = xmalloc(sizeof(*e));
|
||||
e->name = xstrdup(name);
|
||||
e->value = xstrdup(value);
|
||||
|
||||
list_add_tail(&e->node, &env_list);
|
||||
}
|
||||
|
||||
static void env_del(struct env *e)
|
||||
{
|
||||
list_del(&e->node);
|
||||
free(e->name);
|
||||
free(e->value);
|
||||
free(e);
|
||||
}
|
||||
|
||||
/* The returned pointer must be freed when done */
|
||||
static char *env_expand(const char *name)
|
||||
{
|
||||
struct env *e;
|
||||
const char *value;
|
||||
|
||||
if (!*name)
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(e, &env_list, node) {
|
||||
if (!strcmp(name, e->name))
|
||||
return xstrdup(e->value);
|
||||
}
|
||||
|
||||
value = getenv(name);
|
||||
if (!value)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* We need to remember all referenced environment variables.
|
||||
* They will be written out to include/config/auto.conf.cmd
|
||||
*/
|
||||
env_add(name, value);
|
||||
|
||||
return xstrdup(value);
|
||||
}
|
||||
|
||||
void env_write_dep(FILE *f, const char *autoconfig_name)
|
||||
{
|
||||
struct env *e, *tmp;
|
||||
|
||||
list_for_each_entry_safe(e, tmp, &env_list, node) {
|
||||
fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value);
|
||||
fprintf(f, "%s: FORCE\n", autoconfig_name);
|
||||
fprintf(f, "endif\n");
|
||||
env_del(e);
|
||||
}
|
||||
}
|
||||
|
||||
static char *eval_clause(const char *str, size_t len)
|
||||
{
|
||||
char *tmp, *name, *res;
|
||||
|
||||
tmp = xstrndup(str, len);
|
||||
|
||||
name = expand_string(tmp);
|
||||
|
||||
res = env_expand(name);
|
||||
if (res)
|
||||
goto free;
|
||||
|
||||
res = xstrdup("");
|
||||
free:
|
||||
free(name);
|
||||
free(tmp);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand a string that follows '$'
|
||||
*
|
||||
* For example, if the input string is
|
||||
* ($(FOO)$($(BAR)))$(BAZ)
|
||||
* this helper evaluates
|
||||
* $($(FOO)$($(BAR)))
|
||||
* and returns a new string containing the expansion (note that the string is
|
||||
* recursively expanded), also advancing 'str' to point to the next character
|
||||
* after the corresponding closing parenthesis, in this case, *str will be
|
||||
* $(BAR)
|
||||
*/
|
||||
char *expand_dollar(const char **str)
|
||||
{
|
||||
const char *p = *str;
|
||||
const char *q;
|
||||
int nest = 0;
|
||||
|
||||
/*
|
||||
* In Kconfig, variable references always start with "$(".
|
||||
* Neither single-letter variables as in $A nor curly braces as in ${CC}
|
||||
* are supported. '$' not followed by '(' loses its special meaning.
|
||||
*/
|
||||
if (*p != '(') {
|
||||
*str = p;
|
||||
return xstrdup("$");
|
||||
}
|
||||
|
||||
p++;
|
||||
q = p;
|
||||
while (*q) {
|
||||
if (*q == '(') {
|
||||
nest++;
|
||||
} else if (*q == ')') {
|
||||
if (nest-- == 0)
|
||||
break;
|
||||
}
|
||||
q++;
|
||||
}
|
||||
|
||||
if (!*q)
|
||||
pperror("unterminated reference to '%s': missing ')'", p);
|
||||
|
||||
/* Advance 'str' to after the expanded initial portion of the string */
|
||||
*str = q + 1;
|
||||
|
||||
return eval_clause(p, q - p);
|
||||
}
|
||||
|
||||
static char *__expand_string(const char **str, bool (*is_end)(char c))
|
||||
{
|
||||
const char *in, *p;
|
||||
char *expansion, *out;
|
||||
size_t in_len, out_len;
|
||||
|
||||
out = xmalloc(1);
|
||||
*out = 0;
|
||||
out_len = 1;
|
||||
|
||||
p = in = *str;
|
||||
|
||||
while (1) {
|
||||
if (*p == '$') {
|
||||
in_len = p - in;
|
||||
p++;
|
||||
expansion = expand_dollar(&p);
|
||||
out_len += in_len + strlen(expansion);
|
||||
out = xrealloc(out, out_len);
|
||||
strncat(out, in, in_len);
|
||||
strcat(out, expansion);
|
||||
free(expansion);
|
||||
in = p;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_end(*p))
|
||||
break;
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
in_len = p - in;
|
||||
out_len += in_len;
|
||||
out = xrealloc(out, out_len);
|
||||
strncat(out, in, in_len);
|
||||
|
||||
/* Advance 'str' to the end character */
|
||||
*str = p;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool is_end_of_str(char c)
|
||||
{
|
||||
return !c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand variables in the given string. Undefined variables
|
||||
* expand to an empty string.
|
||||
* The returned string must be freed when done.
|
||||
*/
|
||||
char *expand_string(const char *in)
|
||||
{
|
||||
return __expand_string(&in, is_end_of_str);
|
||||
}
|
||||
|
||||
static bool is_end_of_token(char c)
|
||||
{
|
||||
/* Why are '.' and '/' valid characters for symbols? */
|
||||
return !(isalnum(c) || c == '_' || c == '-' || c == '.' || c == '/');
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand variables in a token. The parsing stops when a token separater
|
||||
* (in most cases, it is a whitespace) is encountered. 'str' is updated to
|
||||
* point to the next character.
|
||||
*
|
||||
* The returned string must be freed when done.
|
||||
*/
|
||||
char *expand_one_token(const char **str)
|
||||
{
|
||||
return __expand_string(str, is_end_of_token);
|
||||
}
|
|
@ -33,33 +33,6 @@ struct symbol *sym_defconfig_list;
|
|||
struct symbol *modules_sym;
|
||||
tristate modules_val;
|
||||
|
||||
struct expr *sym_env_list;
|
||||
|
||||
static void sym_add_default(struct symbol *sym, const char *def)
|
||||
{
|
||||
struct property *prop = prop_alloc(P_DEFAULT, sym);
|
||||
|
||||
prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
|
||||
}
|
||||
|
||||
void sym_init(void)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct utsname uts;
|
||||
static bool inited = false;
|
||||
|
||||
if (inited)
|
||||
return;
|
||||
inited = true;
|
||||
|
||||
uname(&uts);
|
||||
|
||||
sym = sym_lookup("UNAME_RELEASE", 0);
|
||||
sym->type = S_STRING;
|
||||
sym->flags |= SYMBOL_AUTO;
|
||||
sym_add_default(sym, uts.release);
|
||||
}
|
||||
|
||||
enum symbol_type sym_get_type(struct symbol *sym)
|
||||
{
|
||||
enum symbol_type type = sym->type;
|
||||
|
@ -1401,32 +1374,3 @@ const char *prop_get_type_name(enum prop_type type)
|
|||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static void prop_add_env(const char *env)
|
||||
{
|
||||
struct symbol *sym, *sym2;
|
||||
struct property *prop;
|
||||
char *p;
|
||||
|
||||
sym = current_entry->sym;
|
||||
sym->flags |= SYMBOL_AUTO;
|
||||
for_all_properties(sym, prop, P_ENV) {
|
||||
sym2 = prop_get_symbol(prop);
|
||||
if (strcmp(sym2->name, env))
|
||||
menu_warn(current_entry, "redefining environment symbol from %s",
|
||||
sym2->name);
|
||||
return;
|
||||
}
|
||||
|
||||
prop = prop_alloc(P_ENV, sym);
|
||||
prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
|
||||
|
||||
sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
|
||||
sym_env_list->right.sym = sym;
|
||||
|
||||
p = getenv(env);
|
||||
if (p)
|
||||
sym_add_default(sym, p);
|
||||
else
|
||||
menu_warn(current_entry, "environment variable %s undefined", env);
|
||||
}
|
||||
|
|
|
@ -34,8 +34,6 @@ struct file *file_lookup(const char *name)
|
|||
/* write a dependency file as used by kbuild to track dependencies */
|
||||
int file_write_dep(const char *name)
|
||||
{
|
||||
struct symbol *sym, *env_sym;
|
||||
struct expr *e;
|
||||
struct file *file;
|
||||
FILE *out;
|
||||
|
||||
|
@ -54,21 +52,7 @@ int file_write_dep(const char *name)
|
|||
fprintf(out, "\n%s: \\\n"
|
||||
"\t$(deps_config)\n\n", conf_get_autoconfig_name());
|
||||
|
||||
expr_list_for_each_sym(sym_env_list, e, sym) {
|
||||
struct property *prop;
|
||||
const char *value;
|
||||
|
||||
prop = sym_get_env_prop(sym);
|
||||
env_sym = prop_get_symbol(prop);
|
||||
if (!env_sym)
|
||||
continue;
|
||||
value = getenv(env_sym->name);
|
||||
if (!value)
|
||||
value = "";
|
||||
fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
|
||||
fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
|
||||
fprintf(out, "endif\n");
|
||||
}
|
||||
env_write_dep(out, conf_get_autoconfig_name());
|
||||
|
||||
fprintf(out, "\n$(deps_config): ;\n");
|
||||
fclose(out);
|
||||
|
@ -165,3 +149,14 @@ char *xstrdup(const char *s)
|
|||
fprintf(stderr, "Out of memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *xstrndup(const char *s, size_t n)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = strndup(s, n);
|
||||
if (p)
|
||||
return p;
|
||||
fprintf(stderr, "Out of memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
%option nostdinit noyywrap never-interactive full ecs
|
||||
%option 8bit nodefault yylineno
|
||||
%option noinput
|
||||
%x COMMAND HELP STRING PARAM
|
||||
%{
|
||||
/*
|
||||
|
@ -35,6 +34,8 @@ struct buffer *current_buf;
|
|||
|
||||
static int last_ts, first_ts;
|
||||
|
||||
static char *expand_token(const char *in, size_t n);
|
||||
static void append_expanded_string(const char *in);
|
||||
static void zconf_endhelp(void);
|
||||
static void zconf_endfile(void);
|
||||
|
||||
|
@ -147,6 +148,13 @@ n [A-Za-z0-9_-]
|
|||
yylval.string = text;
|
||||
return T_WORD;
|
||||
}
|
||||
({n}|[/.$])+ {
|
||||
/* this token includes at least one '$' */
|
||||
yylval.string = expand_token(yytext, yyleng);
|
||||
if (strlen(yylval.string))
|
||||
return T_WORD;
|
||||
free(yylval.string);
|
||||
}
|
||||
#.* /* comment */
|
||||
\\\n ;
|
||||
[[:blank:]]+
|
||||
|
@ -157,12 +165,13 @@ n [A-Za-z0-9_-]
|
|||
}
|
||||
|
||||
<STRING>{
|
||||
[^'"\\\n]+/\n {
|
||||
"$".* append_expanded_string(yytext);
|
||||
[^$'"\\\n]+/\n {
|
||||
append_string(yytext, yyleng);
|
||||
yylval.string = text;
|
||||
return T_WORD_QUOTE;
|
||||
}
|
||||
[^'"\\\n]+ {
|
||||
[^$'"\\\n]+ {
|
||||
append_string(yytext, yyleng);
|
||||
}
|
||||
\\.?/\n {
|
||||
|
@ -249,6 +258,58 @@ n [A-Za-z0-9_-]
|
|||
}
|
||||
|
||||
%%
|
||||
static char *expand_token(const char *in, size_t n)
|
||||
{
|
||||
char *out;
|
||||
int c;
|
||||
char c2;
|
||||
const char *rest, *end;
|
||||
|
||||
new_string();
|
||||
append_string(in, n);
|
||||
|
||||
/* get the whole line because we do not know the end of token. */
|
||||
while ((c = input()) != EOF) {
|
||||
if (c == '\n') {
|
||||
unput(c);
|
||||
break;
|
||||
}
|
||||
c2 = c;
|
||||
append_string(&c2, 1);
|
||||
}
|
||||
|
||||
rest = text;
|
||||
out = expand_one_token(&rest);
|
||||
|
||||
/* push back unused characters to the input stream */
|
||||
end = rest + strlen(rest);
|
||||
while (end > rest)
|
||||
unput(*--end);
|
||||
|
||||
free(text);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void append_expanded_string(const char *str)
|
||||
{
|
||||
const char *end;
|
||||
char *res;
|
||||
|
||||
str++;
|
||||
|
||||
res = expand_dollar(&str);
|
||||
|
||||
/* push back unused characters to the input stream */
|
||||
end = str + strlen(str);
|
||||
while (end > str)
|
||||
unput(*--end);
|
||||
|
||||
append_string(res, strlen(res));
|
||||
|
||||
free(res);
|
||||
}
|
||||
|
||||
void zconf_starthelp(void)
|
||||
{
|
||||
new_string();
|
||||
|
|
|
@ -534,7 +534,6 @@ void conf_parse(const char *name)
|
|||
|
||||
zconf_initscan(name);
|
||||
|
||||
sym_init();
|
||||
_menu_init();
|
||||
|
||||
if (getenv("ZCONF_DEBUG"))
|
||||
|
@ -780,3 +779,4 @@ void zconfdump(FILE *out)
|
|||
#include "expr.c"
|
||||
#include "symbol.c"
|
||||
#include "menu.c"
|
||||
#include "preprocess.c"
|
||||
|
|
Loading…
Reference in a new issue