| /* --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(); |
| } |
| } |
| } |
| } |