blob: 890e1287ad027068a780d783b17382279ac011dc [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--*/
var base = $args[0]; /* base name of config files */
var noasm = $args[1]; /* true for exes, false for assemblies */
var pkg = $args[2]; /* the PackageContents object */
var genTab = $args[3]; /* generation table from target filters */
var prog = this; /* build model Configuration object */
/* create the build object to pass to the configuration domain */
var build = {};
for (var i in prog.attrs) {
build[i] = prog.attrs[i];
}
/*
* ======== _attach ========
*
* Extract differences between an object and its prototype
*
* This function returns true if the objects 'obj' and 'proto' differ.
* Also, the object 'newObj' contains the properties of 'obj'
* that differ from corresponding properties in 'proto'.
*
* Parameters:
* newObj the "diff" object that represents the set of changes made on a
* 'obj' compared to 'proto'
* obj the actual target object at the build time
* proto the prototype object for the target, which is used as an initial
* state of the target
*/
function _attach(newObj, obj, proto)
{
/* if there is at least one property in 'obj' that has to be added to
* 'newObj', we return true so that 'newObj' will be added to its
* potential parent.
*/
var added = false;
for (var prop in obj) {
if (obj[prop] == undefined) {
if (proto != undefined && prop in proto
&& proto[prop] != undefined) {
/* prototype defines a property, but object undefines it */
newObj[prop] = undefined;
added = true;
}
}
else if (typeof obj[prop] == "object" && obj[prop] != undefined) {
var protoField = undefined;
if (proto != undefined) {
protoField = proto[prop];
if (proto[prop] != undefined && "$category" in proto[prop]
&& proto[prop].$category == "Other") {
protoField = undefined;
}
}
if ((protoField instanceof Array || protoField == undefined)
&& obj[prop].$category == "Vector") {
/* XDCscript array, differs from an XDCscript map only by
* the property category. Initializer for the prototype is
* an array in both cases.
*/
var newArray = [];
var arrAdded = false;
for (var i = 0; i < obj[prop].length; i++) {
var protoMember = undefined;
if (protoField != undefined) {
protoMember = protoField[i];
}
if (typeof obj[prop][i] == "object") {
newArray[i] = {};
/* The first call forces obj[prop][i] to get
* attached to newArray anyway. If only one element
* in the array is different, we replace the whole
* array at the config time.
*/
_attach(newArray[i], obj[prop][i], null);
/* The second call verifies if this element is
* different.
*/
if (_attach(newArray[i], obj[prop][i],
protoMember)) {
arrAdded = true;
}
}
else {
newArray[i] = obj[prop][i];
if (obj[prop][i] != protoMember) {
arrAdded = true;
}
}
}
/* If the sizes are different we already know that the
* arrays are different.
*/
var oldLen = 0;
if (protoField != undefined) {
oldLen = protoField.length;
}
if (arrAdded || (newArray.length != oldLen)) {
newObj[prop] = newArray;
added = true;
}
}
else if ((protoField instanceof Array
|| protoField == undefined)
&& obj[prop].$category == "Map") {
/* XDCscript map, its initializer in proto is an array of
* key-value pairs. We have to recreate a map to be able
* to compare 'obj' and 'proto'.
*/
var newProp = {};
var newProto = {};
var len = 0;
if (protoField != undefined) {
len = protoField.length;
}
for (var j = 0; j < len; j++) {
newProto[protoField[j][0]] = protoField[j][1];
}
if (_attach(newProp, obj[prop], newProto)) {
newObj[prop] = newProp;
added = true;
}
}
else if (((protoField instanceof Object
|| protoField == undefined)
&& obj[prop].$category == "Struct")
|| obj[prop].$category == undefined) {
/* obj[prop] is an XDCscript structure or some other kind
* of object, but not an XDCscript object.
*/
var newProp = {};
if (_attach(newProp, obj[prop], protoField)) {
newObj[prop] = newProp;
added = true;
}
}
else if (obj[prop].$category == "Module"
|| obj[prop].$category == "Instance") {
/* references that we will not follow, just copy */
if (obj[prop].$name != protoField) {
newObj[prop] = obj[prop];
added = true;
}
}
else {
print("Remark: Property " + prop + " of the build target"
+ " was not copied to the config object model.");
}
}
else {
if (proto == undefined || !(prop in proto)
|| proto[prop] == undefined || obj[prop] != proto[prop]) {
/* this covers a case where 'obj' defines a primitive type
* that's left undefined in the prototype, and also a
* case where values for a property of a primitive type
* differ.
*/
newObj[prop] = obj[prop];
added = true;
}
}
}
return (added);
}
/* JavaScript object that contains only those properties that were changed
* in the build target.
*/
var tmpTarg = {};
_attach(tmpTarg, prog.target.$orig, prog.target.$orig.Module);
/* get the platform package name and the instance parameters */
var _Utils = xdc.useModule('xdc.bld.Utils');
var _pstat = _Utils.parsePlatName(prog.platform);
var platPkgName = _pstat.platPkgName;
var platCfgName = _pstat.instName;
/* get the platform instance creation args */
var platCfg;
if (_pstat.instMod == null) {
if (prog.platform == "" || prog.platform == null
|| prog.platform == undefined) {
throw xdc.$$XDCException("xdc.bld.PLATFORM_NOT_SET", "Platform is "
+ "not defined for the target '" + prog.target.$name + "'");
}
platCfg =
xdc.om['xdc.bld.BuildEnvironment'].platformTable[prog.platform];
}
else {
if (_pstat.instName == "") {
throw new Error("the platform name '" + prog.platform
+ "' can't be parsed; the module '" + _pstat.instMod
+ "' does not have the specified platform instance field");
}
}
if (platCfg == null) {
platCfg = {};
}
/*
* ======== _inPkg ========
* Determine if the file, cfname, is in the package specified by
* pdir.
*
* Returns true iff cfname is a file name that appears in the package
* base directory pdir (i.e., pdir contains "package.xdc") and *not* in
* any nested package of pdir.
*
* Note: The file cfname does not need to exist; i.e., this function may
* return true even if the file does not exist.
*
* Parameters:
* pdir is the canonical path name of the package's base directory
* followed by java.io.File.separator
* cfname is the canonical path name of a file to check
*/
function _inPkg(pdir, cfname)
{
/* if the canonical path of the package base isn't a prefix of
* the canonical file name, the file can't be in the package
*/
if (cfname.indexOf(pdir) != 0) {
return (false);
}
/* if there is no directory separator in the file name beyond pdir/,
* then the file is in the package (and not in a nested package).
* This is a "quick" check to avoid the more expensive check below.
*/
if ((cfname.substr(pdir.length)).indexOf(java.io.File.separator) == -1) {
return (true);
}
/* use Scan.findPackageSpec() to check if file is in a nested package */
var pf = Packages.xdc.services.intern.cmd.Scan.findPackageSpec(cfname);
if (pf != null) {
pf = (new java.io.File(pf)).getCanonicalPath();
if (pf == (pdir + "package.xdc")) {
return (true);
}
}
return (false);
}
/*
* ======== _inThisPackage ========
*/
function _inThisPackage(fileName, mustExist)
{
var file = new java.io.File(fileName);
if (mustExist && !file.exists()) {
return (false);
}
var cwd = "" + (new java.io.File(".")).getCanonicalPath()
+ java.io.File.separator;
var cfp = "" + file.getCanonicalPath();
return (_inPkg(cwd, cfp));
}
function _isAbsolute(path)
{
return ((new java.io.File(path)).isAbsolute() ? true : false);
}
/*
* ======== _serialize ========
*/
function _serialize(obj, indent)
{
if (indent == null) {
indent = "";
}
if (obj == null) {
return ("null");
}
var prefix = "\n";
var suffix = "";
var s;
if (obj instanceof Array) {
s = "[";
}
else {
s = "{";
}
if ("$name" in obj && obj.$name.match(/#\d+/) == null) {
/* Check CQ14103 for explanation why some $names are removed. */
s = s.concat('\n' + indent + ' ' + '$name:"' + obj.$name + '",');
suffix = "\n" + indent;
}
for (var i in obj) {
if (i[0] != '$') {
var field = obj[i];
var next;
if (typeof field == 'string'
|| field instanceof java.lang.String) {
next = '"' + escape(field) + '"';
}
else if (typeof field == 'object'
|| typeof field == 'function') {
/* we add a new line to keep lines reasonably short; xpr
* has difficulty parsing long lines
*/
var tmp = indent + " ";
next = _serialize(field, tmp);
}
else if (typeof field == 'number'
|| typeof field == 'boolean') {
next = field;
}
else {
continue; /* skip over unknown types *and* undefined */
}
var pname = i.indexOf('.') >= 0 ? '"' + i + '"' : i;
pname = pname + ": ";
/* if in an array, elements should be listed without names */
if (obj instanceof Array) {
pname = "";
}
s = s.concat(prefix + indent + " " + pname + next);
prefix = ",\n";
suffix = "\n" + indent;
}
}
if (obj instanceof Array) {
s = s.concat(suffix + "]");
}
else {
s = s.concat(suffix + "}");
}
return (s);
}
%%}
/*
* ======== `base`.cfg ========
* This generated configuration script runs the user's configuration script
* the context of a specific target and platform in order to generate
* all the files necessary to create an executable; e.g., linker command
* files, static C/C++ data structures, etc.
*/
/* If it exists, add ROV host-side only debug console support */
try {
xdc.useModule("xdc.rov.runtime.Monitor");
}
catch (e) {
;
}
/*
* ======== _applyChanges ========
* Changes that bring the build target to the state at the end of the build
* model
*/
function _applyChanges(obj, chgObj) {
var wasSealed = false;
if (obj.$sealed) {
wasSealed = true;
obj.$unseal();
}
for (var prop in chgObj) {
if (typeof obj[prop] == 'object' && obj[prop] != undefined) {
if ("$category" in obj[prop] && obj[prop].$category == "Vector") {
obj[prop].length = chgObj[prop].length;
for (var i = 0; i < chgObj[prop].length; i++) {
if (obj[prop].length < i + 1) {
obj[prop].length++;
}
obj[prop][i] = chgObj[prop][i];
}
}
else {
_applyChanges(obj[prop], chgObj[prop]);
}
}
else {
obj[prop] = chgObj[prop];
}
}
if (wasSealed) {
obj.$seal();
}
}
/*
* ======== _runescape ========
* Recursive unescape to decode serialized strings
*/
function _runescape(obj) {
for (var i in obj) {
if (obj[i] != null) {
if (typeof obj[i] == 'string') {
obj[i] = unescape(obj[i]);
}
else if (typeof obj[i] == 'object') {
_runescape(obj[i]);
}
}
}
}
% /* If the platform parameters are found in platformTable, we generate
% * this function that will be invoked when creating a platform.
% */
% if (_pstat.instMod == null) {
/*
* ======== _getPlatCfg ========
*/
function _getPlatCfg() {
var tmp = `_serialize(platCfg, " ")`;
_runescape(tmp);
return (tmp);
}
% }
%
/*
* ======== _cfginit ========
*/
function _cfginit() {
xdc.loadPackage('xdc.services.intern.cmd');
var prog = xdc.om['xdc.cfg.Program'];
/* initialize prog attrs from build model */
var build = `_serialize(build, " ")`;
_runescape(build);
% if (build.cfgArgs != "") {
% if (build.cfgArgsEncoded == true) {
build.cfgArgs = `unescape(build.cfgArgs)`;
% }
% else {
build.cfgArgs = `build.cfgArgs`;
% }
% }
build.target = xdc.module("`prog.target.$orig.$name`");
var targChange = `_serialize(tmpTarg, " ")`;
_runescape(targChange);
_applyChanges(build.target, targChange);
prog.build = build;
prog.name = "`prog.$private.progName ? prog.$private.progName : prog.$private.name`";
prog.cfgBase = "`base`";
% if (build.linkTemplate != null) {
% var prefix = "";
% if (!_isAbsolute(build.linkTemplate)
% && _inThisPackage(build.linkTemplate, true)) {
% prefix = "./";
% }
% prefix = (prefix + build.linkTemplate).replace(/\\/g, '/');
prog.linkTemplate = "`prefix`";
% }
% /* gen cmds to: create aliases for commonly needed build properties */
% if (prog.target.$orig.model.endian != null) {
prog.endian = prog.build.target.model.endian;
% }
% if (prog.target.$orig.model.codeModel != null) {
prog.codeModel = prog.build.target.model.codeModel;
% }
% if (prog.target.$orig.model.dataModel != null) {
prog.dataModel = prog.build.target.model.dataModel;
% }
% if (_pstat.instMod == null) {
/* use the platform package's Platform module */
var Platform = xdc.useModule("`platPkgName`.Platform");
%%{
/* When calling create, we are passing the platform instance parameters
* twice. The first copy is for the old platforms that copy the values
* from the second required parameter to their parameters. The second copy
* is for the newer platforms that ignore the second required parameter
* because that parameter will be removed later. We also have to filter
* the properties from the second copy that are not instance parameters,
* otherwise the call to create will fail when the code in schema tries to
* assign a value to a non-existent parameter. The filtering code should
* be removed once we are allowed to break compatibility with old platforms
*/
%%}
var platParams = _getPlatCfg();
%%{
/* We gather invalid parameters here, but we print the warning later when
* the instance is available so we can include the reference to the
* instance in the warning message.
*/
%%}
var invalidParams = [];
for (var prop in platParams) {
if (!(prop in Platform.PARAMS)) {
delete platParams[prop];
invalidParams.push(prop);
}
}
prog.platformName = "`prog.platform`";
prog.platform = Platform.create("`platCfgName`", platParams);
for (var i = 0; i < invalidParams.length; i++) {
Platform.$logWarning("The parameter '" + invalidParams[i] + "' is " +
"passed to this platform instance through Build.platformTable, " +
"but the instance does not have a configuration parameter with " +
"that name.", prog.platform, "`platCfgName`");
}
% }
% else {
var Instances = xdc.useModule("`_pstat.instMod`");
prog.platform = Instances["`_pstat.instName`"];
prog.platformName = prog.platform.$module.$package.$name + ":" + "`_pstat.instName`";
% }
%
/* record the executable's package name */
prog.buildPackage = "`pkg.name`";
/* record build-model information required during config generation */
prog.$$bind("$$isasm", `(noasm ? "0" : "1")`);
prog.$$bind("$$isrom", 0);
prog.$$bind("$$gentab", [
% for (i = 0; i < genTab.length; i++) {
% var desc = genTab[i];
{template: "`desc.template`", file: "`desc.file`"},
% }
]);
/* bind prog to an appropriate execution context */
prog.cpu = prog.platform.getExeContext(prog);
% /* gen cmds to: import RTS package, unless the client sets
% * prog.attrs.rtsName to null
% */
% if (prog.attrs.rtsName !== null) {
% var rts = prog.attrs.rtsName;
% if (rts == null) { /* if prog's rtsName is undef'd, use target's RTS */
% rts = prog.target.$orig.rts;
% }
% if (rts != null) {
/* import the target's run-time support pkg */
xdc.loadPackage("`rts`");
% }
% }
}
/* function to import the cfg script's package */
function _userscript(script) {
var home;
var spath;
% if (build.cfgHome != null) {
home = xdc.loadPackage("`build.cfgHome`");
% }
% else if (build.cfgScript == null
% || _inThisPackage(build.cfgScript, true)) {
/* import the executable's package */
home = xdc.loadPackage("`pkg.name`");
spath = '.';
% }
% else {
/* locate the cfg script's package and import it */
var ppn = xdc.findFile("`build.cfgScript`");
if (ppn != null) {
var scan = new Packages.xdc.services.intern.cmd.Scan(
xdc.$$private.Env);
ppn = scan.findPackageSpec(ppn);
if (ppn != null) {
ppn = scan.read(ppn);
if (ppn != null) {
home = xdc.loadPackage(ppn);
}
}
}
/* if can't find the config script's package, use the executable's */
if (ppn == null) {
home = xdc.loadPackage("`pkg.name`");
spath = '.';
}
% }
xdc.om.$$bind('$homepkg', home);
% if (build.cfgScript != null) {
var cfgScript = "`build.cfgScript`";
if (!script) {
utils.loadCapsule(cfgScript, false, spath);
}
else {
/* set up the same environment that loadCapsule would */
var $saveCsd = utils.csd;
var $cfgFile = utils.findFile(cfgScript, spath);
var cname = cfgScript;
if ($cfgFile) {
$cfgFile = java.io.File($cfgFile);
utils.csd = $cfgFile.getParentFile().getCanonicalPath();
cname = "" + $cfgFile.getCanonicalPath();
}
/* create the capsule object */
var cap = {
prototype: utils.global,
$path: cname,
$private: {path: cname},
$capsule: undefined, /* set to cap below */
};
/* 'this.$capsule' is always cap object */
cap.$capsule = cap;
/* save the capsule object */
utils.$$capmap[cname] = cap;
try {
var cx =
Packages.org.mozilla.javascript.Context.getCurrentContext();
var rdr = new
java.io.BufferedReader(new java.io.StringReader(script));
Packages.config.Shell.evaluateLoad(cx, cap, rdr, cname, 1);
}
finally {
rdr.close();
utils.csd = $saveCsd;
}
}
% }
}
function _postinit() {
var cout = null;
% if (noasm) {
var Program = xdc.om['xdc.cfg.Program'];
/* get the exec command for this executable */
if (Program.execCmd == null) {
Program.execCmd = Program.platform.getExecCmd(Program,
xdc.om["`platPkgName`"].packageBase);
}
cout = "define EXEC." + Program.name + '\n\n';
cout += Program.execCmd;
cout += "\nendef\n\n";
/* if SourceDir generates a makefile, we need to run it */
_genSourceDirMak("`base`", "`prog.$private.name`");
% }
utils.genDep("`base`", "`pkg.name`", utils.loadedFiles, cout, null);
}
function _genSourceDirMak(cfgBase, cfgName)
{
var SourceDir = xdc.om['xdc.cfg.SourceDir'];
if (SourceDir && SourceDir.$instances.length > 0) {
/* construct rule to run SourceDir generated makefile */
var make = "\t$(MAKE) -f "
+ SourceDir.outputDir + "/" + SourceDir.makefileName;
/* this file is included by package.mak (if it exists) */
var file = new java.io.File(cfgBase + ".cfg.mak");
file["delete"]();
var out = new java.io.BufferedWriter(new java.io.FileWriter(file));
/* add rules to run SourceDir generated makefile */
out.write("# invoke SourceDir generated makefile for " + cfgName
+ "\n" + cfgName + ": .libraries," + cfgName
+ "\n.libraries," + cfgName + ": " + cfgBase + ".xdl\n"
+ make + "\n\n"
+ "clean::\n" + make + " clean\n\n"
);
out.close();
out = null;
}
}