1 /*
   2  * Copyright (c) 2005, 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  */
  24 
  25 import java.io.File;
  26 import java.util.Enumeration;
  27 import java.util.Hashtable;
  28 import java.util.Iterator;
  29 import java.util.Vector;
  30 
  31 class BuildConfig {
  32     Hashtable vars;
  33     Vector basicNames, basicPaths;
  34     String[] context;
  35 
  36     static CompilerInterface ci;
  37     static CompilerInterface getCI() {
  38         if (ci == null) {
  39             String comp = (String)getField(null, "CompilerVersion");
  40             try {
  41                 ci = (CompilerInterface)Class.forName("CompilerInterface" + comp).newInstance();
  42             } catch (Exception cnfe) {
  43                 System.err.println("Cannot find support for compiler " + comp);
  44                 throw new RuntimeException(cnfe.toString());
  45             }
  46         }
  47         return ci;
  48     }
  49 
  50     protected void initNames(String flavour, String build, String outDll) {
  51         if (vars == null) vars = new Hashtable();
  52 
  53         String flavourBuild =  flavour + "_" + build;
  54         System.out.println();
  55         System.out.println(flavourBuild);
  56 
  57         put("Name", getCI().makeCfgName(flavourBuild));
  58         put("Flavour", flavour);
  59         put("Build", build);
  60 
  61         // ones mentioned above were needed to expand format
  62         String buildBase = expandFormat(getFieldString(null, "BuildBase"));
  63         String sourceBase = getFieldString(null, "SourceBase");
  64         String outDir = buildBase;
  65 
  66         put("Id", flavourBuild);
  67         put("OutputDir", outDir);
  68         put("SourceBase", sourceBase);
  69         put("BuildBase", buildBase);
  70         put("OutputDll", outDir + Util.sep + outDll);
  71 
  72         context = new String [] {flavourBuild, flavour, build, null};
  73     }
  74 
  75     protected void init(Vector includes, Vector defines) {
  76         initDefaultDefines(defines);
  77         initDefaultCompilerFlags(includes);
  78         initDefaultLinkerFlags();
  79         handleDB();
  80     }
  81 
  82 
  83     protected void initDefaultCompilerFlags(Vector includes) {
  84         Vector compilerFlags = new Vector();
  85 
  86         compilerFlags.addAll(getCI().getBaseCompilerFlags(getV("Define"),
  87                                                           includes,
  88                                                           get("OutputDir")));
  89 
  90         put("CompilerFlags", compilerFlags);
  91     }
  92 
  93     protected void initDefaultLinkerFlags() {
  94         Vector linkerFlags = new Vector();
  95 
  96         linkerFlags.addAll(getCI().getBaseLinkerFlags( get("OutputDir"), get("OutputDll")));
  97 
  98         put("LinkerFlags", linkerFlags);
  99     }
 100 
 101     DirectoryTree getSourceTree(String sourceBase, String startAt) {
 102         DirectoryTree tree = new DirectoryTree();
 103 
 104         tree.addSubdirToIgnore("Codemgr_wsdata");
 105         tree.addSubdirToIgnore("deleted_files");
 106         tree.addSubdirToIgnore("SCCS");
 107         tree.setVerbose(true);
 108         if (startAt != null) {
 109             tree.readDirectory(sourceBase + File.separator + startAt);
 110         } else {
 111             tree.readDirectory(sourceBase);
 112         }
 113 
 114         return tree;
 115     }
 116 
 117 
 118     Vector getPreferredPaths(MacroDefinitions macros) {
 119         Vector preferredPaths = new Vector();
 120         // In the case of multiple files with the same name in
 121         // different subdirectories, prefer the versions specified in
 122         // the platform file as the "os_family" and "arch" macros.
 123         for (Iterator iter = macros.getMacros(); iter.hasNext(); ) {
 124             Macro macro = (Macro) iter.next();
 125             if (macro.name.equals("os_family") ||
 126                 macro.name.equals("arch")) {
 127                 preferredPaths.add(macro.contents);
 128             }
 129         }
 130         // Also prefer "opto" over "adlc" for adlcVMDeps.hpp
 131         preferredPaths.add("opto");
 132 
 133         return preferredPaths;
 134     }
 135 
 136 
 137     void handleDB() {
 138         WinGammaPlatform platform = (WinGammaPlatform)getField(null, "PlatformObject");
 139 
 140         File incls = new File(get("OutputDir")+Util.sep+"incls");
 141 
 142         incls.mkdirs();
 143 
 144         MacroDefinitions macros = new MacroDefinitions();
 145         try {
 146             macros.readFrom(getFieldString(null, "Platform"), false);
 147         } catch (Exception e) {
 148             throw new RuntimeException(e);
 149         }
 150 
 151         putSpecificField("AllFilesHash", computeAllFiles(platform, macros));
 152     }
 153 
 154 
 155     private boolean matchesIgnoredPath(String prefixedName) {
 156         Vector rv = new Vector();
 157         collectRelevantVectors(rv, "IgnorePath");
 158         for (Iterator i = rv.iterator(); i.hasNext(); ) {
 159             String pathPart = (String) i.next();
 160             if (prefixedName.contains(Util.normalize(pathPart)))  {
 161                 return true;
 162             }
 163         }
 164         return false;
 165     }
 166 
 167     void addAll(Iterator i, Hashtable hash,
 168                 WinGammaPlatform platform, DirectoryTree tree,
 169                 Vector preferredPaths, Vector filesNotFound, Vector filesDuplicate) {
 170         for (; i.hasNext(); ) {
 171             String fileName = (String) i.next();
 172             if (lookupHashFieldInContext("IgnoreFile", fileName) == null) {
 173                 String prefixedName = platform.envVarPrefixedFileName(fileName,
 174                                                                       0, /* ignored */
 175                                                                       tree,
 176                                                                       preferredPaths,
 177                                                                       filesNotFound,
 178                                                                       filesDuplicate);
 179                 if (prefixedName != null) {
 180                     prefixedName = Util.normalize(prefixedName);
 181                     if (!matchesIgnoredPath(prefixedName)) {
 182                         addTo(hash, prefixedName, fileName);
 183                     }
 184                 }
 185             }
 186         }
 187     }
 188 
 189     void addTo(Hashtable ht, String key, String value) {
 190         ht.put(expandFormat(key), expandFormat(value));
 191     }
 192 
 193     Hashtable computeAllFiles(WinGammaPlatform platform, MacroDefinitions macros) {
 194         Hashtable rv = new Hashtable();
 195         DirectoryTree tree = getSourceTree(get("SourceBase"), getFieldString(null, "StartAt"));
 196         Vector preferredPaths = getPreferredPaths(macros);
 197 
 198         // Hold errors until end
 199         Vector filesNotFound = new Vector();
 200         Vector filesDuplicate = new Vector();
 201 
 202         Vector includedFiles = new Vector();
 203 
 204         // find all files
 205         Vector dirs = getSourceIncludes();
 206         for (Iterator i = dirs.iterator(); i.hasNext(); ) {
 207             String dir = (String)i.next();
 208             DirectoryTree subtree = getSourceTree(dir, null);
 209             for (Iterator fi = subtree.getFileIterator(); fi.hasNext(); ) {
 210                 String name = ((File)fi.next()).getName();
 211                 includedFiles.add(name);
 212             }
 213         }
 214         addAll(includedFiles.iterator(), rv,
 215                platform, tree,
 216                preferredPaths, filesNotFound, filesDuplicate);
 217 
 218         Vector addFiles = new Vector();
 219         collectRelevantVectors(addFiles, "AdditionalFile");
 220         addAll(addFiles.iterator(), rv,
 221                platform, tree,
 222                preferredPaths, filesNotFound, filesDuplicate);
 223 
 224         collectRelevantHashes(rv, "AdditionalGeneratedFile");
 225 
 226         if ((filesNotFound.size() != 0) ||
 227             (filesDuplicate.size() != 0)) {
 228             System.err.println("Error: some files were not found or " +
 229                                "appeared in multiple subdirectories of " +
 230                                "directory " + get("SourceBase") + " and could not " +
 231                                "be resolved with the os_family and arch " +
 232                                "macros in the platform file.");
 233             if (filesNotFound.size() != 0) {
 234                 System.err.println("Files not found:");
 235                 for (Iterator iter = filesNotFound.iterator();
 236                      iter.hasNext(); ) {
 237                     System.err.println("  " + (String) iter.next());
 238                 }
 239             }
 240             if (filesDuplicate.size() != 0) {
 241                 System.err.println("Duplicate files:");
 242                 for (Iterator iter = filesDuplicate.iterator();
 243                      iter.hasNext(); ) {
 244                     System.err.println("  " + (String) iter.next());
 245                 }
 246             }
 247             throw new RuntimeException();
 248         }
 249 
 250         return rv;
 251     }
 252 
 253     void initDefaultDefines(Vector defines) {
 254         Vector sysDefines = new Vector();
 255         sysDefines.add("WIN32");
 256         sysDefines.add("_WINDOWS");
 257         sysDefines.add("HOTSPOT_BUILD_USER="+System.getProperty("user.name"));
 258         sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
 259         sysDefines.add("_JNI_IMPLEMENTATION_");
 260         sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i386\\\"");
 261 
 262         sysDefines.addAll(defines);
 263 
 264         put("Define", sysDefines);
 265     }
 266 
 267     String get(String key) {
 268         return (String)vars.get(key);
 269     }
 270 
 271     Vector getV(String key) {
 272         return (Vector)vars.get(key);
 273     }
 274 
 275     Object getO(String key) {
 276         return vars.get(key);
 277     }
 278 
 279     Hashtable getH(String key) {
 280         return (Hashtable)vars.get(key);
 281     }
 282 
 283     Object getFieldInContext(String field) {
 284         for (int i=0; i<context.length; i++) {
 285             Object rv = getField(context[i], field);
 286             if (rv != null) {
 287                 return rv;
 288             }
 289         }
 290         return null;
 291     }
 292 
 293     Object lookupHashFieldInContext(String field, String key) {
 294         for (int i=0; i<context.length; i++) {
 295             Hashtable ht = (Hashtable)getField(context[i], field);
 296             if (ht != null) {
 297                 Object rv = ht.get(key);
 298                 if (rv != null) {
 299                     return rv;
 300                 }
 301             }
 302         }
 303         return null;
 304     }
 305 
 306     void put(String key, String value) {
 307         vars.put(key, value);
 308     }
 309 
 310     void put(String key, Vector vvalue) {
 311         vars.put(key, vvalue);
 312     }
 313 
 314     void add(String key, Vector vvalue) {
 315         getV(key).addAll(vvalue);
 316     }
 317 
 318     String flavour() {
 319         return get("Flavour");
 320     }
 321 
 322     String build() {
 323         return get("Build");
 324     }
 325 
 326     Object getSpecificField(String field) {
 327         return getField(get("Id"), field);
 328     }
 329 
 330     void putSpecificField(String field, Object value) {
 331         putField(get("Id"), field, value);
 332     }
 333 
 334     void collectRelevantVectors(Vector rv, String field) {
 335         for (int i = 0; i < context.length; i++) {
 336             Vector v = getFieldVector(context[i], field);
 337             if (v != null) {
 338                 for (Iterator j=v.iterator(); j.hasNext(); ) {
 339                     String val = (String)j.next();
 340                     rv.add(expandFormat(val));
 341                 }
 342             }
 343         }
 344     }
 345 
 346     void collectRelevantHashes(Hashtable rv, String field) {
 347         for (int i = 0; i < context.length; i++) {
 348             Hashtable v = (Hashtable)getField(context[i], field);
 349             if (v != null) {
 350                 for (Enumeration e=v.keys(); e.hasMoreElements(); ) {
 351                     String key = (String)e.nextElement();
 352                     String val =  (String)v.get(key);
 353                     addTo(rv, key, val);
 354                 }
 355             }
 356         }
 357     }
 358 
 359 
 360     Vector getDefines() {
 361         Vector rv = new Vector();
 362         collectRelevantVectors(rv, "Define");
 363         return rv;
 364     }
 365 
 366     Vector getIncludes() {
 367         Vector rv = new Vector();
 368 
 369         collectRelevantVectors(rv, "AbsoluteInclude");
 370 
 371         rv.addAll(getSourceIncludes());
 372 
 373         return rv;
 374     }
 375 
 376     private Vector getSourceIncludes() {
 377         Vector rv = new Vector();
 378         Vector ri = new Vector();
 379         String sourceBase = getFieldString(null, "SourceBase");
 380         collectRelevantVectors(ri, "RelativeInclude");
 381         for (Iterator i = ri.iterator(); i.hasNext(); ) {
 382             String f = (String)i.next();
 383             rv.add(sourceBase + Util.sep + f);
 384         }
 385         return rv;
 386     }
 387 
 388     static Hashtable cfgData = new Hashtable();
 389     static Hashtable globalData = new Hashtable();
 390 
 391     static boolean appliesToTieredBuild(String cfg) {
 392         return (cfg != null &&
 393                 (cfg.startsWith("compiler1") ||
 394                  cfg.startsWith("compiler2")));
 395     }
 396 
 397     // Filters out the IgnoreFile and IgnorePaths since they are
 398     // handled specially for tiered builds.
 399     static boolean appliesToTieredBuild(String cfg, String key) {
 400         return (appliesToTieredBuild(cfg))&& (key != null && !key.startsWith("Ignore"));
 401     }
 402 
 403     static String getTieredBuildCfg(String cfg) {
 404         assert appliesToTieredBuild(cfg) : "illegal configuration " + cfg;
 405         return "tiered" + cfg.substring(9);
 406     }
 407 
 408     static Object getField(String cfg, String field) {
 409         if (cfg == null) {
 410             return globalData.get(field);
 411         }
 412 
 413         Hashtable ht =  (Hashtable)cfgData.get(cfg);
 414         return ht == null ? null : ht.get(field);
 415     }
 416 
 417     static String getFieldString(String cfg, String field) {
 418         return (String)getField(cfg, field);
 419     }
 420 
 421     static Vector getFieldVector(String cfg, String field) {
 422         return (Vector)getField(cfg, field);
 423     }
 424 
 425     static void putField(String cfg, String field, Object value) {
 426         putFieldImpl(cfg, field, value);
 427         if (appliesToTieredBuild(cfg, field)) {
 428             putFieldImpl(getTieredBuildCfg(cfg), field, value);
 429         }
 430     }
 431 
 432     private static void putFieldImpl(String cfg, String field, Object value) {
 433         if (cfg == null) {
 434             globalData.put(field, value);
 435             return;
 436         }
 437 
 438         Hashtable ht = (Hashtable)cfgData.get(cfg);
 439         if (ht == null) {
 440             ht = new Hashtable();
 441             cfgData.put(cfg, ht);
 442         }
 443 
 444         ht.put(field, value);
 445     }
 446 
 447     static Object getFieldHash(String cfg, String field, String name) {
 448         Hashtable ht = (Hashtable)getField(cfg, field);
 449 
 450         return ht == null ? null : ht.get(name);
 451     }
 452 
 453     static void putFieldHash(String cfg, String field, String name, Object val) {
 454         putFieldHashImpl(cfg, field, name, val);
 455         if (appliesToTieredBuild(cfg, field)) {
 456             putFieldHashImpl(getTieredBuildCfg(cfg), field, name, val);
 457         }
 458     }
 459 
 460     private static void putFieldHashImpl(String cfg, String field, String name, Object val) {
 461         Hashtable ht = (Hashtable)getField(cfg, field);
 462 
 463         if (ht == null) {
 464             ht = new Hashtable();
 465             putFieldImpl(cfg, field, ht);
 466         }
 467 
 468         ht.put(name, val);
 469     }
 470 
 471     static void addFieldVector(String cfg, String field, String element) {
 472         addFieldVectorImpl(cfg, field, element);
 473         if (appliesToTieredBuild(cfg, field)) {
 474             addFieldVectorImpl(getTieredBuildCfg(cfg), field, element);
 475         }
 476     }
 477 
 478     private static void addFieldVectorImpl(String cfg, String field, String element) {
 479         Vector v = (Vector)getField(cfg, field);
 480 
 481         if (v == null) {
 482             v = new Vector();
 483             putFieldImpl(cfg, field, v);
 484         }
 485 
 486         v.add(element);
 487     }
 488 
 489     String expandFormat(String format) {
 490         if (format == null) {
 491             return null;
 492         }
 493 
 494         if (format.indexOf('%') == -1) {
 495             return format;
 496         }
 497 
 498         StringBuffer sb = new StringBuffer();
 499         int len = format.length();
 500         for (int i=0; i<len; i++) {
 501             char ch = format.charAt(i);
 502             if (ch == '%') {
 503                 char ch1 = format.charAt(i+1);
 504                 switch (ch1) {
 505                 case '%':
 506                     sb.append(ch1);
 507                     break;
 508                 case 'b':
 509                     sb.append(build());
 510                     break;
 511                 case 'f':
 512                     sb.append(flavour());
 513                     break;
 514                 default:
 515                     sb.append(ch);
 516                     sb.append(ch1);
 517                 }
 518                 i++;
 519             } else {
 520                 sb.append(ch);
 521             }
 522         }
 523 
 524         return sb.toString();
 525     }
 526 }
 527 
 528 abstract class GenericDebugConfig extends BuildConfig {
 529     abstract String getOptFlag();
 530 
 531     protected void init(Vector includes, Vector defines) {
 532         defines.add("_DEBUG");
 533         defines.add("ASSERT");
 534 
 535         super.init(includes, defines);
 536 
 537         getV("CompilerFlags").addAll(getCI().getDebugCompilerFlags(getOptFlag()));
 538         getV("LinkerFlags").addAll(getCI().getDebugLinkerFlags());
 539    }
 540 }
 541 
 542 abstract class GenericDebugNonKernelConfig extends GenericDebugConfig {
 543     protected void init(Vector includes, Vector defines) {
 544         super.init(includes, defines);
 545         getCI().getAdditionalNonKernelLinkerFlags(getV("LinkerFlags"));
 546    }
 547 }
 548 
 549 class C1DebugConfig extends GenericDebugNonKernelConfig {
 550     String getOptFlag() {
 551         return getCI().getNoOptFlag();
 552     }
 553 
 554     C1DebugConfig() {
 555         initNames("compiler1", "debug", "jvm.dll");
 556         init(getIncludes(), getDefines());
 557     }
 558 }
 559 
 560 class C1FastDebugConfig extends GenericDebugNonKernelConfig {
 561     String getOptFlag() {
 562         return getCI().getOptFlag();
 563     }
 564 
 565     C1FastDebugConfig() {
 566         initNames("compiler1", "fastdebug", "jvm.dll");
 567         init(getIncludes(), getDefines());
 568     }
 569 }
 570 
 571 class C2DebugConfig extends GenericDebugNonKernelConfig {
 572     String getOptFlag() {
 573         return getCI().getNoOptFlag();
 574     }
 575 
 576     C2DebugConfig() {
 577         initNames("compiler2", "debug", "jvm.dll");
 578         init(getIncludes(), getDefines());
 579     }
 580 }
 581 
 582 class C2FastDebugConfig extends GenericDebugNonKernelConfig {
 583     String getOptFlag() {
 584         return getCI().getOptFlag();
 585     }
 586 
 587     C2FastDebugConfig() {
 588         initNames("compiler2", "fastdebug", "jvm.dll");
 589         init(getIncludes(), getDefines());
 590     }
 591 }
 592 
 593 class TieredDebugConfig extends GenericDebugNonKernelConfig {
 594     String getOptFlag() {
 595         return getCI().getNoOptFlag();
 596     }
 597 
 598     TieredDebugConfig() {
 599         initNames("tiered", "debug", "jvm.dll");
 600         init(getIncludes(), getDefines());
 601     }
 602 }
 603 
 604 class TieredFastDebugConfig extends GenericDebugNonKernelConfig {
 605     String getOptFlag() {
 606         return getCI().getOptFlag();
 607     }
 608 
 609     TieredFastDebugConfig() {
 610         initNames("tiered", "fastdebug", "jvm.dll");
 611         init(getIncludes(), getDefines());
 612     }
 613 }
 614 
 615 
 616 abstract class ProductConfig extends BuildConfig {
 617     protected void init(Vector includes, Vector defines) {
 618         defines.add("NDEBUG");
 619         defines.add("PRODUCT");
 620 
 621         super.init(includes, defines);
 622 
 623         getV("CompilerFlags").addAll(getCI().getProductCompilerFlags());
 624         getV("LinkerFlags").addAll(getCI().getProductLinkerFlags());
 625     }
 626 }
 627 
 628 class C1ProductConfig extends ProductConfig {
 629     C1ProductConfig() {
 630         initNames("compiler1", "product", "jvm.dll");
 631         init(getIncludes(), getDefines());
 632     }
 633 }
 634 
 635 class C2ProductConfig extends ProductConfig {
 636     C2ProductConfig() {
 637         initNames("compiler2", "product", "jvm.dll");
 638         init(getIncludes(), getDefines());
 639     }
 640 }
 641 
 642 class TieredProductConfig extends ProductConfig {
 643     TieredProductConfig() {
 644         initNames("tiered", "product", "jvm.dll");
 645         init(getIncludes(), getDefines());
 646     }
 647 }
 648 
 649 
 650 class CoreDebugConfig extends GenericDebugNonKernelConfig {
 651     String getOptFlag() {
 652         return getCI().getNoOptFlag();
 653     }
 654 
 655     CoreDebugConfig() {
 656         initNames("core", "debug", "jvm.dll");
 657         init(getIncludes(), getDefines());
 658     }
 659 }
 660 
 661 
 662 class CoreFastDebugConfig extends GenericDebugNonKernelConfig {
 663     String getOptFlag() {
 664         return getCI().getOptFlag();
 665     }
 666 
 667     CoreFastDebugConfig() {
 668         initNames("core", "fastdebug", "jvm.dll");
 669         init(getIncludes(), getDefines());
 670     }
 671 }
 672 
 673 
 674 class CoreProductConfig extends ProductConfig {
 675     CoreProductConfig() {
 676         initNames("core", "product", "jvm.dll");
 677         init(getIncludes(), getDefines());
 678     }
 679 }
 680 
 681 class KernelDebugConfig extends GenericDebugConfig {
 682     String getOptFlag() {
 683         return getCI().getNoOptFlag();
 684     }
 685 
 686     KernelDebugConfig() {
 687         initNames("kernel", "debug", "jvm.dll");
 688         init(getIncludes(), getDefines());
 689     }
 690 }
 691 
 692 
 693 class KernelFastDebugConfig extends GenericDebugConfig {
 694     String getOptFlag() {
 695         return getCI().getOptFlag();
 696     }
 697 
 698     KernelFastDebugConfig() {
 699         initNames("kernel", "fastdebug", "jvm.dll");
 700         init(getIncludes(), getDefines());
 701     }
 702 }
 703 
 704 
 705 class KernelProductConfig extends ProductConfig {
 706     KernelProductConfig() {
 707         initNames("kernel", "product", "jvm.dll");
 708         init(getIncludes(), getDefines());
 709     }
 710 }
 711 abstract class CompilerInterface {
 712     abstract Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir);
 713     abstract Vector getBaseLinkerFlags(String outDir, String outDll);
 714     abstract Vector getDebugCompilerFlags(String opt);
 715     abstract Vector getDebugLinkerFlags();
 716     abstract void   getAdditionalNonKernelLinkerFlags(Vector rv);
 717     abstract Vector getProductCompilerFlags();
 718     abstract Vector getProductLinkerFlags();
 719     abstract String getOptFlag();
 720     abstract String getNoOptFlag();
 721     abstract String makeCfgName(String flavourBuild);
 722 
 723     void addAttr(Vector receiver, String attr, String value) {
 724         receiver.add(attr); receiver.add(value);
 725     }
 726     void extAttr(Vector receiver, String attr, String value) {
 727         int attr_pos=receiver.indexOf(attr) ;
 728         if ( attr_pos == -1) {
 729           // If attr IS NOT present in the Vector - add it
 730           receiver.add(attr); receiver.add(value);
 731         } else {
 732           // If attr IS present in the Vector - append value to it
 733           receiver.set(attr_pos+1,receiver.get(attr_pos+1)+value);
 734         }
 735     }
 736 }