Wed, 15 Dec 2010 07:11:31 -0800
7006354: Updates to Visual Studio project creation and development launcher
Summary: Updates to Visual Studio project creation and development launcher
Reviewed-by: stefank, coleenp
1 /*
2 * Copyright (c) 1999, 2010, 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 */
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;
35 abstract class HsArgHandler extends ArgHandler {
36 static final int STRING = 1;
37 static final int VECTOR = 2;
38 static final int HASH = 3;
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 }
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 }
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 }
70 class ArgRuleSpecific extends ArgRule {
71 ArgRuleSpecific(String arg, ArgHandler handler) {
72 super(arg, handler);
73 }
75 boolean match(String rulePattern, String arg) {
76 return rulePattern.startsWith(arg);
77 }
78 }
81 class SpecificHsArgHandler extends HsArgHandler {
83 String message, argKey, valKey;
84 int type;
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();
105 } else {
106 empty(argKey, message);
107 }
108 }
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 }
119 class HsArgRule extends ArgRuleSpecific {
121 HsArgRule(String argKey, String valKey, String message, int type) {
122 super(argKey, new SpecificHsArgHandler(argKey, valKey, message, type));
123 }
125 }
127 public abstract class WinGammaPlatform {
129 public boolean fileNameStringEquality(String s1, String s2) {
130 return s1.equalsIgnoreCase(s2);
131 }
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 }
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 }
174 protected static class PerFileCondData {
175 public String releaseString;
176 public String debugString;
177 }
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 }
196 protected static class PrelinkCommandData {
197 String description;
198 String commands;
199 }
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 }
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 }
218 return false;
219 }
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 // We shouldn't have duplicate file names in our workspace.
239 System.err.println();
240 System.err.println("There are multiple files named as: " + fileName);
241 System.exit(-1);
242 // The following code could be safely removed if we don't need duplicate
243 // file names.
245 // Iterate through them, trying to find one with a
246 // preferred path
247 search:
248 {
249 for (Iterator locIter = locationsInTree.iterator();
250 locIter.hasNext(); ) {
251 DirectoryTreeNode node =
252 (DirectoryTreeNode) locIter.next();
253 String tmpName = node.getName();
254 for (Iterator prefIter = preferredPaths.iterator();
255 prefIter.hasNext(); ) {
256 // We need to make sure the preferred path is
257 // found from the file path not including the root node name.
258 if (tmpName.indexOf((String)prefIter.next(),
259 rootNameLength) != -1) {
260 name = tmpName;
261 break search;
262 }
263 }
264 }
265 }
267 if (name == null) {
268 filesDuplicate.add(fileName);
269 }
270 } else {
271 name = ((DirectoryTreeNode) locationsInTree.get(0)).getName();
272 }
274 return name;
275 }
277 protected String envVarPrefixedFileName(String fileName,
278 int sourceBaseLen,
279 DirectoryTree tree,
280 Vector preferredPaths,
281 Vector filesNotFound,
282 Vector filesDuplicate) {
283 String fullName = findFileInDirectory(fileName,
284 tree,
285 preferredPaths,
286 filesNotFound,
287 filesDuplicate);
288 return fullName;
289 }
291 String getProjectName(String fullPath, String extension)
292 throws IllegalArgumentException, IOException {
293 File file = new File(fullPath).getCanonicalFile();
294 fullPath = file.getCanonicalPath();
295 String parent = file.getParent();
297 if (!fullPath.endsWith(extension)) {
298 throw new IllegalArgumentException("project file name \"" +
299 fullPath +
300 "\" does not end in "+extension);
301 }
303 if ((parent != null) &&
304 (!fullPath.startsWith(parent))) {
305 throw new RuntimeException(
306 "Internal error: parent of file name \"" + parent +
307 "\" does not match file name \"" + fullPath + "\""
308 );
309 }
311 int len = parent.length();
312 if (!parent.endsWith(Util.sep)) {
313 len += Util.sep.length();
314 }
316 int end = fullPath.length() - extension.length();
318 if (len == end) {
319 throw new RuntimeException(
320 "Internal error: file name was empty"
321 );
322 }
324 return fullPath.substring(len, end);
325 }
327 protected abstract String getProjectExt();
329 public void createVcproj(String[] args)
330 throws IllegalArgumentException, IOException {
332 parseArguments(args);
334 String projectFileName = BuildConfig.getFieldString(null, "ProjectFileName");
335 String ext = getProjectExt();
337 String projectName = getProjectName(projectFileName, ext);
339 writeProjectFile(projectFileName, projectName, createAllConfigs());
340 }
342 protected void writePrologue(String[] args) {
343 System.err.println("WinGammaPlatform platform-specific arguments:");
344 for (int i = 0; i < args.length; i++) {
345 System.err.print(args[i] + " ");
346 }
347 System.err.println();
348 }
351 void parseArguments(String[] args) {
352 new ArgsParser(args,
353 new ArgRule[]
354 {
355 new ArgRule("-sourceBase",
356 new HsArgHandler() {
357 public void handle(ArgIterator it) {
358 String cfg = getCfg(it.get());
359 if (nextNotKey(it)) {
360 String sb = (String) it.get();
361 if (sb.endsWith(Util.sep)) {
362 sb = sb.substring(0, sb.length() - 1);
363 }
364 BuildConfig.putField(cfg, "SourceBase", sb);
365 it.next();
366 } else {
367 empty("-sourceBase", null);
368 }
369 }
370 }
371 ),
373 new HsArgRule("-buildBase",
374 "BuildBase",
375 " (Did you set the HotSpotBuildSpace environment variable?)",
376 HsArgHandler.STRING
377 ),
379 new HsArgRule("-projectFileName",
380 "ProjectFileName",
381 null,
382 HsArgHandler.STRING
383 ),
385 new HsArgRule("-jdkTargetRoot",
386 "JdkTargetRoot",
387 " (Did you set the HotSpotJDKDist environment variable?)",
388 HsArgHandler.STRING
389 ),
391 new HsArgRule("-compiler",
392 "CompilerVersion",
393 " (Did you set the VcVersion correctly?)",
394 HsArgHandler.STRING
395 ),
397 new HsArgRule("-platform",
398 "Platform",
399 null,
400 HsArgHandler.STRING
401 ),
403 new HsArgRule("-absoluteInclude",
404 "AbsoluteInclude",
405 null,
406 HsArgHandler.VECTOR
407 ),
409 new HsArgRule("-relativeInclude",
410 "RelativeInclude",
411 null,
412 HsArgHandler.VECTOR
413 ),
415 new HsArgRule("-define",
416 "Define",
417 null,
418 HsArgHandler.VECTOR
419 ),
421 new HsArgRule("-useToGeneratePch",
422 "UseToGeneratePch",
423 null,
424 HsArgHandler.STRING
425 ),
427 new ArgRuleSpecific("-perFileLine",
428 new HsArgHandler() {
429 public void handle(ArgIterator it) {
430 String cfg = getCfg(it.get());
431 if (nextNotKey(it)) {
432 String fileName = it.get();
433 if (nextNotKey(it)) {
434 String line = it.get();
435 BuildConfig.putFieldHash(cfg, "PerFileLine", fileName, line);
436 it.next();
437 return;
438 }
439 }
440 empty(null, "** Error: wrong number of args to -perFileLine");
441 }
442 }
443 ),
445 new ArgRuleSpecific("-conditionalPerFileLine",
446 new HsArgHandler() {
447 public void handle(ArgIterator it) {
448 String cfg = getCfg(it.get());
449 if (nextNotKey(it)) {
450 String fileName = it.get();
451 if (nextNotKey(it)) {
452 String productLine = it.get();
453 if (nextNotKey(it)) {
454 String debugLine = it.get();
455 BuildConfig.putFieldHash(cfg+"_debug", "CondPerFileLine",
456 fileName, debugLine);
457 BuildConfig.putFieldHash(cfg+"_product", "CondPerFileLine",
458 fileName, productLine);
459 it.next();
460 return;
461 }
462 }
463 }
465 empty(null, "** Error: wrong number of args to -conditionalPerFileLine");
466 }
467 }
468 ),
470 new HsArgRule("-disablePch",
471 "DisablePch",
472 null,
473 HsArgHandler.HASH
474 ),
476 new ArgRule("-startAt",
477 new HsArgHandler() {
478 public void handle(ArgIterator it) {
479 if (BuildConfig.getField(null, "StartAt") != null) {
480 empty(null, "** Error: multiple -startAt");
481 }
482 if (nextNotKey(it)) {
483 BuildConfig.putField(null, "StartAt", it.get());
484 it.next();
485 } else {
486 empty("-startAt", null);
487 }
488 }
489 }
490 ),
492 new HsArgRule("-ignoreFile",
493 "IgnoreFile",
494 null,
495 HsArgHandler.HASH
496 ),
498 new HsArgRule("-ignorePath",
499 "IgnorePath",
500 null,
501 HsArgHandler.VECTOR
502 ),
504 new HsArgRule("-additionalFile",
505 "AdditionalFile",
506 null,
507 HsArgHandler.VECTOR
508 ),
510 new ArgRuleSpecific("-additionalGeneratedFile",
511 new HsArgHandler() {
512 public void handle(ArgIterator it) {
513 String cfg = getCfg(it.get());
514 if (nextNotKey(it)) {
515 String dir = it.get();
516 if (nextNotKey(it)) {
517 String fileName = it.get();
518 BuildConfig.putFieldHash(cfg, "AdditionalGeneratedFile",
519 Util.normalize(dir + Util.sep + fileName),
520 fileName);
521 it.next();
522 return;
523 }
524 }
525 empty(null, "** Error: wrong number of args to -additionalGeneratedFile");
526 }
527 }
528 ),
530 new ArgRule("-prelink",
531 new HsArgHandler() {
532 public void handle(ArgIterator it) {
533 if (nextNotKey(it)) {
534 if (nextNotKey(it)) {
535 String description = it.get();
536 if (nextNotKey(it)) {
537 String command = it.get();
538 BuildConfig.putField(null, "PrelinkDescription", description);
539 BuildConfig.putField(null, "PrelinkCommand", command);
540 it.next();
541 return;
542 }
543 }
544 }
546 empty(null, "** Error: wrong number of args to -prelink");
547 }
548 }
549 ),
551 new ArgRule("-postbuild",
552 new HsArgHandler() {
553 public void handle(ArgIterator it) {
554 if (nextNotKey(it)) {
555 if (nextNotKey(it)) {
556 String description = it.get();
557 if (nextNotKey(it)) {
558 String command = it.get();
559 BuildConfig.putField(null, "PostbuildDescription", description);
560 BuildConfig.putField(null, "PostbuildCommand", command);
561 it.next();
562 return;
563 }
564 }
565 }
567 empty(null, "** Error: wrong number of args to -postbuild");
568 }
569 }
570 ),
571 },
572 new ArgHandler() {
573 public void handle(ArgIterator it) {
575 throw new RuntimeException("Arg Parser: unrecognized option "+it.get());
576 }
577 }
578 );
579 if (BuildConfig.getField(null, "SourceBase") == null ||
580 BuildConfig.getField(null, "BuildBase") == null ||
581 BuildConfig.getField(null, "ProjectFileName") == null ||
582 BuildConfig.getField(null, "CompilerVersion") == null) {
583 usage();
584 }
586 if (BuildConfig.getField(null, "UseToGeneratePch") == null) {
587 throw new RuntimeException("ERROR: need to specify one file to compute PCH, with -useToGeneratePch flag");
588 }
590 BuildConfig.putField(null, "PlatformObject", this);
591 }
593 Vector createAllConfigs() {
594 Vector allConfigs = new Vector();
596 allConfigs.add(new C1DebugConfig());
598 boolean b = true;
599 if (b) {
600 allConfigs.add(new C1FastDebugConfig());
601 allConfigs.add(new C1ProductConfig());
603 allConfigs.add(new C2DebugConfig());
604 allConfigs.add(new C2FastDebugConfig());
605 allConfigs.add(new C2ProductConfig());
607 allConfigs.add(new TieredDebugConfig());
608 allConfigs.add(new TieredFastDebugConfig());
609 allConfigs.add(new TieredProductConfig());
611 allConfigs.add(new CoreDebugConfig());
612 allConfigs.add(new CoreFastDebugConfig());
613 allConfigs.add(new CoreProductConfig());
615 allConfigs.add(new KernelDebugConfig());
616 allConfigs.add(new KernelFastDebugConfig());
617 allConfigs.add(new KernelProductConfig());
618 }
620 return allConfigs;
621 }
623 class FileAttribute {
624 int numConfigs;
625 Vector configs;
626 String shortName;
627 boolean noPch, pchRoot;
629 FileAttribute(String shortName, BuildConfig cfg, int numConfigs) {
630 this.shortName = shortName;
631 this.noPch = (cfg.lookupHashFieldInContext("DisablePch", shortName) != null);
632 this.pchRoot = shortName.equals(BuildConfig.getFieldString(null, "UseToGeneratePch"));
633 this.numConfigs = numConfigs;
635 configs = new Vector();
636 add(cfg.get("Name"));
637 }
639 void add(String confName) {
640 configs.add(confName);
642 // if presented in all configs
643 if (configs.size() == numConfigs) {
644 configs = null;
645 }
646 }
647 }
649 class FileInfo implements Comparable {
650 String full;
651 FileAttribute attr;
653 FileInfo(String full, FileAttribute attr) {
654 this.full = full;
655 this.attr = attr;
656 }
658 public int compareTo(Object o) {
659 FileInfo oo = (FileInfo)o;
660 return full.compareTo(oo.full);
661 }
663 boolean isHeader() {
664 return attr.shortName.endsWith(".h") || attr.shortName.endsWith(".hpp");
665 }
666 }
669 TreeSet sortFiles(Hashtable allFiles) {
670 TreeSet rv = new TreeSet();
671 Enumeration e = allFiles.keys();
672 while (e.hasMoreElements()) {
673 String fullPath = (String)e.nextElement();
674 rv.add(new FileInfo(fullPath, (FileAttribute)allFiles.get(fullPath)));
675 }
676 return rv;
677 }
679 Hashtable computeAttributedFiles(Vector allConfigs) {
680 Hashtable ht = new Hashtable();
681 int numConfigs = allConfigs.size();
683 for (Iterator i = allConfigs.iterator(); i.hasNext(); ) {
684 BuildConfig bc = (BuildConfig)i.next();
685 Hashtable confFiles = (Hashtable)bc.getSpecificField("AllFilesHash");
686 String confName = bc.get("Name");
688 for (Enumeration e=confFiles.keys(); e.hasMoreElements(); ) {
689 String filePath = (String)e.nextElement();
690 FileAttribute fa = (FileAttribute)ht.get(filePath);
692 if (fa == null) {
693 fa = new FileAttribute((String)confFiles.get(filePath), bc, numConfigs);
694 ht.put(filePath, fa);
695 } else {
696 fa.add(confName);
697 }
698 }
699 }
701 return ht;
702 }
704 Hashtable computeAttributedFiles(BuildConfig bc) {
705 Hashtable ht = new Hashtable();
706 Hashtable confFiles = (Hashtable)bc.getSpecificField("AllFilesHash");
708 for (Enumeration e = confFiles.keys(); e.hasMoreElements(); ) {
709 String filePath = (String)e.nextElement();
710 ht.put(filePath, new FileAttribute((String)confFiles.get(filePath), bc, 1));
711 }
713 return ht;
714 }
716 PrintWriter printWriter;
718 public void writeProjectFile(String projectFileName, String projectName,
719 Vector allConfigs) throws IOException {
720 throw new RuntimeException("use compiler version specific version");
721 }
722 }