diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/sam2p/ccdep.pl |
Initial commit
Diffstat (limited to 'graphics/sam2p/ccdep.pl')
-rw-r--r-- | graphics/sam2p/ccdep.pl | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/graphics/sam2p/ccdep.pl b/graphics/sam2p/ccdep.pl new file mode 100644 index 0000000000..987951aadc --- /dev/null +++ b/graphics/sam2p/ccdep.pl @@ -0,0 +1,397 @@ +#! /bin/sh -- +eval '(exit $?0)' && eval 'PERL_BADLANG=x;export PERL_BADLANG;: \ +;exec perl -T -S -- "$0" ${1+"$@"};#'if 0; +eval 'setenv PERL_BADLANG x;exec perl -x -S -- "$0" $argv:q;#'.q +#!perl -w ++($0=~/(.*)/s);do$1;die$@if$@;__END__+if 0; +# Don't touch/remove lines 1--7: http://www.inf.bme.hu/~pts/Magic.Perl.Header +# +# ccdep.pl v0.32 -- semiautomatic dependency discovery for C/C++ programs +# by pts@math.bme.hu at Fri May 31 13:36:29 CEST 2002 +# 0.31 by pts@math.bme.hu at Sat Jun 1 15:19:55 CEST 2002 +# 0.32 by pts@math.bme.hu at Tue Sep 3 19:12:20 CEST 2002 +# 0.33 by pts@math.bme.hu at Thu Oct 31 09:47:25 CET 2002 +# +# Dat: no -T (tainting checks) anymore, does bad to our readpipe() +# OK : emit `TARGETS_yes = ...' +# Imp: make #warning etc. in *.h files work as expected +# OK : generated.h +# Imp: add external libraries (-L...) +# Imp: abort if gcc command not found... +# Imp: abort if not all .o are mentioned in gcc output +# Imp: avoid $ etc. in Makefile +# OK : all 8 combinations of PROVIDES|REQUIRES|CONFLICTS +# +BEGIN { eval { require integer; import integer } } +BEGIN { eval { require strict ; import strict } } + +# Typical invocation: ccdep.pl --FAL=assert,no,yes,checker $(CXX) +my @FAL=(); +if (@ARGV and $ARGV[0]=~/\A--FAL=(.*)/s) { @FAL=split/\W+/,$1; shift@ARGV } +my $GCCP; # 'g++' or 'gcc': C/C++ preproc with `-E -MG' switches +$GCCP="@ARGV"; +$GCCP="gcc" if $GCCP!~y/ \t//c; + +# Make sure we get English error messages from gcc. +delete $ENV{LANG}; +delete $ENV{LANGUAGE}; +$ENV{LC_ALL} = "C"; + +# --- + +# Returns true iff the passed filename is a C or C++ source file (and not .o +# or .h or anything else). +sub is_ds($) { + my $FN = $_[0]; + return $FN =~ /\.(c(|c|xx|pp|[+][+])|C)\Z(?!\n)/; +} + +sub find_ds() { + #** @return a list of .ds file in the current directory + my @L; my $E; + die unless opendir DIR, '.'; + while (defined($E=readdir DIR)) { + push @L, $E if is_ds($E) and -f $E; + } + @L +} + +sub expand_glob($$ $) { + #** @param $_[0] string containing globs (? and *) + #** @param $_[1] listref of names + #** @param $_[2] dest listref + my $S=quotemeta($_[0]); + if (0==($S=~s@\\([?*])@.$1@g)) { push @{$_[2]}, $_[0]; return } + my $RE=eval"+sub{\$_[0]=~/$S/}"; + die$@if$@; + for my $E (@{$_[1]}) { push @{$_[2]}, $E if $RE->($E) } +} + +sub mustbe_subset_of($$ $$) { + #** A must be a subset (sublist) of B + #** @param $_[0] caption A + #** @param $_[1] ref(array(string)) A + #** @param $_[2] caption B + #** @param $_[3] ref(array(string)) B + my @A=sort @{$_[1]}; + my @B=sort @{$_[3]}; + my($AV,$BV); + while (defined($AV=pop@A)) { + 1 while defined($BV=pop@B) and $BV gt $AV; + if (!defined($BV) or $BV ne $AV) { + print STDERR "$0: $_[0] are: @{$_[1]}\n"; + print STDERR "$0: $_[2] are: @{$_[3]}\n"; + die "$0: $_[0] must be a subset of $_[2]\n"; + } + } +} + +# --- + +print "$0: running.\n"; + +sub unix_shq($) { + my $S=$_[0]; + $S=~s@'@'\\''@g; + "'$S'" +} + +sub shq($) { + my $S=$_[0]; + return $S if $S!~/[^\w.-]/; + if ($^O =~ /(?:win32|win64|windows)/i) { # $^O eq 'MSWin32' + # assume the called program is CygWin/Ming32; see later + # Arguments are delimited by white space, which is either a space or a tab. + # . A string surrounded by double quotation marks is interpreted as a + # single argument, regardless of white space contained within. A quoted + # string can be embedded in an argument. Note that the caret (^) is not + # recognized as an escape character or delimiter. + # . A double quotation mark preceded by a backslash, \", is interpreted as + # a literal double quotation mark ("). + # . Backslashes are interpreted literally, unless they immediately precede + # a double quotation mark. + # . If an even number of backslashes is followed by a double quotation + # mark, then one backslash (\) is placed in the argv array for every pair + # of backslashes (\\), and the double quotation mark (") is interpreted as + # a string delimiter. + # . If an odd number of backslashes is followed by a double quotation + # mark, then one backslash (\) is placed in the argv array for every pair + # of backslashes (\\) and the double quotation mark is interpreted as an + # escape sequence by the remaining backslash, causing a literal double + # quotation mark (") to be placed in argv. + $S =~ s@(\\+)(?="|\Z(?!\n))@$1$1@; + $S=~s@"@\\"@g; return qq{"$S"} + } else { + $S=~s@'@'\\''@g; return qq{'$S'} + } +} +#die shq(q{foo\b"ar\\}) eq q{"foo\b\"ar\\\\"}; # For Win32. + +sub backtick(@) { + my $S=$_[0]; + if ($^O eq 'MSWin32') { + # assume the called program is CygWin/Ming32; and we have proper /bin/sh + $S="sh -c ".unix_shq($S); # /bin/sh can handle IO-redirections such as `2>&1' right + } else { + # assume UNIX + } + print "+ $S\n"; + #die unless $ENV{PATH}=~/(.*)/s; # Dat: untaint() + #$ENV{PATH}=$1; + #die "$ENV{PATH}"; + # Dat: if `.' is part of $ENV{PATH}, `Insecure directory...' is reported + #die unless $S=~/(.*)/s; # Dat: untaint() + readpipe $S # `` qx`` +} + +my @DS=find_ds(); +my @DSQ=map{shq$_}@DS; +# g++-4.6 has it, clang++-3.4 doesn't but we don't care to rerun. +my $DIAG = ""; +my $Q="$GCCP -DOBJDEP$DIAG -M -MG -E 2>&1 @DSQ"; +my $R=backtick($Q); + +if ($R!~/#\s*warning\s/) { + # config2.h:314:4: warning: #warning REQUIRES: c_lgcc3.o + # Dat: g++-3.3 and g++-4.8 omit #warning (implicit -w) with -M -MG -E. + # clang++-3.4 still emits warnings, so no need to rerun here. + $R.="\n".backtick("$GCCP -DOBJDEP$DIAG -E 2>&1 >/dev/null @DSQ"); +} + +$R =~ s@\\\n@@g; # Merge line continuations emitted by `gcc -M -MG'. + +#** $idep{"x.ds"} contains the .h and .ds dependency line for x.ds +my %idep; +#** $odep{"x.o"} is "x.ds" +my %odep; +my $included_from; + +my @instructions; + +while ($R=~/\G(.*)\n?/g) { + my $S=$1; + + if ($S=~/\AIn file included from (?:[.]\/)*([^:]+)/) { + # If foo.cpp includes foo.hpp, which includes bar.hpp, then + # clang++-3.4 emits these in a row: foo.cpp, ./foo.hpp, and no bar.hpp. + # We want to keep only foo.cpp, hence we check + # `if !defined($included_from)'. + $included_from=$1 if !defined($included_from); + # Bottommost includer. + } elsif ($S=~/\A\s{3,}from (?:[.]\/)*([^:]+)/) { # From gcc-3.2. + $included_from=$1; # Higher includer, we override the previous one, because we need the topmost one. + } elsif ($S=~/\A(?:[.]\/)*([^:]+):\d+:(\d+:)? warning: (?:#warning )?([A-Z][-A-Z]{2,}):(.*)\Z/) { + # ^^^ (\d+:)? added for gcc-3.1 + # ^^^ clang: appliers.cpp:554:6: warning: REQUIRES: out_gif.o [-W#warnings] + my($DS,$B,$features)=($1, $3, $4); # $B is e.g. 'PROVIDES'. + if (defined $included_from) { $DS=$included_from; undef $included_from } + die "$0: #include detection broken: expected non-header source file, got $DS in line: $S\n" if + not is_ds($DS); + die "$0: unknown dependency verb $B in line: $S\n" if + $B !~ m@\A(NULL-PROVIDES|PROVIDES|CONFLICTS|REQUIRES)\Z(?!\n)@; + for my $feature (split ' ',$features) { + if ($feature !~ m@\A\[-W@) { # g++-4.8 generates extra [-Wcpp] lines. + #print "INSTR $DS $B $feature\n"; + push @instructions, [$DS, $B, $feature]; + } + } + } elsif ($S=~/\A([^: ]+)\.o:( ([^: ]+?)\.([^ \n]+).*)\Z/s and $1 eq $3) { + # Dependency output of `gcc -M -MG'. + + # $O: The .o file. + # $B: All the source dependencies (.cpp, .cxx, .cc, .C, .c, .ci etc.). + # $DS: The .ds file: the source file corresponding to the .o file, e.g. + # $O is 'encoder.o', $DS is 'encoder.cpp'. + my($O,$B,$DS)=("$1.o",$2,"$3.$4"); + # ^^^ Dat: maybe both t.c and t.cxx + $B =~ s@ /[^ ]+@@g; # remove absolute pathnames + $B =~ s@\s+@ @g; $B =~ s@\A\s*@ @; $B =~ s@\s*\Z(?!\n)@ @; + die "$0: .o file in sources for $DS: $B" if $B =~ m@ [.]o @; + # Example reason: foo.c and foo.cpp both present as source files. + die "$0: .o file generated from multiple sources: $O and $odep{$O}" if + exists $odep{$O}; + die if exists $idep{$DS}; # Shouldn't happen, $odep{$O} would exist first. + $odep{$O}=$DS; + $idep{$DS}=$B; + push @instructions, [$DS, 'PROVIDES', $O]; + undef $included_from; + } elsif ($S=~/: (?:warning|error|fatal error|fatal):/) { + undef $included_from; + } else { + # Be resilient, and just ignore every other possible message here. This is + # for future compatibility with compilers. The infamous `invalid depret' + # error by ccdep.pl used to be here, but now it's gone. + } +} +undef $included_from; # Save memory. +%odep=(); # Save memory. + +#** $pro{"x.ds"} is the list of features provided by "x.ds"; multiplicity +my %pro; +#** $req{"x.ds"} is the list of features required by "x.ds"; multiplicity +my %req; +#** $con{"x.ds"} is the list of features conflicted by "x.ds"; multiplicity +my %con; +#** $repro{"feature"} is a hash=>1 of .ds that provide "feature" +my %repro; +#** $mapro{"executable"} eq "x.ds" if "x.ds" provides main() for "executable". +#** It looks like values are never used. +my %mapro; +#** hash=>1 of "feature"s of NULL-PROVIDES +my %nullpro; +for my $instruction (@instructions) { + my($DS, $verb, $feature) = @$instruction; + if ($verb eq 'NULL-PROVIDES') { + $nullpro{$feature} = 1; + } elsif ($verb eq 'PROVIDES') { + push @{$pro{$DS}}, $feature; + push @{$con{$DS}}, $feature; + $repro{$feature}{$DS}=1; + if ($feature=~/\A(.*)_main\Z/) { $mapro{$1}=$DS } + } elsif ($verb eq 'REQUIRES') { + push @{$req{$DS}}, $feature; + } elsif ($verb eq 'CONFLICTS') { + push @{$con{$DS}}, $feature; + } else { + die "$0: unknown verb in instruction: @$instruction\n"; # Never happens. + } +} +@instructions=(); # Save memory. + +mustbe_subset_of "providers"=>[sort keys(%pro)], "dep_sources"=>[sort keys(%idep)]; +mustbe_subset_of "dep_sources"=>[sort keys(%idep)], "sources"=>\@DS; + +{ my @K=keys %repro; + for my $DS (sort keys%con) { + my $L = $con{$DS}; + my @R=(); + for my $feature (@$L) { expand_glob $feature, \@K, \@R } + # ^^^ multiplicity remains + $con{$DS}=\@R; + } +} + +my $outfn = "Makedep"; +die unless open MD, "> $outfn"; +die unless print MD ' +ifndef CCALL +CCALL=$(CC) $(CFLAGS) $(CFLAGSB) $(CPPFLAGS) $(INCLUDES) +endif +ifndef CXXALL +CXXALL=$(CXX) $(CXXFLAGS) $(CXXFLAGSB) $(CPPFLAGS) $(INCLUDES) +endif +ifndef LDALL +LDALL=$(LDY) $(LDFLAGS) $(LIBS) +endif +ifndef CC +CC=gcc +endif +ifndef CXX +CXX=g++ +endif +ifndef LD +LD=$(CC) -s +endif +ifndef LDXX +LDXX=$(CXX) -s +endif +ifndef LDY +LDY=$(LD) +endif +ifndef CFLAGS +CFLAGS=-O2 -W -Wall -fsigned-char +endif +ifndef CXXFLAGS +CXXFLAGS=-O2 -W -Wall -fsigned-char +endif +ifndef GLOBFILES +GLOBFILES=Makefile $outfn +endif +'; + +die unless print MD "ALL +=", join(' ',sort keys%mapro), "\n"; +die unless print MD "TARGETS =", join(' ',sort keys%mapro), "\n"; + +# vvv Thu Oct 31 09:49:02 CET 2002 +# (not required) +#my %targets_fal; +#for my $FA (@FAL) { $targets_fal{$FA}="TARGETS_$FA =" } + +for my $EXE (sort keys%mapro) { + print "exe $EXE\n"; + my @REQO = (); # Will be list of .o files required by $EXE. + my @REQDS = (); # Will be list of .ds files required $EXE. + my @REQH = (); # Will be list of .h files required $EXE. + + # Find the transitive dependencies of $EXE, save to @REQO, @REQDS, @REQH. + { + my %CON=(); # hash=>1 of features already conflicted + my %PRO=%nullpro; # hash=>1 of features already provided + my $feature; + my @features_to_analyze=("${EXE}_main"); + while (defined($feature=pop@features_to_analyze)) { + next if exists $PRO{$feature}; + #print "feat $feature (@features_to_analyze)\n"; ## + # vvv Dat: r.b.e == required by executable + die "$0: feature $feature r.b.e $EXE conflicts\n" if exists $CON{$feature}; + my @L=sort keys%{$repro{$feature}}; + die "$0: feature $feature r.b.e $EXE unprovided\n" if!@L; + die "$0: feature $feature r.b.e $EXE overprovided: @L\n" if$#L>=1; + # Now: $L[0] is a .ds providing the feature + push @REQDS, $L[0]; + my $O=$L[0]; $O=~s@\.[^.]+\Z@.o@; + push @REQO, $O; + + $PRO{$feature}=1; + for my $feature2 (@{$pro{$L[0]}}) { + die "$0: extra feature $feature2 r.b.e $EXE conflicts\n" if exists $CON{$feature2} and not exists $PRO{$feature2}; + $PRO{$feature2}=1; + } + for my $feature2 (@{$req{$L[0]}}) { + push @features_to_analyze, $feature2 if!exists $PRO{$feature2} + } + for my $feature2 (@{$con{$L[0]}}) { $CON{$feature2}=1 } + # die if! exists $PRO{$feature}; # assert + } + my %REQH; + for my $DS (@REQDS) { + for my $HDS (split' ', $idep{$DS}) { + $REQH{$HDS} = 1 if !is_ds($HDS); + } + } + push @REQH, sort keys %REQH; + } + + die unless print MD "${EXE}_DS=@REQDS\n${EXE}_H=@REQH\n". + "$EXE: \$(GLOBFILES) @REQO\n\t\$(LDALL) @REQO -o $EXE\n\t". + q!@echo "Created executable file: !.$EXE. + q! (size: `perl -e 'print -s "!.$EXE.q!"'`)."!. "\n"; + # vvv Sat Jun 1 15:40:19 CEST 2002 + for my $FA (@FAL) { + die unless print MD + "$EXE.$FA: \$(GLOBFILES) \$(${EXE}_DS) \$(${EXE}_H)\n\t". + "\$(CXD_$FA) \$(CXDFAL) \$(${EXE}_DS) -o $EXE.$FA\n"; + # $targets_fal{$FA}.=" $EXE.$FA"; + } +} +print MD "\n"; + +# vvv Thu Oct 31 09:49:02 CET 2002 +# (not required) +# for my $FA (@FAL) { print MD "$targets_fal{$FA}\n" } +# print MD "\n"; + +for my $K (sort keys%idep) { + my $V = $idep{$K}; + my $O=$K; $O=~s@\.([^.]+)\Z@.o@; my $srcext = $1; + my @V = sort split' ', $V; + my $compiler = $srcext eq'c'?"CC":"CXX"; + print MD "$O: \$(GLOBFILES) @V\n\t\$(${compiler}ALL) -c $K\n" +} +print MD "\n"; + +die unless close MD; + +print "$0: done, created $outfn\n"; + +__END__ |