mkdep.pl 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #!/usr/bin/perl
  2. ## --------------------------------------------------------------------------
  3. ##
  4. ## Copyright 1996-2017 The NASM Authors - All Rights Reserved
  5. ## See the file AUTHORS included with the NASM distribution for
  6. ## the specific copyright holders.
  7. ##
  8. ## Redistribution and use in source and binary forms, with or without
  9. ## modification, are permitted provided that the following
  10. ## conditions are met:
  11. ##
  12. ## * Redistributions of source code must retain the above copyright
  13. ## notice, this list of conditions and the following disclaimer.
  14. ## * Redistributions in binary form must reproduce the above
  15. ## copyright notice, this list of conditions and the following
  16. ## disclaimer in the documentation and/or other materials provided
  17. ## with the distribution.
  18. ##
  19. ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  20. ## CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  21. ## INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  22. ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  23. ## DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24. ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  26. ## NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. ## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29. ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  30. ## OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  31. ## EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. ##
  33. ## --------------------------------------------------------------------------
  34. #
  35. # Script to create Makefile-style dependencies.
  36. #
  37. # Usage:
  38. # perl mkdep.pl [-s path-separator][-o obj-ext] dir... > deps
  39. # perl mkdep.pl [-i][-e][-m makefile]...[-M makefile... --] dir...
  40. #
  41. use File::Spec;
  42. use File::Basename;
  43. use File::Copy;
  44. use File::Temp;
  45. use Fcntl;
  46. $barrier = "#-- Everything below is generated by mkdep.pl - do not edit --#\n";
  47. # This converts from filenames to full pathnames for our dependencies
  48. %dep_path = {};
  49. # List of files that cannot be found; these *must* be excluded
  50. @must_exclude = ();
  51. #
  52. # Scan files for dependencies
  53. #
  54. sub scandeps($) {
  55. my($file) = @_;
  56. my $line;
  57. my %xdeps;
  58. my %mdeps;
  59. open(my $fh, '<', $file)
  60. or return; # If not openable, assume generated
  61. while ( defined($line = <$fh>) ) {
  62. chomp $line;
  63. $line =~ s:/\*.*\*/::g;
  64. $line =~ s://.*$::;
  65. if ( $line =~ /^\s*\#\s*include\s+\"(.*)\"\s*$/ ) {
  66. my $nf = $1;
  67. if (!defined($dep_path{$nf})) {
  68. push(@must_exclude, $nf);
  69. next;
  70. }
  71. $nf = $dep_path{$nf};
  72. $mdeps{$nf}++;
  73. $xdeps{$nf}++ unless ( defined($deps{$nf}) );
  74. }
  75. }
  76. close($fh);
  77. $deps{$file} = [keys(%mdeps)];
  78. foreach my $xf ( keys(%xdeps) ) {
  79. scandeps($xf);
  80. }
  81. }
  82. # %deps contains direct dependencies. This subroutine resolves
  83. # indirect dependencies that result.
  84. sub alldeps($$) {
  85. my($file, $level) = @_;
  86. my %adeps;
  87. foreach my $dep ( @{$deps{$file}} ) {
  88. $adeps{$dep} = 1;
  89. foreach my $idep ( alldeps($dep, $level+1) ) {
  90. $adeps{$idep} = 1;
  91. }
  92. }
  93. return sort(keys(%adeps));
  94. }
  95. # This converts a filename from host syntax to target syntax
  96. # This almost certainly works only on relative filenames...
  97. sub convert_file($$) {
  98. my($file,$sep) = @_;
  99. my @fspec = (basename($file));
  100. while ( ($file = dirname($file)) ne File::Spec->curdir() &&
  101. $file ne File::Spec->rootdir() ) {
  102. unshift(@fspec, basename($file));
  103. }
  104. if ( $sep eq '' ) {
  105. # This means kill path completely. Used with Makes who do
  106. # path searches, but doesn't handle output files in subdirectories,
  107. # like OpenWatcom WMAKE.
  108. return $fspec[scalar(@fspec)-1];
  109. } else {
  110. return join($sep, @fspec);
  111. }
  112. }
  113. #
  114. # Insert dependencies into a Makefile
  115. #
  116. sub _insert_deps($$) {
  117. my($file, $out) = @_;
  118. open(my $in, '<', $file)
  119. or die "$0: Cannot open input: $file\n";
  120. my $line, $parm, $val;
  121. my $obj = '.o'; # Defaults
  122. my $sep = '/';
  123. my $cont = "\\";
  124. my $include_command = undef;
  125. my $selfrule = 0;
  126. my $do_external = 0;
  127. my $maxline = 78; # Seems like a reasonable default
  128. my %exclude = (); # Don't exclude anything
  129. my @genhdrs = ();
  130. my $external = undef;
  131. my $raw_output = 0;
  132. my @outfile = ();
  133. my $done = 0;
  134. while ( defined($line = <$in>) && !$done ) {
  135. if ( $line =~ /^([^\s\#\$\:]+\.h):/ ) {
  136. # Note: we trust the first Makefile given best
  137. my $fpath = $1;
  138. my $fbase = basename($fpath);
  139. if (!defined($dep_path{$fbase})) {
  140. $dep_path{$fbase} = $fpath;
  141. print STDERR "Makefile: $fbase -> $fpath\n";
  142. }
  143. } elsif ( $line =~ /^\s*\#\s*@([a-z0-9-]+):\s*\"([^\"]*)\"/ ) {
  144. $parm = $1; $val = $2;
  145. if ( $parm eq 'object-ending' ) {
  146. $obj = $val;
  147. } elsif ( $parm eq 'path-separator' ) {
  148. $sep = $val;
  149. } elsif ( $parm eq 'line-width' ) {
  150. $maxline = $val+0;
  151. } elsif ( $parm eq 'continuation' ) {
  152. $cont = $val;
  153. } elsif ( $parm eq 'exclude' ) {
  154. $excludes{$val}++;
  155. } elsif ( $parm eq 'include-command' ) {
  156. $include_command = $val;
  157. } elsif ( $parm eq 'external' ) {
  158. # Keep dependencies in an external file
  159. $external = $val;
  160. } elsif ( $parm eq 'selfrule' ) {
  161. $selfrule = !!$val;
  162. }
  163. } elsif ( $line =~ /^(\s*\#?\s*EXTERNAL_DEPENDENCIES\s*=\s*)([01])\s*$/ ) {
  164. $is_external = $externalize ? 1 : $force_inline ? 0 : $2+0;
  165. $line = $1.$is_external."\n";
  166. } elsif ( $line eq $barrier ) {
  167. $done = 1; # Stop reading input at barrier line
  168. }
  169. push @outfile, $line;
  170. }
  171. close($in);
  172. $is_external = $is_external && defined($external);
  173. if ( !$is_external || $externalize ) {
  174. print $out @outfile;
  175. } else {
  176. print $out $barrier; # Start generated file with barrier
  177. }
  178. if ( $externalize ) {
  179. if ( $is_external && defined($include_command) ) {
  180. print $out "$include_command $external\n";
  181. }
  182. return undef;
  183. }
  184. my $e;
  185. foreach my $dfile ($external, sort(keys(%deps)) ) {
  186. my $ofile;
  187. my @deps;
  188. if ( $selfrule && $dfile eq $external ) {
  189. $ofile = convert_file($dfile, $sep).':';
  190. @deps = sort(keys(%deps));
  191. } elsif ( $dfile =~ /^(.*)\.[Cc]$/ ) {
  192. $ofile = convert_file($1, $sep).$obj.':';
  193. @deps = ($dfile,alldeps($dfile,1));
  194. }
  195. if (defined($ofile)) {
  196. my $len = length($ofile);
  197. print $out $ofile;
  198. foreach my $dep (@deps) {
  199. unless ($excludes{$dep}) {
  200. my $str = convert_file($dep, $sep);
  201. my $sl = length($str)+1;
  202. if ( $len+$sl > $maxline-2 ) {
  203. print $out ' ', $cont, "\n ", $str;
  204. $len = $sl;
  205. } else {
  206. print $out ' ', $str;
  207. $len += $sl;
  208. }
  209. }
  210. }
  211. print $out "\n";
  212. }
  213. }
  214. return $external;
  215. }
  216. sub insert_deps($)
  217. {
  218. my($mkfile) = @_;
  219. my $tmp = File::Temp->new(DIR => dirname($mkfile));
  220. my $tmpname = $tmp->filename;
  221. my $newname = _insert_deps($mkfile, $tmp);
  222. close($tmp);
  223. $newname = $mkfile unless(defined($newname));
  224. move($tmpname, $newname);
  225. }
  226. #
  227. # Main program
  228. #
  229. my %deps = ();
  230. my @files = ();
  231. my @mkfiles = ();
  232. my $mkmode = 0;
  233. $force_inline = 0;
  234. $externalize = 0;
  235. $debug = 0;
  236. while ( defined(my $arg = shift(@ARGV)) ) {
  237. if ( $arg eq '-m' ) {
  238. $arg = shift(@ARGV);
  239. push(@mkfiles, $arg);
  240. } elsif ( $arg eq '-i' ) {
  241. $force_inline = 1;
  242. } elsif ( $arg eq '-e' ) {
  243. $externalize = 1;
  244. } elsif ( $arg eq '-d' ) {
  245. $debug++;
  246. } elsif ( $arg eq '-M' ) {
  247. $mkmode = 1; # Futher filenames are output Makefile names
  248. } elsif ( $arg eq '--' && $mkmode ) {
  249. $mkmode = 0;
  250. } elsif ( $arg =~ /^-/ ) {
  251. die "Unknown option: $arg\n";
  252. } else {
  253. if ( $mkmode ) {
  254. push(@mkfiles, $arg);
  255. } else {
  256. push(@files, $arg);
  257. }
  258. }
  259. }
  260. my @cfiles = ();
  261. foreach my $dir ( @files ) {
  262. opendir(DIR, $dir) or die "$0: Cannot open directory: $dir";
  263. while ( my $file = readdir(DIR) ) {
  264. $path = ($dir eq File::Spec->curdir())
  265. ? $file : File::Spec->catfile($dir,$file);
  266. if ( $file =~ /\.[Cc]$/ ) {
  267. push(@cfiles, $path);
  268. } elsif ( $file =~ /\.[Hh]$/ ) {
  269. print STDERR "Filesystem: $file -> $path\n" if ( $debug );
  270. $dep_path{$file} = $path; # Allow the blank filename
  271. $dep_path{$path} = $path; # Also allow the full pathname
  272. }
  273. }
  274. closedir(DIR);
  275. }
  276. foreach my $cfile ( @cfiles ) {
  277. scandeps($cfile);
  278. }
  279. foreach my $mkfile ( @mkfiles ) {
  280. insert_deps($mkfile);
  281. }