blob: acf27e580de9bae47877aaa9a85fd16f55b0ce45 [file] [log] [blame]
/* --COPYRIGHT--,EPL
* Copyright (c) 2008 Texas Instruments and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Texas Instruments - initial implementation
*
* --/COPYRIGHT--*/
/*
* ======== Prog.java ========
* Generate program configuration files
*/
package xdc.services.intern.gen;
import org.mozilla.javascript.*;
import xdc.services.global.*;
import xdc.services.intern.xsr.*;
import java.io.*;
import java.util.*;
public class Prog
{
private Out out;
Vector genList;
Vector linkList;
private Glob glob = new Glob();
/*
* ======== gen ========
*/
public void gen(
String cfgName, String exeName, Object om, Object prog, boolean genC)
throws JavaScriptException
{
gen(cfgName, exeName, (Value)om, (Value)prog, genC);
}
public void gen(
String cfgName, String exeName, Value om, Value prog, boolean genC)
throws JavaScriptException
{
try {
Config configGen = new Config(glob, this);
genList = new Vector();
linkList = new Vector();
File file;
OutputStream fos;
long t0;
/* generate the *.c file */
if (genC) {
file = new File(cfgName + ".c");
file.delete();
fos = new FileOutputStream(file);
out = new Out(new BufferedOutputStream(fos));
configGen.gen(om, prog, out);
out.close();
}
/* generate a *.h with declarations of all static objects */
if (genC) {
file = new File(cfgName + ".h");
file.delete();
fos = new FileOutputStream(file);
out = new Out(new BufferedOutputStream(fos));
configGen.genGlobals(prog, out);
configGen.genSymbols(prog, out);
out.close();
}
/* generate the linker command file */
file = new File(cfgName + ".xdl");
file.delete();
fos = new FileOutputStream(file);
out = new Out(new BufferedOutputStream(fos));
genLibs(om, prog);
out.close();
if (false) {
out = new Out(new FileOutputStream(cfgName + ".asm"));
genBoot(om, prog);
out.close();
}
/* generate a makefile of dependencies to trigger re-config */
if (genC) {
file = new File(cfgName + ".dep");
if (!file.canWrite()) {
file.delete();
}
out = new Out(new FileOutputStream(cfgName + ".dep", true));
genDeps(om, prog, cfgName, exeName);
out.close();
}
out = null;
}
catch (JavaScriptException e) {
if (out != null) {
out.close();
}
throw (e);
}
catch (Exception e) {
xdc.services.intern.xsr.Err.exit(e);
}
}
/*
* ======== genBoot ========
* Generates a boot.asm file from the platform's boot template.
*
* Returns a vector of all files that are "referenced" that should
* trigger a re-link of the executable; e.g., all libraries named in
* the generated linker command file.
*
* The template file, however, is added to genList because changes
* to this file should trigger a re-generatation not just a re-link.
*/
public void genBoot(Value om, Value prog)
throws JavaScriptException
{
String pname = prog.gets("platformName");
Value plat = prog.getv(".platform");
if (plat == null) {
xdc.services.intern.xsr.Err.exit("can't get platform '" + pname
+ "' from program configuration.");
}
String boot = plat.gets("bootTemplate");
if (boot != null) {
String path;
if ((path = Path.search(boot)) == null) {
xdc.services.intern.xsr.Err.exit("can't find platform '" +
pname + "'s boot template file: " + boot);
}
genList.addElement(path); /* add top-lev template */
/* pass prog and plat to template */
Object[] args = new Object[] {
prog, plat
};
genList.addAll( /* add recurs templates */
Template.exec(boot, out, plat, args)/* gen the boot file */
);
}
}
/*
* ======== genDeps ========
*/
public void genDeps(Value om, Value prog, String cfg, String exe)
{
Vector<String> ext = new Vector<String>(); /* list of files outside the pkg */
boolean [] inside = new boolean[1];
/* get the current package directory */
String cpd = null;
try {
File d = new File(System.getProperty("user.dir"));
cpd = d.getCanonicalPath() + File.separatorChar;
}
catch (IOException ex) {
;
}
/* generate a banner so we know were this stuff is coming from */
out.printf("#\n# The following is generated by java\n#\n");
/* generate dependencies that cause program re-link */
out.printf("\n%1: ", exe);
for (int i = 0; i < linkList.size(); i++) {
String file = genFileName((String)linkList.elementAt(i), cpd, inside);
if (!inside[0]) {
ext.addElement(file);
}
out.printf("%1 ", file.replaceAll(" ", "\\\\ "));
}
out.printf("\n");
/* generate dependencies that cause <program>.c re-generation */
out.printf("\n%1.c: ", cfg);
for (int i = 0; i < genList.size(); i++) {
String file = genFileName((String)genList.elementAt(i), cpd, inside);
if (!inside[0]) {
ext.addElement(file);
}
out.printf("%1 ", file.replaceAll(" ", "\\\\ "));
}
out.printf("\n");
/* generate package interface dependencies to cause re-config */
out.printf("%1.c %1.xdl: ", cfg);
Value pkgarr = om.getv("$packages");
int len = pkgarr.geti("length");
for (int i = 0; i < len; i++) {
/* construct a path relative to the package path */
Value pkg = pkgarr.getv(i);
String qn = pkg.gets("$$qn");
if (!(qn.equals("$Main"))) {
String iname = glob.mkFname(qn) + "package/" + qn + "sch";
String path;
if ((path = Path.search(iname)) != null) {
path = genFileName(path, cpd, inside);
if (!inside[0]) {
ext.addElement(path);
}
else {
path = ".interfaces";
}
out.printf("%s ", path.replaceAll(" ", "\\\\ "));
}
}
}
out.printf("\n\n");
/* generate goals with no rules to force re-build in case any file
* external to the current package is missing
*/
out.printf("#\n# rule-less goals for files outside this package\n");
out.printf("# (these goals force a re-build if these files are\n");
out.printf("# moved or deleted)\n#\n");
for (int i = 0; i < ext.size(); i++) {
String file = (String)ext.elementAt(i);
out.printf("%s:\n", file.replaceAll(" ", "\\\\ "));
}
out.printf("\n");
}
/*
* ======== genFileName ========
*/
private String genFileName(String fileName, String cpd,
boolean [] inside)
{
// System.out.println("gen file (" + cpd + "): " + fileName);
/* expand fileName to cannonical path */
try {
fileName = (new File(fileName)).getCanonicalPath();
}
catch (IOException e) {
;
}
inside[0] = false;
if (cpd != null && fileName.indexOf(cpd) == 0) {
inside[0] = true;
fileName = fileName.substring(cpd.length());
}
/* convert to forward slash because the GNU makefiles see "foo/bar"
* as a different file from "foo\bar" and all other generated make
* files use forward slash for file names
*/
return (fileName.replace('\\', '/'));
}
/*
* ======== genLibs ========
* Generates a linker command file from the platform's linker template.
*
* Returns a vector of all files that are "referenced" that should
* trigger a re-link of the executable; e.g., all libraries named in
* the generated linker command file.
*
* The template file, however, is added to genList because changes
* to this file should trigger a re-generatation not just a re-link.
*/
public void genLibs(Value om, Value prog)
throws JavaScriptException
{
String lcmd = null;
String path = null;
Vector libList = new Vector();
/* Get the library names from each included package; each package
* gets to select an appropriate library for the current
* configuration.
*/
Value pkgarr = om.getv("$packages");
int len = pkgarr.geti("length");
/* get current package name */
String curpkg = prog.gets("buildPackage") + ".";
for (int i = len - 1; i >= 0; i--) {
Value pkg = pkgarr.getv(i).getv("$orig");
Scriptable scope = Global.getTopScope();
String libseq = null;
if (pkg.geti("$$genflg") == 0) {
continue;
}
/* first get the library names from the package's getlib fxn */
try {
Object s = pkg.invoke("getLibs", new Object[] {prog});
if (s == org.mozilla.javascript.Undefined.instance) {
xdc.services.intern.xsr.Err.exit(
"The getLibs() function for the package "
+ pkg.gets("$name") + " returned undefined; it must return a string or null.");
}
libseq = (String)s;
}
catch (Exception e) {
xdc.services.intern.xsr.Err.exit(e);
}
if (libseq == null || libseq.equals("")) {
continue;
}
/* for each item returned by getLibs() ... */
String qn = pkg.gets("$$qn");
String pn = pkg.gets("$name");
for (;;) {
int idx = libseq.indexOf(';');
String lib = (idx == -1) ? libseq : libseq.substring(0, idx);
/* If the list of libraries contains a trailing ';', or there
* are multiple';', 'lib' is empty and we should skip the rest
* of the loop to avoid misleading error messages.
*/
if (lib.equals("")) {
libseq = libseq.substring(idx + 1);
continue;
}
/* if the package is not the distinguished unnamed package */
if (!(qn.equals("$Main"))) {
/* look for the named file */
File file = new File(lib);
if (file.isAbsolute()) {
if (!file.exists()) {
xdc.services.intern.xsr.Err.exit("can't find the "
+ "library '" + lib + "' specified by package "
+ qn);
}
path = lib;
}
else if ((path = Path.search(glob.mkFname(qn) + lib)) ==
null) {
if (!qn.equals(curpkg)) {
xdc.services.intern.xsr.Err.exit("can't find the "
+ "library '" + lib + "' specified by package "
+ qn + " It wasn't found along the path '"
+ Path.curpath() + "'.");
}
else {
/* BUG?? don't treat current pkg specially */
try {
path = file.getCanonicalPath();
}
catch (IOException x) {
xdc.services.intern.xsr.Err.exit("IO error: "
+ "can't create full path for the library '"
+ file + "' specified by package " + qn);
}
}
}
}
else { /* otherwise, assume library will exist */
path = lib;
}
if (path != null && !path.equals("")) {
linkList.addElement(path);
Trace.print(this, "xdc: getLibs: package '" + pn
+ "' supplying library '" + path + "'.", 0,
new String[] {"getLibs"});
libList.addElement(pn + ":" + lib);
}
if (idx == -1) {
break;
}
libseq = libseq.substring(idx + 1);
}
}
/* first ask program for a link template */
String pname = prog.gets("platformName").split(":")[0];
Value plat = prog.getv("platform");
String from = "program '" + prog.gets("name") + "'s";
if (plat == null) {
xdc.services.intern.xsr.Err.exit("can't find "
+ from + " platform package " + pname);
}
if ((lcmd = prog.gets("linkTemplate")) == null) {
/* program does not have one, so we try the platform */
try {
lcmd = (String)plat.invoke("getLinkTemplate",
new Object[] {prog});
}
catch (Exception e) {
xdc.services.intern.xsr.Err.exit(e);
}
from = "platform '" + pname + "'s";
}
/* if lcmd is null, linker file doesn't need to be generated(?) */
if (lcmd != null) {
/* otherwise, locate the template file */
if ((path = Path.search(lcmd)) == null) {
xdc.services.intern.xsr.Err.exit("can't find "
+ from + " linker command template file: '"
+ lcmd + "' along the path " + Path.curpath());
}
/* add top-lev template to dependency list */
genList.addElement(path);
/* generate the linker command file */
Object[] args = linkList.toArray(); /* get arr of libs only */
genList.addAll( /* add recurs templates */
Template.exec(lcmd, out, prog, args) /* gen linker cmd file */
);
}
else {
// System.out.println("java: template is null.");
}
/* now generate any files specified by $$gentab */
Scriptable gentab = (Scriptable)prog.geto("$$gentab");
if (gentab != null) {
Double d = (Double)gentab.get("length", gentab);
int tabLen = d.intValue();
Object[] args = libList.toArray(); /* get arr of libs only */
for (int i = 0; i < tabLen; i++) {
Scriptable desc = (Scriptable)gentab.get(i, gentab);
/* get template from descriptor */
String template = desc.get("template", desc).toString();
String fname = Path.search(template);
if (fname == null) {
xdc.services.intern.xsr.Err.exit("can't find "
+ from + " template file: '"
+ template + "' along the path " + Path.curpath());
}
/* add top-level template full file name to dependents */
genList.addElement(fname);
/* generate file from template */
fname = desc.get("file", desc).toString();
Out tout = null;
try {
File file = new File(fname);
file.delete();
FileOutputStream fos = new FileOutputStream(file);
tout = new Out(new BufferedOutputStream(fos));
}
catch (Exception e) {
xdc.services.intern.xsr.Err.exit(e);
}
genList.addAll( /* add recurs templates */
Template.exec(template, tout, prog, new Object[] {args})
);
tout.close();
}
}
}
}