📄 abc.pl
字号:
#!/usr/bin/perl -w
# This perl script is the core of a generic configuration system as
# described in TIDKs bugzilla Bug #3 The configuration system depends
# on a *.cfg file. This script will generate appropriate configuration
# include files (i.e. *.h files) from the *.cfg file.
# NOTE! If you think you need to edit this script, you are probably
# wrong or I forgot something, so please email me (mmj@ti.com)
# Known bugs/limitations:
# The comment character '#' cannot be embedded within quoted strings
# Notes:
# A target section in the master config file can include another
# section with a line "&SECTION". SECTION can be any section,
# including the special sub-sections which are just like a normal
# section but with the name prefixed by '&'. Only special thing about
# the sub-sections is that they cannot be built and they are not shown
# in the list printed by the -l option.
# TODO:
# Should we delete the configuration file for which there is no
# corresponding lines in the master config file, e.g. if there is no
# DSP_ lines, should we delete the dsp.cfg file? Or should it be an
# option (-od) Should we give a warning?
# Perhaps we should check for duplicate config lines. This is
# especially useful with the include feature, as this feature increase
# the risk of duplicate lines. As it is now, the lines are just copied
# into the corresponding config/*.cfg file so the compiler will
# complain
###############################################################################
# Customization
###############################################################################
# none!
###############################################################################
# Globals
###############################################################################
# Full list of valid configuration prefixes
@Prefixes = ();
# Target(s) from the global cfg file to build
@Targets = ();
# Default options (overridden by command line arguments)
$verbose = 1; # verbosity level
$nomake = 0; # don't invoke make at end of script
$dryrun = 0; # don't make actual config changes.
$listtargets = 0; # List all configs from master config
$printconfig = 0;
$printenv = 0; # Print out all ENV variables that are set.
$ConfigDir = "config"; # directory to put output config files
$makedb = 0; # Print out the make database to stdout (gnumake option -p)
$MakeParams = "";
$MakeFile = "";
$MasterConfigFile = "";
$warnings = 0;
$make_name = "gmake";
my %sections;
my $line = 0;
my $current_section = "";
my %expanded;
my %env_var;
my %cfg_file;
####################################################################
# Main
####################################################################
GetOpts();
# Find the configuration file to use
@ConfigFiles = glob("*.cfg");
$#ConfigFiles < 0 && die "No configuration file found\n";
# Check if MasterConfigFile was already set with the -f<cfg file> option
if ($MasterConfigFile eq "") {
$#ConfigFiles > 0 && die "Multiple config-files found! (@ConfigFiles)\n";
$MasterConfigFile = $ConfigFiles[0];
}
# Find name of make file, using the basename of the master config-file
if ($MakeFile eq "") {
@tmp = $MasterConfigFile =~ /(\w+)/;
$MakeFile = $tmp[0] . ".mak";
}
ReadMasterConfig($MasterConfigFile);
if ($listtargets) { ListTargets(); }
if ($printconfig) { PrintConfig(); }
foreach $build (@Targets) {
# >>>> Start Adding SB : 17/03/03
# Add an environment variable for master.mak
$RFname = "DELIVERY_BASENAME" ;
$RFvalue = $build ;
if ( defined( $ENV{"$RFname"} ) )
{
print STDERR " Warning : environement vartiable $RFname already set to $ENV{\"$RFname\"} updated to $RFvalue\n" ;
}
$ENV{"$RFname"} = $RFvalue ; # set environment variable
# >>>> Stop Adding SB : 17/03/03
verb(2,"ExpandMasterConfig for $build\n");
%expanded = ();
ExpandMasterConfig($build);
verb(1, "Building target: $build\n");
Process($build);
if ($nomake == 0) {
@args = ( "$make_name", "$MakeParams", "-f", "$MakeFile" );
if ($makedb == 1) {
push (@args,"-p");
}
verb(1, "Invoking make: @args \n\n");
system("@args");
}
}
####################################################################
# Admin procedures
####################################################################
sub GetOpts {
foreach (@ARGV) {
if (/^-n/) { $dryrun++; }
if (/^-c/) { $nomake++; }
if (/^-p/) { $printconfig++; }
if (/^-d/) { $makedb++; }
if (/^-l/) { $listtargets++; }
if (/^-e/) { $printenv++; }
if (/^-f(\w+\.?\w*)/) { $MasterConfigFile = $1; }
if (/^-m(\w+\.?\w*)/) { $MakeFile = $1; }
if (/^-x([^\s]+)/) {
$MakeParams = $1;
$MakeParams =~ tr/,/ /;
}
if (/^-o(\w+\.?\w*)/) { $ConfigDir = $1; }
if (/^-h|--help/) { Usage(); }
if (/^-v/) { $verbose++; }
if (/^-q/) { $verbose = -1; }
if (/^[^\-](\w+)/) {
push (@Targets,uc($_)); # push uppercased string
}
}
if ($#Targets < 0) { $Targets[0] = "DEFAULT"; }
}
sub PrintConfig {
foreach (@Targets) {
unless (/\&/) {
!defined($sections{$_}) && die "Target section $_ not found\n";
print "Target [$_]:\n";
%expanded = ();
ExpandSection ("$_",0,1);
print "\n\n";
}
}
exit(0);
}
sub ListTargets {
print "Targets:\n";
foreach (sort keys %sections) {
unless (/\&/) { print " [$_]\n"; }
}
exit(0);
}
sub Usage
{
print <<USAGE_END;
abc.pl v1.10. Automatic Building, Configuration and Dependencies System.
Copyright TI 2001.
Usage: [perl] abc.pl [OPTION]... [TARGETS]...
OPTIONS:
-h Display this help and exit
-c Only do configuration step. Do not invoke gnumake.
-n Dry run. Print what is going to be done without doing it.
-l List all configurations in master config file, then exit
-f<name> Specify which master configuration file to use.
Note that there must be no spaces between "-f" and the file name.
Default is to use the *.cfg file from the current directory.
-m<name> Specify which make file use.
Note that there must be no spaces between "-m" and the file name.
Default is to use the makefile <file>.mak file from the current
directory, where <file> corresponds to the basename of the
config file.
-o<name> Specify output directory name (where to put *.cfg files).
Default is 'config'.
Note that there must be no spaces between "-o" and the dir name.
-p Print out contents of the specified target(s)
-d Print make database (corresponds to gnumake -p)
-e Print out all ENVironment variables that are set
-v Be verbose (repeat several times to be more verbose)
-q Be quiet
TARGETS Name(s) of the target(s) to build.
Report bugs and suggestions to mmj\@ti.com or skl\@ti.com
USAGE_END
# -t Touch. Invoke make with additional parameter: -t
exit(0);
}
####################################################################
## Core procedures
####################################################################
# Expand all section inclusions in each target
sub ExpandMasterConfig
{
my ($default_section) = @_;
if (defined($sections{$default_section})){
#print default section only
ExpandSection ($default_section);
} else {
#error in $default_section
verb (1,"Section [$default_section] is not defined in $MasterConfigFile \n");
exit 1;
}
}
sub ExpandSection
{
my ($section,$level,$show);
my $j;
my $var;
my @values;
my $indent;
my $egal_column = 40;
($section,$level,$show) = @_;
verb (2,"Expanding [$section]\n");
if (!$level){$level = 1};
$indent = " "x$level."+- ";
if ($level > 9){
die "Including somewhat deep! Did you make a loop?\n";
}
@values = split(' ',$sections{"$_[0]"});
foreach $j (@values){
if($j =~ /^&/){
if ($show){
print "$indent$j\n";}
}else{
$j =~ /([^=]*)=(.*)/;
$var = $1;
$value = $2;
$value =~ s/\#.*$//;
$env_var = '';
if ($var =~ /^\$/){
$var =~ s/^\$//;
$env_var = '$';
}
if ( exists $expanded{$var} ) {
print STDERR "Warning : in [$section], $env_var{$var}$var = $expanded{$var} is overwritten by $env_var$var = $value\n";
}
$env_var{$var} = $env_var;
$expanded{$var} = $value;
if ($show){
$line = $indent.$var;
$points = "."x(40-length($line)-1);
print "$line$points = $value\n";
}
}
if ($j =~ /^&(\w*)/){
ExpandSection ($1,++$level,$show);
$level--;
}
}
}
sub ReadMasterConfig
{
my ($filename)=(@_);
verb(1, "Reading master config file: $filename\n");
[-e $filename] || die "File $filename not found\n";
#Gather informations from master.cfg
open (MASTER_CFG,"$filename") || die "Can't open $filename\n";
while (<MASTER_CFG>){
while (/[\r\n]$/){s/[\r\n]$//}
#line counter
$line++;
#ignore line comment
if (/^\s*\#/) {
verb(5, "Skip: comment line \n");
next};
#ignore blank lines
if (/^$/) {
verb(5, "Skip: empty line\n");
next};
#identify new section
if (/\[(\w*)\]/){
$current_section = uc($1);
verb(4, "Reading section: $current_section\n");
if (defined($sections{"$current_section"})){
print STDERR "Warning [$line]: Section $current_section is already defined\n";
die;
} else {
$sections{"$current_section"}="";
}
next;
}
#add section lines
if ($current_section eq ""){
die "Error [$line]: $filename must starts by a [section] definition\n";
}
s/ //g;
verb(5, "Read: $_\n");
$sections{"$current_section"} .= " $_";
if (/^\$?([^_]+)_\w+\s*=\s*.*/){
$Prefixes{$1}=1;
}
}
close (MASTER_CFG);
verb(4, "Successfully read configuration sections\n");
verb(3, "\n");
}
sub ReadConfigFile
{
my ($cfg)=(@_);
my (@list);
my ($prefix);
%cfg_file = ();
$filename = $cfg;
$filename =~ s@$cfg@$ConfigDir/\L$cfg\E.cfg@;
# If the file does not exist, just return empty list
if (-e $filename) {
verb(2, "Reading current config file: $filename\n");
}
else {
verb(2, "Config file $filename non-existing\n");
return;
}
$protect = "";
open (FH, "<$filename") || die "Can't open $filename\n";
while (<FH>)
{
chomp;
if (m/\#ifndef\s*(\w+)/){
$protect = $1;
}
# here we add the $cfg prefix to each line
if (m/\#define\s*([^ ]+)\s*(.*)/) {
$var = $1;
$val = $2;
if ($var =~ /$protect/i){
verb(6,"Ignore $protect define\n");
next;
}
verb(5, "Read: $var=$val\n");
$cfg_file{"${cfg}_$var"}=$val;
}
}
close (FH) || die "Can't close $filename\n";
}
sub Process
{
if (-e $ConfigDir) {
-d $ConfigDir || die "'$ConfigDir' is a file, should be a directory!\n";
}
else {
verb(4, "Config-dir $ConfigDir not found - creating it...\n");
@args = ("mkdir", "$ConfigDir");
system("@args");
}
foreach $cfg (keys (%Prefixes)){
$update = 0;
ReadConfigFile($cfg);
verb (2,"File read\n");
foreach $i (keys(%expanded)){
if ($i =~ /^${cfg}_/){
if (defined($cfg_file{$i})) {
if ($cfg_file{$i} ne $expanded{$i}){
$update = 1;
}
delete $cfg_file{$i};
} else {
$update = 1;
}
}
}
if (keys(%cfg_file) > 0){
verb (2,"Some variables are deleted.\n");
$update = 1;
}
#update ENV vars and cfg files
if ($update && !$dryrun) {
open (FH, ">$filename") || die "Can't open $filename\n";
print FH "#ifndef __$cfg\_CFG__\n";
print FH "#define __$cfg\_CFG__\n";
}
foreach $i (sort (keys(%expanded))){
if ($i =~ /^${cfg}_/){
$var = $i;
$var =~ s/^${cfg}_//;
if ($update && !$dryrun){
print FH "#define $var $expanded{$i}\n";
}
if ($env_var{$i}){
if (exists $ENV{$var}){
verb(1,"Warning environnement varaible is already set to $ENV{$i} in the system and is overwritten by $expanded{$i}\n");}
$ENV{$var}=$expanded{$i};
verb (2,"Setting $var environnement variable to $ENV{$var}\n");
}
}
}
if ($update && !$dryrun) {
print FH "#endif /* __$cfg\_CFG__ \*/ \n";
close (FH) || die "Can't close $filename\n";
}
if ($update){
verb(2, "Updating $filename.\n");
} else {
verb (2,"$cfg file leaved untouched.\n");
}
}
}
# Print trace message (without indentation if $level < 0)
sub verb
{
my ($level, $str) = @_;
my ($indent) = 0;
if ($level < 0) {
$level = -$level;
}
else {
$indent = ($level || 1) - 1;
}
if ($verbose >= $level) {
print " " x $indent . $str;
}
}
sub warning
{
my ($str) = @_;
print STDERR "WARNING: $str";
$warnings++;
}
sub error
{
my ($str) = @_;
print STDERR "ERROR: $str";
exit(1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -