blob: 8a0636ff46d4e4efe5f44f41e763271de009c879 [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--*/
/*
* ======== Main.xs ========
*/
/*
* ======== Main.genFiles ========
*/
function genFiles(executable, prefix)
{
/* Check version consistency and fail on any discrepancy. This was moved
* here out of validate() to save some time when xgconf calls validate().
* But, this still has to be in some of the declared Main functions because
* a client should get the complete configuration step by calling the
* declared functions in the order in which Main.main() calls them.
*/
var result = checkVersions(environment["xdc.cfg.check.exclude"]);
_Clock.print("cfg package version checks done.");
if (result.msg != "") {
if (environment["xdc.cfg.check.fatal"] == "false"
|| result.eCount == 0) {
print("Warning: " + result.msg);
}
else {
return (result.msg);
}
}
/* generate <executable>.xdc.inc include file + the test rule for this exe */
this.$private.$$cfgCapsule._postinit();
/* sort the packages in order of declared dependencies */
xdc.om.$packages.$self = _genDependencyList();
/* generate configuration files */
var progGen = new Packages.xdc.services.intern.gen.Prog;
progGen.gen(prefix, executable, xdc.om, Program, true);
/* We are checking hasReportedError here because Prog.gen evaluates
* templates, and if load() is called during a template evaluation, Rhino's
* load is called instead of one in config/Shell. In Rhino, loading a
* non-existent file is reported as an error by calling
* Context.reportError(), but no exception is thrown. There might be other
* cases where an error does not cause an exception.
*/
if (utils.hasReportedError()) {
throw xdc.$$XDCException(
"xdc.cfg.CONFIG_ERROR", "Error in configuration");
}
_Clock.print("cfg core generation done.");
/*
* If an assembly, also gen linker files for executable's final link.
* Specifically we want a linker command file that includes the memory
* map. If the generated linker command file for the assembly is
* named 'XX_pYY.xdl', the new linker command file will be 'XX_pYY_x.xdl'.
*/
if (Program.$$isasm) {
var save$$isasm = Program.$$isasm;
Program.$$bind('$$isasm', 0);
progGen.gen(prefix + '_x', executable, xdc.om, Program, false);
Program.$$bind('$$isasm', save$$isasm);
}
if (utils.hasReportedError()) {
throw xdc.$$XDCException(
"xdc.cfg.CONFIG_ERROR", "Error in configuration");
}
/* generate config xml file, config graph, and debugger project files */
if (environment["xdc.cfg.gen.metadataFiles"] == null
|| environment["xdc.cfg.gen.metadataFiles"] == "true") {
genXML(prefix + ".cfg.xml");
genDot(prefix + ".cfg.dot");
}
/* always generate ROV/RTA support files */
genRov(prefix + ".rov.xs");
var Rta = xdc.module('xdc.runtime.Rta');
Rta.genRta(prefix + ".rta.xml");
var genDebug = Program.gen.debuggerFiles;
if (genDebug == null) {
if (environment["xdc.cfg.gen.debuggerFiles"] != null) {
genDebug = environment["xdc.cfg.gen.debuggerFiles"] == "true";
}
}
if (genDebug
|| (genDebug == null
&& Program.build.profile.match(/debug/) != null)) {
genDbg(prefix, executable, Program);
}
/* build any libraries generated by packages */
_Clock.print("cfg generated files done.");
var SourceDir = xdc.module("xdc.cfg.SourceDir");
SourceDir.build();
_Clock.print("cfg build of library sources done.");
if (xdc.om.$$errors.length > 0 || xdc.om.$$warnings.length > 0) {
return (getErrors());
}
return ("");
}
/*
* ======== Main.init ========
*/
function init()
{
this.$private.$$usestk = null;
/* replace the default version of xdc.useModule with a cfg specific
* version.
*/
xdc.useModule = $$cfgUseModule;
this.$private.$$usemod = $$usemod;
Program = xdc.useModule('xdc.cfg.Program');
xdc.om.$$bind('$root', Program);
prog = Program; /* TODO: this should go away; find who uses it*/
}
var _Clock = xdc.useModule('xdc.services.global.Clock');
/* When users create a global variable 'Error', the code in this file that
* throws Errors fails. This local variable is used as a reference to a top
* level JavaScript object Error to prevent this problem.
*/
var _localError = Error;
/*
* ======== Main.main ========
*/
function main(args)
{
function errorCheck(val) {
if (val != "") {
/* There are some errors or warnings. If only warnings are present,
* the configuration step continues.
*/
if (val.substring(0, 2) == "@@") {
/* These are warnings/errors reported via $log functions */
printErrors();
if (xdc.om.$$errors.length > 0) {
throw new _localError("Configuration failed!");
}
else {
xdc.om.$$warnings.length = 0;
}
}
else {
throw new _localError(val);
}
}
}
if (args.length < 3) {
print("usage: xs xdc.cfg exe-name cfg-file gen-files-prefix [pkg-name]");
throw new _localError("Too few arguments");
}
if ($traceQuery()) {
_Clock.enable = true;
}
_Clock.reset();
var executable = args[0];
var cfgScript = args[1];
var prefix = args[2];
var pathPrefix = args[3];
xdc.$$make_om('cfg');
var cfgmodel = xdc.useModule('xdc.cfg.Main');
cfgmodel.init();
_myTrace("config model initialization: $$phase -> 1", 1,
["xdccore", "bench"]);
xdc.om.$$bind('$$phase', 1);
var ret = cfgmodel.setExecutable(cfgScript, pathPrefix);
errorCheck(ret);
_Clock.print("cfg model initialized.");
_myTrace("user script: $$phase -> 2", 1, ["xdccore", "bench"]);
xdc.om.$$bind('$$phase', 2);
ret = cfgmodel.runCfg();
errorCheck(ret);
_Clock.print("cfg user script done.");
_myTrace("validation phase: $$phase -> 6", 1, ["xdccore", "bench"]);
xdc.om.$$bind('$$phase', 6);
ret = cfgmodel.validate();
errorCheck(ret);
_myTrace("C config file generation: $$phase -> 7", 1, ["xdccore", "bench"]);
xdc.om.$$bind('$$phase', 7);
ret = cfgmodel.genFiles(executable, prefix);
errorCheck(ret);
_Clock.print("cfg generation done. Total cfg time: "
+ _Clock.getElapsedTime());
}
/*
* ======== Main.runCfg ========
*/
function runCfg()
{
return (this.runStringCfg(null));
}
/*
* ======== Main.runStringCfg ========
*/
function runStringCfg(script)
{
try {
this.$private.$$cfgCapsule._userscript(script);
_myTrace("package closing phase: $$phase -> 3", 1,
["xdccore", "bench"]);
xdc.om.$$bind('$$phase', 3);
closePackages();
sealConfig();
_myTrace("all config parameters sealed", 2, ["xdccore"]);
_myTrace("module$static$init phase: $$phase -> 4", 1,
["xdccore", "bench"]);
xdc.om.$$bind('$$phase', 4);
configureModules();
_myTrace("instance$static$init phase: $$phase -> 5", 1,
["xdccore", "bench"]);
xdc.om.$$bind('$$phase', 5);
configureInstances();
}
catch (e if !(e instanceof JavaException)) {
if (typeof(e) == "object" && "toString" in e
&& e.toString() == "Error: xdc.fatal.error") {
return (getErrors());
}
else {
/* The code that examines $$warnings and $$errors must not be a
* function because a function changes stack trace for the caught
* exception rethrown later.
* Error and warning messages are generated initially with ':::'
* as a separator between fields, so that XGCONF can parse them.
* When printed ':::' are replaced with ': '.
*/
if (xdc.om.$$warnings.length > 0) {
for (var i = 0; i < xdc.om.$$warnings.length; i++) {
java.lang.System.err.println
(xdc.om.$$warnings[i].replace(/\:\:\:/g, ": "));
}
}
if (xdc.om.$$errors.length > 0) {
for (var i = 0; i < xdc.om.$$errors.length; i++) {
java.lang.System.err.println
(xdc.om.$$errors[i].replace(/\:\:\:/g, ": "));
}
}
throw (e);
}
}
if (xdc.om.$$errors.length > 0) {
return (getErrors());
}
return ("");
}
/*
* ======== sealConfig ========
*/
function sealConfig()
{
for (var i = 0; i < xdc.om.$packages.length; i++) {
var pkg = xdc.om.$packages[i].$orig;
for (var j = 0; j < pkg.$modules.length; j++) {
var mod = pkg.$modules[j];
if ('PROXY$' in mod && mod.PROXY$) {
continue;
}
if (mod.$used && mod.$name != "xdc.cfg.Program") {
/* We leave internal config parameters unsealed because they
* should be accessed only by modules within this package
* because we keep changing them.
*/
var internMap = {};
/* We need to check for existence of $$icfgs, because we didn't
* increment the schema number when this code was added. When
* we increment from 170, the else clause can be removed.
*/
if ("$$icfgs" in mod) {
var modParams = mod.$$icfgs;
for (var k = 0; k < modParams.length; k++) {
internMap[modParams[k]] = 1;
}
}
else {
var modParams = mod.$spec.getConfigs().listIterator();
while (modParams.hasNext()) {
var param = modParams.next();
if (param.isInternal() || param.isSys()) {
internMap[param.getName()] = 1;
}
internMap[param] = 1;
}
}
for (var f in mod) {
if (!(f in internMap)) {
mod.$seal(f);
}
}
}
}
}
}
/*
* ======== Main.setExecutable ========
*/
function setExecutable(cfgScript, pathPrefix)
{
environment['config.scriptName'] = cfgScript;
var cfgFile = null;
if (pathPrefix == undefined) {
cfgFile = new java.io.File(cfgScript);
}
else {
cfgFile = new java.io.File(pathPrefix + "/" + cfgScript);
}
if (cfgFile == null) {
throw new _localError("Configuration file " + cfgScript
+ " is not found!");
}
var genCfg = utils.loadCapsule(cfgFile.getCanonicalPath());
this.$private.$$cfgCapsule = genCfg;
try {
genCfg._cfginit();
}
catch (e if !(e instanceof JavaException)) {
if (typeof(e) == "object" && "toString" in e
&& e.toString() == "Error: xdc.fatal.error") {
return (getErrors());
}
else {
/* The code that examines $$warnings and $$errors must not be a
* function because a function changes stack trace for the caught
* exception rethrown later.
* Error and warning messages are generated initially with ':::'
* as a separator between fields, so that XGCONF can parse them.
* When printed ':::' are replaced with ': '.
*/
if (xdc.om.$$warnings.length > 0) {
for (var i = 0; i < xdc.om.$$warnings.length; i++) {
java.lang.System.err.println
(xdc.om.$$warnings[i].replace(/\:\:\:/g, ": "));
}
}
if (xdc.om.$$errors.length > 0) {
for (var i = 0; i < xdc.om.$$errors.length; i++) {
java.lang.System.err.println
(xdc.om.$$errors[i].replace(/\:\:\:/g, ": "));
}
}
throw (e);
}
}
if (xdc.om.$$errors.length > 0 || xdc.om.$$warnings.length > 0) {
return (getErrors());
}
return ("");
}
/*
* ======== Main.validate ========
*/
function validate()
{
/* only the throws by $$logFatal are caught here */
try {
/* package validate() */
for (var i = xdc.om.$packages.length - 1; i >= 0; i--) {
var pkg = xdc.om['xdc.IPackage'].Module(xdc.om.$packages[i]);
_myTrace("validating " + pkg.$name, 2, ["xdccore"]);
for (var j = 0; j < pkg.$modules.length; j++) {
if (pkg.$modules[j].$used) {
pkg.$modules[j].module$validate();
}
}
pkg.validate();
}
}
catch (e if !(e instanceof JavaException)) {
if (typeof(e) == "object" && "toString" in e
&& e.toString() == "Error: xdc.fatal.error") {
return (getErrors());
}
else {
/* The code that examines $$warnings and $$errors must not be a
* function because a function changes stack trace for the caught
* exception rethrown later.
* Error and warning messages are generated initially with ':::'
* as a separator between fields, so that XGCONF can parse them.
* When printed ':::' are replaced with ': '.
*/
if (xdc.om.$$warnings.length > 0) {
for (var i = 0; i < xdc.om.$$warnings.length; i++) {
java.lang.System.err.println
(xdc.om.$$warnings[i].replace(/\:\:\:/g, ": "));
}
}
if (xdc.om.$$errors.length > 0) {
for (var i = 0; i < xdc.om.$$errors.length; i++) {
java.lang.System.err.println
(xdc.om.$$errors[i].replace(/\:\:\:/g, ": "));
}
}
throw (e);
}
}
if (xdc.om.$$errors.length > 0) {
return (getErrors());
}
_Clock.print("cfg model validate done.");
_myTrace("validation phase done", 0, ["bench"]);
if (utils.hasReportedError()) {
return ("Validation error");
}
if (xdc.om.$$warnings.length > 0) {
return (getErrors());
}
return ("");
}
/*---------------- private functions ----------------- */
/* From this point on, 'this' refers to the file scope, not module Main */
/*
* ======== checkVersions ========
* Validate that the "built-with" versions of imported packages are
* compatible with their actual versions.
*
* Returns an object with the properties wCount, eCount, and msg. If there
* is no incompatibility msg == ""; otherwise msg is a meaningful message
* describing all incompatibilities found. wCount is a count of warnings
* and eCount is a count of errors
*/
function checkVersions(exclude)
{
var result = {eCount: 0, wCount: 0, msg: ""};
var msgs = {};
/* optionally subset the list of imported packages to check */
var pkgList = [];
if (exclude != null && exclude != undefined) {
for (var i = 0; i < xdc.om.$packages.length; i++) {
var pkg = xdc.om.$packages[i].$orig;
var tmp = pkg.$name.match(exclude);
if (tmp == null || tmp[0] != pkg.$name) {
// print("including package " + pkg.$name);
pkgList.push(xdc.om.$packages[i]);
}
else {
// print("excluding package " + pkg.$name);
}
}
}
else {
pkgList = xdc.om.$packages;
}
/* For every package pkg imported in this configuration, check that
* the target version used by pkg is compatible with the target
* version used by Program.
*/
if (Program.build.target.version != null) {
var pa = Program.build.target.version.split("{");
/* Get the raw compiler version or get the compiler version from the
* compatibility key.
*/
var it3 = xdc.module("xdc.bld.ITarget3");
var t3 = it3.Module(Program.build.target);
var parw = (t3 != null) ? ("" + t3.rawVersion)
: ("" + pa[1].substring(4).replace("\,", "\."));
for (var i = 0; i < pkgList.length; i++) {
var pkg = pkgList[i].$orig;
if (pkg.build.libraries.length == 0) {
continue; /* if pkg has no libraries, don't check it */
}
/* get target version info from pkg */
var trgs = Packages.xdc.services.global.Vers.getTargetReferences(
pkg.packageBase + "/package/package.bld.xml");
/* get target raw version info from pkg */
var trawver = Packages.xdc.services.global.Vers.
getRawTargetReferences(pkg.packageBase
+ "/package/package.bld.xml");
/* verify compatibility with Program.build.target version */
for (var j = 0; j < trgs.length; j++) {
var ta = ("" + trgs[j]).split("{");
/* Get the raw compiler version or get the compiler version
* from compatibility key.
*/
var tarw = (trawver[j] != null) ? ("" + trawver[j])
: ("" + ta[1].substring(4).replace("\,", "\."));
if (ta[0] == pa[0]) {
var emsg = isCompatible(ta[0], pa[1], ta[1], pkg.$name);
if (emsg != null) {
result.eCount += emsg.eCount;
result.wCount += emsg.wCount;
if (msgs[ta[0]] == null) {
msgs[ta[0]] = "xdc.cfg.INCOMPATIBLE_TARGET_VERSION:"
+ " the compiler version [" + parw
+ "] used by the current target '" + ta[0]
+ "' is not compatible with compiler version "
+ "of targets used to build the following "
+ "packages";
}
msgs[ta[0]] += "; " + "package " + pkg.$name
+ " [in " + pkg.packageBase + "]"
+ " was built using the target '" + ta[0]
+ "' with compiler version [" + tarw + "].\n";
}
break;
}
}
/*
* Note that we do *not* ensure that the same targets are used.
* We only verify that for the targets used their keys indicate
* that they are compatible. This allows a package to use a
* different target to build a library that is contributed to
* this executable; e.g., BIOS can use a single C55 target that
* supports 1510, 1610, and 1710 but the application can use a
* target that assumes the 1710.
*/
if (j >= trgs.length) {
; /* package pkg was not built with the same target! */
}
}
}
/* For every package pkg imported by this configuration, check that
* the packages used to build pkg are compatible with the packages
* imported by this configuration.
*/
for (var i = 0; i < pkgList.length; i++) {
var pkg = pkgList[i].$orig;
/* get packages referenced by pkg during its build */
// print(" imported package " + pkg.$name);
var refs = Packages.xdc.services.global.Vers.getReferences(
pkg.packageBase + "/package/package.rel.xml");
/* for each referenced package, check consistency with imported set */
for (var j = 0; j < refs.length; j++) {
var pa = ("" + refs[j]).split("{");
// print(" built with: " + refs[j]);
/* pa[1] is the key of a referenced package loaded when 'pkg'
* was built. If pa[1] is empty, it means that the referenced
* package loaded at the build time is compatible with any of its
* version loaded in this configuration, so no need to check the
* loaded packages. Skip to the next referenced package.
*/
if (pa[1] == "") {
continue;
}
for (var k = 0; k < pkgList.length; k++) {
var tmp = pkgList[k].$orig;
/* if ref[j] is in the imported set ... */
if (pa[0] == tmp.$name) {
/* build tmp's version string from vers number array */
var vers = "";
if (tmp.$vers != null) {
vers = tmp.$vers.slice(0, 4).join(", ");
}
else {
/* We found the loaded version of the referenced
* package, and that version has an empty key. So, it
* doesn't matter what was the key for the referenced
* package at the time when 'pkg' was built. We can't
* have two versions of the same package loaded, so we
* can stop searching through the loaded package. Skip
* to the next referenced package.
*/
break;
}
var emsg = isCompatible(tmp.$name, vers, pa[1], pkg.$name);
if (emsg != null) {
result.eCount += emsg.eCount;
result.wCount += emsg.wCount;
if (msgs[tmp.$name] == null) {
msgs[tmp.$name] = "incompatible use of package '"
+ tmp.$name + "' [in " + tmp.packageBase
+ "]: version of the loaded package '"
+ tmp.$name + "' is [" + vers + "]";
}
msgs[tmp.$name] += ", while '" + pkg.$name + "' [in "
+ pkg.packageBase + "]" + " was built with '"
+ tmp.$name + "' [" + pa[1] + "]";
}
}
}
}
}
var sep = "";
for (var m in msgs) {
result.msg += sep + msgs[m];
sep = "; ";
}
if (result.msg != "" && environment["xdc.cfg.check.fatal"] != "false"
&& result.eCount > 0) {
result.msg += "\nAdding the following line to your program "
+ "configuration script:\n\tenvironment['xdc.cfg.check.fatal'] = "
+ "'false';\nconverts this incompatibility error into a warning. "
+ "Please, check the documentation for the package xdc.cfg for "
+ "more information.";
}
return (result);
}
/*
* ======== _genDependencyList ========
* Sort packages into a order that is appropriate for linking:
* if pkgA requires pkgB, then pkgA appears earlier than pkgB
*
* Returns a new package list suitable for assignment to xdc.om.$packages
*/
function _genDependencyList()
{
// print("_genDependencyList: (requires)"); for (var key in xdc.om.$require) print(" " + key);
_Clock.print("cfg tsort start (" + xdc.om.$require.length + " edges, "
+ xdc.om.$packages.length + " pkgs)");
/* xdc.cfg.tsort.policy can be set in config.bld via
* Pkg.attrs.xsopts = "-Dxdc.cfg.tsort.policy=fast";
*/
var policy = environment["xdc.cfg.tsort.policy"];
var pkgList;
if (policy == "fast") {
pkgList = _tsort();
}
else if (policy == "test") {
/* test the two sorts but use the new one */
pkgList = _tsort();
_legacySort(pkgList);
}
else {
pkgList = _legacySort();
}
_Clock.print("cfg tsort done.");
/* return sorted list of packages */
return (pkgList);
}
/*
* ======== _tsort ========
* Do standard topological sort of the packages named by
* xdc.om.$require "edges" initialized by xdc.loadPackage()
*
* Returns an array of pkg objects suitable for assignment to
* xdc.om.$packages.
*/
function _tsort()
{
/* function called only when graph cycles are detected */
function myWarning(node, prefix, cycle) {
var lcount = 0;
for (var i = 0; i < cycle.length; i++) {
var pkg = xdc.om[cycle[i].name];
if (pkg.build.libraries.length > 0) {
lcount++;
}
}
if (lcount > 1) {
print("warning: xdc.cfg.Main: cycle involving " + lcount
+ " packages with libraries\n "
+ cycle.join(" <-- "));
}
}
/* Here we need to go through xdc.om.$require map and put the packages
* in order determined by dependencies from xdc.om.$require.
*/
/* create a graph that we can use to do a topological sort */
var Graph = xdc.loadCapsule("xdc/cfg/Graph.xs");
var graph = new Graph.Instance("xdc.cfg.Main: package dependencies",
myWarning);
for (var edge in xdc.om.$require) {
var nodes = edge.split(/\s/);
graph.mkNode(nodes[0]).pointsTo(graph.mkNode(nodes[1]));
//print(" " + nodes[0] + " --> " + nodes[1]);
}
/* do a topological sort of the nodes in the graph */
var genList = graph.tsort();
/* create new packages array */
var pkgList = [];
for (var i = 0; i < genList.length; i++) {
var name = genList[i];
if (name in xdc.om) {
var pkg = xdc.om[name];
/* if a package is referenced, make sure its getLibs is called */
if (graph[name].getInDegree() > 0) {
pkg.$$bind('$$genflg', 1);
pkg.$$bind('$$inDegree', graph[name].getInDegree());
}
/* put package object in pkgList (not the node/package name) */
pkgList.push(pkg);
}
}
/* get $homepkg out of the list and add it at the end to ensure its
* libraries will end up at the top of the linker command file.
*/
for (var i = 0; i < pkgList.length; i++) {
if (pkgList[i] == xdc.om.$homepkg) {
pkgList.splice(i, 1);
pkgList.push(xdc.om.$homepkg);
break;
}
}
_Clock.print("cfg fast tsort done.");
/* return sorted list of packages */
return (pkgList);
}
/*
* ======== _legacySort ========
* Same as _tsort except:
* o we use the legacy algorithm for compatibility, and
* o if the pkgList argument is non-null, it is a new algorithm's
* result to be "validated" against the legacy algorithm
*/
function _legacySort(pkgList)
{
/* run old algorithm: NOTE: it destroys the $requires list! */
var Legacy = xdc.loadCapsule("Legacy.xs");
if (pkgList != null) {
/* check new list against xdc.om.$require requirements, before
* it gets trashed by Legacy.tsort()
*/
Legacy.validate(pkgList, xdc.om.$require);
}
/* run the legacy algorithm */
var oldList = Legacy.tsort();
_Clock.print("cfg legacy tsort done.");
if (pkgList != null) {
/* run a comparison of the two results */
Legacy.test(oldList, pkgList);
}
return (oldList);
}
/*
* ======== closePackages ========
*
* call pkg.close() for all packages in the configuration
*/
function closePackages ()
{
var curIndex = 0;
var closeStack = [];
var saveCurPkg = xdc.om.$curpkg;
for (;;) {
/* transfer current set of packages to a stack */
for (var i = curIndex; i < xdc.om.$packages.length; i++) {
closeStack.push(xdc.om.$packages[i]);
}
curIndex = xdc.om.$packages.length;
if (closeStack.length == 0) {
break;
}
/* close the top-most package */
var curpkg = xdc.om['xdc.IPackage'].Module(closeStack.pop());
/* Setting $curpkg to curpkg.$name must precede the useModule calls */
xdc.om.$$bind('$curpkg', curpkg.$name);
for each (var mod in curpkg.$modules) {
/* Modules that never made it to $$usemod or went through it only
* partially are calling $$usemod again.
*/
if (mod.$used &&
(!('$$cfgPhase' in mod) || (mod.$$cfgPhase == 1))) {
xdc.useModule(mod.$name);
}
}
_myTrace("calling " + curpkg.$name + ".close()", 1, ["xdccore"]);
curpkg.close();
}
/* If xdc.runtime is loaded, we need to make a special call into
* xdc.runtime package to "finalize" the modules in this configuration;
* e.g., propagate logggers, gates, and heap managers to all runtime
* modules in the configuration
*
* Warning: no new modules can be added after this point; otherwise the
* common settings will not be properly initialized!
*/
if ("xdc.runtime" in xdc.om) {
xdc.om.$$bind('$curpkg', "xdc.runtime");
xdc.loadPackage('xdc.runtime').$capsule.finalize();
}
xdc.om.$$bind('$curpkg', saveCurPkg);
Program.$capsule._close.apply(Program);
}
/*
* ======== configureInstances ========
*
* call instance$static$init for all instances
*/
function configureInstances()
{
/* construct instance meta-objects */
for (var i = 0; i < xdc.om.$modules.length; i++) {
var mod = xdc.om.$modules[i].$orig;
if (!mod.$used || mod.$hostonly) {
continue;
}
for (var aname in {$instances: null, $objects: null}) {
var arr = mod[aname];
for (var j = 0; j < arr.length; j++) {
var inst = arr[j];
if ('$$phase' in inst && inst.$$phase >= 5) {
continue;
}
inst.$$bind('$$phase', 5);
_myTrace("calling " + mod.$name + ".instance$static$init for "
+ "instance " + aname, 2, ["xdccore"]);
mod.__initObject(inst);
}
}
}
}
/*
* ======== configureModules ========
*
* call module$static$init for all modules
*/
function configureModules()
{
var cfgModel = xdc.module('xdc.cfg.Main');
/* propagate default profile to each imported package */
for (var i = xdc.om.$packages.length - 1; i >= 0; i--) {
var pkg = xdc.om['xdc.IPackage'].Module(xdc.om.$packages[i]);
if (pkg.profile == null) {
pkg.profile = Program.build.profile;
}
}
/* propagate assertions of modules used */
cfgModel.$private.$$usestk = [];
for (var i = 0; i < xdc.om.$modules.length; i++) {
var mod = xdc.om.$modules[i];
//mod.$seal();
if (mod.$used) {
_myTrace("calling " + mod.$orig.$name + ".module$static$init", 2,
["xdccore"]);
mod.$orig.module$static$init(
'$object' in mod ? mod.$object : null, mod.$orig);
}
}
}
/*
* ======== genDbg ========
* Generate debug support files for IDEs such as CCS.
*
* Params:
* cfgName - the name of the generated configuration script
* exeName - the name of the output executable
* prog - the configured xdc.cfg.Program object
*
* both cfgName and exeName are relative to the directory containing
* package.bld.
*/
function genDbg(cfgName, exeName, prog)
{
var template;
var fPattern;
var fname;
// print("cfgName = '" + cfgName + "', " + "exeName = '" + exeName);
if (prog.build.target.debugGen != null) {
template = prog.build.target.debugGen.execTemplate;
fPattern = prog.build.target.debugGen.execPattern;
}
if (template != null) {
var bldUtils = xdc.module('xdc.bld.Utils');
/* expand the output file name pattern */
fname = bldUtils.expandDbgName(cfgName, exeName, fPattern);
/* expand template */
// print("template file '" + template + "', generating '" + fname + "'");
var t = xdc.loadTemplate(template);
t.genFile(fname, prog, [exeName]);
}
return (fname);
}
/*
* ======== genDot ========
* Generate Dot file that contains information about the configuration.
*/
function genDot(outputFileName)
{
function toLabel(name)
{
return (name.replace(/\./g, '_'));
}
/* if outputFileName is null, write to stdout */
var out;
if (outputFileName != null) {
var file = new java.io.File(outputFileName);
file["delete"]();
out = new java.io.FileWriter(outputFileName);
out = new java.io.BufferedWriter(out);
}
else {
out = new java.io.OutputStreamWriter(java.lang.System.out);
}
out.write('digraph configuration {\n');
out.write(' size="7.5,10";\n');
out.write(' rankdir=LR;\n');
out.write(' ranksep=".50 equally";\n');
out.write(' concentrate=true;\n');
out.write(' compound=true;\n');
out.write(' label="\\nConfiguration for '
+ Program.buildPackage + '/' + Program.name + '"\n');
/* Create a distinguished subgraph that represents the config script */
out.write(' node [font=Helvetica, fontsize=14, fontcolor=black];');
out.write(' subgraph cluster0 {label=""; __cfg [label="'
+ Program.build.cfgScript + '", color=white, fontcolor=blue];\n');
out.write(' node [font=Helvetica, fontsize=10];');
/* For every package imported by this configuration, create
* sub-graph cluster of modules within the package.
*/
var pkgNodes = [];
for (var i = 0; i < xdc.om.$packages.length; i++) {
var pkg = xdc.om.$packages[i].$orig;
var vers = "";
if (pkg.$vers != null) {
vers = pkg.$vers.join(",");
}
out.write(' subgraph cluster' + (i + 1) + ' {\n');
out.write(' label="";\n');
/* create top node in the cluster to represent the pkg as a whole */
var pnname = toLabel(pkg.$name);
out.write(' '+ pnname + '__top [shape=box,label="'
+ pkg.$name + '\\n' + vers + '", color=white];\n');
/* create bottom node in the cluster to represent pkg as a whole */
if (pkg.$modules.length > 0) {
out.write(' '+ pnname + '__bot [shape=point,label=""'
+ ', style=invis];\n');
pkgNodes[i] = {top: pnname + '__top', bot: pnname + '__bot'};
}
else {
pkgNodes[i] = {top: pnname + '__top', bot: pnname + '__top'};
}
/* create nodes for each module in the package pkg */
for (var j = 0; j < pkg.$modules.length; j++) {
var mod = pkg.$modules[j];
var nname = toLabel(mod.$name);
var mname = mod.$name + "";
if (mname.indexOf(pkg.$name + '.') == 0) {
mname = mname.substr(pkg.$name.length + 1);
}
/* make a node for each module; gray are used, white aren't */
if (mod.$used) {
out.write(' ' + nname + ' [style=filled,fillcolor='
+ 'lightgray, label="' + mname + '"];\n');
}
else {
// out.write(' ' + nname + ' [style=filled,fillcolor='
// + 'white, label="' + mname + '"];\n');
continue;
}
/* top invisibly points to all modules in the package */
out.write(' ' + pkgNodes[i].top + ' -> '
+ nname + '[style=invis];\n');
/* and all modules in the package invisibly point to bot */
out.write(' ' + nname + ' -> '
+ pkgNodes[i].bot + '[style=invis];\n');
/* each module points to every other module it "uses" */
for (var k = 0; k < mod.$uses.length; k++) {
out.write(' ' + nname + ' -> '
+ toLabel(mod.$uses[k].$name) + '\n');
}
}
out.write(' }\n'); /* end package subgraph */
}
out.write(' }\n'); /* end cfg script sub-graph */
/* For every package pkg imported in this configuration, draw an edge
* from the bottom of the cluster to the target version used by pkg.
*/
out.write(' node [font=Helvetica, fontsize=10];\n');
var pa = Program.build.target.version.split("{");
for (var i = 0; i < xdc.om.$packages.length; i++) {
var pkg = xdc.om.$packages[i].$orig;
/* get target version info from pkg */
var trgs = Packages.xdc.services.global.Vers.getTargetReferences(
pkg.packageBase + "/package/package.bld.xml");
/* find the target used by this config, and output its version */
var tname = null;
for (var j = 0; j < trgs.length; j++) {
var ta = ("" + trgs[j]).split("{");
if (ta[0] == pa[0]) {
/* create a unique node name for each target version */
tname = toLabel(ta[0]) + '__'
+ ta[1].replace(/\./g, '__').replace(/,/g,'_');
/* create the target node */
out.write(' ' + tname
+ ' [shape=record,label="' + ta[0] + '|' + ta[1]
+ '",style=filled, fillcolor=lightgrey];\n');
break;
}
}
/* draw an edge to the target used by the package */
if (tname != null) {
out.write(' ' + pkgNodes[i].bot
+ ' -> ' + tname + ' [ltail=cluster' + (i + 1) + '];\n');
}
}
out.write('}\n');
out.flush();
if (outputFileName != null) {
out.close();
}
_Clock.print("cfg DOT generation done.");
}
/*
* ======== genRov ========
*
* Recapture configuration information for rov model
*/
function genRov(outputFileName)
{
var o = {};
o.build = Program.build;
o.$modules = {};
for (var i = 0; i < xdc.om.$modules.length; i++) {
var m = xdc.om.$modules[i];
if (!m.$hostonly && m.$used && !m.PROXY$) {
o.$modules[m.$name] = m;
o.$modules["#" + m.Module__id] = m;
}
}
if (outputFileName != null) {
var file = new java.io.File(outputFileName);
file["delete"]();
}
xdc.recapObject(o, outputFileName);
_Clock.print("cfg ROV generation done.");
}
/*
* ======== genXML ========
* Generate XML file that contains information about the configuration.
*/
function genXML(outputFileName)
{
/* if outputFileName is null, write to stdout */
var out;
if (outputFileName != null) {
var file = new java.io.File(outputFileName);
file["delete"]();
out = new java.io.FileWriter(outputFileName);
out = new java.io.BufferedWriter(out);
}
else {
out = new java.io.OutputStreamWriter(java.lang.System.out);
}
var encoding = java.nio.charset.Charset.defaultCharset().name();
out.write('<?xml version="1.0" encoding="' + encoding + '"?>\n');
// out.write('<!DOCTYPE release SYSTEM "configuration.dtd">\n');
out.write('<!-- This file conforms to the DTD xdc/cfg/configuration.dtd -->\n');
out.write('<configuration name="'
+ Program.buildPackage + '/' + Program.name + '"\n '
+ 'platformName="' + Program.platformName + '"\n '
+ 'globalSection="' + Program.globalSection + '"\n '
+ 'sysStack="' + Program.sysStack + '"\n '
+ 'stack="' + Program.stack + '"\n '
+ 'heap="' + Program.heap + '"\n '
+ 'argSize="' + Program.argSize + '"\n '
+ 'execCmd="' + escape(Program.execCmd) + '"\n '
+ 'endian="' + Program.endian + '"\n '
+ 'codeModel="' + Program.codeModel + '"\n '
+ 'dataModel="' + Program.dataModel + '">\n');
/* For every package pkg imported in this configuration, output
* the target version used by the pkg.
*/
out.write('<targets>\n');
var pa = Program.build.target.version.split("{");
for (var i = 0; i < xdc.om.$packages.length; i++) {
var pkg = xdc.om.$packages[i].$orig;
/* get target version info from pkg */
var trgs = Packages.xdc.services.global.Vers.getTargetReferences(
pkg.packageBase + "/package/package.bld.xml");
/* find the target used by this config, and output its version */
for (var j = 0; j < trgs.length; j++) {
var ta = ("" + trgs[j]).split("{");
if (ta[0] == pa[0]) {
out.write(' <target name="' + ta[0] + '"\n');
out.write(' version="' + ta[1] + '"\n');
out.write(' usedby="' + pkg.$name + '"/>\n');
break;
}
}
}
out.write('</targets>\n');
/* For every package pkg imported by this configuration, output its
* version and its modules used list, and for each module, its uses
* list.
*/
out.write('<imports>\n');
for (var i = 0; i < xdc.om.$packages.length; i++) {
var pkg = xdc.om.$packages[i].$orig;
var vers = "";
if (pkg.$vers != null) {
vers = pkg.$vers.join(",");
}
out.write(' <package name="' + pkg.$name + '" version="'
+ vers + '" repository="' + pkg.packageRepository + '">\n');
/* dump all modules (except for proxies) */
for (var j = 0; j < pkg.$modules.length; j++) {
var mod = pkg.$modules[j];
if ('PROXY$' in mod && mod.PROXY$) {
continue;
}
out.write(' <module name="' + mod.$name + '"\n');
out.write(' used="' + mod.$used + '"\n');
out.write(' uses="');
var prefix = "";
for (var k = 0; k < mod.$uses.length; k++) {
out.write(prefix + mod.$uses[k].$name);
prefix = ';';
}
out.write('">\n');
/* if the module is used, dump its config settings */
if (mod.$used) {
var m = xdc.om[mod.$name].Module(mod);
for (f in m) {
var type = typeof m[f];
var value = String(m[f]);
var xml = null;
if (m[f] != null && type == "object") {
if ("$type" in m[f]) {
type = escape("" + m[f].$type);
}
if ("$toText" in m[f]) {
try {
xml = ("$toTextXml" in m[f]) ? m[f].$toTextXml() : null;
}
catch (e) {
// print("failed to gen XML for " + m + "." + f);
}
value = (xml == null) ? m[f].$toText() : null;
}
}
out.write(' <feature name="' + f
+ '" type="' + type + '"');
if (xml == null) {
out.write(' value="' + escape(value) + '"/>\n');
}
else {
out.write(">" + xml + "\n </feature>\n");
}
}
}
out.write(' </module>\n');
}
out.write(' </package>\n');
}
out.write('</imports>\n');
out.write('</configuration>\n');
out.flush();
if (outputFileName != null) {
out.close();
}
_Clock.print("cfg XML state generation done.");
}
/*
* ======== getErrors ========
* Create a string out of all warnings and error messages separated by '@@'.
* The interface between XGCONF and cfg server does not allow arrays, so we
* had to use one long string.
*/
function getErrors()
{
var ret = "@@";
if (xdc.om.$$warnings.length > 0) {
ret = ret + xdc.om.$$warnings.join("@@");
}
if (xdc.om.$$errors.length > 0) {
if (xdc.om.$$warnings.length > 0) {
ret = ret + "@@";
}
ret = ret + xdc.om.$$errors.join("@@");
}
return (ret);
}
/*
* ======== isCompatible ========
* Check compatibility when package rname uses version bvers of package
* pname during rname's build but version avers is being used in the
* current configuration.
*
* Params:
* pname - package name
* avers - imported (actual) version of package pname
* bvers - version referenced during rname's build
* rname - name of package referencing package pname
*
* Returns:
* null if versions avers and bvers are compatible; otherwise it returns
* a string starting with "Error" or "Warning" that indicates the
* failure.
*/
function isCompatible(pname, avers, bvers, rname)
{
// print("checking compatibility between " + pname + " (vers = " + avers + ") and vers = " + bvers + " used by " + rname);
if (avers == bvers) {
return (null);
}
var result = {wCount: 0, eCount: 0, msg: ""};
/* versions differ, check version numbers */
var ava = avers.split(',');
var bva = bvers.split(',');
/* if one is a version number and the other isn't, assume incompatible */
if (ava == null || bva == null) {
result.wCount = 1;
result.msg = "Warning: can't determine version of " + pname
+ " or the version of " + pname + " used to build " + rname;
return (result);
}
/* otherwise, we need to interpret the version number to decide */
for (var i = 0; i < bva.length; i++) {
/* convert string digits to numbers */
var a = ava[i] - 0;
var b = bva[i] - 0;
/* if digits differ (or as non-numeric strings they don't match) */
if (a != b || (isNaN(a - b) && ava[i] != bva[i])) {
switch (i) {
case 0: { /* incompatible releases */
result.eCount = 1;
result.msg = "Error: re-write of "+ rname + " is required";
return (result);
}
case 1: { /* source compatible release */
result.eCount = 1;
result.msg = "Error: re-build of "+ rname + " is required";
return (result);
}
case 2: { /* API radius */
if (a < b) {
result.wCount = 1;
result.msg = "Warning: the version of " + pname
+ " included in this configuration is older than the version of "
+ pname + " used to build " + rname;
return (result);
}
break;
}
case 3: { /* binary 100% compatible release */
break;
}
}
return (null);
}
}
/* if we get here, the required version is prefix of the avail version */
return (null);
}
/*
* ======== printErrors ========
* Print all warnings and error messages accumulated in $$warning and $$errors
* arrays.
*/
function printErrors()
{
/* Error and warning messages are generated initially with ':::' as a
* separator between fields, so that XGCONF can parse them. When printed
* ':::' are replaced with ': '.
*/
if (xdc.om.$$warnings.length > 0) {
for (var i = 0; i < xdc.om.$$warnings.length; i++) {
java.lang.System.err.println
(xdc.om.$$warnings[i].replace(/\:\:\:/g, ": "));
}
}
if (xdc.om.$$errors.length > 0) {
for (var i = 0; i < xdc.om.$$errors.length; i++) {
java.lang.System.err.println
(xdc.om.$$errors[i].replace(/\:\:\:/g, ": "));
}
}
}
/*
* ======== $$usemod ========
*/
function $$usemod(mod)
{
mod.$used = true;
if (xdc.om.$$phase >= 4) {
print("WARNING: Can't call useModule('" + mod.$name
+ "') after all packages are closed (phase 4 or above)");
}
/* We need to know when the module was loaded for the first time; if it
* is loaded by the config script, it is a "top-level" module whose
* entry points need to be "exported" (preserved as part of any partial
* link). Otherwise, the application may reference a function F that
* is removed from the partial link, the object containing the F will
* be linked with the partial link, and duplicate symbol errors may
* occur.
*/
if (!('$$scope' in mod)) {
mod.$$bind('$$scope', (xdc.om.$$phase < 3) ? 1 : 0);
}
/* cfgPhase undefined => this is the first time mod is being used */
if (!('$$cfgPhase' in mod)) {
mod.$$bind('$$cfgPhase', 0);
}
else if (mod.$$cfgPhase == -1 || mod.$$cfgPhase == 2) {
/* this module is either in the middle of being used (-1) or
* has already been used (2), so we can simply return
*/
return (mod);
}
/* if we're in user's script or before, set cfgPhase == 1 and return;
* i.e., defer execution of mod.module$use() until just before
* mod.$package.close() is to be run (see closePackages())
*/
if (xdc.om.$$phase < 3) {
mod.$$bind('$$cfgPhase', 1);
return (mod);
}
/* cfgPhase == -1 => calling module$use() */
mod.$$bind('$$cfgPhase', -1);
/* call module$use() */
_myTrace("calling " + mod.$orig.$name + ".module$use", 2, ["useModule"]);
mod.$orig.module$use();
/* use proxy/delagates for any bound proxies */
if (!mod.$hostonly && '$$proxies' in mod && !mod.PROXY$) {
for each (var p in mod.$$proxies) {
var pud = mod[p + '$proxy'];
$$usemod(pud);
if (pud.delegate$) {
/* set curpkg to the delegate's pkg to prevent associating
* $curpkg with the delegate; the reason for a delegate is
* to prevent mod from having any association with the
* delegate.
*/
var saveCurpkg = xdc.om.$curpkg;
xdc.om.$$bind('$curpkg', pud.delegate$.$package.$name);
$$usemod(pud.delegate$);
xdc.om.$$bind('$curpkg', saveCurpkg);
}
}
}
/* cfgPhase == 2 => module$use() all done */
mod.$$bind('$$cfgPhase', 2);
return (mod);
}
/*
* ======== cfgUseModule ========
* Use a module in a package
*/
function $$cfgUseModule(qname, cycles)
{
if (typeof qname != 'string') {
throw xdc.$$XDCException("xdc.cfg.USE_MODULE_PARAMETER_ERROR",
"The first parameter of an xdc.useModule() call must be a string");
}
/* xdc.om.$curpkg contains the name of the current package. We keep track
* of it to be able to record dependencies between packages in
* xdc.loadPackage() function. We need to keep saving and retrieving
* $curpkg here because calls to xdc.module end up calling xdc.loadPackage,
* where dependencies are recorded, and the value of $curpkg could be
* changed.
*
* Afterwards, when calling xdc.module(qname), we need to set $curpkg back
* to its initial value to correctly record the dependency between the
* initial $curpkg and qname's package.
*
* Finally, when calling $$usemod, $curpkg is set to qname's package
* because $$usemod may call qname.module$use, and there the current
* package must be 'qname'.
*
* The value of $curpkg is also changed in closePackages(), when calling
* module$use for modules used in the user's script phase, and in
* xdc.loadPackage() before loading schemas.
*/
var caller = xdc.om.$curpkg != undefined ? xdc.om.$curpkg :
(xdc.om.$$phase == 2 ? Program.build.cfgScript : "xdc.cfg shell");
_myTrace("xdc.useModule called on " + qname + " from " + caller,
2, ["useModule"]);
var saveCurpkg = xdc.om.$curpkg;
var cfgModel = xdc.om['xdc.cfg.Main'];
var unit = xdc.module(qname, cycles == undefined ? false : cycles);
if (unit.$category == "Interface") {
if ("$used" in unit) {
unit.$used = true;
}
return (unit);
}
xdc.om.$$bind('$curpkg', unit.$orig.$package.$name);
cfgModel.$private.$$usemod(unit);
xdc.om.$$bind('$curpkg', saveCurpkg);
return (unit);
}
/*
* ======== _myTrace ========
*/
function _myTrace(msg, level, groups)
{
groups.push("all");
utils._tracePrint("xdc: " + msg, "xdc/cfg/Main.xs", "xdc/cfg",
groups, level);
}