diff options
Diffstat (limited to 'nixpkgs/pkgs/os-specific/linux/kernel/generate-config.pl')
-rw-r--r-- | nixpkgs/pkgs/os-specific/linux/kernel/generate-config.pl | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/os-specific/linux/kernel/generate-config.pl b/nixpkgs/pkgs/os-specific/linux/kernel/generate-config.pl new file mode 100644 index 000000000000..f886fcfdc358 --- /dev/null +++ b/nixpkgs/pkgs/os-specific/linux/kernel/generate-config.pl @@ -0,0 +1,145 @@ +# This script runs `make config' to generate a Linux kernel +# configuration file. For each question (i.e. kernel configuration +# option), unless an override is provided, it answers "m" if possible, +# and otherwise uses the default answer (as determined by the default +# config for the architecture). Overrides are read from the file +# $KERNEL_CONFIG, which on each line contains an option name and an +# answer, e.g. "EXT2_FS_POSIX_ACL y". The script warns about ignored +# options in $KERNEL_CONFIG, and barfs if `make config' selects +# another answer for an option than the one provided in +# $KERNEL_CONFIG. + +use strict; +use IPC::Open2; +use Cwd; + +# exported via nix +my $debug = $ENV{'DEBUG'}; +my $autoModules = $ENV{'AUTO_MODULES'}; +my $preferBuiltin = $ENV{'PREFER_BUILTIN'}; +my $ignoreConfigErrors = $ENV{'ignoreConfigErrors'}; +my $buildRoot = $ENV{'BUILD_ROOT'}; +$SIG{PIPE} = 'IGNORE'; + +# Read the answers. +my %answers; +my %requiredAnswers; +open ANSWERS, "<$ENV{KERNEL_CONFIG}" or die "Could not open answer file"; +while (<ANSWERS>) { + chomp; + s/#.*//; + if (/^\s*([A-Za-z0-9_]+)(\?)?\s+(\S+)\s*$/) { + $answers{$1} = $3; + $requiredAnswers{$1} = !(defined $2); + } elsif (!/^\s*$/) { + die "invalid config line: $_"; + } +} +close ANSWERS; + +sub runConfig { + + # Run `make config'. + my $pid = open2(\*IN, \*OUT, "make -C $ENV{SRC} O=$buildRoot config SHELL=bash ARCH=$ENV{ARCH}"); + + # Parse the output, look for questions and then send an + # appropriate answer. + my $line = ""; my $s; + my %choices = (); + + my ($prevQuestion, $prevName); + + while (!eof IN) { + read IN, $s, 1 or next; + $line .= $s; + + #print STDERR "LINE: $line\n"; + + if ($s eq "\n") { + print STDERR "GOT: $line" if $debug; + + # Remember choice alternatives ("> 1. bla (FOO)" or " 2. bla (BAR) (NEW)"). + if ($line =~ /^\s*>?\s*(\d+)\.\s+.*?\(([A-Za-z0-9_]+)\)(?:\s+\(NEW\))?\s*$/) { + $choices{$2} = $1; + } + + $line = ""; + } + + elsif ($line =~ /###$/) { + # The config program is waiting for an answer. + + # Is this a regular question? ("bla bla (OPTION_NAME) [Y/n/m/...] ") + if ($line =~ /(.*) \(([A-Za-z0-9_]+)\) \[(.*)\].*###$/) { + my $question = $1; my $name = $2; my $alts = $3; + my $answer = ""; + # Build everything as a module if possible. + $answer = "m" if $autoModules && $alts =~ /\/m/ && !($preferBuiltin && $alts =~ /Y/); + $answer = $answers{$name} if defined $answers{$name}; + print STDERR "QUESTION: $question, NAME: $name, ALTS: $alts, ANSWER: $answer\n" if $debug; + print OUT "$answer\n"; + die "repeated question: $question" if $prevQuestion && $prevQuestion eq $question && $name eq $prevName; + $prevQuestion = $question; + $prevName = $name; + } + + # Is this a choice? ("choice[1-N]: ") + elsif ($line =~ /choice\[(.*)\]: ###$/) { + my $answer = ""; + foreach my $name (keys %choices) { + $answer = $choices{$name} if ($answers{$name} || "") eq "y"; + } + print STDERR "CHOICE: $1, ANSWER: $answer\n" if $debug; + print OUT "$answer\n" if $1 =~ /-/; + } + + # Some questions lack the option name ("bla bla [Y/n/m/...] "). + elsif ($line =~ /(.*) \[(.*)\] ###$/) { + print OUT "\n"; + } + + else { + warn "don't know how to answer this question: $line\n"; + print OUT "\n"; + } + + $line = ""; + %choices = (); + } + } + + close IN; + waitpid $pid, 0; +} + +# Run `make config' several times to converge on the desired result. +# (Some options may only become available after other options are +# set in a previous run.) +runConfig; +runConfig; + +# Read the final .config file and check that our answers are in +# there. `make config' often overrides answers if later questions +# cause options to be selected. +my %config; +open CONFIG, "<$buildRoot/.config" or die "Could not read .config"; +while (<CONFIG>) { + chomp; + if (/^CONFIG_([A-Za-z0-9_]+)="(.*)"$/) { + # String options have double quotes, e.g. 'CONFIG_NLS_DEFAULT="utf8"' and allow escaping. + ($config{$1} = $2) =~ s/\\([\\"])/$1/g; + } elsif (/^CONFIG_([A-Za-z0-9_]+)=(.*)$/) { + $config{$1} = $2; + } elsif (/^# CONFIG_([A-Za-z0-9_]+) is not set$/) { + $config{$1} = "n"; + } +} +close CONFIG; + +foreach my $name (sort (keys %answers)) { + my $f = $requiredAnswers{$name} && $ignoreConfigErrors ne "1" + ? sub { die "error: " . $_[0]; } : sub { warn "warning: " . $_[0]; }; + &$f("unused option: $name\n") unless defined $config{$name}; + &$f("option not set correctly: $name (wanted '$answers{$name}', got '$config{$name}')\n") + if $config{$name} && $config{$name} ne $answers{$name}; +} |