| /* | |
| * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| * | |
| */ | |
| import java.io.File; | |
| import java.io.IOException; | |
| import java.nio.file.FileSystemLoopException; | |
| import java.nio.file.FileVisitResult; | |
| import java.nio.file.FileVisitor; | |
| import java.nio.file.Files; | |
| import java.nio.file.Path; | |
| import java.nio.file.Paths; | |
| import java.nio.file.attribute.BasicFileAttributes; | |
| import java.nio.file.attribute.PosixFilePermission; | |
| import java.util.ArrayList; | |
| import java.util.HashMap; | |
| import java.util.HashSet; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Set; | |
| import java.util.TreeSet; | |
| public final class XcodeProjectMaker { | |
| private static final String JDK_SCRIPT_TOKEN_1 = "configure"; | |
| private static final String JDK_SCRIPT_TOKEN_2 = ".jcheck"; | |
| private static final String COMPILER_LINE_HEADER = "-I"; | |
| private static final String COMPILER_IFRAMEWORK = "-iframework"; | |
| private static final String COMPILER_FFRAMEWORK = "-F"; | |
| private static final String SRC_HOTSPOT_PATH = "/src/hotspot"; | |
| private static final String TEST_HOTSPOT_PATH = "/test/hotspot/gtest"; | |
| private static final String ALIAS_JAVA_OLD = "java_old.sh"; | |
| private static final String ALIAS_JAVA_NEW = "java_new.sh"; | |
| private static final String JDK_BIN_JAVA = "/jdk/bin/java"; | |
| private static final String FILE_TOKEN = "\"file\": "; | |
| private static final String COMMAND_TOKEN = "\"command\": "; | |
| private static final String QUOTE_START_TOKEN = "'\\\""; | |
| private static final String QUOTE_END_TOKEN = "\\\"'"; | |
| private static final String VERSION = "2.0.0"; | |
| private static final String EXCLUDE_PARSE_TOKEN_1 = "gtest"; | |
| private static final String TEMPLATE_FRAMEWORK_SEARCH_PATHS = "TEMPLATE_FRAMEWORK_SEARCH_PATHS"; | |
| private static final String TEMPLATE_OTHER_CFLAGS = "TEMPLATE_OTHER_CFLAGS"; | |
| private static final String TEMPLATE_OTHER_LDFLAGS = "TEMPLATE_OTHER_LDFLAGS"; | |
| private static final String TEMPLATE_USER_HEADER_SEARCH_PATHS = "TEMPLATE_USER_HEADER_SEARCH_PATHS"; | |
| private static final String TEMPLATE_GROUP_GENSRC = "TEMPLATE_GROUP_GENSRC"; | |
| private static final String TEMPLATE_GROUP_SRC = "TEMPLATE_GROUP_SRC"; | |
| private static final String TEMPLATE_GROUP_TEST = "TEMPLATE_GROUP_TEST"; | |
| private static final String TEMPLATE_GROUPS = "TEMPLATE_GROUPS"; | |
| private static final String TEMPLATE_PBXBUILDFILE = "TEMPLATE_PBXBUILDFILE"; | |
| private static final String TEMPLATE_PBXFILEREFERENCE = "TEMPLATE_PBXFILEREFERENCE"; | |
| private static final String TEMPLATE_PBXSOURCESSBUILDPHASE = "TEMPLATE_PBXSOURCESSBUILDPHASE"; | |
| private static final String TEMPLATE_JDK_PATH = "TEMPLATE_JDK_PATH"; | |
| private static final String HOTSPOT_PBXPROJ = "hotspot.xcodeproj"; | |
| private static final String PBXPROJ = "project.pbxproj"; | |
| private static final String XCSAHAREDDATA = "xcshareddata"; | |
| private static final String XCSCHEMES = "xcschemes"; | |
| private static final String JVM_XCSCHEME = "jvm.xcscheme"; | |
| private static final String J2D_XCSCHEME = "runJ2Demo.xcscheme"; | |
| private static final String XCDEBUGGER = "xcdebugger"; | |
| private static final String XCBKPTLIST = "Breakpoints_v2.xcbkptlist"; | |
| private static final String TEMPLATE_PBXPROJ = PBXPROJ + ".template"; | |
| private static final String TEMPLATE_JVM_XCSCHEME = JVM_XCSCHEME + ".template"; | |
| private static final String TEMPLATE_J2D_XCSCHEME = J2D_XCSCHEME + ".template"; | |
| private static final String TEMPLATE_XCBKPTLIST = XCBKPTLIST + ".template"; | |
| private static final String[] EXCLUDE_FILES_PREFIX = {"."}; | |
| private static final String[] EXCLUDE_FILES_POSTFIX = {".log", ".cmdline"}; | |
| private static final String[] COMPILER_FLAGS_INCLUDE = {"-m", "-f", "-D", "-W"}; | |
| private static final String[] COMPILER_FLAGS_IS = {"-g", "-Os", "-0"}; | |
| private static final String[] COMPILER_FLAGS_EXCLUDE = {"-DTHIS_FILE", "-DGTEST_OS_MAC", "-mmacosx-version-min", "-Werror"}; // "-Werror" causes Xcode to stop compiling | |
| private static final int EXIT4 = -4; | |
| private static final int EXIT5 = -5; | |
| private static final int EXIT6 = -6; | |
| private static final int EXIT7 = -7; | |
| private final HashMap<String, ArrayList<String>> compiledFiles = new HashMap<>(); | |
| private final TreeSet<String> compilerFlags = new TreeSet<>(); | |
| private List<String> linkerFlags = List.of(); | |
| private final TreeSet<String> headerPaths = new TreeSet<>(); | |
| private final boolean debugLog; | |
| private String projectMakerDataPath = null; | |
| private String generatedHotspotPath = null; | |
| private String iframework = null; | |
| private String fframework = null; | |
| private DiskFile rootGensrc = new DiskFile("/", true); | |
| private DiskFile rootSrc = new DiskFile("/", true); | |
| private DiskFile rootTest = new DiskFile("/", true); | |
| public XcodeProjectMaker(boolean debugLog) { | |
| this.debugLog = debugLog; | |
| } | |
| public static void main(String[] args) { | |
| String workspaceRoot = args[0]; | |
| String outputDir = args[1]; | |
| String pathToProjectMakerData = args[2]; | |
| String pathToCompileCommands = args[3]; | |
| String pathToLinkerOptionsFile = args[4]; | |
| String linkerOptionsString = readFile(pathToLinkerOptionsFile); | |
| boolean debugLog = args.length > 5 && args[5].equals("-d"); | |
| File xcodeFolder = new File(outputDir); | |
| xcodeFolder.mkdirs(); | |
| String workspaceRootPathFromOutputDir = findRelativePathToWorkspaceRoot(outputDir); | |
| if (debugLog) { | |
| System.out.println(); | |
| System.out.println("Version " + VERSION); | |
| System.out.println(); | |
| System.out.println(" Path to workspace root is \"" + workspaceRoot + "\""); | |
| System.out.println("Path to compile commands file is \"" + pathToCompileCommands + "\""); | |
| System.out.println(" Xcode project will be placed in \"" + outputDir + "\""); | |
| System.out.println(); | |
| } | |
| XcodeProjectMaker maker = new XcodeProjectMaker(debugLog); | |
| maker.parseHotspotCompileCommands(pathToCompileCommands); | |
| maker.linkerFlags = List.of(linkerOptionsString.split(" ")); | |
| maker.projectMakerDataPath = pathToProjectMakerData; | |
| maker.printLogDetails(); | |
| maker.prepareFiles(workspaceRoot); | |
| maker.makeXcodeProj(outputDir, workspaceRootPathFromOutputDir); | |
| String pathToBuild = getFileParent(outputDir); | |
| maker.makeAliases(outputDir, pathToBuild); | |
| System.out.println(); | |
| System.out.println("The Xcode project for hotspot was succesfully created"); | |
| System.out.println("It can be found in '" + outputDir + "/" + HOTSPOT_PBXPROJ + "'"); | |
| System.out.println(); | |
| } | |
| // find a path to what looks like jdk | |
| private static String findRelativePathToWorkspaceRoot(String root) { | |
| String pathToWorkspaceRoot = null; | |
| String path = root; | |
| boolean found1 = false; | |
| boolean found2 = false; | |
| while (!found1 && !found2) { | |
| File folder = new File(path); | |
| File[] files = folder.listFiles(); | |
| for (File file : files) { | |
| String fileName = file.toPath().getFileName().toString(); | |
| if (fileName.equals(JDK_SCRIPT_TOKEN_1)) { | |
| found1 = true; | |
| } | |
| if (fileName.equals(JDK_SCRIPT_TOKEN_2)) { | |
| found2 = true; | |
| } | |
| if (found1 && found2) { | |
| break; | |
| } | |
| } | |
| if (!found1 && !found2) { | |
| path = Paths.get(path).getParent().toString(); | |
| if (pathToWorkspaceRoot == null) { | |
| pathToWorkspaceRoot = ".."; | |
| } else { | |
| pathToWorkspaceRoot += "/.."; | |
| } | |
| } | |
| } | |
| return pathToWorkspaceRoot; | |
| } | |
| private static String readFile(File file) { | |
| return readFile(file.toPath()); | |
| } | |
| private static String readFile(String path) { | |
| return readFile(Paths.get(path)); | |
| } | |
| private static String readFile(Path path) { | |
| try { | |
| return Files.readString(path); | |
| } catch (IOException e) { | |
| e.printStackTrace(); | |
| return null; | |
| } | |
| } | |
| private static void writeFile(File file, String string) { | |
| writeFile(file.toPath(), string); | |
| } | |
| private static void writeFile(Path path, String string) { | |
| try { | |
| Files.writeString(path, string); | |
| } catch (IOException e) { | |
| e.printStackTrace(); | |
| System.exit(EXIT4); | |
| } | |
| } | |
| private static boolean excludeFile(Path path) { | |
| return excludeFile(path.toString()); | |
| } | |
| private static boolean excludeFile(String string) { | |
| return excludeFile(string, null); | |
| } | |
| private static boolean excludeFile(String string, String exclude) { | |
| if (exclude != null) { | |
| if (contains(string, exclude)) { | |
| return true; | |
| } | |
| } | |
| for (String excludeFilesPrefix : EXCLUDE_FILES_PREFIX) { | |
| if (string.startsWith(excludeFilesPrefix)) { | |
| return true; | |
| } | |
| } | |
| for (String excludeFilesPostfix : EXCLUDE_FILES_POSTFIX) { | |
| if (string.endsWith(excludeFilesPostfix)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| private static boolean isExcludeCompilerFlag(String string) { | |
| boolean flag = false; | |
| for (String exclude : COMPILER_FLAGS_EXCLUDE) { | |
| if (string.contains(exclude)) { | |
| flag = true; | |
| break; | |
| } | |
| } | |
| return flag; | |
| } | |
| private static boolean isCompilerFlag(String string) { | |
| boolean flag = false; | |
| for (String include : COMPILER_FLAGS_INCLUDE) { | |
| if (string.startsWith(include)) { | |
| flag = true; | |
| break; | |
| } | |
| } | |
| for (String is : COMPILER_FLAGS_IS) { | |
| if (string.equals(is)) { | |
| flag = true; | |
| break; | |
| } | |
| } | |
| if (isExcludeCompilerFlag(string)) { | |
| flag = false; | |
| } | |
| return flag; | |
| } | |
| private static String strip(String string) { | |
| return string.substring(2, string.length() - 1); | |
| } | |
| private static String strip(String string, String token) { | |
| int start = string.indexOf(token); | |
| int end = start + token.length(); | |
| return strip(string.substring(end)); | |
| } | |
| private static boolean contains(String string, String token) { | |
| return ((string.length() >= token.length()) && (string.contains(token))); | |
| } | |
| private static String getFileParent(String path) { | |
| return Paths.get(path).getParent().toString(); | |
| } | |
| private static String extractPath(String string, String from, String to) { | |
| String result = null; | |
| String[] tokens = string.split("/"); | |
| int i = 0; | |
| for (; i < tokens.length; i++) { | |
| if (tokens[i].equals(from)) { | |
| result = ""; | |
| break; | |
| } | |
| } | |
| for (; i < tokens.length; i++) { | |
| result += "/" + tokens[i]; | |
| if (tokens[i].equals(to)) { | |
| break; | |
| } | |
| } | |
| return result; | |
| } | |
| private void extractCommonCompilerFlags() { | |
| // heuristic, find average count of number of flags used by each compiled file | |
| int countFiles = 0; | |
| int countFlags = 0; | |
| for (Map.Entry<String, ArrayList<String>> entry : this.compiledFiles.entrySet()) { | |
| countFiles++; | |
| List<String> flags = entry.getValue(); | |
| countFlags += flags.size(); | |
| } | |
| // when finding common flags, only consider files with this many flags | |
| int flagCutoff = (countFlags / countFiles) / 2; | |
| // collect all flags | |
| for (Map.Entry<String, ArrayList<String>> entry : this.compiledFiles.entrySet()) { | |
| List<String> flags = entry.getValue(); | |
| if (flags.size() > flagCutoff) { | |
| this.compilerFlags.addAll(flags); | |
| } | |
| } | |
| // find flags to remove | |
| Set<String> removeFlags = new TreeSet<>(); | |
| for (Map.Entry<String, ArrayList<String>> entry : this.compiledFiles.entrySet()) { | |
| List<String> flags = entry.getValue(); | |
| if (flags.size() > flagCutoff) { | |
| for (String common : this.compilerFlags) { | |
| if (!flags.contains(common)) { | |
| removeFlags.add(common); | |
| } | |
| } | |
| } | |
| } | |
| // leave only common flags | |
| for (String flag : removeFlags) { | |
| this.compilerFlags.remove(flag); | |
| } | |
| // remove common flags from each compiler file, leaving only the unique ones | |
| for (Map.Entry<String, ArrayList<String>> entry : this.compiledFiles.entrySet()) { | |
| List<String> flags = entry.getValue(); | |
| if (flags.size() > flagCutoff) { | |
| for (String common : this.compilerFlags) { | |
| flags.remove(common); | |
| } | |
| } | |
| } | |
| } | |
| private void extractCompilerFlags(String line) { | |
| boolean verboseCompilerTokens = false; | |
| String file = null; | |
| ArrayList<String> flags = null; | |
| String[] commands = line.split(","); | |
| for (String command : commands) { | |
| if (contains(command, FILE_TOKEN)) { | |
| file = strip(command, FILE_TOKEN); | |
| //verbose_compiler_tokens = Contains(file, "vm_version.cpp"); | |
| } else if (contains(command, COMMAND_TOKEN)) { | |
| String tokens = strip(command, COMMAND_TOKEN); | |
| String[] arguments = tokens.split(" "); | |
| if (arguments.length >= 3) { | |
| flags = new ArrayList<>(); | |
| for (int a = 2; a < arguments.length; a++) { | |
| String argument = arguments[a]; | |
| if (isCompilerFlag(argument)) { | |
| // catch argument like -DVMTYPE=\"Minimal\" | |
| if (contains(argument, "\\\\\\\"") && argument.endsWith("\\\\\\\"")) { | |
| // TODO: more robust fix needed here | |
| argument = argument.replace("\\", ""); | |
| argument = argument.replaceFirst("\"", "~.~"); // temp token ~.~ | |
| argument = argument.replace("\"", "\\\"'"); | |
| argument = argument.replace("~.~", "'\\\""); | |
| } | |
| // argument like -DHOTSPOT_VM_DISTRO='\"Java HotSpot(TM)\"' | |
| // gets split up, so reconstruct as single string | |
| if (contains(argument, QUOTE_START_TOKEN) && !argument.endsWith(QUOTE_END_TOKEN)) { | |
| String fullArgument = argument; | |
| do { | |
| ++a; | |
| argument = arguments[a]; | |
| fullArgument = fullArgument + " " + argument; | |
| } while (!argument.endsWith(QUOTE_END_TOKEN)); | |
| argument = fullArgument; | |
| } | |
| flags.add(argument); | |
| if (verboseCompilerTokens) { | |
| System.out.println(" FOUND COMPILER FLAG: " + argument); | |
| } | |
| } else if (argument.startsWith(COMPILER_LINE_HEADER)) { | |
| this.headerPaths.add(argument.substring(2)); | |
| } else if (argument.equals(COMPILER_IFRAMEWORK)) { | |
| if (iframework == null) { | |
| ++a; | |
| this.iframework = arguments[a]; // gets the value, so skip it for the next loop | |
| } | |
| } else if (argument.equals(COMPILER_FFRAMEWORK)) { | |
| if (fframework == null) { | |
| ++a; | |
| this.fframework = arguments[a]; // gets the value, so skip it for the next loop | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| if ((file != null) && (flags != null)) { | |
| this.compiledFiles.put(file, flags); | |
| } else { | |
| System.err.println(" WARNING: extractCompilerFlags returns file:" + file + ", flags:" + flags); | |
| } | |
| if (verboseCompilerTokens) { | |
| System.exit(0); | |
| } | |
| } | |
| public void parseHotspotCompileCommands(String path) { | |
| String content = readFile(path); | |
| String[] parts = content.split("\\{"); // } | |
| int found = 0; | |
| for (String line : parts) { | |
| if (!contains(line, EXCLUDE_PARSE_TOKEN_1) && !line.startsWith("[")) { | |
| extractCompilerFlags(line); | |
| found++; | |
| } | |
| } | |
| if (debugLog) { | |
| System.out.println("Found total of " + found + " files that make up the libjvm.dylib"); | |
| } | |
| extractCommonCompilerFlags(); | |
| // figure out "gensrc" folder | |
| // from: "/Users/gerard/Desktop/jdk_test/jdk10/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/gensrc/adfiles/ad_x86_clone.cpp" | |
| // to: "/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/gensrc" | |
| for (Map.Entry<String, ArrayList<String>> entry : this.compiledFiles.entrySet()) { | |
| String file = entry.getKey(); | |
| if (file.contains("gensrc")) { | |
| this.generatedHotspotPath = extractPath(file, "build", "gensrc"); | |
| //generatedHotspotPath = "/build/macosx-x64/hotspot/variant-server/gensrc"; | |
| //generatedHotspotPath = "/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/gensrc"; | |
| } | |
| } | |
| } | |
| // https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/essential/io/examples/Copy.java | |
| private DiskFile getHotspotFiles(DiskFile root, String workspaceRoot, String hotspotPath) { | |
| File file = new File(workspaceRoot + "/" + hotspotPath); | |
| if (!file.exists()) { | |
| return null; | |
| } | |
| try { | |
| final Path rootDir = Paths.get(workspaceRoot + hotspotPath); | |
| Files.walkFileTree(rootDir, new HotspotFileVisitor(root, hotspotPath)); | |
| } catch (IOException ex) { | |
| System.err.println("ex: " + ex); | |
| } | |
| return root; | |
| } | |
| public void prepareFiles(String workspaceRoot) { | |
| this.rootGensrc = getHotspotFiles(this.rootGensrc, workspaceRoot, this.generatedHotspotPath); | |
| this.rootSrc = getHotspotFiles(this.rootSrc, workspaceRoot, SRC_HOTSPOT_PATH); | |
| this.rootTest = getHotspotFiles(this.rootTest, workspaceRoot, TEST_HOTSPOT_PATH); | |
| // make a copy of files from the log | |
| Set<String> logFiles = new TreeSet<>(this.compiledFiles.keySet()); | |
| int totalMarkedFiles = 0; | |
| DiskFile[] roots = { this.rootGensrc, this.rootSrc }; | |
| for (DiskFile root : roots) { | |
| List<DiskFile> diskFiles = root.getFiles(); | |
| for (DiskFile diskFile : diskFiles) { | |
| if (!diskFile.isDirectory()) { | |
| String logFileProcessed = null; | |
| String diskFilePath = diskFile.getFilePath(); | |
| for (String logFilePath : logFiles) { | |
| if (contains(logFilePath, diskFilePath)) { | |
| totalMarkedFiles++; | |
| logFileProcessed = logFilePath; | |
| // mark the file as needing compilation | |
| diskFile.markAsCompiled(this.compiledFiles.get(logFilePath)); | |
| // break early if found | |
| break; | |
| } | |
| } | |
| if (logFileProcessed != null) { | |
| // remove the file, so we don't have to search through it again | |
| logFiles.remove(logFileProcessed); | |
| } | |
| } | |
| } | |
| } | |
| if (this.compiledFiles.size() != totalMarkedFiles) { | |
| System.err.println("\nError: was expecting to compile " + this.compiledFiles.size() + " files, but marked " + totalMarkedFiles); | |
| for (String file : logFiles) { | |
| System.err.println("file: " + file); | |
| } | |
| System.exit(EXIT5); | |
| } | |
| if (!logFiles.isEmpty()) { | |
| System.err.println("\nError: unprocessed files left over:"); | |
| for (String logFile : logFiles) { | |
| System.err.println(" " + logFile); | |
| } | |
| System.exit(EXIT6); | |
| } | |
| } | |
| public void printLogDetails() { | |
| if (!debugLog) return; | |
| System.out.println("\nFound " + this.compilerFlags.size() + " common compiler flags:"); | |
| for (String flag : this.compilerFlags) { | |
| System.out.println(" " + flag); | |
| } | |
| System.out.println("\nList of compiled files (each one uses common compiler flags plus extra ones as specified):"); | |
| int count = 1; | |
| for (Map.Entry<String, ArrayList<String>> entry : this.compiledFiles.entrySet()) { | |
| String file = entry.getKey(); | |
| System.out.format("%4d: %s\n", (count), file); | |
| count++; | |
| List<String> flags = entry.getValue(); | |
| for (String flag : flags) { | |
| System.out.println(" " + flag); | |
| } | |
| } | |
| System.out.println("\nFound " + this.linkerFlags.size() + " linker flags:"); | |
| for (String flag : this.linkerFlags) { | |
| System.out.println(" " + flag); | |
| } | |
| System.out.println("\nFound " + this.headerPaths.size() + " header paths:"); | |
| for (String header : this.headerPaths) { | |
| System.out.println(" " + header); | |
| } | |
| System.out.println("\nFrameworks:"); | |
| System.out.println(" -iframework " + iframework); | |
| System.out.println(" -f " + fframework); | |
| } | |
| private String makeProjectPbxproj(String workspaceRootPathFromOutputDir, String string) { | |
| String cFlags = ""; | |
| for (String flag : this.compilerFlags) { | |
| cFlags += " \"" + flag.replace("\"", "\\\\\"") + "\",\n"; | |
| } | |
| cFlags = cFlags.substring(0, cFlags.length() - 2); | |
| string = string.replaceFirst(TEMPLATE_OTHER_CFLAGS, cFlags); | |
| String ldFlags = ""; | |
| for (String flag : this.linkerFlags) { | |
| ldFlags += " \"" + flag + "\",\n"; | |
| } | |
| ldFlags = ldFlags.substring(0, ldFlags.length() - 2); | |
| string = string.replaceFirst(TEMPLATE_OTHER_LDFLAGS, ldFlags); | |
| String headerPaths = ""; | |
| for (String header : this.headerPaths) { | |
| headerPaths += " \"" + header + "\",\n"; | |
| } | |
| headerPaths = headerPaths.substring(0, headerPaths.length() - 2); | |
| string = string.replaceFirst(TEMPLATE_USER_HEADER_SEARCH_PATHS, headerPaths); | |
| String frameworkPaths = ""; | |
| if (fframework != null) { | |
| frameworkPaths += " \"" + fframework + "\"\n"; | |
| } | |
| string = string.replaceFirst(TEMPLATE_FRAMEWORK_SEARCH_PATHS, frameworkPaths); | |
| DiskFile gensrcFile = this.rootGensrc.getChild("gensrc"); | |
| string = string.replaceFirst(TEMPLATE_GROUP_GENSRC, " " + gensrcFile.getXcodeId()); | |
| DiskFile srcFile = this.rootSrc.getChild("src"); | |
| string = string.replaceFirst(TEMPLATE_GROUP_SRC, " " + srcFile.getXcodeId()); | |
| DiskFile testFile = this.rootTest.getChild("test"); | |
| string = string.replaceFirst(TEMPLATE_GROUP_TEST, " " + testFile.getXcodeId()); | |
| String gensrcGroups = gensrcFile.generatePbxGroup(); | |
| String srcGroups = srcFile.generatePbxGroup(); | |
| String testGroups = testFile.generatePbxGroup(); | |
| string = string.replaceFirst(TEMPLATE_GROUPS, gensrcGroups + srcGroups + testGroups); | |
| String gensrcFiles = gensrcFile.generatePbxFileReference(workspaceRootPathFromOutputDir); | |
| String srcFiles = srcFile.generatePbxFileReference(workspaceRootPathFromOutputDir); | |
| String testFiles = testFile.generatePbxFileReference(workspaceRootPathFromOutputDir); | |
| string = string.replaceFirst(TEMPLATE_PBXFILEREFERENCE, gensrcFiles + srcFiles + testFiles); | |
| String gensrcCompiled = gensrcFile.generatePbxBuildFile(); | |
| String compiled = srcFile.generatePbxBuildFile(); | |
| string = string.replaceFirst(TEMPLATE_PBXBUILDFILE, gensrcCompiled + compiled); | |
| String gensrcBuilt = gensrcFile.generatePbxSourcesBuildPhase(); | |
| String built = srcFile.generatePbxSourcesBuildPhase(); | |
| string = string.replaceFirst(TEMPLATE_PBXSOURCESSBUILDPHASE, gensrcBuilt + built); | |
| return string; | |
| } | |
| private String makeTemplateXcscheme(String outputDir, String string) { | |
| string = string.replaceAll(TEMPLATE_JDK_PATH, outputDir); | |
| return string; | |
| } | |
| public void makeXcodeProj(String outputDir, String workspaceRootPathFromOutputDir) { | |
| /* | |
| jvm.xcodeproj <-- folder | |
| project.pbxproj <-- file | |
| xcshareddata <-- folder | |
| xcschemes <-- folder | |
| jvm.xcscheme <-- file | |
| xcdebugger <-- folder | |
| Breakpoints_v2.xcbkptlist <-- file | |
| */ | |
| File xcodeDir = new File(outputDir); | |
| File jvmXcodeprojDir = new File(xcodeDir, HOTSPOT_PBXPROJ); | |
| File projectPbxprojFile = new File(jvmXcodeprojDir, PBXPROJ); | |
| File xcshareddataDir = new File(jvmXcodeprojDir, XCSAHAREDDATA); | |
| File xcschemesDir = new File(xcshareddataDir, XCSCHEMES); | |
| File jvmXcschemeFile = new File(xcschemesDir, JVM_XCSCHEME); | |
| File j2DemoXcschemeFile = new File(xcschemesDir, J2D_XCSCHEME); | |
| File xcdebuggerDir = new File(xcshareddataDir, XCDEBUGGER); | |
| File jBreakpointsV2XcbkptlistFile = new File(xcdebuggerDir, XCBKPTLIST); | |
| if (xcodeDir.exists()) { | |
| xcodeDir.delete(); | |
| } | |
| jvmXcodeprojDir.mkdirs(); | |
| xcshareddataDir.mkdirs(); | |
| xcschemesDir.mkdirs(); | |
| xcdebuggerDir.mkdirs(); | |
| File dataDir = new File(projectMakerDataPath); | |
| File templateProjectPbxprojFile = new File(dataDir, TEMPLATE_PBXPROJ); | |
| File templateJvmXcschemeFile = new File(dataDir, TEMPLATE_JVM_XCSCHEME); | |
| File templateJ2DemoXcschemeFile = new File(dataDir, TEMPLATE_J2D_XCSCHEME); | |
| File templateJBreakpointsV2XcbkptlistFile = new File(dataDir, TEMPLATE_XCBKPTLIST); | |
| String projectPbxprojString = readFile(templateProjectPbxprojFile); | |
| String jvmXcschemeString = readFile(templateJvmXcschemeFile); | |
| String j2DemoXcschemeString = readFile(templateJ2DemoXcschemeFile); | |
| String jBreakpointsV2XcbkptlistString = readFile(templateJBreakpointsV2XcbkptlistFile); | |
| writeFile(projectPbxprojFile, makeProjectPbxproj(workspaceRootPathFromOutputDir, projectPbxprojString)); | |
| writeFile(jvmXcschemeFile, makeTemplateXcscheme(outputDir, jvmXcschemeString)); | |
| writeFile(j2DemoXcschemeFile, makeTemplateXcscheme(outputDir, j2DemoXcschemeString)); | |
| writeFile(jBreakpointsV2XcbkptlistFile, jBreakpointsV2XcbkptlistString); | |
| } | |
| public void makeAliases(String outputDir, String pathToBuild) { | |
| File xcodeDir = new File(outputDir); | |
| File jdkOldSh = new File(xcodeDir, ALIAS_JAVA_OLD); | |
| File jdkNewSh = new File(xcodeDir, ALIAS_JAVA_NEW); | |
| writeFile(jdkOldSh, "#!/bin/bash\n" + pathToBuild + JDK_BIN_JAVA + " $@"); | |
| writeFile(jdkNewSh, "#!/bin/bash\n" + outputDir + "/build" + JDK_BIN_JAVA + " $@"); | |
| try { | |
| Set<PosixFilePermission> permissions = new HashSet<>(); | |
| permissions.add(PosixFilePermission.OWNER_READ); | |
| permissions.add(PosixFilePermission.OWNER_WRITE); | |
| permissions.add(PosixFilePermission.OWNER_EXECUTE); | |
| permissions.add(PosixFilePermission.GROUP_READ); | |
| permissions.add(PosixFilePermission.OTHERS_READ); | |
| Files.setPosixFilePermissions(jdkOldSh.toPath(), permissions); | |
| Files.setPosixFilePermissions(jdkNewSh.toPath(), permissions); | |
| } catch (IOException ex) { | |
| System.err.println("Warning: unable to change file permissions"); | |
| System.err.println(ex); | |
| } | |
| } | |
| private static class HotspotFileVisitor implements FileVisitor<Path> { | |
| private final DiskFile root; | |
| private final String hotspotPath; | |
| public HotspotFileVisitor(DiskFile root, String hotspotPath) { | |
| this.root = root; | |
| this.hotspotPath = hotspotPath; | |
| } | |
| @Override | |
| public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) { | |
| if (excludeFile(path)) { | |
| return FileVisitResult.SKIP_SUBTREE; | |
| } else { | |
| // consider folders based on their names | |
| Path file = path.getFileName(); | |
| if (!excludeFile(file)) { | |
| root.addDirectory(path, hotspotPath); | |
| return FileVisitResult.CONTINUE; | |
| } else { | |
| // skip folders with names beginning with ".", etc | |
| return FileVisitResult.SKIP_SUBTREE; | |
| } | |
| } | |
| } | |
| @Override | |
| public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { | |
| Path file = path.getFileName(); | |
| if (!excludeFile(file)) { | |
| //System.err.println(path.toString()); | |
| root.addFile(path, hotspotPath); | |
| } | |
| return FileVisitResult.CONTINUE; | |
| } | |
| @Override | |
| public FileVisitResult postVisitDirectory(Path path, IOException exc) { | |
| return FileVisitResult.CONTINUE; | |
| } | |
| @Override | |
| public FileVisitResult visitFileFailed(Path path, IOException exc) { | |
| if (exc instanceof FileSystemLoopException) { | |
| System.err.println("cycle detected: " + path); | |
| } else { | |
| System.err.format("Unable to process: %s: %s\n", path, exc); | |
| } | |
| return FileVisitResult.CONTINUE; | |
| } | |
| } | |
| } |