From: David Howells <dhowells@redhat.com>
To: linux-arch@vger.kernel.org
Cc: dhowells@redhat.com
Subject: Re: [PATCH 00/35] UAPI header file split - scripts
Date: Sat, 02 Jul 2011 12:33:52 +0100 [thread overview]
Message-ID: <23016.1309606432@redhat.com> (raw)
In-Reply-To: <20110702110716.21948.74214.stgit@warthog.procyon.org.uk>
[-- Attachment #1: Type: text/plain, Size: 349 bytes --]
Here are the scripts for splitting the headers. There are three:
(1) A script to disintegrate a single header file.
(2) A script to scan all the Kbuild files and work out what headers are
exported to userspace.
(3) A script to make use of the above two and to drive git to build a commit
per directory of exported headers.
David
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: disintegrate-one.pl --]
[-- Type: text/x-perl, Size: 29596 bytes --]
#!/usr/bin/perl -w
#
# Disintegrate a file to extract out the userspace API bits into their own file
# in a separate directory. The original file retains the residue.
#
# The original file is given a #include_next to refer to the UAPI file, and
# both headers will get guards, unless one of them is simply turned into a
# #include_next.
#
# Call as: disintegrate-one.pl <orig_header_file> <uapi_header_file>
#
use File::Path;
use strict;
sub reduce_file(@);
# Don't put a "don't include this in asm" notice in the following files
my %asm_includeable_linux_files = (
"include/linux/const.h" => 1,
"include/linux/elf-em.h" => 1,
"include/linux/errno.h" => 1,
"include/linux/serial_reg.h" => 1,
);
die if ($#ARGV != 1);
my $linuxhdr = $ARGV[0];
my $uapihdr = $ARGV[1];
#
# The UAPI header file is called the same as the Linux header file as far as
# cpp is concerned - the latter just #include_next's the former, and if the
# latter doesn't exist, the former is used directly.
#
my $inchdr = $linuxhdr;
$inchdr =~ s@.*include/@@;
#
# Read the entire Linux header file into an array of lines.
#
open(FD, '<', $linuxhdr) or die $linuxhdr, ": $!\n";
my @lines = <FD> or die $linuxhdr, ": $!\n";
close(FD) or die $linuxhdr, ": $!\n";
my @kernellines = ();
my @uapilines = ();
#
# If the entire file is just a single #include, then don't change it
#
# We do want to create the API file _if_ the included file is an API file
#
if ($#lines == 0 && $lines[0] =~ /^#\s*include\s+<([^>]+)>/) {
@kernellines = "#include_next <$1>\n";
@uapilines = @lines;
goto output;
}
goto output if ($#lines == -1);
#
# Attempt to disintegrate the file
# - The initial banner comment gets duplicated if there is one
# - The reinclusion guard is duplicated and modified for the API file
# - non-__KERNEL__ lines get put into the API file
#
my $nr_blocks = 0;
sub new_block($$$$)
{
my ($type, $l, $parent, $prev) = @_;
my %block = (
type => $type, # n = normal block, c = conditional block
l => $l + 1,
next_block => undef,
prev_block => $prev,
nr => ++$nr_blocks,
parent => $parent,
);
$block{lines} = [] if ($type eq "n");
$block{kernel_mark} = 0 if ($type ne "n");
$prev->{next_block} = \%block if ($prev);
return \%block;
}
#
# First of all, build a tree of normal blocks and conditionals
#
my $first_block = new_block("n", 0, undef, undef);
my $conditional_tree = $first_block;
my $cur_body = $first_block;
my $specified_include_point = 0;
my @conditional_stack = ();
my @body_stack = ( $first_block );
my $l = 0;
if ($lines[$l] =~ m@^/[*]@) {
my @buffer = ();
for (; $l <= $#lines; $l++) {
if ($lines[$l] =~ "(.*)[*]/(.*)") {
push @buffer, "$1*/\n";
$lines[$l] = $2;
$l++;
goto got_banner_comment;
}
push @buffer, $lines[$l];
}
got_banner_comment:
$first_block->{lines} = \@buffer;
$first_block->{banner} = 1;
$first_block->{next_block} = new_block("n", $l, undef, $first_block);
$cur_body = $first_block->{next_block};
$body_stack[0] = $cur_body;
}
for (; $l <= $#lines; $l++) {
my $line = $lines[$l];
my @buffer = ( $line );
# parse out the actual CPP directive
# - this may be split over multiple lines using backslashes and comments
# that have embedded newlines
my $cpp = $line;
restart:
$cpp =~ s@\s+$@@g;
$cpp =~ s@\s+@ @g;
while ($cpp =~ m@(/[*])@) {
my $o = index($cpp, "/*");
if ($cpp =~ m@([*]/)@) {
my $c = index($cpp, "*/") + 2;
substr($cpp, $o, $c - $o) = "";
} else {
$l++;
$cpp .= $lines[$l];
push @buffer, $lines[$l];
goto restart;
}
}
if ($cpp =~ /^(.*)[\\]$/) {
$l++;
$cpp = $1 . $lines[$l];
push @buffer, $lines[$l];
goto restart;
}
$cpp =~ s@\s+$@@g;
$cpp =~ s@\s\s+@ @g;
if ($cpp eq "// DISINTEGRATE: INCLUDE UAPI HERE") {
die if ($specified_include_point);
my $marker;
if ($#{$cur_body->{lines}} == -1) {
$marker = $cur_body;
$marker->{type} = "i";
$marker->{include_point} = undef;
delete $marker->{lines};
} else {
my $marker = new_block("i", $l, $cur_body->{parent}, $cur_body);
$cur_body = $marker;
$body_stack[$#body_stack] = $marker;
}
die if ($marker->{lines});
my $body_block = new_block("n", $l + 1, $cur_body->{parent}, $cur_body);
$body_stack[$#body_stack] = $body_block;
$cur_body = $body_block;
$specified_include_point = 1;
next;
}
my $retain_next = 0;
if ($line =~ "(.*) // DISINTEGRATE: RETAIN\n") {
$line = "$1\n";
$retain_next = 1;
}
if ($line =~ /^#/) {
#print "r:\e[36m", $cpp, "\e[m@@@ $l\n";
# handle conditional macros
if ($cpp =~ /^#\s*if/) {
#print "#if ", $#conditional_stack + 1, ": ", $#body_stack + 1, "\n";
my $cond_block = new_block("c", $l, $cur_body->{parent}, $cur_body);
$cond_block->{clauses} = []; # #if..#elif..#elif..#else..#endif
$cond_block->{retain} = 1 if ($retain_next == 1);
push @conditional_stack, $cond_block;
my $clause = new_block("if", $l, $cond_block, undef);
$clause->{cpp} = $cpp;
push @{$clause->{lines}}, @buffer;
push @{$cond_block->{clauses}}, $clause;
my $body_block = new_block("n", $l + 1, $clause, undef);
$clause->{body} = $body_block;
$cur_body->{next_block} = $cond_block;
$body_stack[$#body_stack] = $cond_block;
push @body_stack, $body_block;
$cur_body = $body_block;
die ("Unexpected body types '",
join("", map {$_->{type};} @body_stack),
"' after #if\n")
if ($body_stack[$#body_stack]->{type} ne "n" ||
$body_stack[$#body_stack - 1]->{type} ne "c");
if ($#conditional_stack == 0 &&
$cpp =~ /^#\s*ifndef\s+([_A-Za-z0-9]+)/) {
# keep an eye open for a guard's #define or an include-order check's #error
my $macro = $1;
$cur_body->{check_first_line} = $macro
if ($macro ne "__KERNEL__" && $macro !~ /^CONFIG_/);
}
next;
}
my $cond_block = $conditional_stack[$#conditional_stack];
my $cur_clause = $cond_block->{clauses}->[$#{$cond_block->{clauses}}];
if ($cpp =~ /^#\s*elif/) {
die if ($#conditional_stack < 0);
die if (exists $cond_block->{has_else});
my $clause = new_block("elif", $l, $cond_block, $cur_clause);
$clause->{cpp} = $cpp;
push @{$clause->{lines}}, @buffer;
push @{$cond_block->{clauses}}, $clause;
my $body_block = new_block("n", $l + 1, $clause, undef);
$clause->{body} = $body_block;
$body_stack[$#body_stack] = $body_block;
$cur_body = $body_block;
next;
}
if ($cpp =~ /^#\s*else/) {
#print "#else ", $#conditional_stack + 1, ": ", $#body_stack + 1, "\n";
die if ($#conditional_stack < 0);
die if (exists $cond_block->{has_else});
$cond_block->{has_else} = 1;
my $clause = new_block("else", $l, $cond_block, $cur_clause);
push @{$clause->{lines}}, @buffer;
push @{$cond_block->{clauses}}, $clause;
my $body_block = new_block("n", $l + 1, $clause, undef);
$clause->{body} = $body_block;
$body_stack[$#body_stack] = $body_block;
$cur_body = $body_block;
next;
}
if ($cpp =~ /^#\s*endif/) {
#print "#endif ", $#conditional_stack + 1, ": ", $#body_stack + 1, "\n";
die if ($#conditional_stack < 0);
my $clause = new_block("endif", $l, $cond_block, $cur_clause);
push @{$clause->{lines}}, @buffer;
push @{$cond_block->{clauses}}, $clause;
pop @conditional_stack;
pop @body_stack;
$cur_body = $body_stack[$#body_stack];
my $body_block = new_block("n", $l + 1, $cur_body->{parent}, $cur_body);
die "Unexpected body type '", $cur_body->{type}, "' at #endif\n"
if ($cur_body->{type} ne "c");
$body_stack[$#body_stack] = $body_block;
$cur_body = $body_block;
next;
}
if (($cpp =~ /^#\s*define\s+([_A-Za-z0-9]+)$/ ||
$cpp =~ /^#\s*define\s+([_A-Za-z0-9]+)\s+1$/) &&
exists $cur_body->{check_first_line}
) {
my $macro = $1;
#print "GUARD $macro\n";
if ($macro eq $cur_body->{check_first_line}) {
$cond_block->{guard_label} = $cur_body->{check_first_line};
$cur_clause->{guard} = \@buffer;
delete $cur_body->{check_first_line};
next;
}
}
if ($cpp =~ /^#\s*error/ &&
exists $cur_body->{check_first_line}
) {
delete $cur_body->{check_first_line};
$cur_clause->{order_check} = \@buffer;
next;
}
}
delete $cur_body->{check_first_line} if (exists $cur_body->{check_first_line});
push @{$cur_body->{lines}}, @buffer;
}
die "Conditional level mismatch (", $#conditional_stack, ")\n"
if ($#conditional_stack != -1);
die "Body level mismatch (", $#body_stack, ")\n"
if ($#body_stack != 0);
###############################################################################
#
# Dump the parse tree
#
###############################################################################
sub dump_tree(@);
sub dump_tree(@)
{
my $root = $#_ >= 0 ? $_[0] : $first_block;
my $level = $#_ >= 1 ? $_[1] : 0;
for (my $block = $root; $block; $block = $block->{next_block}) {
my $l = $block->{l};
my $nr = $block->{nr};
my $lines = $block->{lines};
print " " x $level;
if ($block->{type} eq "n") {
if ($#{$lines} < 0) {
print '- Empty (line ', $l, " nr ", $nr, ")\n";
} elsif ($#{$lines} == 0) {
print '- Body (line ', $l, " nr ", $nr, ")\n";
} else {
print '- Body (lines ', $l, "-", $l + $#{$lines} + 1, " nr ", $nr, ")";
print " BANNER" if (exists $block->{banner});
print "\n";
}
#print map {"\t\t\t>" . $_; } @{$block->{lines}} if (exists $block->{lines});
} elsif ($block->{type} eq "i") {
print '- UAPI Inclusion (line ', $l, " nr ", $nr, ")\n";
} elsif ($block->{type} eq "c") {
my $clauses = $block->{clauses};
die "Must be at least 2 clauses\n" if ($#{$clauses} < 1);
print '@ Cond (line ', $l, " nr ", $nr, ") ", $#{$clauses}, " clauses";
if (exists $block->{kernel_mark}) {
print " KO" if ($block->{kernel_mark} & 1);
print " UO" if ($block->{kernel_mark} & 2);
print " IK" if ($block->{kernel_mark} & 4);
print " IU" if ($block->{kernel_mark} & 8);
print " GUARD" if (exists $block->{guard});
print " ORDER_CHECK" if (exists $block->{order_check});
print " RETAIN" if (exists $block->{retain});
}
print "\n";
foreach my $clause (@{$clauses}) {
my $nr = $clause->{nr};
print " " x ($level + 1);
print "#", $clause->{type}, " nr ", $nr;
if (exists $clause->{kernel_mark}) {
print " KO" if ($clause->{kernel_mark} & 1);
print " UO" if ($clause->{kernel_mark} & 2);
print " IK" if ($clause->{kernel_mark} & 4);
print " IU" if ($clause->{kernel_mark} & 8);
}
print "\n";
#print map {"\t\t\t>" . $_; } @{$clause->{lines}} if (exists $clause->{lines});
dump_tree($clause->{body}, $level + 2);
}
} else {
die;
}
}
}
###############################################################################
#
# Validate the parse tree structure
#
###############################################################################
sub validate_tree(@);
sub validate_tree(@)
{
my ($parent, $body) = @_;
if ($#_ == -1) {
$parent = undef;
$body = $first_block;
}
my $previous = undef;
#print "-->validate_tree(", $parent ? $parent->{nr} : "-", ",", $body->{nr}, ")\n";
for (my $block = $body; $block; $previous = $block, $block = $block->{next_block}) {
my $nr = $block->{nr};
die $nr, ": Unset parent\n" unless (exists $block->{parent});
if (!$parent) {
die $nr, ": Unexpected parent\n" if ($block->{parent});
} else {
die $nr, ": Missing parent\n" if (!$block->{parent});
die $nr, ": Incorrect parent", $block->{parent}->{nr}, "!=", $parent->{nr}, "\n"
unless ($block->{parent} == $parent);
}
if ($previous) {
die($nr, ": Incorrect prev_block ", $block->{prev_block}->{nr},
" not ", $previous->{nr}, "\n")
unless ($block->{prev_block} == $previous);
} else {
die $nr, ": Unexpected prev_block ", $block->{prev_block}->{nr}, "\n"
if ($block->{prev_block});
}
if ($block->{type} eq "n") {
die $nr, ": Missing line array\n" unless (exists $block->{lines});
die $nr, ": Unexpected __KERNEL__ mark\n" if (exists $block->{kernel_mark});
die $nr, ": Unexpected guard\n" if (exists $block->{guard});
die $nr, ": Unexpected order check\n" if (exists $block->{order_check});
} elsif ($block->{type} eq "i") {
die $nr, ": Unexpected line array\n" if (exists $block->{lines});
die $nr, ": Unexpected guard\n" if (exists $block->{guard});
die $nr, ": Unexpected order check\n" if (exists $block->{order_check});
} elsif ($block->{type} eq "c") {
die $nr, ": Unexpected line array\n" if (exists $block->{lines});
die $nr, ": Missing clause array\n" unless (exists $block->{clauses});
my $clauses = $block->{clauses};
my $nc = $#{$clauses};
die $nr, ": Must be at least 2 clauses\n" if ($nc < 1);
die $nr, ": Missing #if clause\n" if ($clauses->[0]->{type} ne "if");
die $nr, ": Missing #endif clause\n" if ($clauses->[$nc]->{type} ne "endif");
if ($nc >= 2) {
for (my $i = 1; $i < $nc - 1; $i++) {
my $j = $clauses->[$i]->{nr};
die $nr, ": Missing #elif clause [$j]\n"
if ($clauses->[$i]->{type} ne "elif");
}
my $j = $clauses->[$nc - 1]->{nr};
die $nr, ": Missing #elif/#else clause [$j]\n"
if ($clauses->[$nc - 1]->{type} ne "elif" &&
$clauses->[$nc - 1]->{type} ne "else");
}
foreach my $clause (@{$clauses}) {
my $j = $clause->{nr};
die "$j: Clause missing parent\n" unless ($clause->{parent});
die "$j: Clause has wrong parent: ", $clause->{parent}->{nr}, "\n"
unless ($clause->{parent} == $block);
die "$j: Unexpected body in #endif: ", $clause->{body}->{nr}, "\n"
if ($clause->{type} eq "endif" && exists $clause->{body});
die "$j: Missing clause line array\n" unless (exists $clause->{lines});
validate_tree($clause, $clause->{body}) if (exists $clause->{body});
}
} else {
die "$nr: Invalid block type: '", $block->{type}, "'\n";
}
}
#print "<--validate_tree()\n";
}
validate_tree();
#dump_tree(); exit 123;
###############################################################################
#
# Eliminate empty bodies from the tree
#
###############################################################################
sub discard_empties($);
sub discard_empties($)
{
my ($block) = @_;
while ($block) {
die unless exists $block->{type};
if ($block->{type} eq "n") {
if ($#{$block->{lines}} < 0) {
#print "EMPTY: ", $block->{nr};
my $parent = $block->{parent};
my $prev = $block->{prev_block};
my $next = $block->{next_block};
delete $block->{type};
if ($next) {
#print " next";
die if ($next->{prev_block} != $block);
$next->{prev_block} = $prev;
}
if ($prev) {
#print " prev";
die if ($prev->{next_block} != $block);
$prev->{next_block} = $next;
} else {
if ($parent) {
#print " parent(", $parent->{nr}, ")";
die unless ($parent->{body} == $block);
$parent->{body} = $next;
} else {
#print " root";
die "Mismatch ", $first_block->{nr}, " != ", $block->{nr}, "\n"
if ($first_block != $block);
$first_block = $next;
}
}
die if ($next && $block == $next);
$block = $next;
#print "\n";
next;
} else {
$block = $block->{next_block};
next;
}
} elsif ($block->{type} eq "i") {
;
} elsif ($block->{type} eq "c") {
my $clauses = $block->{clauses};
die "Must be at least 2 clauses\n" if ($#{$clauses} < 1);
foreach my $clause (@{$clauses}) {
discard_empties($clause->{body});
}
} else {
die;
}
$block = $block->{next_block};
next;
}
}
discard_empties($first_block);
validate_tree();
###############################################################################
#
# Mark up single variable only __KERNEL__ conditions and percolate marks up the
# tree.
#
###############################################################################
sub mark__KERNEL__($);
sub mark__KERNEL__($)
{
my ($first) = @_;
my $combined_kernel_mark = 0;
for (my $block = $_[0]; $block; $block = $block->{next_block}) {
next if ($block->{type} ne "c");
my $clauses = $block->{clauses};
my $cpp = $clauses->[0]->{cpp};
my $kernel_mark = 0;
if ($block->{retain}) {
;
} elsif ($cpp =~ /^#\s*ifdef\s+__KERNEL__/ ||
($cpp =~ /^#\s*if\s+defined\s*\(\s*__KERNEL__\s*\)/ &&
$cpp !~ /[|][|]|[&][&]/)) {
$kernel_mark |= 1 | 4;
} elsif ($cpp =~ /^#\s*ifndef\s+__KERNEL__/ ||
($cpp =~ /^#\s*if\s+!\s*defined\s*\(\s*__KERNEL__\s*\)/ &&
$cpp !~ /[|][|]|[&][&]/)) {
$kernel_mark |= 2 | 8;
}
if ($kernel_mark) {
$clauses->[0]->{kernel_mark} = $kernel_mark;
if ($#{$clauses} > 1) {
die $linuxhdr, ":", $clauses->[1]->{l}, ": __KERNEL__ guard has #elif clause\n"
if ($#{$clauses} > 2 || $clauses->[1]->{type} eq "elif");
$clauses->[1]->{kernel_mark} = $kernel_mark ^ 15;
$kernel_mark = 15;
$clauses->[2]->{kernel_mark} = $kernel_mark;
} else {
$clauses->[1]->{kernel_mark} = $kernel_mark;
}
}
foreach my $clause (@{$clauses}) {
die $linuxhdr, ":", $clause->{l}, ": #elif contains __KERNEL__\n"
if ($clause->{type} eq "elif" && $clause->{cpp} =~ /__KERNEL__/);
if (exists $clause->{body}) {
my $k = mark__KERNEL__($clause->{body});
if ($k) {
die $linuxhdr, ":", $clause->{l}, ": Body contains nested __KERNEL__\n"
if ($kernel_mark & 3);
$clause->{kernel_mark} |= $k | 8;
$kernel_mark = $k | 8;
}
}
}
$block->{kernel_mark} = $kernel_mark;
$combined_kernel_mark |= $kernel_mark;
}
return $combined_kernel_mark & (4 | 8);
}
mark__KERNEL__($first_block);
validate_tree();
#dump_tree(); exit 123;
###############################################################################
#
# Determine reinclusion guards and validate inclusion order checks that are
# outside the guards
#
###############################################################################
sub determine_guards()
{
for (my $block = $first_block; $block; $block = $block->{next_block}) {
next if ($block->{type} ne "c");
if ($block->{clauses}->[0]->{guard}) {
$block->{guard} = 1;
$block->{kernel_mark} = 8;
die unless (exists $block->{guard_label});
} elsif ($block->{clauses}->[0]->{order_check}) {
$block->{order_check} = 1;
$block->{kernel_mark} = 8;
die $linuxhdr, ":", $block->{l}, ": Inclusion order check with multiple clauses\n"
unless ($#{$block->{clauses}} == 1);
die $linuxhdr, ":", $block->{l}, ": Inclusion order check with extra body\n"
if ($block->{clauses}->[0]->{body});
}
}
}
determine_guards();
#dump_tree();
validate_tree();
###############################################################################
#
# Render the two header files
#
###############################################################################
my $include_next_at = -1;
sub render(@);
sub render(@)
{
my $root = $#_ >= 0 ? $_[0] : $first_block;
my $parent_kernel_mark = $#_ >= 1 ? $_[1] : 8;
for (my $block = $root; $block; $block = $block->{next_block}) {
my $kernel_mark = $parent_kernel_mark;
#push @kernellines, "KM$kernel_mark\n";
if ($block->{type} eq "n") {
my $is_banner = exists $block->{banner};
my $lines = $block->{lines};
push @kernellines, @{$lines} if ($is_banner || !($kernel_mark & 8));
push @uapilines, @{$lines} if ($is_banner || $kernel_mark & 8);
next;
}
if ($block->{type} eq "i") {
push @kernellines, "#include_next <$inchdr>\n";
next;
}
if ($block->{type} eq "c") {
my $clauses = $block->{clauses};
if ($block->{order_check}) {
push(@uapilines,
@{$clauses->[0]->{lines}},
@{$clauses->[0]->{order_check}},
@{$clauses->[1]->{lines}});
next;
}
if ($block->{guard}) {
push(@kernellines,
@{$clauses->[0]->{lines}},
@{$clauses->[0]->{guard}});
push @kernellines, "\n";
if ($linuxhdr =~ m!^include/! &&
$linuxhdr !~ m@^include/asm-generic/@ &&
!exists($asm_includeable_linux_files{$linuxhdr})) {
push @kernellines, "#ifdef __ASSEMBLY__\n";
push @kernellines, "#error include/linux headers may not be included in .S files\n";
push @kernellines, "#endif\n";
push @kernellines, "\n";
}
push @kernellines, "#define __EXPORTED_HEADERS__\n"
if ($linuxhdr eq "include/linux/types.h");
unless ($specified_include_point) {
push @kernellines, "#include_next <$inchdr>\n";
$include_next_at = $#kernellines;
push @kernellines, "\n";
}
push(@uapilines,
"#ifndef _UAPI" . $block->{guard_label} . "\n",
"#define _UAPI" . $block->{guard_label} . "\n");
render($block->{clauses}->[0]->{body}, $kernel_mark);
push(@kernellines,
@{$clauses->[1]->{lines}});
push(@uapilines,
"#endif /* _UAPI" . $block->{guard_label} . " */\n");
next;
}
$kernel_mark = $block->{kernel_mark} if ($block->{kernel_mark});
if (($kernel_mark & 3) == 0) {
# no mention of __KERNEL__ only
foreach my $clause (@{$clauses}) {
my $lines = $clause->{lines};
push @kernellines, @{$clause->{lines}} if ($kernel_mark & 4);
push @uapilines, @{$clause->{lines}} if ($kernel_mark & 8);
render($clause->{body}, $kernel_mark)
if (exists $clause->{body});
}
} elsif (($kernel_mark & 3) == 1) {
# #ifdef __KERNEL__
render($block->{clauses}->[0]->{body}, 4);
} elsif (($kernel_mark & 3) == 2) {
# #ifndef __KERNEL__
push @uapilines, @{$block->{clauses}->[0]->{lines}};
render($block->{clauses}->[0]->{body}, 8);
push @uapilines, @{$block->{clauses}->[1]->{lines}};
} else {
if ($block->{clauses}->[0]->{kernel_mark} & 1) {
# #ifdef __KERNEL__ ... #else
render($block->{clauses}->[0]->{body}, 4);
my @iflines = @{$block->{clauses}->[0]->{lines}};
$iflines[0] =~ s/#(\s*if)def/#$1ndef/;
$iflines[0] =~ s/#(\s*if\s+)defined/#$1!defined/;
push @uapilines, @iflines;
render($block->{clauses}->[1]->{body}, 8);
push @uapilines, @{$block->{clauses}->[2]->{lines}};
} else {
# #ifndef __KERNEL__ ... #else
render($block->{clauses}->[1]->{body}, 4);
push @uapilines, @{$block->{clauses}->[0]->{lines}};
render($block->{clauses}->[0]->{body}, 8);
push @uapilines, @{$block->{clauses}->[2]->{lines}};
}
}
}
}
}
render();
###############################################################################
#
# See if a file actually has anything left in it after all the blank lines,
# comments and CPP conditionals and inclusions are removed.
#
# Returns:
# 0: non-reducible
# 1: reducible to nothing
# 2: reducible to a single #include
# 3: reducible to a multiple #includes
#
###############################################################################
sub reduce_file(@)
{
my (@lines) = @_;
my $blocks = 0;
my $level = 0;
my $guarded = 0;
my $guardname = "";
my $guarddefline = -2;
my $first_if = 1;
my $includes = 0;
for (my $l = 0; $l <= $#lines; $l++) {
my $line = $lines[$l];
my $suppress = 0;
# parse out the blocks
# - this may be split over multiple lines using backslashes and comments
# that have embedded newlines
my $block = $line;
restart:
$block =~ s@\s+$@@g;
$block =~ s@\s+@ @g;
while ($block =~ m@(/[*])@) {
my $o = index($block, "/*");
if ($block =~ m@([*]/)@) {
my $c = index($block, "*/") + 2;
substr($block, $o, $c - $o) = "";
} else {
$l++;
$block .= $lines[$l];
#push @buffer, $lines[$l];
goto restart;
}
}
if ($block =~ /^(.*)[\\]$/) {
$l++;
$block = $1 . $lines[$l];
#push @buffer, $lines[$l];
goto restart;
}
$block =~ s@\s+$@@g;
$block =~ s@\s\s+@ @g;
if ($line =~ /^#/) {
# handle conditional macros
if ($block =~ /^#\s*if/) {
$level++;
if ($block =~ /^#\s*ifndef\s+([_A-Za-z0-9]+)/ && $first_if == 1) {
$guardname = $1;
$guarddefline = $l + 1;
$first_if = 0;
next;
}
$first_if = 0;
} elsif ($block =~ /^#\s*endif/) {
$level--;
next;
} elsif ($block =~ /^#\s*else/) {
next;
} elsif ($block =~ /^#\s*elif/) {
next;
} elsif ($l == $guarddefline && $block =~ /^#\s*define\s+$guardname/) {
next;
} elsif ($block =~ /^#\s*include_next/) {
next;
} elsif ($block =~ /^#\s*include/) {
$includes++;
next;
} elsif ($block =~ /^#error only arch headers may be included in asm/) {
next;
}
} elsif ($block eq "") {
next;
}
#print "[", $block, "]\n";
$blocks++;
}
die $linuxhdr, ": #if/#endif level mismatch ($level)\n"
if ($level != 0);
return 0 if ($blocks > 0);
return 2 if ($includes == 1);
return 3 if ($includes > 0);
return 1;
}
###############################################################################
#
# Attempt to slide down the #include_next to after the #include set if it was
# added automatically (if it was manually specified, then we leave it where it
# is).
#
###############################################################################
sub slide_include_next()
{
# first of all, locate the #include_next
my $include_next = $kernellines[$include_next_at];
die if ($include_next !~ m/#include_next/);
my $here = -1;
my $if_level = 0;
my $cond_include = 0;
for (my $l = $include_next_at + 1; $l <= $#kernellines; $l++) {
my $line = $kernellines[$l];
chomp $line;
if ($line eq "") {
} elsif ($line =~ /#\s*include\s+<([^>]*)>/) {
last if ($1 eq "linux/byteorder/generic.h");
if ($if_level == 0) {
$here = $l;
} else {
$cond_include = 1;
}
} elsif ($line =~ /#\s*if/) {
$if_level++;
} elsif ($line =~ /#\s*else/) {
} elsif ($line =~ /#\s*elif/) {
} elsif ($line =~ /#\s*endif/) {
$if_level--;
if ($if_level == 0) {
$here = $l if ($cond_include);
$cond_include = 0;
}
} else {
last;
}
}
if ($here > -1) {
splice @kernellines, $include_next_at, 2;
splice @kernellines, $here - 1, 0, $include_next;
splice @kernellines, $here, 0, "\n" unless ($kernellines[$here] eq "\n");
}
}
slide_include_next() if ($include_next_at > -1);
###############################################################################
#
#
#
###############################################################################
output:
;
#print @kernellines;
#print "_" x 79, "\n";
#print @uapilines;
my $kred = reduce_file(@kernellines);
my $ured = reduce_file(@uapilines);
#print "kred: ", $kred, "\n";
#print "ured: ", $ured, "\n";
#exit 123;
if ($ured == 2) {
@uapilines = grep /^#\s*include/, @uapilines;
} elsif ($ured == 1) {
@uapilines = ();
}
if ($kred == 1) {
# if all we're doing is #include_next'ing the UAPI header, then we may as
# well delete the file and let CPP include the UAPI header directly
@kernellines = ();
@uapilines = @lines;
}
my $uapidir = $uapihdr;
$uapidir = $1 if ($uapidir =~ m!(.*)/!);
mkpath($uapidir) if (! -d $uapidir);
if ($#kernellines >= 0) {
# we must create a UAPI header, even if it is blank
open(FD, '>', $uapihdr) or die "$uapihdr: $!\n";
print FD @uapilines or die "$uapihdr: $!\n";
close FD or die "$uapihdr: $!\n";
my $linuxhdrorig = $linuxhdr . ".orig";
open(FD, '>', $linuxhdrorig) or die $linuxhdrorig, ": $!\n";
print FD @kernellines or die $linuxhdrorig, ": $!\n";
close FD or die $linuxhdrorig, ": $!\n";
rename $linuxhdrorig, $linuxhdr or die $linuxhdr, ": $!\n";
} else {
rename $linuxhdr, $uapihdr or die $uapihdr, ": $!\n";
}
###############################################################################
#
# Add the file to the uapi Kbuild file
#
###############################################################################
my $uapi_kbuild = $uapidir . "/Kbuild";
die "$uapi_kbuild: Not found\n" unless (-f $uapi_kbuild);
my $hdrname;
$uapihdr =~ m@([^/]*)$@, $hdrname = $1;
open(FD, '>>', $uapi_kbuild) or die "$uapi_kbuild: $!\n";
if ($linuxhdr eq "include/linux/a.out.h" ||
$linuxhdr eq "include/linux/kvm.h" ||
$linuxhdr eq "include/linux/kvm_para.h"
) {
print FD
"\n",
'ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/', $hdrname, " \\\n",
"\t\t", ' $(srctree)/include/asm-$(SRCARCH)/', $hdrname, " \\\n",
"\t\t", ' $(INSTALL_HDR_PATH)/include/asm-*/', $hdrname, "),)\n",
"header-y += ", $hdrname, "\n",
"endif\n\n"
or die "$uapi_kbuild: $!\n";
} else {
print FD "header-y += $hdrname\n" or die "$uapi_kbuild: $!\n";
}
close FD or die "$uapi_kbuild: $!\n";
###############################################################################
#
# Delete the file from the include/ Kbuild file
#
###############################################################################
my $linuxdir;
$linuxhdr =~ m@(.*)/[^/]*$@, $linuxdir = $1;
my $linux_kbuild = $linuxdir . "/Kbuild";
open(FD, '<', $linux_kbuild) or die $linux_kbuild, ": $!\n";
my @kblines = <FD> or die $linux_kbuild, ": $!\n";
close(FD) or die $linux_kbuild, ": $!\n";
my $temp = $linux_kbuild . ".temp";
open(FD, '>', $temp) or die "$temp: $!\n";
foreach my $kbline (@kblines) {
if ($kbline =~ m@^header-y\s+[+]=\s+([a-zA-Z0-9_.-]+)@) {
next if ($1 eq $hdrname);
}
print FD $kbline or die "$temp: $!\n";
}
close FD or die "$temp: $!\n";
rename $temp, $linux_kbuild or die "$temp -> $linux_kbuild: $!\n";
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: genlist.pl --]
[-- Type: text/x-perl, Size: 1828 bytes --]
#!/usr/bin/perl -w
use File::Find;
#
# We assume that only Kbuild files in include directories are pertinent to
# determining which headers are UAPI headers.
#
@kbuilds = ();
%headers = ();
sub find_Kbuild()
{
push(@kbuilds, $File::Find::name) if ($_ eq "Kbuild");
$headers{$File::Find::name} = 1 if ($_ =~ /[.]h$/ || $_ =~ /[.]agh$/);
}
find(\&find_Kbuild, "arch", "include");
# Read the common arch list
open FD, '<include/asm-generic/Kbuild.asm' or die "open Kbuild.asm: $!\n";
my @kbuild_asm = <FD>;
close FD or die;
my %uapihdrs = ();
foreach my $i (sort(grep { $_ !~ m@uapi/@ } @kbuilds)) {
#print "[[[ $i ]]]\n";
my $dir = $i;
$dir =~ m@(^.*)/@, $dir = $1;
open FD, '<', $i or die "open $i: $!\n";
my @lines = <FD>;
close FD or die;
for (my $l = 0; $l <= $#lines; $l++) {
my $line = $lines[$l];
# parse out the blocks
# - this may be split over multiple lines using backslashes
my $block = $line;
restart:
$block =~ s@#.*$@@;
$block =~ s@\s+$@@g;
$block =~ s@\s+@ @g;
if ($block =~ /^(.*)[\\]$/) {
$l++;
$block = $1 . $lines[$l];
goto restart;
}
$block =~ s@\s+$@@g;
$block =~ s@\s\s+@ @g;
if ($block =~ m@^include include/asm-generic/Kbuild.asm@) {
push @lines, @kbuild_asm;
}
if ($block =~ m@^header-y\s*[+:]?=\s*(.*)@ ||
$block =~ m@^opt-header\s*[+:]?=\s*(.*)@ ||
$block =~ m@^asm-headers\s*[+:]?=\s*(.*)@
) {
foreach $h (map { "$dir/" . $_ } grep m@[^/]$@, split /\s+/, $1) {
if (exists $headers{$h}) {
$uapihdrs{$h} = 1;
}
}
}
}
}
if ($#ARGV == -1) {
# no arguments: all listed header files
print map { $_ . "\n"; } sort keys %uapihdrs;
} else {
# any arguments: all unlisted header files
print map { $_ . "\n"; } sort grep { !exists $uapihdrs{$_}; } keys %headers;
}
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: disintegrate-to-git-by-dir.pl --]
[-- Type: text/x-perl, Size: 1525 bytes --]
#!/usr/bin/perl -w
#
# Perform header disintegration of the user API, producing commits on a
# dir-by-dir basis to GIT
#
use strict;
use File::Basename;
my $main_branch = "uapi-split";
my $UAPI = "uapi";
$ENV{UAPI} = "uapi";
my $execdir = dirname($0);
sub commit($@) {
my ($dirname, @files) = @_;
system("git commit -m 'UAPI: Disintegrate $dirname\n\nSigned-off-by: David Howells <dhowells\@redhat.com>\n' " . join(" ", @files)) == 0 or die;
}
###############################################################################
#
#
#
###############################################################################
system("git checkout $main_branch") == 0 or die;
my $curdir = "xxxxx";
my @headerlist = sort {
dirname($a) cmp dirname($b) || $a cmp $b;
} `$execdir/genlist.pl`;
my @files = ();
foreach my $origfile (@headerlist) {
chomp $origfile;
if (! -f $origfile) {
print "Skip $origfile\n";
next;
}
my $odir = dirname($origfile);
if ($odir ne $curdir) {
print "[]";
commit($curdir, @files) unless ($curdir eq "xxxxx");
$curdir = $odir;
@files = ();
}
print "$origfile\n";
my $uapifile = $origfile;
$uapifile =~ s@include/@$UAPI/@;
my $udir = dirname($uapifile);
system("$execdir/disintegrate-one.pl $origfile $uapifile") == 0 or die;
if (-r $uapifile) {
push @files, $uapifile;
system("git add $uapifile") == 0 or die;
}
push @files, "$udir/Kbuild", $origfile, "$odir/Kbuild";
}
commit($curdir, @files) unless ($curdir eq "xxxxx");
next prev parent reply other threads:[~2011-07-02 11:33 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-07-02 11:07 [PATCH 00/35] UAPI header file split David Howells
2011-07-02 11:07 ` [PATCH 01/35] UAPI: Convert #include "..." to #include <path/...> in kernel system headers David Howells
2011-07-02 11:08 ` [PATCH 03/35] UAPI: Add uapi/ include directory to build David Howells
2011-07-02 11:08 ` [PATCH 04/35] UAPI: Differentiate userspace build and kernelspace build include path sets David Howells
2011-07-02 11:08 ` [PATCH 05/35] UAPI: Fix AHZ multiple inclusion when __KERNEL__ is removed David Howells
2011-07-02 11:08 ` [PATCH 06/35] UAPI: ac_etime in linux/acct.h must keep its __KERNEL__ guards David Howells
2011-07-02 11:08 ` [PATCH 07/35] UAPI: Make linux/patchkey.h easier to parse David Howells
2011-07-02 11:08 ` [PATCH 08/35] UAPI: Don't have a #elif clause in a __KERNEL__ guard in linux/soundcard.h David Howells
2011-07-02 11:08 ` [PATCH 09/35] UAPI: Fix nested __KERNEL__ guards in video/edid.h David Howells
2011-07-02 11:09 ` [PATCH 10/35] UAPI: Split trivial #if defined(__KERNEL__) && X conditionals David Howells
2011-07-02 11:09 ` [PATCH 11/35] UAPI: Remove the inclusion of linux/types.h from x86's asm/page.h David Howells
2011-07-02 11:09 ` [PATCH 12/35] UAPI: Fix definition of HZ in asm-generic/param.h David Howells
2011-07-02 11:09 ` [PATCH 13/35] UAPI: elf_read_implies_exec() is a kernel-only feature - so hide from userspace David Howells
2011-07-02 11:09 ` [PATCH 14/35] UAPI: Fix sigset_t ordering problem David Howells
2011-07-02 11:09 ` [PATCH 15/35] UAPI: Fix E820_X_MAX " David Howells
2011-07-02 11:09 ` [PATCH 16/35] UAPI: Fix linux/netfilter.h inclusion order David Howells
2011-07-02 11:10 ` [PATCH 17/35] UAPI: Fix linux/input.h " David Howells
2011-07-02 11:10 ` [PATCH 18/35] UAPI: Fix up linux/netfilter/xt_policy.h David Howells
2011-07-02 11:10 ` [PATCH 19/35] UAPI: Fix linux/auto_fs.h inclusion order David Howells
2011-07-02 11:10 ` [PATCH 20/35] UAPI: Fix drmP.h to use #include <...> when referring to system header files David Howells
2011-07-02 11:10 ` [PATCH 21/35] UAPI: sound/sound_core.c should include linux/fs.h David Howells
2011-07-02 11:10 ` [PATCH 22/35] UAPI: Fix SNDRV_*_ENDIAN ordering problem David Howells
2011-07-02 11:10 ` [PATCH 23/35] UAPI: Fix u_quad_t ordering problem in linux/coda.h David Howells
2011-07-02 11:11 ` [PATCH 24/35] UAPI: Fix linux/coda.h David Howells
2011-07-02 11:11 ` [PATCH 25/35] UAPI: Guard linux/isdn_divertif.h David Howells
2011-07-02 11:11 ` [PATCH 26/35] UAPI: Guard linux/sound.h David Howells
2011-07-02 11:11 ` [PATCH 27/35] UAPI: Fix linux/ncp.h David Howells
2011-07-02 11:11 ` [PATCH 28/35] UAPI: Fix x86_64 system call count and generation David Howells
2011-07-02 11:11 ` [PATCH 29/35] UAPI: Fix arch/mips/include/asm/Kbuild to have separate header-y lines David Howells
2011-07-02 11:12 ` [PATCH 31/35] UAPI: Plumb the UAPI Kbuilds into the user header handling system David Howells
2011-07-02 11:12 ` [PATCH 32/35] UAPI: Set up uapi/asm/Kbuild.asm David Howells
2011-07-02 11:12 ` [PATCH 33/35] UAPI: Move linux/version.h David Howells
2011-07-02 11:12 ` [PATCH 34/35] UAPI: Make UAPI headers install to usr/include/ David Howells
2011-07-02 11:12 ` [PATCH 35/35] UAPI: Fix the page-types query program in the docs David Howells
2011-07-02 11:33 ` David Howells [this message]
2011-07-05 20:46 ` [PATCH 00/35] UAPI header file split Randy Dunlap
2011-07-06 11:04 ` David Howells
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=23016.1309606432@redhat.com \
--to=dhowells@redhat.com \
--cc=linux-arch@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).