1#! /usr/bin/perl 2 3## $Id: buildconfig.in 8817 2009-11-17 18:57:19Z iulius $ 4## 5## Generate linkage code and makefiles for storage and overview methods. 6## 7## Goes through all subdirectories of the current directory and finds 8## directories that are either storage methods or overview methods. Builds 9## methods.[ch] and ovmethods.[ch] as well as makefile stubs. 10 11require 5.003; 12 13use strict; 14use vars qw(@OVERVIEW @STORAGE); 15 16# Storage API functions. 17@STORAGE = qw(init store retrieve next freearticle cancel ctl flushcacheddata 18 printfiles explaintoken shutdown); 19 20# Overview API functions. 21@OVERVIEW = qw(open groupstats groupadd groupdel add cancel opensearch search 22 closesearch getartinfo expiregroup ctl close); 23 24# Used to make heredocs more readable. 25sub unquote { my ($string) = @_; $string =~ s/^:( {0,7}|\t)//gm; $string } 26 27# Parse a method.config file for a storage method, putting information about 28# that storage method into the given hash ref. 29sub parse_config { 30 my ($dir, $file, $config) = @_; 31 local $_; 32 $$config{sources} ||= []; 33 $$config{extra} ||= []; 34 $$config{programs} ||= []; 35 $$config{makefiles} ||= []; 36 open (CONFIG, "$dir/$file") or die "Can't open $dir/$file: $!\n"; 37 while (<CONFIG>) { 38 s/^\s+//; 39 s/\s+$//; 40 if (/^name\s*=\s*(\S+)$/) { 41 my $method = $1; 42 die "$dir/$file: $method has already been defined\n" 43 if (defined $$config{method}{$method}); 44 $$config{method}{$method} = $dir; 45 } elsif (/^number\s*=\s*(\d+)$/) { 46 my $number = $1; 47 if (defined $$config{number}{$number}) { 48 die "$dir/$file: method number $number was already " 49 . "allocated in $$config{number}{$number}\n"; 50 } 51 $$config{number}{$dir} = $number; 52 } elsif (/^sources\s*=\s*(.*)/) { 53 my $sources = $1; 54 my @sources = split (' ', $sources); 55 push (@{ $$config{sources} }, map { "$dir/$_" } @sources); 56 } elsif (/^extra-sources\s*=\s*(.*)/) { 57 my $extra = $1; 58 my @extra = split (' ', $extra); 59 push (@{ $$config{extra} }, map { "$dir/$_" } @extra); 60 } elsif (/^programs\s*=\s*(.*)/) { 61 my $programs = $1; 62 my @programs = split (' ', $programs); 63 push (@{ $$config{programs} }, map { "$dir/$_" } @programs); 64 } else { 65 warn "$dir/$file: ignoring unknown line: $_\n"; 66 } 67 } 68 69 # If there is a makefile fragment in the directory, note it. 70 if (-f "$dir/method.mk") { 71 push (@{ $$config{makefiles} }, "$dir/method.mk"); 72 } elsif (-f "$dir/ovmethod.mk") { 73 push (@{ $$config{makefiles} }, "$dir/ovmethod.mk"); 74 } 75} 76 77# Write out include directives for a list of files. 78sub write_includes { 79 my ($fh, $config) = @_; 80 my $method; 81 for $method (sort keys %{ $$config{method} }) { 82 my $path = $$config{method}{$method}; 83 print $fh qq(\#include "$path/$method.h"\n); 84 } 85} 86 87# Write out the method struct. 88sub write_methods { 89 my ($fh, $config, $prefix, @funcs) = @_; 90 my ($notfirst, $method); 91 for $method (sort keys %{ $$config{method} }) { 92 print $fh "\n},\n" if $notfirst; 93 print $fh qq(\{\n "$method"); 94 print $fh ', ', $prefix, '_', uc ($method) if $prefix; 95 for (@funcs) { 96 print $fh ",\n ${method}_$_"; 97 } 98 $notfirst++; 99 } 100 print $fh "\n}\n};\n\n"; 101} 102 103# Write out the constant defines for methods. 104sub write_constants { 105 my ($fh, $config, $prefix) = @_; 106 my $method; 107 for $method (sort keys %{ $$config{method} }) { 108 printf $fh "#define ${prefix}_%-30s%d\n", uc ($method), 109 $$config{number}{$$config{method}{$method}}; 110 } 111} 112 113# Write out methods.c and methods.h for the interface to the storage 114# methods. 115sub write_storage { 116 my $storage = shift; 117 open (DEF, '> methods.c.new') or die "Can't create methods.c.new: $!\n"; 118 print DEF unquote (<<'EOE'); 119: /* This file is automatically generated by buildconfig. */ 120: 121: #include "interface.h" 122: #include "methods.h" 123EOE 124 my $method; 125 write_includes (\*DEF, $storage); 126 print DEF "\nSTORAGE_METHOD storage_methods[", 127 scalar (keys %{ $$storage{method} }), "] = {\n"; 128 write_methods (\*DEF, $storage, 'TOKEN', @STORAGE); 129 close DEF; 130 rename ('methods.c.new', 'methods.c'); 131 132 open (H, '> methods.h.new') or die "Can't open methods.h.new: $!\n"; 133 print H unquote (<<'EOE'); 134: /* This file is automatically generated by buildconfig */ 135: 136: #ifndef METHODS_H 137: #define METHODS_H 1 138: 139: #include "interface.h" 140: 141EOE 142 print H '#define NUM_STORAGE_METHODS ', 143 scalar (keys %{ $$storage{method} }), "\n\n"; 144 write_constants (\*H, $storage, 'TOKEN'); 145 print H unquote (<<'EOE'); 146: 147: extern STORAGE_METHOD storage_methods[NUM_STORAGE_METHODS]; 148: 149: #endif /* METHODS_H */ 150EOE 151 close H; 152 rename ('methods.h.new', 'methods.h'); 153} 154 155# Write out ovmethods.c and ovmethods.h for the interface to the overview 156# methods. 157sub write_overview { 158 my $overview = shift; 159 open (DEF, '> ovmethods.c.new') 160 or die "Can't create ovmethods.c.new: $!\n"; 161 print DEF unquote (<<'EOE'); 162: /* This file is automatically generated by buildconfig. */ 163: 164: #include "ovinterface.h" 165EOE 166 write_includes (\*DEF, $overview); 167 print DEF "\nOV_METHOD ov_methods[", 168 scalar (keys %{ $$overview{method} }), "] = {\n"; 169 write_methods (\*DEF, $overview, undef, @OVERVIEW); 170 close DEF; 171 rename ('ovmethods.c.new', 'ovmethods.c'); 172 173 open (H, '> ovmethods.h.new') or die "Can't open ovmethods.h.new: $!\n"; 174 print H unquote (<<'EOE'); 175: /* This file is automatically generated by buildconfig */ 176: 177: #ifndef OVMETHODS_H 178: #define OVMETHODS_H 1 179: 180: #include "ovinterface.h" 181: 182EOE 183 print H '#define NUM_OV_METHODS ', 184 scalar (keys %{ $$overview{method} }), "\n"; 185 print H unquote (<<'EOE'); 186: 187: extern OV_METHOD ov_methods[NUM_OV_METHODS]; 188: 189: #endif /* OVMETHODS_H */ 190EOE 191 close H; 192 rename ('ovmethods.h.new', 'ovmethods.h'); 193} 194 195# Return a string setting a makefile variable. Tab over the = properly and 196# wrap to fit our coding standards. 197sub makefile_var { 198 my ($variable, @values) = @_; 199 my $output; 200 $output = sprintf ("%-15s =", $variable); 201 my $column = 17; 202 for (@values) { 203 if ($column > 17 && 77 - $column < length ($_)) { 204 $output .= " \\\n" . ' ' x 17; 205 $column = 17; 206 } 207 $output .= " $_"; 208 $column += 1 + length ($_); 209 } 210 $output .= "\n"; 211 return $output; 212} 213 214# Write out the makefile fragment for overview and storage methods. 215sub write_makefile { 216 my ($dirs, $sources, $extra, $programs, $makefiles) = @_; 217 open (MAKE, '> Make.methods.new') 218 or die "Can't create Make.methods.new: $!\n"; 219 print MAKE "# This file is automatically generated by buildconfig\n\n"; 220 print MAKE makefile_var ('METHOD_SOURCES', @$sources); 221 print MAKE makefile_var ('EXTRA_SOURCES', @$extra); 222 print MAKE makefile_var ('PROGRAMS', @$programs); 223 for (@$makefiles) { 224 print MAKE "\n\n## Included from $_\n\n"; 225 open (FRAG, $_) or die "Can't open $_: $!\n"; 226 print MAKE <FRAG>; 227 close FRAG; 228 } 229 rename ('Make.methods.new', 'Make.methods'); 230} 231 232my ($dir, %storage, %overview); 233if (!-d 'cnfs') { 234 if (-d 'storage/cnfs') { 235 chdir 'storage' or die "Can't chdir to storage: $!\n"; 236 } else { 237 die "Can't find storage directory (looking for storage/cnfs)\n"; 238 } 239} 240opendir (D, ".") or die "Can't open current directory: $!\n"; 241my @dirs = sort readdir D; 242for $dir (@dirs) { 243 if (-e "$dir/method.config") { 244 parse_config ($dir, 'method.config', \%storage); 245 } 246 if (-e "$dir/ovmethod.config") { 247 parse_config ($dir, 'ovmethod.config', \%overview); 248 } 249} 250write_storage (\%storage); 251write_overview (\%overview); 252@dirs = (sort values %{ $storage{method} }, 253 sort values %{ $overview{method} }); 254my @sources = (sort @{ $storage{sources} }, sort @{ $overview{sources} }); 255my @extra = (sort @{ $storage{extra} }, sort @{ $overview{extra} }); 256my @programs = sort (@{ $storage{programs} }, @{ $overview{programs} }); 257my @makefiles = sort (@{ $storage{makefiles} }, @{ $overview{makefiles} }); 258write_makefile (\@dirs, \@sources, \@extra, \@programs, \@makefiles); 259