/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program 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 program 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 at /legal/license.txt).
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package makedep;
import java.io.*;
import java.util.*;
public class Database {
private MacroDefinitions macros;
// allFiles is kept in lexicographically sorted order. See get().
private FileList allFiles;
// files that have implicit dependency on platform files
// e.g. os.hpp: os_<os_family>.hpp os_<os_arch>.hpp but only
// recorded if the platform file was seen.
private FileList platformFiles;
private FileList outerFiles;
private FileList indivIncludes;
private FileList grandInclude; // the results for the grand include file
private long threshold;
private int nOuterFiles;
private int nPrecompiledFiles;
private boolean missingOk;
private Platform plat;
/** These allow you to specify files not in the include database
which are prepended and appended to the file list, allowing
you to have well-known functions at the start and end of the
text segment (allows us to find out in a portable fashion
whether the current PC is in VM code or not upon a crash) */
private String firstFile;
private String lastFile;
private boolean resolveVpath;
private int sourceMergerLimit = 0;
private String workspace;
private String genDir;
private Vector vpaths = null;
private Hashtable resolvedFileNames;
private Hashtable grandIncludeEntries = new Hashtable();
static private String outputDir = ".";
public Database(Platform plat, long t) {
this.plat = plat;
macros = new MacroDefinitions();
allFiles = new FileList("allFiles", plat);
platformFiles = new FileList("platformFiles", plat);
outerFiles = new FileList("outerFiles", plat);
indivIncludes = new FileList("IndivIncludes", plat);
grandInclude = new FileList(plat.getGIFileTemplate().nameOfList(), plat);
threshold = t;
nOuterFiles = 0;
nPrecompiledFiles = 0;
missingOk = false;
firstFile = null;
lastFile = null;
resolveVpath = false;
};
public FileList getAllFiles() {
return allFiles;
}
public FileList getOuterFiles() {
return outerFiles;
}
public String getMacroContent(String name) {
return macros.getMacroContent(name);
}
public void canBeMissing() {
missingOk = true;
}
public boolean hfileIsInGrandInclude(FileList hfile, FileList cfile) {
return ((hfile.getCount() >= threshold) && (cfile.getUseGrandInclude()));
}
/** These allow you to specify files not in the include database
which are prepended and appended to the file list, allowing
you to have well-known functions at the start and end of the
text segment (allows us to find out in a portable fashion
whether the current PC is in VM code or not upon a crash) */
public void setFirstFile(String fileName) {
firstFile = fileName;
}
public void setLastFile(String fileName) {
lastFile = fileName;
}
public void setWorkspace(String fileName) {
workspace = fileName;
}
public String getWorkspace() {
return workspace;
}
public void setGenDir(String path) {
genDir = path;
}
public String getGenDir() {
return genDir;
}
public void setOutputDir(String path) {
outputDir = path;
}
private void initVpath() {
if (vpaths != null) {
return;
}
resolvedFileNames = new Hashtable();
vpaths = new Vector();
if (genDir != null) {
addVpath(genDir);
addVpath(genDir + "/incls");
}
String cpu = macros.getMacroContent("arch");
String cpu_variant = macros.getMacroContent("cpu_variant");
addVpath(workspace + "/src/vm/cpu/arm");
addVpath(workspace + "/src/vm/cpu/arm/jazelle");
addVpath(workspace + "/src/vm/cpu/c");
addVpath(workspace + "/src/vm/cpu/i386");
addVpath(workspace + "/src/vm/cpu/sh");
addVpath(workspace + "/src/vm/cpu/thumb");
addVpath(workspace + "/src/vm/cpu/thumb2");
if ((cpu_variant != null) && (!cpu_variant.equals(""))) {
addVpath(workspace + "/src/vm/cpu/" + cpu + "/" + cpu_variant);
}
addVpath(workspace + "/src/vm/os/"+ macros.getMacroContent("os_family"));
addVpath(workspace + "/src/vm/os/utilities");
addVpath(workspace + "/src/vm/share/compiler");
addVpath(workspace + "/src/vm/share/float");
addVpath(workspace + "/src/vm/share/handles");
addVpath(workspace + "/src/vm/share/interpreter");
addVpath(workspace + "/src/vm/share/memory");
addVpath(workspace + "/src/vm/share/natives");
addVpath(workspace + "/src/vm/share/ROM");
addVpath(workspace + "/src/vm/share/reflection");
addVpath(workspace + "/src/vm/share/runtime");
addVpath(workspace + "/src/vm/share/utilities");
addVpath(workspace + "/src/vm/share/verifier");
addVpath(workspace + "/src/vm/share/debugger");
addVpath(workspace + "/src/vm/share/isolate");
addVpath(workspace + "/src/vm/share/dynupdate");
addVpath(workspace + "/src/vm/share/memoryprofiler");
}
private void addVpath(String path) {
// System.out.println("adding = " + path);
File file = new File(path);
if (file.isDirectory()) {
vpaths.addElement(path);
}
}
public void setResolveVpath(boolean r) {
resolveVpath = r;
}
/**
* Reads an entire includeDB file and stores its contents into
* internal representations.
*/
public void get(String platFileName, String dbFileName,
Properties globalProps)
throws FileFormatException, IOException, FileNotFoundException {
macros.readFrom(platFileName, missingOk);
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(dbFileName));
} catch (FileNotFoundException e) {
if (missingOk) {
return;
} else {
throw(e);
}
}
System.out.println("\treading database: " + dbFileName);
String line;
int lineNo = 0;
Stack ifdef_stack = new Stack();
do {
line = reader.readLine();
lineNo++;
if (line != null) {
StreamTokenizer tokenizer =
new StreamTokenizer(new StringReader(line));
tokenizer.slashSlashComments(true);
tokenizer.wordChars('_', '_');
tokenizer.wordChars('<', '>');
tokenizer.wordChars('#', '#');
tokenizer.wordChars('!', '!');
// NOTE: if we didn't have to do this line by line,
// we could trivially recognize C-style comments as
// well.
// tokenizer.slashStarComments(true);
int numTok = 0;
int res;
String unexpandedIncluder = null;
String unexpandedIncludee = null;
String thirdToken = null;
do {
res = tokenizer.nextToken();
if (res != StreamTokenizer.TT_EOF) {
if (numTok == 0) {
unexpandedIncluder = tokenizer.sval;
} else if (numTok == 1) {
unexpandedIncludee = tokenizer.sval;
} else if (numTok == 2) {
thirdToken = tokenizer.sval;
} else {
throw new FileFormatException(
"invalid line: \"" + line +
"\". Error position: line " + lineNo
);
}
numTok++;
}
} while (res != StreamTokenizer.TT_EOF);
boolean valid = true;
if (numTok == 0) {
valid = true;
} else if (unexpandedIncluder != null &&
unexpandedIncluder.charAt(0) == '#') {
if (equalsIgnoreCase(unexpandedIncluder, "#if")) {
valid = (numTok == 2);
} else if (equalsIgnoreCase(unexpandedIncluder, "#ifeq")) {
valid = (numTok == 3);
} else if (equalsIgnoreCase(unexpandedIncluder, "#endif")) {
valid = (numTok == 1 || numTok == 2);
} else {
System.out.println("Unknown preprocessor command: " +
unexpandedIncluder + " at line " +
lineNo);
System.exit(1);
}
} else {
valid = (numTok == 2);
}
if (!valid) {
throw new FileFormatException("invalid line: \"" + line +
"\". Error position: line " + lineNo);
}
if (numTok != 0) { // Non-empty line
if (equalsIgnoreCase(unexpandedIncluder, "#if")) {
push(ifdef_stack, getIfdefValue(globalProps,
unexpandedIncludee));
continue;
}
else if (equalsIgnoreCase(unexpandedIncluder, "#ifeq")) {
push(ifdef_stack, getIfeqValue(globalProps,
unexpandedIncludee,
thirdToken));
continue;
}
else if (equalsIgnoreCase(unexpandedIncluder, "#endif")) {
if (ifdef_stack.empty()) {
throw new FileFormatException(
"#endif without #if at line: \"" + line);
}
}
if (!ifdef_stack.empty()) {
if (equalsIgnoreCase(unexpandedIncluder, "#endif")) {
ifdef_stack.pop();
continue;
}
Object obj = ifdef_stack.peek();
Boolean b = (Boolean)obj;
if (b.booleanValue() == false) {
continue;
}
}
String includer = macros.expand(unexpandedIncluder);
String includee = macros.expand(unexpandedIncludee);
if (includee.equals(plat.generatePlatformDependentInclude())) {
generatePlatformDependentInclude(unexpandedIncluder,
includer);
} else {
FileList p = allFiles.listForFile(includer);
if (isOuterFile(includer)) {
outerFiles.addIfAbsent(p);
}
if (includee.equals(plat.noGrandInclude())) {
p.setUseGrandInclude(false);
} else {
FileList q = allFiles.listForFile(includee);
p.addIfAbsent(q);
}
}
}
}
} while (line != null);
if (!ifdef_stack.empty()) {
throw new FileFormatException("#endif not found before end of file");
}
reader.close();
if (sourceMergerLimit > 1) {
createMergedOuterFiles();
}
// Keep allFiles in well-known order so we can easily determine
// whether the known files are the same
allFiles.sortByName();
// Add first and last files differently to prevent a mistake
// in ordering in the include databases from breaking the
// error reporting in the VM.
if (firstFile != null) {
FileList p = allFiles.listForFile(firstFile);
allFiles.setFirstFile(p);
outerFiles.setFirstFile(p);
}
if (lastFile != null) {
FileList p = allFiles.listForFile(lastFile);
allFiles.setLastFile(p);
outerFiles.setLastFile(p);
}
}
static boolean equalsIgnoreCase(String a, String b) {
return (a.compareToIgnoreCase(b) == 0);
}
/**
* @param boolValue must be "true" or "false"
*/
void push(Stack ifdef_stack, String boolValue) {
if (!ifdef_stack.empty()) {
Object obj = ifdef_stack.peek();
Boolean b = (Boolean)obj;
String prop;
if (b.booleanValue() == false) {
boolValue = "false";
}
}
ifdef_stack.push(new Boolean(boolValue));
}
void generatePlatformDependentInclude(String unexpandedIncluder,
String includer) throws IOException {
MacroDefinitions localExpander = macros.copy();
MacroDefinitions localExpander2 = macros.copy();
localExpander.setAllMacroBodiesTo("pd");
localExpander2.setAllMacroBodiesTo("");
// unexpanded_includer e.g. thread_<os_arch>.hpp
// thread_solaris_i486.hpp -> _thread_pd.hpp.incl
FileName pdName =
plat.getInclFileTemplate().copyStem(
localExpander.expand(unexpandedIncluder)
);
// derive generic name from platform specific name
// e.g. os_<arch_os>.hpp => os.hpp
String newIncluder =
localExpander2.expand(unexpandedIncluder);
FileList p = allFiles.listForFile(includer);
p.setPlatformDependentInclude(pdName.dirPreStemSuff());
// Add an implicit dependency on platform
// specific file for the generic file
p = platformFiles.listForFile(newIncluder);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(baos);
PrintWriter pdFile = new PrintWriter(writer);
String incname = tryGetFullPath(includer);
incname = plat.translateFileName(incname);
pdFile.println("#include \"" + incname + "\"");
pdFile.flush();
updateFile(pdName.dirPreStemSuff(), baos);
pdFile.close();
// Add the platform specific file to the list
// for this generic file.
FileList q = allFiles.listForFile(includer);
p.addIfAbsent(q);
}
static String getIfdefValue(Properties globalProps, String token) {
boolean negate = false;
if (token.startsWith("!")) {
token = token.substring(1);
negate = true;
}
String result = globalProps.getProperty(token, "false");
if (negate) {
if (result.equals("false")) {
result = "true";
} else {
result = "false";
}
}
return result;
}
String getIfeqValue(Properties globalProps, String name, String value) {
String result = macros.getMacroContent(name);
if (result == null) {
result = globalProps.getProperty(name, null);
}
if (value.equals(result)) {
return "true";
} else {
return "false";
}
}
/**
* We need to exclude some files from the merged source files. See
* in-line comments for reasons.
*/
boolean needToExcludeFromMerge(String file) {
if (file.equals("ROMImage.cpp")) {
// ROM image is not part of VM library.
return true;
}
if (file.equals("JniAdapters.cpp")) {
// JNI adapters are not part of VM library.
return true;
}
if (file.equals("NativesTable.cpp")) {
// Natives Table is not part of VM library.
return true;
}
if (file.equals("BSDSocket.cpp")) {
// BSDSocket is not part of VM library.
return true;
}
if (file.equals("PCSLSocket.cpp")) {
// PCSLSocket is not part of VM library.
return true;
}
if (file.equals("ReflectNatives.cpp")) {
// ReflectNatives is not part of VM library.
return true;
}
if (file.equals("HotRoutines0.cpp") ||
file.equals("HotRoutines1.cpp") ) {
// These could be placed in fast memory on low-end
// ARM7TDMI devices, so don't merge them with other
// files.
return true;
}
if (file.equals("jvmspi.cpp")) {
// SPI implementation is not part of VM library
return true;
}
if (file.toLowerCase().startsWith("main_")) {
// Main function is not part of VM library.
return true;
}
if (file.toLowerCase().startsWith("ossocket_")) {
// socket code is not part of VM library.
return true;
}
if (file.toLowerCase().startsWith("floatsupport_")) {
// On ARM we should build FloatSupport_arm.cpp in ARM
// mode. If compiled in THUMB mode functions like jvm_fadd()
// will be compiled into library calls instead of VFP instructions.
return true;
}
if (file.toLowerCase().endsWith("uncommon.cpp")) {
// This file is rarely used by optimized MIDP, so let's
// leave in a separate .o file, which gcc could eliminate from
// final executable image.
return true;
}
if (file.toLowerCase().startsWith("os") && !file.equals("OS.cpp")) {
// IMPORTANT: this has to be here for Linux and ADS:
// -> leads to compilation problems (FIELD_OFFSET) if merged
// IMPORTANT: this has to be here for GBA:
// contains interrupt handler that HAVE to be in ARM, not Thumb
return true;
}
return false;
}
/**
* Merge multiple .cpp files into a single .cpp file to speed
* up GCC compilation. This is done by creating a new 'outer' source
* file that depends on several of the original outer source files.
* E.g., if we merge Foo1.cpp, Foo2.cpp Foo3.cpp into _MergedSrc001.cpp,
* we'd have the following files:
*
* _MergedSrc001.cpp:
* #include "incls/_precompiled.incl"
* #include "incls/__MergedSrc001.cpp.incl"
*
* incls/__MergedSrc001.cpp.incl:
* #include "/path/to/Foo1.cpp"
* #include "/path/to/Foo2.cpp"
* #include "/path/to/Foo3.cpp"
*
* The Makefile is directed to build _MergedSrc001.o, which will include
* the contents of Foo1.cpp, Foo2.cpp and Foo3.cpp
*
* This speeds up GCC compilation time by 2x ~ 3x.
*/
void createMergedOuterFiles() throws IOException {
System.out.println("\tmerging source files, limit = " +
sourceMergerLimit);
int nNewFiles = 1;
int nMerged = 0;
FileList oldOuterFiles = outerFiles;
outerFiles = new FileList("outerFiles", plat);
FileList newOuter = null;
for (int i=0; i<oldOuterFiles.size(); i++) {
FileList oldOuter = (FileList)oldOuterFiles.elementAt(i);
if (needToExcludeFromMerge(oldOuter.getName())) {
System.out.println("\t\texcluded from merging: " +
oldOuter.getName());
outerFiles.addIfAbsent(oldOuter);
} else {
if (newOuter == null) {
String name= "_MergedSrc"+ numToString(nNewFiles)+ ".cpp";
newOuter = new FileList(name, plat);
outerFiles.addIfAbsent(newOuter);
nNewFiles++;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(baos);
PrintWriter pw = new PrintWriter(writer);
pw.println("#include \"incls/_precompiled.incl\"");
pw.println("#include \"incls/_" + name + ".incl\"");
pw.flush();
updateFile(name, baos);
pw.close();
}
// Create blank incl file for the oldOuter
String blankFile = "incls/_" + oldOuter.getName() + ".incl";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
updateFile(blankFile, baos);
baos.close();
newOuter.addIfAbsent(oldOuter);
nMerged ++;
if (nMerged >= sourceMergerLimit) {
nMerged = 0;
newOuter = null;
}
}
}
}
String numToString(int n) {
String s = Integer.toString(n);
while (s.length() < 3) {
s = "0" + s;
}
return s;
}
public void compute() {
// build both indiv and grand results
for (Iterator iter = outerFiles.iterator(); iter.hasNext(); ) {
indivIncludes.add(((FileList) iter.next()).doCFile());
++nOuterFiles;
}
if (!plat.haveGrandInclude())
return; // nothing in grand include
// count how many times each include is included & add em to grand
for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) {
FileList indivInclude = (FileList) iter.next();
if (!indivInclude.getUseGrandInclude()) {
continue; // do not bump count if my files cannot be
// in grand include
}
indivInclude.doFiles(grandInclude); // put em on
// grand_include list
for (Iterator incListIter = indivInclude.iterator();
incListIter.hasNext(); ) {
((FileList) incListIter.next()).incrementCount();
}
}
}
// Consider whether it is necessary in Java
public void verify() {
for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) {
if (iter.next() == null) {
plat.abort();
}
}
}
public void put() throws IOException {
writeIndividualIncludes();
writeGrandInclude();
writeCompleteInclude();
writeGrandUnixMakefile();
writeDox();
}
// Write the include file for each individual .cpp file. E.g.,
// create _BinaryAssembler_arm.cpp.incl for _BinaryAssembler_arm.cpp
private void writeIndividualIncludes() throws IOException {
System.out.print("\twriting individual include files ...");
int count = 0;
for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) {
FileList list = (FileList) iter.next();
//System.out.println("\tcreating " + list.getName());
list.putInclFile(this);
++ count;
}
System.out.println(" done (" + count + " files.)");
}
// Write the header file that contains all of the VM's
// .hpp files. This file can be used for compiling C++ files
// that are not part of the VM code (e.g.,
// src/tests/natives/InternalNatives.cpp). This makes it possible
// to link extra C++ files into the VM without editing includeDB
private void writeCompleteInclude() throws IOException {
Hashtable written = new Hashtable();
String filename = outputDir + "/incls/_CompleteInclude.incl";
PrintWriter inclFile = new PrintWriter(new FileWriter(filename));
String filename2 = outputDir + "/incls/_CompleteInclude2.incl";
PrintWriter inclFile2 = new PrintWriter(new FileWriter(filename2));
inclFile2.println("/* This file contains all files that are in */");
inclFile2.println("/* _CompleteInclude.incl but not in */");
inclFile2.println("/* _precompiled.incl */");
for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) {
FileList list = (FileList) iter.next();
for (Iterator files = list.iterator(); files.hasNext(); ) {
FileList file = (FileList) files.next();
String name = file.getName();
if (!name.endsWith(".hpp") && !name.endsWith(".h")) {
continue;
}
String incname = plat.getInclFileTemplate().getInvDir() +
tryGetFullPath(name);
incname = plat.translateFileName(incname);
if (written.get(incname) == null) {
written.put(incname, incname);
inclFile.println("#include \"" + incname + "\"");
if (grandIncludeEntries.get(incname) == null) {
inclFile2.println("#include \"" + incname + "\"");
}
}
}
}
inclFile.close();
inclFile2.close();
}
// Write a file for controlling the Doxygen documentation
// processor. See build/share/dox.make.
private void writeDox() throws IOException {
Hashtable written = new Hashtable();
String filename = outputDir + "/Dox.tail";
PrintWriter doxFile = new PrintWriter(new FileWriter(filename));
doxFile.println("# Dox.tail -- this file is auto-generated.");
doxFile.println("# do not edit");
doxFile.println("#");
doxFile.print("INPUT =");
for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) {
FileList list = (FileList) iter.next();
for (Iterator files = list.iterator(); files.hasNext(); ) {
FileList file = (FileList) files.next();
String name = file.getName();
if (!name.endsWith(".hpp") && !name.endsWith(".h")) {
continue;
}
String incname = plat.getInclFileTemplate().getInvDir() +
tryGetFullPath(name);
incname = plat.translateFileName(incname);
if (written.get(incname) == null) {
written.put(incname, incname);
//if (incname.indexOf("memory") >= 0) {
doxFile.print(" " + incname);
//}
}
}
}
doxFile.println("");
doxFile.close();
}
// Write the _precompiled.incl file
private void writeGrandInclude() throws IOException {
System.out.println("\twriting grand include file\n");
String filename = outputDir + "/" +
plat.getGIFileTemplate().dirPreStemSuff();
PrintWriter inclFile = new PrintWriter(new FileWriter(filename));
// This file is always included first
inclFile.println("#include \"jvmconfig.h\"");
if (plat.haveGrandInclude()) {
plat.writeGIPragma(inclFile);
for (Iterator iter = grandInclude.iterator(); iter.hasNext(); ) {
FileList list = (FileList) iter.next();
if (list.getCount() >= threshold) {
String incname = tryGetFullPath(list.getName());
incname = plat.translateFileName(incname);
inclFile.println("#include \"" +
plat.getGIFileTemplate().getInvDir() +
incname +
"\"");
nPrecompiledFiles += 1;
grandIncludeEntries.put(incname, incname);
}
}
}
inclFile.println();
inclFile.close();
}
private void writeGrandUnixMakefile() throws IOException {
if (resolveVpath) {
initVpath();
}
if (!plat.writeDeps()) {
return;
}
System.out.println("\twriting dependencies file\n");
String fileName =
outputDir + "/" + plat.getGDFileTemplate().dirPreStemSuff();
PrintWriter gd = new PrintWriter(new FileWriter(fileName));
gd.println("# generated by makeDeps");
gd.println();
{
// write Obj_Files = ...
String prefix = "Obj_Files = \\\n\t";
outerFiles.sortByName();
for (Iterator iter = outerFiles.iterator(); iter.hasNext(); ) {
FileList anOuterFile = (FileList) iter.next();
gd.print(prefix);
String stemName = removeSuffixFrom(anOuterFile.getName());
gd.print(stemName + plat.objFileSuffix());
prefix = " \\\n\t";
}
gd.println();
gd.println();
}
if (plat.haveGrandInclude()) {
String prefix = "Precompiled_Headers = \\\n\t";
for (Iterator iter = grandInclude.iterator(); iter.hasNext(); ) {
FileList list = (FileList) iter.next();
if (list.getCount() >= threshold) {
gd.print(prefix);
gd.print(tryGetFullPath(list.getName()));
prefix = " \\\n\t";
}
}
gd.println();
gd.println();
}
{
// write each dependency
for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) {
FileList anII = (FileList) iter.next();
String stemName = removeSuffixFrom(anII.getName());
gd.println(stemName + plat.objFileSuffix() + ": \\");
gd.print("$(GEN_DIR)/jvmconfig.h ");
printDependentOn(gd, anII.getName());
for (Iterator iiIter = anII.iterator(); iiIter.hasNext(); ) {
FileList hfile = (FileList) iiIter.next();
if (!hfileIsInGrandInclude(hfile, anII)) {
printDependentOn(gd, hfile.getName());
}
if (platformFiles.hasListForFile(hfile.getName())) {
FileList p =
platformFiles.listForFile(hfile.getName());;
for (Iterator hiIter = p.iterator();
hiIter.hasNext(); ) {
FileList hi2 = (FileList) hiIter.next();
if (!hfileIsInGrandInclude(hi2, p)) {
printDependentOn(gd, hi2.getName());
}
}
}
}
if (plat.haveGrandInclude()) {
gd.println(" $(Precompiled_Headers)");
}
gd.println();
gd.println();
}
}
gd.close();
}
public void putDiffs(Database previous) throws IOException {
System.out.println("\tupdating output files\n");
if (!indivIncludes.compareLists(previous.indivIncludes)
|| !grandInclude.compareLists(previous.grandInclude)) {
System.out.println("The order of .c or .s has changed, or " +
"the grand include file has changed.");
put();
return;
}
Iterator curIter = indivIncludes.iterator();
Iterator prevIter = previous.indivIncludes.iterator();
try {
while (curIter.hasNext()) {
FileList newCFileList = (FileList) curIter.next();
FileList prevCFileList = (FileList) prevIter.next();
if (!newCFileList.compareLists(prevCFileList)) {
System.out.println("\tupdating " + newCFileList.getName());
newCFileList.putInclFile(this);
}
}
}
catch (Exception e) {
throw new InternalError("assertion failure: cur and prev " +
"database lists changed unexpectedly.");
}
writeGrandUnixMakefile();
}
private void printDependentOn(PrintWriter gd, String name) {
gd.print(" ");
gd.print(tryGetFullPath(plat.dependentPrefix(), name));
}
public String tryGetFullPath(String filename) {
return tryGetFullPath("", filename);
}
private String tryGetFullPath(String prefix, String filename) {
if (resolveVpath) {
String file = getFullPath(prefix, filename);
if (file != null) {
return file;
}
}
return prefix + filename;
}
public String getFullPath(String filename) {
return getFullPath("", filename);
}
public String getFullPath(String prefix, String filename) {
initVpath();
String cached = (String)resolvedFileNames.get(filename);
if (cached != null) {
return cached;
}
String found = null;
for (int i=0; i<vpaths.size(); i++) {
String vpath = (String)vpaths.elementAt(i);
File file = new File(vpath + "/" + filename);
if (file.isFile()) {
found = vpath + "/" + filename;
break;
}
}
if (found == null) {
if (filename.equals("NativesTable.cpp") ||
filename.equals("ROMImage.cpp") ||
filename.startsWith("_MergedSrc")) {
found = "../generated/" + filename;
}
}
if (found != null) {
resolvedFileNames.put(filename, found);
return found;
}
System.err.println("couldn't find in vpath: " + filename);
return null;
}
/**
* Checks whether a file is an outer file - which means a
* makefile rule has to be generated to compile this file
* into an object file.
*
* This is done by checking if the suffix of the file is one
* of plat.outerSuffixes(), which are typically .cpp and .c
*/
private boolean isOuterFile(String s) {
int len = s.length();
String[] suffixes = plat.outerSuffixes();
for (int i = 0; i < suffixes.length; i++) {
String suffix = suffixes[i];
int suffLen = suffix.length();
if ((len >= suffLen) &&
(plat.fileNameStringEquality(s.substring(len - suffLen),
suffix))) {
return true;
}
}
return false;
}
private String removeSuffixFrom(String s) {
int idx = s.lastIndexOf('.');
if (idx <= 0)
plat.abort();
return s.substring(0, idx);
}
public void setSourceMergerLimit(int size) {
sourceMergerLimit = size;
}
/**
* Write the content of the baos to the given file, but only if the
* change has been changed. We don't rewrite the file if the content is
* the same. This avoids excessive rebuilding.
*/
public static void updateFile(String filename, ByteArrayOutputStream baos)
throws IOException
{
byte newContent[] = baos.toByteArray();
byte oldContent[] = readFile(filename);
// We won't write to the file if the content has not changed.
// This will avoid excessive rebuilding when we change
// includeDB, etc.
if (oldContent != null && oldContent.length == newContent.length) {
boolean same = true;
for (int i=0; i<oldContent.length; i++) {
if (oldContent[i] != newContent[i]) {
same = false;
break;
}
}
if (same) {
//System.out.println(filename + " same");
return;
}
}
filename = outputDir + "/" + filename;
FileOutputStream out = new FileOutputStream(filename);
out.write(newContent);
out.close();
}
public static byte[] readFile(String filename) throws IOException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileInputStream in = new FileInputStream(filename);
byte buffer[] = new byte[1024];
int n;
while ((n = in.read(buffer)) > 0) {
baos.write(buffer, 0, n);
}
byte result[] = baos.toByteArray();
baos.close();
in.close();
return result;
} catch (IOException e) {
return null;
}
}
}