1 /*
   2  * Copyright (c) 2011, 2016, 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 package build.tools.projectcreator;
  26 
  27 import java.io.File;
  28 import java.io.FileNotFoundException;
  29 import java.io.IOException;
  30 import java.io.PrintWriter;
  31 import java.io.UnsupportedEncodingException;
  32 import java.nio.file.FileSystems;
  33 import java.util.Iterator;
  34 import java.util.LinkedList;
  35 import java.util.UUID;
  36 import java.util.Vector;
  37 
  38 public class WinGammaPlatformVC10 extends WinGammaPlatform {
  39 
  40 
  41    LinkedList <String>filters = new LinkedList<String>();
  42    LinkedList <String[]>filterDeps = new LinkedList<String[]>();
  43 
  44     @Override
  45     protected String getProjectExt() {
  46         return ".vcxproj";
  47     }
  48 
  49     @Override
  50     public void writeProjectFile(String projectFileName, String projectName,
  51             Vector<BuildConfig> allConfigs) throws IOException {
  52         System.out.println();
  53         System.out.println("    Writing .vcxproj file: " + projectFileName);
  54 
  55         String projDir = Util.normalize(new File(projectFileName).getParent());
  56 
  57         printWriter = new PrintWriter(projectFileName, "UTF-8");
  58         printWriter.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  59         startTag("Project",
  60                 "DefaultTargets", "Build",
  61                 "ToolsVersion", "4.0",
  62                 "xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  63         startTag("ItemGroup",
  64                 "Label", "ProjectConfigurations");
  65         for (BuildConfig cfg : allConfigs) {
  66             startTag("ProjectConfiguration",
  67                     "Include", cfg.get("Name"));
  68             tagData("Configuration", cfg.get("Id"));
  69             tagData("Platform", cfg.get("PlatformName"));
  70             endTag();
  71         }
  72         endTag();
  73 
  74         startTag("PropertyGroup", "Label", "Globals");
  75         tagData("ProjectGuid", "{8822CB5C-1C41-41C2-8493-9F6E1994338B}");
  76         tagData("Keyword", "MakeFileProj");
  77         tag("SccProjectName");
  78         tag("SccLocalPath");
  79         endTag();
  80 
  81         tag("Import", "Project", "$(VCTargetsPath)\\Microsoft.Cpp.Default.props");
  82 
  83         for (BuildConfig cfg : allConfigs) {
  84             startTag(cfg, "PropertyGroup", "Label", "Configuration");
  85             tagData("ConfigurationType", "Makefile");
  86             tagData("UseDebugLibraries", "true");
  87             endTag();
  88         }
  89 
  90         tag("Import", "Project", "$(VCTargetsPath)\\Microsoft.Cpp.props");
  91         startTag("ImportGroup", "Label", "ExtensionSettings");
  92         endTag();
  93         for (BuildConfig cfg : allConfigs) {
  94             startTag(cfg, "ImportGroup", "Label", "PropertySheets");
  95             tag("Import",
  96                     "Project", "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props",
  97                     "Condition", "exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')",
  98                     "Label", "LocalAppDataPlatform");
  99             endTag();
 100         }
 101 
 102         tag("PropertyGroup", "Label", "UserMacros");
 103 
 104         startTag("PropertyGroup");
 105         tagData("_ProjectFileVersion", "10.0.30319.1");
 106         for (BuildConfig cfg : allConfigs) {
 107             tagData(cfg, "OutDir", cfg.get("OutputDir") + Util.sep);
 108             tagData(cfg, "IntDir", cfg.get("OutputDir") + Util.sep);
 109             tagData(cfg, "LinkIncremental", "false");
 110         }
 111         for (BuildConfig cfg : allConfigs) {
 112             tagData(cfg, "CodeAnalysisRuleSet", "AllRules.ruleset");
 113             tag(cfg, "CodeAnalysisRules");
 114             tag(cfg, "CodeAnalysisRuleAssemblies");
 115         }
 116         for (BuildConfig cfg : allConfigs) {
 117             tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile hotspot LOG=info");
 118             tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot hotspot LOG=info");
 119             tagData(cfg, "NMakeCleanCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot LOG=info");
 120             tagData(cfg, "NMakeOutput", cfg.get("MakeOutput") + Util.sep + "jvm.dll");
 121             tagData(cfg, "NMakePreprocessorDefinitions", Util.join(";", cfg.getDefines()));
 122             tagData(cfg, "NMakeIncludeSearchPath", Util.join(";", cfg.getIncludes()));
 123         }
 124         endTag();
 125 
 126         for (BuildConfig cfg : allConfigs) {
 127             startTag(cfg, "ItemDefinitionGroup");
 128             startTag("ClCompile");
 129             tagV(cfg.getV("CompilerFlags"));
 130             endTag();
 131 
 132             startTag("Link");
 133             tagV(cfg.getV("LinkerFlags"));
 134             endTag();
 135 
 136             endTag();
 137         }
 138 
 139         writeFiles(allConfigs, projDir);
 140 
 141         tag("Import", "Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets");
 142         startTag("ImportGroup", "Label", "ExtensionTargets");
 143         endTag();
 144 
 145         endTag();
 146         printWriter.close();
 147         System.out.println("    Done writing .vcxproj file.");
 148 
 149         writeFilterFile(projectFileName, projectName, allConfigs, projDir);
 150         writeUserFile(projectFileName, allConfigs);
 151     }
 152 
 153 
 154     private void writeUserFile(String projectFileName, Vector<BuildConfig> allConfigs) throws FileNotFoundException, UnsupportedEncodingException {
 155         String userFileName = projectFileName + ".user";
 156         if (new File(userFileName).exists()) {
 157             return;
 158         }
 159         System.out.print("    Writing .vcxproj.user file: " + userFileName);
 160         printWriter = new PrintWriter(userFileName, "UTF-8");
 161 
 162         printWriter.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
 163         startTag("Project",
 164                 "ToolsVersion", "4.0",
 165                 "xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
 166 
 167         for (BuildConfig cfg : allConfigs) {
 168             startTag(cfg, "PropertyGroup");
 169             tagData("LocalDebuggerCommand", cfg.get("JdkTargetRoot") + "\\bin\\java.exe");
 170             // Since we run "make hotspot-import", we get the correct jvm.dll by java.exe.
 171             // The '-XX:+PauseAtExit' option
 172             // causes the VM to wait for key press before exiting; this
 173             // allows any stdout or stderr messages to be seen before
 174             // the cmdtool exits.
 175             tagData("LocalDebuggerCommandArguments",
 176                     "-XX:+UnlockDiagnosticVMOptions -XX:+PauseAtExit");
 177             tagData("LocalDebuggerEnvironment", "JAVA_HOME=" + cfg.get("JdkTargetRoot"));
 178             endTag();
 179         }
 180 
 181         endTag();
 182         printWriter.close();
 183         System.out.println("    Done.");
 184     }
 185 
 186     public void addFilter(String rPath) {
 187        filters.add(rPath);
 188     }
 189 
 190     public void addFilterDependency(String fileLoc, String filter) {
 191       filterDeps.add(new String[] {fileLoc, filter});
 192     }
 193 
 194     private void writeFilterFile(String projectFileName, String projectName,
 195             Vector<BuildConfig> allConfigs, String base) throws FileNotFoundException, UnsupportedEncodingException {
 196         String filterFileName = projectFileName + ".filters";
 197         System.out.print("    Writing .vcxproj.filters file: " + filterFileName);
 198         printWriter = new PrintWriter(filterFileName, "UTF-8");
 199 
 200         printWriter.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
 201         startTag("Project",
 202                 "ToolsVersion", "4.0",
 203                 "xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
 204 
 205         startTag("ItemGroup");
 206         for (String filter : filters) {
 207            startTag("Filter", "Include",filter);
 208            UUID uuid = UUID.randomUUID();
 209            tagData("UniqueIdentifier", "{" + uuid.toString() + "}");
 210            endTag();
 211         }
 212         endTag();
 213 
 214         //TODO - do I need to split cpp and hpp files?
 215 
 216         // then all files
 217         startTag("ItemGroup");
 218         for (String[] dep : filterDeps) {
 219            String tagName = getFileTagFromSuffix(dep[0]);
 220 
 221            startTag(tagName, "Include", dep[0]);
 222            tagData("Filter", dep[1]);
 223            endTag();
 224         }
 225         endTag();
 226 
 227         endTag();
 228         printWriter.close();
 229         System.out.println("    Done.");
 230     }
 231 
 232     public String getFileTagFromSuffix(String fileName) {
 233        if (fileName.endsWith(".cpp")) {
 234           return"ClCompile";
 235        } else if (fileName.endsWith(".c")) {
 236           return "ClCompile";
 237        } else if (fileName.endsWith(".hpp")) {
 238           return"ClInclude";
 239        } else if (fileName.endsWith(".h")) {
 240           return "ClInclude";
 241        } else {
 242           return"None";
 243        }
 244     }
 245 
 246     void writeFiles(Vector<BuildConfig> allConfigs, String projDir) {
 247        // This code assummes there are no config specific includes.
 248        startTag("ItemGroup");
 249 
 250        String sourceBase = BuildConfig.getFieldString(null, "SourceBase");
 251 
 252        // Use first config for all global absolute includes.
 253        BuildConfig baseConfig = allConfigs.firstElement();
 254        Vector<String> rv = new Vector<String>();
 255 
 256        // Then use first config for all relative includes
 257        Vector<String> ri = new Vector<String>();
 258        baseConfig.collectRelevantVectors(ri, "RelativeSrcInclude");
 259        for (String f : ri) {
 260           rv.add(sourceBase + Util.sep + f);
 261        }
 262 
 263        baseConfig.collectRelevantVectors(rv, "AbsoluteSrcInclude");
 264 
 265        handleIncludes(rv, allConfigs);
 266 
 267        endTag();
 268     }
 269 
 270     // Will visit file tree for each include
 271     private void handleIncludes(Vector<String> includes, Vector<BuildConfig> allConfigs) {
 272        for (String path : includes)  {
 273           FileTreeCreatorVC10 ftc = new FileTreeCreatorVC10(FileSystems.getDefault().getPath(path) , allConfigs, this);
 274           try {
 275              ftc.writeFileTree();
 276           } catch (IOException e) {
 277              e.printStackTrace();
 278           }
 279        }
 280     }
 281 
 282     String buildCond(BuildConfig cfg) {
 283         return "'$(Configuration)|$(Platform)'=='"+cfg.get("Name")+"'";
 284     }
 285 
 286     void tagV(Vector<String> v) {
 287         Iterator<String> i = v.iterator();
 288         while(i.hasNext()) {
 289             String name = i.next();
 290             String data = i.next();
 291             tagData(name, data);
 292         }
 293     }
 294 
 295     void tagData(BuildConfig cfg, String name, String data) {
 296         tagData(name, data, "Condition", buildCond(cfg));
 297     }
 298 
 299     void tag(BuildConfig cfg, String name, String... attrs) {
 300         String[] ss = new String[attrs.length + 2];
 301         ss[0] = "Condition";
 302         ss[1] = buildCond(cfg);
 303         System.arraycopy(attrs, 0, ss, 2, attrs.length);
 304 
 305         tag(name, ss);
 306     }
 307 
 308     void startTag(BuildConfig cfg, String name, String... attrs) {
 309         String[] ss = new String[attrs.length + 2];
 310         ss[0] = "Condition";
 311         ss[1] = buildCond(cfg);
 312         System.arraycopy(attrs, 0, ss, 2, attrs.length);
 313 
 314         startTag(name, ss);
 315     }
 316 
 317 }
 318 
 319 class CompilerInterfaceVC10 extends CompilerInterface {
 320 
 321     @Override
 322     Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) {
 323         Vector rv = new Vector();
 324 
 325         addAttr(rv, "AdditionalIncludeDirectories", Util.join(";", includes));
 326         addAttr(rv, "PreprocessorDefinitions",
 327                 Util.join(";", defines).replace("\\\"", "\""));
 328         addAttr(rv, "PrecompiledHeaderFile", "precompiled.hpp");
 329         addAttr(rv, "PrecompiledHeaderOutputFile", outDir+Util.sep+"vm.pch");
 330         addAttr(rv, "AssemblerListingLocation", outDir);
 331         addAttr(rv, "ObjectFileName", outDir+Util.sep);
 332         addAttr(rv, "ProgramDataBaseFileName", outDir+Util.sep+"jvm.pdb");
 333         // Set /nologo option
 334         addAttr(rv, "SuppressStartupBanner", "true");
 335         // Surpass the default /Tc or /Tp.
 336         addAttr(rv, "CompileAs", "Default");
 337         // Set /W3 option.
 338         addAttr(rv, "WarningLevel", "Level3");
 339         // Set /WX option,
 340         addAttr(rv, "TreatWarningAsError", "true");
 341         // Set /GS option
 342         addAttr(rv, "BufferSecurityCheck", "false");
 343         // Set /Zi option.
 344         addAttr(rv, "DebugInformationFormat", "ProgramDatabase");
 345         // Set /Yu option.
 346         addAttr(rv, "PrecompiledHeader", "Use");
 347         // Set /EHsc- option
 348         addAttr(rv, "ExceptionHandling", "");
 349 
 350         addAttr(rv, "MultiProcessorCompilation", "true");
 351 
 352         return rv;
 353     }
 354 
 355     @Override
 356     Vector getDebugCompilerFlags(String opt, String platformName) {
 357         Vector rv = new Vector();
 358 
 359         // Set /On option
 360         addAttr(rv, "Optimization", opt);
 361         // Set /MD option.
 362         addAttr(rv, "RuntimeLibrary", "MultiThreadedDLL");
 363         // Set /Oy- option
 364         addAttr(rv, "OmitFramePointers", "false");
 365         // Set /homeparams for x64 debug builds
 366         if(platformName.equals("x64")) {
 367             addAttr(rv, "AdditionalOptions", "/homeparams");
 368         }
 369 
 370         return rv;
 371     }
 372 
 373     @Override
 374     Vector getProductCompilerFlags() {
 375         Vector rv = new Vector();
 376 
 377         // Set /O2 option.
 378         addAttr(rv, "Optimization", "MaxSpeed");
 379         // Set /Oy- option
 380         addAttr(rv, "OmitFramePointers", "false");
 381         // Set /Ob option.  1 is expandOnlyInline
 382         addAttr(rv, "InlineFunctionExpansion", "OnlyExplicitInline");
 383         // Set /GF option.
 384         addAttr(rv, "StringPooling", "true");
 385         // Set /MD option. 2 is rtMultiThreadedDLL
 386         addAttr(rv, "RuntimeLibrary", "MultiThreadedDLL");
 387         // Set /Gy option
 388         addAttr(rv, "FunctionLevelLinking", "true");
 389 
 390         return rv;
 391     }
 392 
 393     @Override
 394     Vector getBaseLinkerFlags(String outDir, String outDll, String platformName) {
 395         Vector rv = new Vector();
 396 
 397         if(platformName.equals("Win32")) {
 398             addAttr(rv, "AdditionalOptions",
 399                     "/export:JNI_GetDefaultJavaVMInitArgs " +
 400                     "/export:JNI_CreateJavaVM " +
 401                     "/export:JVM_FindClassFromBootLoader "+
 402                     "/export:JNI_GetCreatedJavaVMs "+
 403                     "/export:jio_snprintf /export:jio_printf "+
 404                     "/export:jio_fprintf /export:jio_vfprintf "+
 405                     "/export:jio_vsnprintf "+
 406                     "/export:JVM_GetVersionInfo "+
 407                     "/export:JVM_InitAgentProperties");
 408         }
 409         addAttr(rv, "AdditionalDependencies", "kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;Wsock32.lib;winmm.lib;psapi.lib;version.lib");
 410         addAttr(rv, "OutputFile", outDll);
 411         addAttr(rv, "SuppressStartupBanner", "true");
 412         addAttr(rv, "ModuleDefinitionFile", outDir+Util.sep+"vm.def");
 413         addAttr(rv, "ProgramDatabaseFile", outDir+Util.sep+"jvm.pdb");
 414         addAttr(rv, "SubSystem", "Windows");
 415         addAttr(rv, "BaseAddress", "0x8000000");
 416         addAttr(rv, "ImportLibrary", outDir+Util.sep+"jvm.lib");
 417 
 418         if(platformName.equals("Win32")) {
 419             addAttr(rv, "TargetMachine", "MachineX86");
 420         } else {
 421             addAttr(rv, "TargetMachine", "MachineX64");
 422         }
 423 
 424         // We always want the /DEBUG option to get full symbol information in the pdb files
 425         addAttr(rv, "GenerateDebugInformation", "true");
 426 
 427         return rv;
 428     }
 429 
 430     @Override
 431     Vector getDebugLinkerFlags() {
 432         Vector rv = new Vector();
 433 
 434         // Empty now that /DEBUG option is used by all configs
 435 
 436         return rv;
 437     }
 438 
 439     @Override
 440     Vector getProductLinkerFlags() {
 441         Vector rv = new Vector();
 442 
 443         // Set /OPT:REF option.
 444         addAttr(rv, "OptimizeReferences", "true");
 445         // Set /OPT:ICF option.
 446         addAttr(rv, "EnableCOMDATFolding", "true");
 447 
 448         return rv;
 449     }
 450 
 451     @Override
 452     void getAdditionalNonKernelLinkerFlags(Vector rv) {
 453         extAttr(rv, "AdditionalOptions", " /export:AsyncGetCallTrace");
 454     }
 455 
 456     @Override
 457     String getOptFlag() {
 458         return "MaxSpeed";
 459     }
 460 
 461     @Override
 462     String getNoOptFlag() {
 463         return "Disabled";
 464     }
 465 
 466     @Override
 467     String makeCfgName(String flavourBuild, String platform) {
 468         return  flavourBuild + "|" + platform;
 469     }
 470 
 471 }