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