1/*
2 * Copyright (c) 2011, 2017, 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
25package build.tools.projectcreator;
26
27import java.io.File;
28import java.io.FileNotFoundException;
29import java.io.IOException;
30import java.io.PrintWriter;
31import java.io.UnsupportedEncodingException;
32import java.nio.file.FileSystems;
33import java.util.Iterator;
34import java.util.LinkedList;
35import java.util.UUID;
36import java.util.Vector;
37
38public 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
319class 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}
472