Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
6.1 KiB

  1. ###############################################################
  2. #
  3. # generateDEF.pl
  4. #
  5. # Parses a .map file and generates a .def file
  6. # for exporting functions from a dll.
  7. #
  8. # Note: Map Exports must be enabled in the project properties
  9. #
  10. ###############################################################
  11. my @baselist;
  12. my @output;
  13. my $baseLen = 63;
  14. ######################################
  15. # Adds tabs for better formatting
  16. sub Add_Tabs
  17. {
  18. my $name = shift;
  19. my $num = int( ($baseLen - length( $name )) / 8 );
  20. for( $i = 0; $i < $num; $i++ )
  21. {
  22. push( @output, "\t" );
  23. }
  24. }
  25. ######################################
  26. # Open, validate, and read a file (not implemented yet)
  27. sub Read_File
  28. {
  29. my $name = shift;
  30. my @file = shift;
  31. # read in the file
  32. if ( open(INFILE, "$name" ) )
  33. {
  34. @file = <INFILE>;
  35. close( INFILE );
  36. }
  37. else
  38. {
  39. print( "Error opening file $name\n" );
  40. exit 1;
  41. }
  42. }
  43. #####################################
  44. # Start of script
  45. print( "Valve Software - make360def.pl\n" );
  46. print( "Copyright (c) 1996-2006, Valve LLC, All rights reserved.\n" );
  47. my $filename = $ARGV[0];
  48. my $numArgs = 1;
  49. my @lines = ();
  50. my @deflines = ();
  51. if ( $ARGV[0] =~ /-check$/i )
  52. {
  53. $numArgs = 3;
  54. $check = 1;
  55. $filename = $ARGV[1];
  56. $defname = $ARGV[2];
  57. }
  58. elsif ( $ARGV[0] =~ /-checkauto/i )
  59. {
  60. $defname = $ARGV[1];
  61. $check = 2;
  62. }
  63. if ( @ARGV < $numArgs )
  64. {
  65. print( "ERROR: Missing filename(s)\n" );
  66. exit 1;
  67. }
  68. if ( $check == 1 )
  69. {
  70. # swap filenames if necessary
  71. if ( $filename =~ /.def/ )
  72. {
  73. my $temp = $filename;
  74. $filename = $defname;
  75. $defname = $temp;
  76. }
  77. # validate extensions
  78. unless ( $filename =~ /.map/ && $defname =~ /.def/ )
  79. {
  80. print( "ERROR: Invalid file extensions. -check requires a .map file and a .def file.\n" );
  81. exit 1;
  82. }
  83. # read in the def file
  84. if ( open(INFILE, "$defname" ) )
  85. {
  86. @deflines = <INFILE>;
  87. close( INFILE );
  88. }
  89. else
  90. {
  91. print( "ERROR: Couldn't open file $defname.\n" );
  92. exit 1;
  93. }
  94. }
  95. elsif ( $check == 2 )
  96. {
  97. # read in the def file
  98. if ( open(INFILE, "$defname" ) )
  99. {
  100. @deflines = <INFILE>;
  101. close( INFILE );
  102. }
  103. else
  104. {
  105. print( "ERROR: Couldn't open file $defname.\n" );
  106. exit 1;
  107. }
  108. # validate that the first export is CreateInterface*
  109. # validate that the export ordinals are sequential and ordered
  110. my $line;
  111. my $start = false;
  112. my $idx = 1;
  113. for ( @deflines )
  114. {
  115. $line = $_;
  116. if ( $line =~ /@(\d+)[ |\n]/ )
  117. {
  118. if ( $1 == 1 )
  119. {
  120. unless ( $line =~ /CreateInterface/ )
  121. {
  122. # first export must be CreateInterface*
  123. $line =~ /\s+([\S]*)/;
  124. print( "**************************************************\n" );
  125. print( " ERROR: First export must be CreateInterface*. \n" );
  126. print( " Export \"", $1, "\" found instead! \n" );
  127. print( " This is a FATAL ERROR with the def file. \n" );
  128. print( " Please contact an Xbox 360 engineer immediately.\n" );
  129. print( "**************************************************\n" );
  130. exit 1;
  131. }
  132. }
  133. if ( $1 != $idx )
  134. {
  135. # exports are out of order
  136. print( "**************************************************\n" );
  137. print( " ERROR: Def file exports are not sequential \n" );
  138. print( " This may cause unexpected behavior at runtime. \n" );
  139. print( " Please contact an Xbox 360 engineer immediately.\n" );
  140. print( "**************************************************\n" );
  141. exit 1;
  142. }
  143. ++$idx;
  144. }
  145. }
  146. exit 0;
  147. }
  148. # Get the base name
  149. $filename =~ /(\w+(\.360)?).map/;
  150. my $basename = $1;
  151. # Read in the source file
  152. if ( open(INFILE, "$filename" ) )
  153. {
  154. @lines = <INFILE>;
  155. close( INFILE );
  156. }
  157. else
  158. {
  159. print( "ERROR: Couldn't open file $filename.\n" );
  160. exit 1;
  161. }
  162. # Delete the lines up to the exports section
  163. my $len = 0;
  164. my $exportsFound = 0;
  165. for( @lines )
  166. {
  167. $len++;
  168. if( /^ Exports$/ )
  169. {
  170. splice( @lines, 0, $len+3 );
  171. $exportsFound = 1;
  172. }
  173. }
  174. if ( $exportsFound == 0 )
  175. {
  176. print( "ERROR: No Exports section found in $filename. " );
  177. print( "Relink the project with 'Map Exports' enabled.\n" );
  178. exit 1;
  179. }
  180. if ( $check == 1 )
  181. {
  182. # Check for exports in the map that aren't in the def
  183. print( "make360def: Comparing $filename and $defname\n" );
  184. # strip the first 2 lines from the def
  185. splice( @deflines, 0, 2 );
  186. my $defEntryCt = $#deflines + 1;
  187. my $defMatches = 0;
  188. # for each line in the map
  189. for( @lines )
  190. {
  191. my $found = 0;
  192. # Pull the export name from the map line
  193. my $mapline;
  194. if ( /(\d+)\s+(\S+)/ )
  195. {
  196. $mapline = $2;
  197. }
  198. else
  199. {
  200. # ignore this line
  201. next;
  202. }
  203. # for each line in the def
  204. for( @deflines )
  205. {
  206. /(\S+)/;
  207. if ( $1 =~ /^\Q$mapline\E$/ )
  208. {
  209. $found = 1;
  210. $defMatches++;
  211. last;
  212. }
  213. }
  214. if ( $found == 0 )
  215. {
  216. print( "ERROR: New export found in $filename, " );
  217. print( "so the map file and def file are out of sync. " );
  218. print( "You must relink the project to generate a new def file.\n" );
  219. exit 1;
  220. }
  221. }
  222. # Make sure all the def lines were matched
  223. if ( $defMatches != $defEntryCt )
  224. {
  225. print( "ERROR: An export was removed from $filename, " );
  226. print( "so the map file and def file are out of sync. " );
  227. print( "You must relink the project to generate a new def file.\n" );
  228. exit 1;
  229. }
  230. print( "make360def: Comparison complete, files match.\n" );
  231. exit 0;
  232. }
  233. # start the def file
  234. print( "make360def: Generating $basename.def\n" );
  235. push( @output, "LIBRARY\t$basename.dll\n" );
  236. push( @output, "EXPORTS\n" );
  237. # process each line in the export section
  238. my $interfacePrefix = "0000000000";
  239. for( @lines )
  240. {
  241. if ( /(\d+)\s+(\S+)/ )
  242. {
  243. my $func = $2;
  244. if ( $func =~ /CreateInterface/ )
  245. {
  246. # Force createInterface to sort first
  247. $func = join( '', $interfacePrefix, $func );
  248. }
  249. push( @baselist, $func );
  250. }
  251. }
  252. # sort the list
  253. my @sortedlist = sort {uc($a) cmp uc($b)} @baselist;
  254. #my @sortedlist = @baselist;
  255. my $ordinal = 1;
  256. for( @sortedlist )
  257. {
  258. my $func = $_;
  259. if ( /$interfacePrefix(.*)/ )
  260. {
  261. # Strip the added characters
  262. $func = $1;
  263. }
  264. push( @output, "\t$func\t" );
  265. Add_Tabs( $func );
  266. push( @output, "\@$ordinal\n" );
  267. $ordinal++;
  268. }
  269. # write the def file
  270. print( "make360def: Saving $basename.def.\n" );
  271. open ( OUTFILE, ">$basename.def" );
  272. print OUTFILE @output;
  273. close ( OUTFILE );
  274. print( "make360def: Finished.\n" );
  275. exit 0;