Counter Strike : Global Offensive Source Code
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.

676 lines
14 KiB

  1. #!perl
  2. use IO::File;
  3. use File::Basename;
  4. use File::Find;
  5. use Cwd;
  6. use Cwd 'abs_path';
  7. $nprocs=`grep vendor_id /proc/cpuinfo | wc -l `;
  8. $nprocs=~s/[\n\r]//g;
  9. print "$nprocs processors found\n";
  10. #find where to include master make file from
  11. $srcdir=getcwd;
  12. die "can't determine path to src"
  13. unless ($srcdir=~s@/src.*$@/src@);
  14. find( { wanted=> \&handle_vpc_file } ,"$srcdir"); # search through all directories for .vpc files
  15. @MAINTARGETS=("all", "clean", "objs");
  16. @TARGETS=("all", "clean", "objs", "tags");
  17. # now, write a master makefile in each dir, and a master-master makefile in ~/src
  18. foreach $dir ( keys %dir_written )
  19. {
  20. open( MAKEOUT,">$dir/Makefile" ) || die "can't write $dir/Makefile";
  21. foreach $target ( @TARGETS )
  22. {
  23. print MAKEOUT ".PHONY: $target\n\n";
  24. print MAKEOUT "$target:\n";
  25. foreach $_ (split(/,/,$dir_written{$dir}) )
  26. {
  27. print MAKEOUT "\tmake -j $nprocs -f $_ $target\n" if length($_);
  28. }
  29. }
  30. close MAKEOUT;
  31. }
  32. # now, write a master makefile in ~/src
  33. open( MAKEOUT,">$srcdir/Makefile" ) || die "can't write master makefile to $srcdir";
  34. foreach $target ( @MAINTARGETS )
  35. {
  36. print MAKEOUT ".PHONY: $target\n\n";
  37. print MAKEOUT "$target:\n";
  38. foreach $dir ( keys %dir_written )
  39. {
  40. if ($target ne "clean" )
  41. {
  42. print MAKEOUT "\tmake -j $nprocs -C $dir $target\n";
  43. }
  44. else
  45. {
  46. print MAKEOUT "\tmake -C $dir $target\n";
  47. }
  48. }
  49. }
  50. print MAKEOUT "\n\nmakefiles:\n\tperl $srcdir/devtools/bin/vpc2linuxmake.pl\n";
  51. print MAKEOUT "\ntags:\n\tctags --languages=c++ -eR\n";
  52. close MAKEOUT;
  53. sub handle_vpc_file
  54. {
  55. # called for each file in the callers dir tree
  56. my $dir=$File::Find::dir;
  57. return if ( $dir=~/vpc_scripts/i );
  58. if ( /_base\.vpc$/i )
  59. {
  60. unless ( /hk_base\.vpc$/i )
  61. {
  62. return;
  63. }
  64. }
  65. return if (/_inc\.vpc/i);
  66. if (/\.vpc$/)
  67. {
  68. (%ignore_file,@DEFINES, @CPPFILES, @CXXFILES,@CFILES, @LITERAL_LIBFILES,@LIBFILES, %define_seen,%macros,%include_seen,@INCLUDEDIRS)=undef;
  69. undef $buildforlinux;
  70. undef $conf_type;
  71. undef $gccflags;
  72. $OptimizeLevel=3;
  73. # some defines to ignore in vpc files when generating linux include files
  74. $define_seen{'WIN32'}=1;
  75. $define_seen{'_WIN32'}=1;
  76. $define_seen{'_WINDOWS'}=1;
  77. $define_seen{'_USRDLL'}=1;
  78. $define_seen{'DEBUG'}=1;
  79. $define_seen{'_DEBUG'}=1;
  80. $define_seen{'NDEBUG'}=1;
  81. $define_seen{'_CRT_SECURE_NO_DEPRECATE'}=1;
  82. $define_seen{'_CRT_NONSTDC_NO_DEPRECATE'}=1;
  83. $define_seen{'fopen'}=1;
  84. # print STDERR "parsing project $pname\n";
  85. &ParseVPC($_);
  86. $pname=lc($pname);
  87. $pname=~s/\s+/_/g;
  88. $pname=~s/[\(\)]//g;
  89. # if anything seen, output a makefile
  90. if ( $buildforlinux && ( @CPPFILES || @CXXFILES || @CFILES || @LIBFILES ) )
  91. {
  92. print STDERR "writing project $pname\n";
  93. $projdir=getcwd;
  94. $projdir=~s@/$@@;
  95. $dir_written{$projdir}.=",$pname.mak";
  96. &WriteMakefile("$projdir/$pname.mak");
  97. &WriteCodeBlocksProj("$projdir/$pname.cbp");
  98. }
  99. else
  100. {
  101. die "no .lib or source files found in .vpc" if ( $buildforlinux );
  102. }
  103. }
  104. }
  105. sub WriteCodeBlocksProj
  106. {
  107. local($_)=@_;
  108. open(CBPROJ,">$_") || die "can't write $_";
  109. print CBPROJ <<HEADER
  110. <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
  111. <CodeBlocks_project_file>
  112. <FileVersion major="1" minor="6" />
  113. <Project>
  114. <Option title="$pname" />
  115. <Option pch_mode="2" />
  116. <Option compiler="gcc" />
  117. <Build>
  118. <Target title="Release">
  119. </Target>
  120. </Build>
  121. HEADER
  122. ;
  123. foreach $fl (@CPPFILES)
  124. {
  125. push @cppfiles2, $fl unless ( $ignore_file{$fl} > 0 );
  126. }
  127. foreach $fl (@CXXFILES)
  128. {
  129. push @cxxfiles2, $fl unless ( $ignore_file{$fl} > 0 );
  130. }
  131. printf CBPROJ "\t\t<Compiler>\n";
  132. foreach $_ (@DEFINES)
  133. {
  134. print CBPROJ "\t\t\t<Add option=\"-DSWDS\" />\n";
  135. print CBPROJ "\t\t\t<Add option=\"-D_LINUX\" />\n";
  136. print CBPROJ "\t\t\t<Add option=\"-fpermissive\" />\n";
  137. print CBPROJ "\t\t\t<Add option=\"-Dstricmp=strcasecmp\" />\n";
  138. print CBPROJ "\t\t\t<Add option=\"-D_stricmp=strcasecmp\" />\n";
  139. print CBPROJ "\t\t\t<Add option=\"-D_strnicmp=strncasecmp\" />\n";
  140. print CBPROJ "\t\t\t<Add option=\"-Dstrnicmp=strncasecmp\" />\n";
  141. print CBPROJ "\t\t\t<Add option=\"-D_snprintf=snprintf\" />\n";
  142. print CBPROJ "\t\t\t<Add option=\"-D_vsnprintf=vsnprintf\" />\n";
  143. print CBPROJ "\t\t\t<Add option=\"-D_alloca=alloca\" />\n";
  144. print CBPROJ "\t\t\t<Add option=\"-Dstrcmpi=strcasecmp\" />\n";
  145. print CBPROJ "\t\t\t<Add option=\"-D$_\" />\n";
  146. }
  147. foreach $_ (@INCLUDEDIRS)
  148. {
  149. print CBPROJ "\t\t\t<Add directory=\"$_\" />\n";
  150. }
  151. printf CBPROJ "\t\t</Compiler>\n";
  152. @CPPFILES = sort(@CPPFILES);
  153. @CXXFILES = sort(@CXXFILES);
  154. @CFILES = sort(@CFILES);
  155. # now, output obj dependencies
  156. foreach $_ (@CPPFILES, @CFILES, @CXXFILES)
  157. {
  158. unless (( $ignore_file{$_} > 0 ) || ( length($_) < 2 ) )
  159. {
  160. ($filename,$dir,$suffix) = fileparse($_,qr/\.[^.]*/);
  161. print CBPROJ "\t\t<Unit filename=\"".$dir . $filename. ".cpp\" />\n";
  162. }
  163. }
  164. print CBPROJ <<FOOTER
  165. <Extensions>
  166. <code_completion />
  167. </Extensions>
  168. </Project>
  169. </CodeBlocks_project_file>
  170. FOOTER
  171. ;
  172. close CBPROJ;
  173. }
  174. sub WriteMakefile
  175. {
  176. local($_)=@_;
  177. open(MAKEFILE,">$_") || die "can't write $_";
  178. print MAKEFILE "NAME=$pname\n\n";
  179. print MAKEFILE "SRCROOT=$srcdir\n";
  180. print MAKEFILE "PROJDIR=$projdir\n";
  181. print MAKEFILE "CONFTYPE=$conf_type\n";
  182. print MAKEFILE "PROJECT_SPECIFIC_GCCFLAGS = $gccflags\n";
  183. if ( int($OptimizeLevel) )
  184. {
  185. print MAKEFILE "OLEVEL=-O$OptimizeLevel\n";
  186. }
  187. else
  188. {
  189. print MAKEFILE "OLEVEL=\n";
  190. }
  191. if (@DEFINES)
  192. {
  193. print MAKEFILE "DEFINES= -D",join(" -D", @DEFINES),"\n";
  194. }
  195. if (@INCLUDEDIRS)
  196. {
  197. print MAKEFILE "INCLUDEDIRS= -I",join(" -I", @INCLUDEDIRS),"\n";
  198. }
  199. undef @cppfiles2;
  200. undef @cxxfiles2;
  201. foreach $fl (@CPPFILES)
  202. {
  203. if ( length($fl) )
  204. {
  205. print "warning file $fl does not exist\n" unless( -e $fl);
  206. push @cppfiles2, $fl unless ( $ignore_file{$fl} > 0 );
  207. }
  208. }
  209. foreach $fl (@CXXFILES)
  210. {
  211. push @cxxfiles2, $fl unless ( $ignore_file{$fl} > 0 );
  212. }
  213. if (@cppfiles2)
  214. {
  215. print MAKEFILE "CPPFILES= \\\n ", join(" \\\n ",@cppfiles2), "\n";
  216. }
  217. if (@cxxfiles2)
  218. {
  219. print MAKEFILE "CXXFILES= \\\n ", join(" \\\n ",@cxxfiles2), "\n";
  220. }
  221. if (@CFILES)
  222. {
  223. print MAKEFILE "CFILES= \\\n ", join(" \\\n ",@CFILES), "\n";
  224. }
  225. if (@LIBFILES)
  226. {
  227. undef @LIBNAMES;
  228. print MAKEFILE "\nLIBFILES= \\\n";
  229. unless( $pname=~/(tier0)|(mathlib)|(tier1)/i)
  230. {
  231. print MAKEFILE " $srcdir/lib/linux/tier1_486.a \\\n"
  232. }
  233. foreach $lib (@LIBFILES)
  234. {
  235. my @DLLNAMES=("tier0", "vstdlib", "steam_api");
  236. unless ( $ignore_file{$lib} > 0 )
  237. {
  238. $lib=lc($lib);
  239. my ($filename,$dir,$suffix) = fileparse($lib,qr/\.[^.]*/);
  240. my $dll=0;
  241. foreach $dllname (@DLLNAMES)
  242. {
  243. $dll=1 if ( $dllname eq $filename);
  244. }
  245. if ( $dll )
  246. {
  247. $lib=~s@^(.*)\.lib@$1_i486.so@i;
  248. $lib=~s@/lib/.*/([^/]+)@/linux/$1@g;
  249. }
  250. else
  251. {
  252. $lib=~s/\.lib/_486.a/i;
  253. $lib=~s@/lib/(\S+)/@/lib/linux/@g;
  254. }
  255. push @LIBNAMES, $lib;
  256. }
  257. }
  258. foreach $lib (@LITERAL_LIBFILES)
  259. {
  260. unless ( $ignore_file{$lib} > 0 )
  261. {
  262. $lib=~s/\\/\//g;
  263. $lib=~s@/linux/([a-zA-Z_0-9\.]+)$@/linux/$1@;
  264. $lib=~s@^.*/linux/([a-zA-Z_0-9]+)\.so$@$1.so@;
  265. push @LIBNAMES, $lib;
  266. }
  267. }
  268. # now, sort libs for link order
  269. foreach $lib ( sort bypriority @LIBNAMES )
  270. {
  271. print MAKEFILE " $lib \\\n";
  272. }
  273. print MAKEFILE "\n\n";
  274. }
  275. if ( $conf_type eq "dll" )
  276. {
  277. print MAKEFILE "OUTPUT_SO_FILE=$srcdir/linux/$pname","_i486.so\n\n";
  278. }
  279. elsif ( $conf_type eq "exe" )
  280. {
  281. if ( $macros{'OUTBINNAME'} eq "" )
  282. {
  283. die "Missing OUTBINNAME macro";
  284. }
  285. print MAKEFILE "OUTPUT_EXECUTABLE=$srcdir/linux/$macros{'OUTBINNAME'}\n\n";
  286. }
  287. print MAKEFILE "\n\n\# include base make file\ninclude $srcdir/devtools/makefile_base_linux.mak\n";
  288. # now, output obj dependencies
  289. foreach $_ (@CPPFILES, @CFILES)
  290. {
  291. unless (( $ignore_file{$_} > 0 ) || ( length($_) < 2 ) )
  292. {
  293. ($filename) = fileparse($_,qr/\.[^.]*/);
  294. print MAKEFILE getcwd,"/obj/$filename.o : $_\n\t\$(DO_CC)\n";
  295. }
  296. }
  297. foreach $_ (@CXXFILES)
  298. {
  299. unless (( $ignore_file{$_} > 0 ) || ( length($_) < 2 ) )
  300. {
  301. ($filename) = fileparse($_,qr/\.[^.]*/);
  302. print MAKEFILE getcwd,"/obj/$filename.oxx : $_\n\t\$(DO_CC)\n";
  303. }
  304. }
  305. close MAKEFILE;
  306. }
  307. sub bypriority
  308. {
  309. # sort libs for gcc linkgoodness
  310. $priority{"mathlib"}="0005";
  311. $priority{"tier1"}="0010";
  312. $priority{"tier2"}="0020";
  313. $priority{"tier3"}="0030";
  314. my ($filenamea) = fileparse($a,qr/\.[^.]*/);
  315. my ($filenameb) = fileparse($b,qr/\.[^.]*/);
  316. $filenamea =~ s/_.86.*$//; # lose _i486
  317. $filenameb =~ s/_.86.*$//;
  318. my $pa=$priority{$filenamea} || 1000;
  319. my $pb=$priority{$filenameb} || 1000;
  320. return $pb cmp $pa;
  321. }
  322. sub ParseVPC
  323. {
  324. local($fname)=@_;
  325. &startreading($fname);
  326. while(&nextvpcline)
  327. {
  328. # print "$_\n";
  329. if ( (/^\$linux/i) )
  330. {
  331. &skipblock(0,\&handlelinuxline);
  332. }
  333. if ( (/^\$configuration/i) )
  334. {
  335. &skipblock(0,\&handleconfigline);
  336. }
  337. elsif (/^\s*\$project/i)
  338. {
  339. &parseproject;
  340. }
  341. }
  342. }
  343. sub massageline
  344. {
  345. # strip leading and trailing spaces and carriage returns and comments from vpc lines
  346. s/[\n\r]//g;
  347. s@//.*$@@g;
  348. s@^\s*@@g;
  349. s@\s*$@@g;
  350. }
  351. sub submacros
  352. {
  353. # replace all macros within a line
  354. my $mac;
  355. foreach $mac (keys %macros)
  356. {
  357. s/\$$mac/$macros{$mac}/g;
  358. }
  359. }
  360. sub startreading
  361. {
  362. # initialize recursive file reader
  363. my( $fname)=@_;
  364. $curfile=IO::File->new($fname) || die "can't open $fname";
  365. }
  366. sub nextvpcline
  367. {
  368. # get the next line from the file, handling line continuations, macro substitution, and $include
  369. # return 0 if out of lines
  370. my $ret=0;
  371. if ( $_ = <$curfile> )
  372. {
  373. $ret=1;
  374. &massageline;
  375. while(s@\\$@ @)
  376. {
  377. my $old=$_;
  378. $_=<$curfile>;
  379. &massageline;
  380. $_=$old.$_;
  381. }
  382. s@\s+@ @g;
  383. my $old=$_;
  384. &submacros;
  385. # now, parse
  386. if (/\$macro (\S+) \"(\S+)\"$/i)
  387. {
  388. $macros{$1}=$2;
  389. return &nextvpcline;
  390. }
  391. s/\[\$WIN32\]//g;
  392. return &nextvpcline if (/\[\$X360\]/);
  393. if ( /^\s*[\$\#]include\s+\"(.*)\"/i)
  394. {
  395. # process $include
  396. my $incfile=$1;
  397. push @filestack, $curfile;
  398. $incfile=~s@\\@/@g;
  399. if ( $curfile=IO::File->new($incfile) )
  400. {
  401. return &nextvpcline;
  402. }
  403. else
  404. {
  405. print STDERR "can't open include file $incfile, ignoring\n";
  406. $curfile=pop(@filestack);
  407. return "";
  408. }
  409. }
  410. }
  411. else
  412. {
  413. $curfile->close;
  414. if (@filestack)
  415. {
  416. $curfile=pop(@filestack);
  417. return &nextvpcline;
  418. }
  419. else
  420. {
  421. return 0;
  422. }
  423. }
  424. return $ret;
  425. }
  426. sub skipblock
  427. {
  428. # skip a named block in the key values, handling nested {} pairs
  429. my($empty_ok, $callback)=@_;
  430. my $lnstat=&nextvpcline;
  431. die "parse error eof in block" if ( (! $lnstat) && ( ! $empty_ok) );
  432. my $nest=0;
  433. if (/^\{/)
  434. {
  435. $nest++;
  436. }
  437. else
  438. {
  439. die "no start block found, $_ found instead" unless($empty_ok);
  440. }
  441. while ($nest)
  442. {
  443. die "prematur eof" unless &nextvpcline;
  444. &$callback($_) if ( $callback );
  445. $nest++ if (/^\{/);
  446. $nest-- if (/^\}/);
  447. }
  448. }
  449. sub parseproject
  450. {
  451. # handle a project block, picking up files mentioned
  452. $pname="";
  453. if (/^\s*\$project\s*(.*)$/i)
  454. {
  455. $pname=$1;
  456. $pname=~s@\"@@g;
  457. }
  458. local($_);
  459. my $nest=0;
  460. &nextvpcline || die "empty project?";
  461. $nest++ if (/^\s*\{/);
  462. while($nest )
  463. {
  464. &nextvpcline || die "premature eof in project?";
  465. $nest++ if (/^\{/);
  466. $nest-- if (/^\}/);
  467. &CheckForFileLine($_);
  468. }
  469. }
  470. sub CheckForFileLine
  471. {
  472. local($_)=@_;
  473. if (/^\s*\-\$File\s+(.*$)/i)
  474. {
  475. foreach $_ (split(/ /,$1))
  476. {
  477. s/\"//g;
  478. $ignore_file{&process_path($_)} = 1;
  479. }
  480. }
  481. elsif (/^\s*\$File\s+(.*$)/i)
  482. {
  483. foreach $_ (split(/ /,$1))
  484. {
  485. s/\"//g;
  486. &handlefile($_);
  487. }
  488. }
  489. }
  490. sub handlefile
  491. {
  492. # given a project file (.cpp, etc), figure out what to do with it
  493. local($_)=@_;
  494. # hardcoded exclusions for linux
  495. return if (/dx9sdk/i);
  496. return if (/_360/i);
  497. return if (/xbox_console.cpp/i);
  498. return if (/xbox_system.cpp/i);
  499. return if (/xbox_win32stubs.cpp/i);
  500. return if (/binkw32/i || /binkxenon/i );
  501. if (/\.cpp$/)
  502. {
  503. push @CPPFILES,process_path($_);
  504. }
  505. if (/\.cxx$/)
  506. {
  507. push @CXXFILES,process_path($_);
  508. }
  509. elsif (/\.c$/)
  510. {
  511. push @CFILES,process_path($_);
  512. }
  513. elsif (/\.lib$/)
  514. {
  515. push @LIBFILES,process_path($_);
  516. }
  517. elsif (/\.a$/)
  518. {
  519. push @LITERAL_LIBFILES, process_path($_);
  520. }
  521. elsif (/\.so$/)
  522. {
  523. push @LITERAL_LIBFILES, process_path($_);
  524. }
  525. }
  526. sub process_path
  527. {
  528. local($_)=@_;
  529. s@\\@/@g;
  530. if ( (! -e $_) && ( -e lc($_)) )
  531. {
  532. # print STDERR "$_ does not exist try lc($_)\n";
  533. $_=lc($_);
  534. }
  535. my $ap=abs_path($_);
  536. if ( (! length($ap) ) && length($_))
  537. {
  538. # print "abs path of $_ is empty. bad dir?\n";
  539. }
  540. $_=$ap;
  541. s@i686@i486@g;
  542. if ( (! -e $_) && ( -e lc($_)) )
  543. {
  544. # print STDERR "$_ does not exist try lc($_)\n";
  545. $_=lc($_);
  546. }
  547. # kill ..s for prettyness
  548. s@/[^/]+/\.\./@/@g;
  549. if (! -e $_)
  550. {
  551. # print STDERR "$_ does not exist\n";
  552. }
  553. return $_;
  554. }
  555. sub handlelinuxline
  556. {
  557. local($_)=@_;
  558. $buildforlinux = 1 if ( /^\s*\$buildforlinux.*1/i);
  559. $OptimizeLevel= $1 if (/^\s*\$OptimizerLevel\s+(\d+)/i);
  560. $buildforlinux = 1 if ( /^\s*\$buildforlinux.*1/i);
  561. $gccflags = $1 if (/^\s*\$ProjectSpecificGCCFLags\s+\"(\S+)\"/i);
  562. &CheckForFileLine($_); # allows linux-specific file includes and excludes
  563. &handleconfigline($_); # allow linux-specific #defines
  564. }
  565. sub CheckPreprocessorDefs
  566. {
  567. local($_)=@_;
  568. if (/^\s*\$PreprocessorDefinitions\s+\"(.*)\"/i)
  569. {
  570. foreach $_ (split(/[;,]/,$1) )
  571. {
  572. unless( /\$/ || $define_seen{$_} || /fopen/i)
  573. {
  574. push(@DEFINES,$_);
  575. $define_seen{$_}=1;
  576. }
  577. }
  578. }
  579. }
  580. sub handleconfigline
  581. {
  582. # handle a line within a $Configuration block
  583. local($_)=@_; # the line
  584. if (/^\s*\$AdditionalIncludeDirectories\s+\"(.*)\"/i)
  585. {
  586. foreach $_ (split(/[;,]/,$1) )
  587. {
  588. unless( /\$/ || $include_seen{$_} )
  589. {
  590. push(@INCLUDEDIRS,process_path($_));
  591. $include_seen{$_}=1;
  592. }
  593. }
  594. }
  595. if (/^\s*\$ConfigurationType\s*\"(.*)\"/)
  596. {
  597. undef $conf_type;
  598. $conf_type="lib" if ($1 =~ /Static Library/i);
  599. $conf_type="dll" if ($1 =~ /Dynamic Library/i);
  600. $conf_type="exe" if ($1 =~ /Application/i);
  601. print STDERR " unknown conf type $1\n" if (! length($conf_type) );
  602. }
  603. &CheckPreprocessorDefs($_);
  604. }