755 lines
31 KiB
Java
755 lines
31 KiB
Java
|
/*
|
||
|
* 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;
|
||
|
}
|
||
|
}
|
||
|
}
|