Build shadow header files when necessary on Linux
[openafs.git] / src / libafs / make_kbuild_makefile.pl
1 #!/usr/bin/perl
2 # make_kbuild_makefile.pl
3 # Generate a Makefile for use with the Linux 2.6+ kernel build system
4 #
5 # Usage: make_kbuild_makefile.pl ${KDIR} ${TARG} Makefiles...
6 #
7 # The specified makefiles will be scanned for variable values
8 # The module ${TARG} will be built in ${TOP_SRCDIR}/src/libafs/${KDIR}.
9 # It will include objects listed in ${AFSAOBJS} and ${AFSNFSOBJS}
10 # The afspag.ko module will be built from objects listed in ${AFSPAGOBJS}.
11 # Appropriate source files for each object will be symlinked into ${KDIR}
12 # EXTRA_CFLAGS will be set to ${CFLAGS} ${COMMON_INCLUDE}
13 # Any CFLAGS_* and AFLAGS_* variables will be copied
14
15 # Produces ${KDIR}/Makefile, suitable for use with kbuild
16
17 use IO::File;
18
19
20 if (@ARGV < 3) {
21   die "Usage: $0 KDIR TARG Makefiles...\n";
22 }
23
24 ($KDIR, $TARG, @Makefiles) = @ARGV;
25 $TARG =~ s/\.k?o$//;
26
27 ## Read in all of the Makefiles given on the command line
28 ## Our ultimate goal is to find the correct source file for each object.
29 ## We make the following assumptions:
30 ## - Every variable is defined before it is used.
31 ## - Each of our objects has exactly one dependency, which is the name
32 ##   of the source file that needs to be symlinked into $KDIR
33 foreach $mf (@Makefiles) {
34   $F = new IO::File($mf, O_RDONLY) or die "$mf: $!\n";
35   $text = '';
36   while (<$F>) {
37     chomp;
38     $text .= $_;
39     next if $text =~ s/\\$/ /;                 ## Continuation
40     if ($text =~ /^#/) { $text = ''; next }    ## Comment
41     #print STDERR "<< $text\n";
42
43     $text =~ s/\$\((\w+)\)/$vars{$1}/g;        # Substitute variables
44     $text =~ s/\$\{(\w+)\}/$vars{$1}/g;
45     #print STDERR ">> $text\n";
46
47     if ($text =~ /^\s*(\S+)\s*=/) {            ## Variable definition
48       ($key, $value) = ($1, $');
49       $value =~ s/^\s*//;                      # Remove leading and
50       $value =~ s/\s*$//;                      # trailing whitespace
51       $vars{$key} = $value;                    # Store it
52     }
53     elsif ($text =~ /^(\S+\.o):\s*(\S+\.c)/) {    ## Dependency
54       $deps{$1} = $2;
55     }
56     elsif ($text =~ /^(\S+\.o):\s*(\S+\.s)/) {    ## Dependency
57       $deps{$1} = $2;
58     }
59     $text = '';
60   }
61   $F->close();
62 }
63
64
65 $KDIR = "$vars{TOP_OBJDIR}/src/libafs/$KDIR";
66 @libafs_objs = (split(' ', $vars{AFSAOBJS}), split(' ', $vars{AFSNFSOBJS}));
67 @afspag_objs = (split(' ', $vars{AFSPAGOBJS}));
68
69 $MV = new IO::File("$vars{TOP_OBJDIR}/src/config/Makefile.version", O_RDONLY)
70         or die "$vars{TOP_OBJDIR}/src/config/Makefile.version: $!\n";
71 while (<$MV>) {
72   s#AFS_component_version_number#$KDIR/AFS_component_version_number#g;
73   $MakefileVersion .= $_;
74 }
75 $MV->close();
76
77 if (! -d $KDIR) {
78   mkdir($KDIR, 0777) or die "$KDIR: $!\n";
79 }
80
81 %all_objs = map(($_ => 1), @libafs_objs, @afspag_objs);
82
83 foreach (keys %all_objs) {
84   die "No source known for $_\n" unless exists $deps{$_};
85   if($deps{$_} =~ /\.s$/) {
86      ($src = $_) =~ s/\.o$/.S/;
87   } else {
88      ($src = $_) =~ s/\.o$/.c/;
89   }
90   if (-e "$KDIR/$src" || -l "$KDIR/$src") {
91     unlink("$KDIR/$src") or die "$KDIR/$src: $!\n";
92   }
93   next unless $deps{$_} =~ m#/#;
94   symlink($deps{$_}, "$KDIR/$src") or die "$KDIR/$src: $!\n";
95 }
96
97 %remap = ('h' => 'linux', 'netinet' => 'linux', 'sys' => 'linux');
98 if (-f "$vars{LINUX_KERNEL_PATH}/include/linux/types.h") {
99   foreach $src (keys %remap) {
100     if (-e "$KDIR/$src" || -l "$KDIR/$src") {
101       unlink("$KDIR/$src") or die "$KDIR/$src: $!\n";
102     }
103     symlink("$vars{LINUX_KERNEL_PATH}/include/linux", "$KDIR/$src")
104       or die "$KDIR/$src: $!\n";
105   }
106 } else {
107   foreach $src (keys %remap) {
108     system ('rm', '-rf', "$KDIR/$src"); # too crude?
109     mkdir("$KDIR/$src", 0777) or die "$KDIR/$src: $!\n";
110   }
111   %seen = ();
112   @q = <$KDIR/*.[Sc]>;
113   @include_dirs = map { /^\// ? $_ : "$KDIR/$_" }
114     split /[\s\\]*-I/, $vars{COMMON_INCLUDE};
115   push @include_dirs, "$vars{TOP_SRCDIR}/../include/rx", "$vars{TOP_SRCDIR}/rx";
116   while (@q) {
117     $src = shift @q;
118     $content = new IO::File($src, O_RDONLY) or die "$src: $!\n";
119   LINE:
120     while (<$content>) {
121       chomp;
122       if (/^\s*#\s*include\s*[<"](?:\.\.\/)?([^\/>"]*)(.*?)[>"]/) {
123         $inc = "$1$2";
124         if (exists $seen{$inc}) {
125           next;
126         } elsif (exists $remap{$1}  &&  $2 !~ /.\//) {
127           $H = new IO::File("$KDIR/$inc", O_WRONLY|O_CREAT|O_TRUNC, 0666)
128             or die "$KDIR/$inc: $!\n";
129           print $H "#include <linux$2>\n";
130           $H->close() or die "$KDIR/$inc: $!\n";
131         } else {
132           for $dir (@include_dirs) {
133             if (-f "$dir/$inc") {
134               push @q, "$dir/$inc";
135               $seen{$inc} = 1;
136               next LINE;
137             }
138           }
139           if ($1 =~ /^(arpa|asm|.*fs|i?net|kern|ksys|linux|mach|rpc|scsi|vm)$/
140               ||  !length($2)) {
141             # Safe to ignore silently.
142           } else {
143             warn "Ignoring $_ ($inc not found)\n";
144           }
145         }
146         $seen{$inc} = 1;
147       } elsif (/^\s*#\s*include/) {
148         warn "Ignoring $_ (unrecognized syntax)\n";
149       }
150     }
151   }
152 }
153
154 $cflags = "$vars{CFLAGS} $vars{COMMON_INCLUDE}";
155 $cflags =~ s#-I(?!/)#-I$KDIR/#g;
156 $cflags =~ s/\s+/ \\\n /g;
157 $F = new IO::File("$KDIR/Makefile", O_WRONLY|O_CREAT|O_TRUNC, 0666)
158      or die "$KDIR/Makefile: $!\n";
159 foreach (sort keys %vars) {
160   next unless /^[AC]FLAGS_/;
161   print $F "$_ = $vars{$_}\n";
162 }
163 print $F "EXTRA_CFLAGS=$cflags\n";
164 print $F "obj-m := $TARG.o afspag.o\n";
165 print $F "$TARG-objs := ", join("\\\n $_", @libafs_objs), "\n";
166 print $F "afspag-objs := ", join("\\\n $_", @afspag_objs), "\n";
167 print $F "\n$MakefileVersion\n";
168 $F->close() or die "$KDIR/Makefile: $!\n";
169