+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
*/
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
return 0;
}
+static char depfile_path[PATH_MAX];
+static size_t depfile_prefix_len;
+
+/* touch depfile for symbol 'name' */
+static int conf_touch_dep(const char *name)
+{
+ int fd, ret;
+ const char *s;
+ char *d, c;
+
+ /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */
+ if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path))
+ return -1;
+
+ d = depfile_path + depfile_prefix_len;
+ s = name;
+
+ while ((c = *s++))
+ *d++ = (c == '_') ? '/' : tolower(c);
+ strcpy(d, ".h");
+
+ /* Assume directory path already exists. */
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ if (errno != ENOENT)
+ return -1;
+
+ ret = make_parent_dir(depfile_path);
+ if (ret)
+ return ret;
+
+ /* Try it again. */
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ return -1;
+ }
+ close(fd);
+
+ return 0;
+}
+
struct conf_printer {
void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
void (*print_comment)(FILE *, const char *, void *);
conf_warning("symbol value '%s' invalid for %s",
p, sym->name);
return 1;
- case S_OTHER:
- if (*p != '"') {
- for (p2 = p; *p2 && !isspace(*p2); p2++)
- ;
- sym->type = S_STRING;
- goto done;
- }
- /* fall through */
case S_STRING:
if (*p++ != '"')
break;
/* fall through */
case S_INT:
case S_HEX:
- done:
if (sym_string_valid(sym, p)) {
sym->def[def].val = xstrdup(p);
sym->flags |= def_flags;
sym = sym_find(line + 2 + strlen(CONFIG_));
if (!sym) {
sym_add_change_count(1);
- goto setsym;
+ continue;
}
} else {
sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
if (*p2 == '\r')
*p2 = 0;
}
- if (def == S_DEF_USER) {
- sym = sym_find(line + strlen(CONFIG_));
- if (!sym) {
+
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym) {
+ if (def == S_DEF_AUTO)
+ /*
+ * Reading from include/config/auto.conf
+ * If CONFIG_FOO previously existed in
+ * auto.conf but it is missing now,
+ * include/config/foo.h must be touched.
+ */
+ conf_touch_dep(line + strlen(CONFIG_));
+ else
sym_add_change_count(1);
- goto setsym;
- }
- } else {
- sym = sym_lookup(line + strlen(CONFIG_), 0);
- if (sym->type == S_UNKNOWN)
- sym->type = S_OTHER;
+ continue;
}
+
if (sym->flags & def_flags) {
conf_warning("override: reassigning to symbol %s", sym->name);
}
continue;
}
-setsym:
+
if (sym && sym_is_choice_value(sym)) {
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
switch (sym->def[def].tri) {
fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
}
-static void
-kconfig_print_cmake_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
-{
-
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- if (*value == 'n') {
- bool skip_unset = (arg != NULL);
-
- if (!skip_unset)
- fprintf(fp, "set(%s%s false)\n",
- CONFIG_, sym->name, value);
- return;
- } else if (*value == 'm') {
- abort();
- } else {
- fprintf(fp, "set(%s%s true)\n", CONFIG_, sym->name, value);
- }
- break;
- case S_HEX: {
- const char *prefix = "";
-
- if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
- prefix = "0x";
- fprintf(fp, "set(%s%s %s%s)\n",
- CONFIG_, sym->name, prefix, value);
- break;
- }
- case S_STRING:
- case S_INT:
- fprintf(fp, "set(%s%s %s)\n",
- CONFIG_, sym->name, value);
- break;
- default:
- break;
- }
-
-}
-
static void
kconfig_print_comment(FILE *fp, const char *value, void *arg)
{
.print_comment = kconfig_print_comment,
};
-static struct conf_printer kconfig_printer_cmake_cb =
-{
- .print_symbol = kconfig_print_cmake_symbol,
- .print_comment = kconfig_print_comment,
-};
-
/*
* Header printer
*
const char *str;
switch (sym->type) {
- case S_OTHER:
case S_UNKNOWN:
break;
case S_STRING:
return 0;
}
-static int conf_split_config(void)
+static int conf_touch_deps(void)
{
const char *name;
- char path[PATH_MAX+1];
- char *s, *d, c;
struct symbol *sym;
- int res, i, fd;
+ int res, i;
+
+ strcpy(depfile_path, "include/generated/");
+ depfile_prefix_len = strlen(depfile_path);
name = conf_get_autoconfig_name();
conf_read_simple(name, S_DEF_AUTO);
sym_calc_value(modules_sym);
- if (make_parent_dir("include/generated/foo.h"))
- return 1;
- if (chdir("include/generated"))
- return 1;
-
- res = 0;
for_all_symbols(i, sym) {
sym_calc_value(sym);
if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
* different from 'no').
*/
- /* Replace all '_' and append ".h" */
- s = sym->name;
- d = path;
- while ((c = *s++)) {
- c = tolower(c);
- *d++ = (c == '_') ? '/' : c;
- }
- strcpy(d, ".h");
-
- /* Assume directory path already exists. */
- fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1) {
- if (errno != ENOENT) {
- res = 1;
- break;
- }
-
- if (make_parent_dir(path)) {
- res = 1;
- goto out;
- }
-
- /* Try it again. */
- fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (fd == -1) {
- res = 1;
- break;
- }
- }
- close(fd);
+ res = conf_touch_dep(sym->name);
+ if (res)
+ return res;
}
-out:
- if (chdir("../.."))
- return 1;
- return res;
+ return 0;
}
-int conf_write_autoconf(void)
+int conf_write_autoconf(int overwrite)
{
struct symbol *sym;
const char *name;
- FILE *out, *tristate, *out_h, *out_c;
+ const char *autoconf_name = conf_get_autoconfig_name();
+ FILE *out, *tristate, *out_h;
int i;
+ if (!overwrite && is_present(autoconf_name))
+ return 0;
+
sym_clear_all_valid();
conf_write_dep("include/generated/auto.conf.cmd");
- if (conf_split_config())
+ if (conf_touch_deps())
return 1;
out = fopen(".tmpconfig", "w");
return 1;
}
- out_c = fopen(".tmpconfig.cmake", "w");
- if (!out_c) {
- fclose(out);
- fclose(tristate);
- fclose(out_h);
- }
-
conf_write_heading(out, &kconfig_printer_cb, NULL);
conf_write_heading(tristate, &tristate_printer_cb, NULL);
conf_write_heading(out_h, &header_printer_cb, NULL);
- conf_write_heading(out_c, &kconfig_printer_cmake_cb, NULL);
-
for_all_symbols(i, sym) {
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
-
- conf_write_symbol(out_c, sym, &kconfig_printer_cmake_cb, NULL);
}
fclose(out);
fclose(tristate);
fclose(out_h);
- fclose(out_c);
name = getenv("KCONFIG_AUTOHEADER");
if (!name)
if (rename(".tmpconfig_tristate", name))
return 1;
- name = getenv("KCONFIG_CMAKE");
- if (!name)
- name = "config.cmake";
- if (make_parent_dir(name))
- return 1;
- if (rename(".tmpconfig.cmake", name))
- return 1;
-
- name = conf_get_autoconfig_name();
- if (make_parent_dir(name))
+ if (make_parent_dir(autoconf_name))
return 1;
-
/*
* This must be the last step, kbuild has a dependency on auto.conf
* and this marks the successful completion of the previous steps.
*/
- if (rename(".tmpconfig", name))
+ if (rename(".tmpconfig", autoconf_name))
return 1;
return 0;