1 /*
   2  * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 import java.io.File;
  26 import java.io.IOException;
  27 import java.io.PrintWriter;
  28 import java.util.Enumeration;
  29 import java.util.Hashtable;
  30 import java.util.Iterator;
  31 import java.util.List;
  32 import java.util.TreeSet;
  33 import java.util.Vector;
  34 
  35 abstract class HsArgHandler extends ArgHandler {
  36     static final int STRING = 1;
  37     static final int VECTOR = 2;
  38     static final int HASH   = 3;
  39 
  40     boolean nextNotKey(ArgIterator it) {
  41         if (it.next()) {
  42             String s = it.get();
  43             return (s.length() == 0) || (s.charAt(0) != '-');
  44         } else {
  45             return false;
  46         }
  47     }
  48 
  49     void empty(String key, String message) {
  50         if (key != null) {
  51             System.err.println("** Error: empty " + key);
  52         }
  53         if (message != null) {
  54             System.err.println(message);
  55         }
  56         WinGammaPlatform.usage();
  57     }
  58 
  59     static String getCfg(String val) {
  60         int under = val.indexOf('_');
  61         int len = val.length();
  62         if (under != -1 && under < len - 1) {
  63             return val.substring(under+1, len);
  64         } else {
  65             return null;
  66         }
  67     }
  68 }
  69 
  70 class ArgRuleSpecific extends ArgRule {
  71     ArgRuleSpecific(String arg, ArgHandler handler) {
  72         super(arg, handler);
  73     }
  74 
  75     boolean match(String rulePattern, String arg) {
  76         return rulePattern.startsWith(arg);
  77     }
  78 }
  79 
  80 
  81 class SpecificHsArgHandler extends HsArgHandler {
  82 
  83     String message, argKey, valKey;
  84     int type;
  85 
  86     public void handle(ArgIterator it) {
  87         String cfg = getCfg(it.get());
  88         if (nextNotKey(it)) {
  89             String val = it.get();
  90             switch (type) {
  91             case VECTOR:
  92                 BuildConfig.addFieldVector(cfg, valKey, val);
  93                 break;
  94             case HASH:
  95                 BuildConfig.putFieldHash(cfg, valKey, val, "1");
  96                 break;
  97             case STRING:
  98                 BuildConfig.putField(cfg, valKey, val);
  99                 break;
 100             default:
 101                 empty(valKey, "Unknown type: "+type);
 102             }
 103             it.next();
 104 
 105         } else {
 106             empty(argKey, message);
 107         }
 108     }
 109 
 110     SpecificHsArgHandler(String argKey, String valKey, String message, int type) {
 111         this.argKey = argKey;
 112         this.valKey = valKey;
 113         this.message = message;
 114         this.type = type;
 115     }
 116 }
 117 
 118 
 119 class HsArgRule extends ArgRuleSpecific {
 120 
 121     HsArgRule(String argKey, String valKey, String message, int type) {
 122         super(argKey, new SpecificHsArgHandler(argKey, valKey, message, type));
 123     }
 124 
 125 }
 126 
 127 public abstract class WinGammaPlatform {
 128 
 129     public boolean fileNameStringEquality(String s1, String s2) {
 130         return s1.equalsIgnoreCase(s2);
 131     }
 132 
 133     static void usage() throws IllegalArgumentException {
 134         System.err.println("WinGammaPlatform platform-specific options:");
 135         System.err.println("  -sourceBase <path to directory (workspace) " +
 136                            "containing source files; no trailing slash>");
 137         System.err.println("  -projectFileName <full pathname to which project file " +
 138                            "will be written; all parent directories must " +
 139                            "already exist>");
 140         System.err.println("  If any of the above are specified, "+
 141                            "they must all be.");
 142         System.err.println("  Additional, optional arguments, which can be " +
 143                            "specified multiple times:");
 144         System.err.println("    -absoluteInclude <string containing absolute " +
 145                            "path to include directory>");
 146         System.err.println("    -relativeInclude <string containing include " +
 147                            "directory relative to -sourceBase>");
 148         System.err.println("    -define <preprocessor flag to be #defined " +
 149                            "(note: doesn't yet support " +
 150                            "#define (flag) (value))>");
 151         System.err.println("    -startAt <subdir of sourceBase>");
 152         System.err.println("    -additionalFile <file not in database but " +
 153                            "which should show up in project file>");
 154         System.err.println("    -additionalGeneratedFile <absolute path to " +
 155                            "directory containing file; no trailing slash> " +
 156                            "<name of file generated later in the build process>");
 157         throw new IllegalArgumentException();
 158     }
 159 
 160 
 161     public void addPerFileLine(Hashtable table,
 162                                String fileName,
 163                                String line) {
 164         Vector v = (Vector) table.get(fileName);
 165         if (v != null) {
 166             v.add(line);
 167         } else {
 168             v = new Vector();
 169             v.add(line);
 170             table.put(fileName, v);
 171         }
 172     }
 173 
 174     protected static class PerFileCondData {
 175         public String releaseString;
 176         public String debugString;
 177     }
 178 
 179     protected void addConditionalPerFileLine(Hashtable table,
 180                                            String fileName,
 181                                            String releaseLine,
 182                                            String debugLine) {
 183         PerFileCondData data = new PerFileCondData();
 184         data.releaseString = releaseLine;
 185         data.debugString = debugLine;
 186         Vector v = (Vector) table.get(fileName);
 187         if (v != null) {
 188             v.add(data);
 189         } else {
 190             v = new Vector();
 191             v.add(data);
 192             table.put(fileName, v);
 193         }
 194     }
 195 
 196     protected static class PrelinkCommandData {
 197       String description;
 198       String commands;
 199     }
 200 
 201     protected void addPrelinkCommand(Hashtable table,
 202                                      String build,
 203                                      String description,
 204                                      String commands) {
 205       PrelinkCommandData data = new PrelinkCommandData();
 206       data.description = description;
 207       data.commands = commands;
 208       table.put(build, data);
 209     }
 210 
 211     public boolean findString(Vector v, String s) {
 212         for (Iterator iter = v.iterator(); iter.hasNext(); ) {
 213             if (((String) iter.next()).equals(s)) {
 214                 return true;
 215             }
 216         }
 217 
 218         return false;
 219     }
 220 
 221     /* This returns a String containing the full path to the passed
 222        file name, or null if an error occurred. If the file was not
 223        found or was a duplicate and couldn't be resolved using the
 224        preferred paths, the file name is added to the appropriate
 225        Vector of Strings. */
 226     private String findFileInDirectory(String fileName,
 227                                        DirectoryTree directory,
 228                                        Vector preferredPaths,
 229                                        Vector filesNotFound,
 230                                        Vector filesDuplicate) {
 231         List locationsInTree = directory.findFile(fileName);
 232         int  rootNameLength = directory.getRootNodeName().length();
 233         String name = null;
 234         if ((locationsInTree == null) ||
 235             (locationsInTree.size() == 0)) {
 236             filesNotFound.add(fileName);
 237         } else if (locationsInTree.size() > 1) {
 238             // Iterate through them, trying to find one with a
 239             // preferred path
 240         search:
 241             {
 242                 for (Iterator locIter = locationsInTree.iterator();
 243                      locIter.hasNext(); ) {
 244                     DirectoryTreeNode node =
 245                         (DirectoryTreeNode) locIter.next();
 246                     String tmpName = node.getName();
 247                     for (Iterator prefIter = preferredPaths.iterator();
 248                          prefIter.hasNext(); ) {
 249                         // We need to make sure the preferred path is
 250                         // found from the file path not including the root node name.
 251                         if (tmpName.indexOf((String)prefIter.next(),
 252                                             rootNameLength) != -1) {
 253                             name = tmpName;
 254                             break search;
 255                         }
 256                     }
 257                 }
 258             }
 259 
 260             if (name == null) {
 261                 filesDuplicate.add(fileName);
 262             }
 263         } else {
 264             name = ((DirectoryTreeNode) locationsInTree.get(0)).getName();
 265         }
 266 
 267         return name;
 268     }
 269 
 270     protected String envVarPrefixedFileName(String fileName,
 271                                             int sourceBaseLen,
 272                                             DirectoryTree tree,
 273                                             Vector preferredPaths,
 274                                             Vector filesNotFound,
 275                                             Vector filesDuplicate) {
 276         String fullName = findFileInDirectory(fileName,
 277                                               tree,
 278                                               preferredPaths,
 279                                               filesNotFound,
 280                                               filesDuplicate);
 281         return fullName;
 282     }
 283 
 284      String getProjectName(String fullPath, String extension)
 285         throws IllegalArgumentException, IOException {
 286         File file = new File(fullPath).getCanonicalFile();
 287         fullPath = file.getCanonicalPath();
 288         String parent = file.getParent();
 289 
 290         if (!fullPath.endsWith(extension)) {
 291             throw new IllegalArgumentException("project file name \"" +
 292                                                fullPath +
 293                                                "\" does not end in "+extension);
 294         }
 295 
 296         if ((parent != null) &&
 297             (!fullPath.startsWith(parent))) {
 298             throw new RuntimeException(
 299                 "Internal error: parent of file name \"" + parent +
 300                 "\" does not match file name \"" + fullPath + "\""
 301             );
 302         }
 303 
 304         int len = parent.length();
 305         if (!parent.endsWith(Util.sep)) {
 306             len += Util.sep.length();
 307         }
 308 
 309         int end = fullPath.length() - extension.length();
 310 
 311         if (len == end) {
 312             throw new RuntimeException(
 313                 "Internal error: file name was empty"
 314             );
 315         }
 316 
 317         return fullPath.substring(len, end);
 318     }
 319 
 320     protected abstract String getProjectExt();
 321 
 322     public void createVcproj(String[] args)
 323         throws IllegalArgumentException, IOException {
 324 
 325         parseArguments(args);
 326 
 327         String projectFileName = BuildConfig.getFieldString(null, "ProjectFileName");
 328         String ext = getProjectExt();
 329 
 330         String projectName = getProjectName(projectFileName, ext);
 331 
 332         writeProjectFile(projectFileName, projectName, createAllConfigs(BuildConfig.getFieldString(null, "PlatformName")));
 333     }
 334 
 335     protected void writePrologue(String[] args) {
 336         System.err.println("WinGammaPlatform platform-specific arguments:");
 337         for (int i = 0; i < args.length; i++) {
 338             System.err.print(args[i] + " ");
 339         }
 340         System.err.println();
 341     }
 342 
 343 
 344     void parseArguments(String[] args) {
 345         new ArgsParser(args,
 346                        new ArgRule[]
 347             {
 348                 new ArgRule("-sourceBase",
 349                             new HsArgHandler() {
 350                                 public void handle(ArgIterator it) {
 351                                    String cfg = getCfg(it.get());
 352                                    if (nextNotKey(it)) {
 353                                       String sb = (String) it.get();
 354                                       if (sb.endsWith(Util.sep)) {
 355                                          sb = sb.substring(0, sb.length() - 1);
 356                                       }
 357                                       BuildConfig.putField(cfg, "SourceBase", sb);
 358                                       it.next();
 359                                    } else {
 360                                       empty("-sourceBase", null);
 361                                    }
 362                                 }
 363                             }
 364                             ),
 365 
 366                 new HsArgRule("-buildBase",
 367                               "BuildBase",
 368                               "   (Did you set the HotSpotBuildSpace environment variable?)",
 369                               HsArgHandler.STRING
 370                               ),
 371 
 372               new HsArgRule("-platformName",
 373                               "PlatformName",
 374                               null,
 375                               HsArgHandler.STRING
 376                               ),
 377 
 378               new HsArgRule("-projectFileName",
 379                               "ProjectFileName",
 380                               null,
 381                               HsArgHandler.STRING
 382                               ),
 383 
 384                 new HsArgRule("-jdkTargetRoot",
 385                               "JdkTargetRoot",
 386                               "   (Did you set the HotSpotJDKDist environment variable?)",
 387                               HsArgHandler.STRING
 388                               ),
 389 
 390                 new HsArgRule("-compiler",
 391                               "CompilerVersion",
 392                               "   (Did you set the VcVersion correctly?)",
 393                               HsArgHandler.STRING
 394                               ),
 395 
 396                 new HsArgRule("-absoluteInclude",
 397                               "AbsoluteInclude",
 398                               null,
 399                               HsArgHandler.VECTOR
 400                               ),
 401 
 402                 new HsArgRule("-relativeInclude",
 403                               "RelativeInclude",
 404                               null,
 405                               HsArgHandler.VECTOR
 406                               ),
 407 
 408                 new HsArgRule("-define",
 409                               "Define",
 410                               null,
 411                               HsArgHandler.VECTOR
 412                               ),
 413 
 414                 new HsArgRule("-useToGeneratePch",
 415                               "UseToGeneratePch",
 416                               null,
 417                               HsArgHandler.STRING
 418                               ),
 419 
 420                 new ArgRuleSpecific("-perFileLine",
 421                             new HsArgHandler() {
 422                                 public void handle(ArgIterator it) {
 423                                     String cfg = getCfg(it.get());
 424                                     if (nextNotKey(it)) {
 425                                         String fileName = it.get();
 426                                         if (nextNotKey(it)) {
 427                                             String line = it.get();
 428                                             BuildConfig.putFieldHash(cfg, "PerFileLine", fileName, line);
 429                                             it.next();
 430                                             return;
 431                                         }
 432                                     }
 433                                     empty(null, "** Error: wrong number of args to -perFileLine");
 434                                 }
 435                             }
 436                             ),
 437 
 438                 new ArgRuleSpecific("-conditionalPerFileLine",
 439                             new HsArgHandler() {
 440                                 public void handle(ArgIterator it) {
 441                                     String cfg = getCfg(it.get());
 442                                     if (nextNotKey(it)) {
 443                                         String fileName = it.get();
 444                                         if (nextNotKey(it)) {
 445                                             String productLine = it.get();
 446                                             if (nextNotKey(it)) {
 447                                                 String debugLine = it.get();
 448                                                 BuildConfig.putFieldHash(cfg+"_debug", "CondPerFileLine",
 449                                                                          fileName, debugLine);
 450                                                 BuildConfig.putFieldHash(cfg+"_product", "CondPerFileLine",
 451                                                                          fileName, productLine);
 452                                                 it.next();
 453                                                 return;
 454                                             }
 455                                         }
 456                                     }
 457 
 458                                     empty(null, "** Error: wrong number of args to -conditionalPerFileLine");
 459                                 }
 460                             }
 461                             ),
 462 
 463                 new HsArgRule("-disablePch",
 464                               "DisablePch",
 465                               null,
 466                               HsArgHandler.HASH
 467                               ),
 468 
 469                 new ArgRule("-startAt",
 470                             new HsArgHandler() {
 471                                 public void handle(ArgIterator it) {
 472                                     if (BuildConfig.getField(null, "StartAt") != null) {
 473                                         empty(null, "** Error: multiple -startAt");
 474                                     }
 475                                     if (nextNotKey(it)) {
 476                                         BuildConfig.putField(null, "StartAt", it.get());
 477                                         it.next();
 478                                     } else {
 479                                         empty("-startAt", null);
 480                                     }
 481                                 }
 482                             }
 483                             ),
 484 
 485                 new HsArgRule("-ignoreFile",
 486                                       "IgnoreFile",
 487                                       null,
 488                                       HsArgHandler.HASH
 489                                       ),
 490 
 491                 new HsArgRule("-ignorePath",
 492                               "IgnorePath",
 493                               null,
 494                               HsArgHandler.VECTOR
 495                               ),
 496 
 497                 new HsArgRule("-additionalFile",
 498                               "AdditionalFile",
 499                               null,
 500                               HsArgHandler.VECTOR
 501                               ),
 502 
 503                 new ArgRuleSpecific("-additionalGeneratedFile",
 504                             new HsArgHandler() {
 505                                 public void handle(ArgIterator it) {
 506                                     String cfg = getCfg(it.get());
 507                                     if (nextNotKey(it)) {
 508                                         String dir = it.get();
 509                                         if (nextNotKey(it)) {
 510                                             String fileName = it.get();
 511                                             BuildConfig.putFieldHash(cfg, "AdditionalGeneratedFile",
 512                                                                      Util.normalize(dir + Util.sep + fileName),
 513                                                                      fileName);
 514                                             it.next();
 515                                             return;
 516                                         }
 517                                     }
 518                                     empty(null, "** Error: wrong number of args to -additionalGeneratedFile");
 519                                 }
 520                             }
 521                             ),
 522 
 523                 new ArgRule("-prelink",
 524                             new HsArgHandler() {
 525                                 public void handle(ArgIterator it) {
 526                                     if (nextNotKey(it)) {
 527                                         if (nextNotKey(it)) {
 528                                             String description = it.get();
 529                                             if (nextNotKey(it)) {
 530                                                 String command = it.get();
 531                                                 BuildConfig.putField(null, "PrelinkDescription", description);
 532                                                 BuildConfig.putField(null, "PrelinkCommand", command);
 533                                                 it.next();
 534                                                 return;
 535                                             }
 536                                         }
 537                                     }
 538 
 539                                     empty(null,  "** Error: wrong number of args to -prelink");
 540                                 }
 541                             }
 542                             ),
 543 
 544                 new ArgRule("-postbuild",
 545                             new HsArgHandler() {
 546                                 public void handle(ArgIterator it) {
 547                                     if (nextNotKey(it)) {
 548                                         if (nextNotKey(it)) {
 549                                             String description = it.get();
 550                                             if (nextNotKey(it)) {
 551                                                 String command = it.get();
 552                                                 BuildConfig.putField(null, "PostbuildDescription", description);
 553                                                 BuildConfig.putField(null, "PostbuildCommand", command);
 554                                                 it.next();
 555                                                 return;
 556                                             }
 557                                         }
 558                                     }
 559 
 560                                     empty(null,  "** Error: wrong number of args to -postbuild");
 561                                 }
 562                             }
 563                             ),
 564             },
 565                                        new ArgHandler() {
 566                                            public void handle(ArgIterator it) {
 567 
 568                                                throw new RuntimeException("Arg Parser: unrecognized option "+it.get());
 569                                            }
 570                                        }
 571                                        );
 572         if (BuildConfig.getField(null, "SourceBase") == null      ||
 573             BuildConfig.getField(null, "BuildBase") == null       ||
 574             BuildConfig.getField(null, "ProjectFileName") == null ||
 575             BuildConfig.getField(null, "CompilerVersion") == null) {
 576             usage();
 577         }
 578 
 579         if (BuildConfig.getField(null, "UseToGeneratePch") == null) {
 580             throw new RuntimeException("ERROR: need to specify one file to compute PCH, with -useToGeneratePch flag");
 581         }
 582 
 583         BuildConfig.putField(null, "PlatformObject", this);
 584     }
 585 
 586     Vector createAllConfigs(String platform) {
 587         Vector allConfigs = new Vector();
 588 
 589         allConfigs.add(new C1DebugConfig());
 590         allConfigs.add(new C1FastDebugConfig());
 591         allConfigs.add(new C1ProductConfig());
 592 
 593         allConfigs.add(new C2DebugConfig());
 594         allConfigs.add(new C2FastDebugConfig());
 595         allConfigs.add(new C2ProductConfig());
 596 
 597         allConfigs.add(new TieredDebugConfig());
 598         allConfigs.add(new TieredFastDebugConfig());
 599         allConfigs.add(new TieredProductConfig());
 600 
 601         allConfigs.add(new CoreDebugConfig());
 602         allConfigs.add(new CoreFastDebugConfig());
 603         allConfigs.add(new CoreProductConfig());
 604 
 605         if (platform.equals("Win32")) {
 606             allConfigs.add(new KernelDebugConfig());
 607             allConfigs.add(new KernelFastDebugConfig());
 608             allConfigs.add(new KernelProductConfig());
 609         }
 610 
 611         return allConfigs;
 612     }
 613 
 614     class FileAttribute {
 615         int     numConfigs;
 616         Vector  configs;
 617         String  shortName;
 618         boolean noPch, pchRoot;
 619 
 620         FileAttribute(String shortName, BuildConfig cfg, int numConfigs) {
 621             this.shortName = shortName;
 622             this.noPch =  (cfg.lookupHashFieldInContext("DisablePch", shortName) != null);
 623             this.pchRoot = shortName.equals(BuildConfig.getFieldString(null, "UseToGeneratePch"));
 624             this.numConfigs = numConfigs;
 625 
 626             configs = new Vector();
 627             add(cfg.get("Name"));
 628         }
 629 
 630         void add(String confName) {
 631             configs.add(confName);
 632 
 633             // if presented in all configs
 634             if (configs.size() == numConfigs) {
 635                 configs = null;
 636             }
 637         }
 638     }
 639 
 640     class FileInfo implements Comparable {
 641         String        full;
 642         FileAttribute attr;
 643 
 644         FileInfo(String full, FileAttribute  attr) {
 645             this.full = full;
 646             this.attr = attr;
 647         }
 648 
 649         public int compareTo(Object o) {
 650             FileInfo oo = (FileInfo)o;
 651             return full.compareTo(oo.full);
 652         }
 653 
 654         boolean isHeader() {
 655             return attr.shortName.endsWith(".h") || attr.shortName.endsWith(".hpp");
 656         }
 657 
 658         boolean isCpp() {
 659             return attr.shortName.endsWith(".cpp");
 660         }
 661     }
 662 
 663 
 664     TreeSet sortFiles(Hashtable allFiles) {
 665         TreeSet rv = new TreeSet();
 666         Enumeration e = allFiles.keys();
 667         while (e.hasMoreElements()) {
 668             String fullPath = (String)e.nextElement();
 669             rv.add(new FileInfo(fullPath, (FileAttribute)allFiles.get(fullPath)));
 670         }
 671         return rv;
 672     }
 673 
 674     Hashtable computeAttributedFiles(Vector allConfigs) {
 675         Hashtable ht = new Hashtable();
 676         int numConfigs = allConfigs.size();
 677 
 678         for (Iterator i = allConfigs.iterator(); i.hasNext(); ) {
 679             BuildConfig bc = (BuildConfig)i.next();
 680             Hashtable  confFiles = (Hashtable)bc.getSpecificField("AllFilesHash");
 681             String confName = bc.get("Name");
 682 
 683             for (Enumeration e=confFiles.keys(); e.hasMoreElements(); ) {
 684                 String filePath = (String)e.nextElement();
 685                 FileAttribute fa = (FileAttribute)ht.get(filePath);
 686 
 687                 if (fa == null) {
 688                     fa = new FileAttribute((String)confFiles.get(filePath), bc, numConfigs);
 689                     ht.put(filePath, fa);
 690                 } else {
 691                     fa.add(confName);
 692                 }
 693             }
 694         }
 695 
 696         return ht;
 697     }
 698 
 699      Hashtable computeAttributedFiles(BuildConfig bc) {
 700         Hashtable ht = new Hashtable();
 701         Hashtable confFiles = (Hashtable)bc.getSpecificField("AllFilesHash");
 702 
 703         for (Enumeration e = confFiles.keys(); e.hasMoreElements(); ) {
 704             String filePath = (String)e.nextElement();
 705             ht.put(filePath,  new FileAttribute((String)confFiles.get(filePath), bc, 1));
 706         }
 707 
 708         return ht;
 709     }
 710 
 711     PrintWriter printWriter;
 712 
 713     public void writeProjectFile(String projectFileName, String projectName,
 714                                  Vector<BuildConfig> allConfigs) throws IOException {
 715         throw new RuntimeException("use compiler version specific version");
 716     }
 717 }