From RTSC-Pedia
[printable version] | offline version generated on 04-Aug-2010 21:08 UTC |
RTSC Packaging Primer/Lesson 7
Program Configuration selecting charlie.sqrtlib libraries
Having finally built and released the charlie.sqrtlib function librariesone pair per RTSC targetwe'll turn now to the task of selecting the appropriate library from this set during program configuration at the client's site. While the configuration process in general affords packages many opportunities to become active participants in building client applicationswhich we'll highlight towards the end of this lessonselecting the appropriate function libraries that satisfy a particular set of program requirements becomes another "sweet spot" of RTSC packaging.
As you may recall from the flow introduced in Lesson 3, program configuration requires that the client designate a particular RTSC target as an input to the processclearly one factor in guiding library selection. But you may also recall that the client configured the optimize parameter of the charlie.sqrtlib.Settings module in prog.cfgan additional piece of data used internally by the package when choosing between the isqrt_loop and isqrt_unroll libraries for the current target.
Contents |
Specifying the Settings module
From the very outset, we've exposed you to a wide range of RTSC modules used in a variety of contexts:
- acme.utils.Bench, with its begin and end functions and its enable configuration parameter;
- xdc.bld.PackageContents, with its addLibrary function and otherFiles parameter;
- ti.targets.C64 and gnu.targets.Mingw, with their rootDir parameters; and now
- charlie.sqrtlib.Settings, with its optimize configuration parameter.
As a rule, content suppliers will explicitly declare the public (client-visible) features of a RTSC moduleits constants, types, parameters, functionsthrough a separate XDCspec source file found in the corresponding package directory. Applying a simple physical design pattern borrowed from Java, the specification for the charlie.sqrtlib.Settings module must reside in a file named Settings.xdc housed in the charlie/sqrtlib package directory.
charlie/sqrtlib/package.xdc | |
1 | /*! Library of square-root functions */ package charlie.sqrtlib { module Settings; } |
charlie/sqrtlib/Settings.xdc | |
2 3 4 | /*! Controls library selection during program configuration */ metaonly module Settings { enum OptType { OPTIMIZE_FOR_SPACE, OPTIMIZE_FOR_TIME }; config OptType optimize = OPTIMIZE_FOR_TIME; } |
To complete the picture, we've also listed the package.xdc specification file for charlie.sqrtlib which first introduces the Settings module within the scope of this package at line 1.
Even more suggestive of a header filebut clearly expressed in a higher-level language than CSettings.xdc like package.xdc before it defines its own namespace that in turns scopes other programmatic identifiers. In the case of the module declaration beginning at line 2again, using a notation suggestive of a C structwe've then introduced OptType and optimize within the scope of Settings itself.
The enum declaration at line 3 mirrors the syntax and semantics of C, and merits no further explanation at this point. As for the config declaration at line 4a new keyword to match a new constructsuffice it to say that optimize becomes a property of the XDCscript object representing the Settings module with the client's prog.cfg file, with OPTIMIZE_FOR_TIME serving as its initial (default) value. Not unlike variables or fields in C, config declarations will effectively constrain the type of values this parameter can receive during assignment.
As a practical matter, virtually any sort of declaration normally placed within a C language header fileconstants, types, functionscan appear within an XDCspec module specification with little or no change. Suffice it to say that you'd find const, typedef, struct, and extern amongst the keywords of the XDCspec language; a cursory scan through some of the module specifications bundled with the XDCtools productviewed using xdc.tools.cdoc.sg or else by browsing rtsc.eclipse.orgwould also reveal an XDCspec type system that effectively supersets standard C.
Implementation domain. Whereas all RTSC modules will uniformly define their public client-visible features through a corresponding XDCspec source fileinvariably found within the containing package directory, and viewable through client documentation utilities such as xdc.tools.cdoc.sginternal implementation strategies can vary considerably from one module to the next:
- acme.utils.Bench has C-based implementations for its begin and end functions, callable from within executable target programs at runtime; whereas
- xdc.bld.PackageContents has an XDCscript-based implementation for its addLibrary function, callable from within hosted scripts generally running in a very specific context.
Our charlie.sqrtlib.Settings module of course has no functions at all, just a configuration parameter plus some supporting types and constants; practically speaking, the module does not require a private implementation in either programming language. Still, to reinforce the fact that its features remain limited to the client's configuration meta-programas opposed to also having a presence in the client's executable target-programwe've qualified the declaration back at line 2 with the metaonly keyword.
By contrast, a module like acme.utils.Benchwhose XDCspec specification omits the metaonly keywordmaintains a presence in the domain of XDCscript and C. In particular, the final value held by the assignable Bench.enable parameter at configuration-time becomes the initial value of the Bench_enable const at run-timeused internally within the C implementation of the Bench_begin and Bench_end functions. The concept of a single XDCspec specificationone set of constant, type, parameter, or function declarations in a C-based notationdriving a realization within the XDCscript meta-language as well as the C target-language remains a basic premise of RTSC.
Implementing the getLibs function
Back to the task at handselecting the appropriate set of libraries during program configurationRTSC packages can explicitly participate at this stage of the process by implementing a special meta-function named getLibs. Sourced in XDCscript and found in a special file named package.xs within the corresponding package directory, the getLibs function returns a string naming each library actually used further downstream when linking the current program.
The makefile and prog.cfg script used to build and configure the client application in Lesson 3 respectively selected ti.targets.C64P as the program's target and assigned OPTIMIZE_FOR_TIME to the Settings.optimize configuration parameter. As you'd discover by inspecting the program linker.cmd file generated through the RTSC configuration process, this particular combination of inputs selects lib/isqrt_loop.a64P as the library contribution from the charlie.sqrtlib package.
charlie/sqrtlib/package.xs | |
1 2 3 4 5 | function getLibs( prog ) { var pkg = this; var Settings = pkg.Settings; var suffix = prog.build.target.findSuffix(pkg); var name; switch (Settings.optimize) { case Settings.OPTIMIZE_FOR_SPACE: name = "isqrt_loop"; break; case Settings.OPTIMIZE_FOR_TIME: name = "isqrt_unroll"; break; } if (suffix && name) { return "lib/" + name + ".a" + suffix; } else { return null; } } |
Automatically invoked during the final stages of RTSC configurationwell after first executing the client's prog.cfg scriptthe getLibs function has access to two important XDCscript objects used when constructing the list of libraries contributed by this package:
- prog (an explicitly named argument to getLibs) references an object whose properties characterize the program as a wholeincluding information about the current target extracted at line 3; and
- this (an implicit argument to getLibs) references an object representing the charlie.sqrtlib package per sebound here to the local variable pkg at line 1 to improve readability.
In object-oriented languages such as XDCscript, calls of the form «object».«function»( «args» )sometimes termed a method invocationwould here bind the distinguished variable this to the value of «object» once inside the body of «function». Said another way, the configuration process automatically invokes the getLibs method on each XDCscript «package-object» corresponding to some RTSC package contributing directly or indirectly to the current program.
Working backwards now, the string returned at line 5 relies on earlier assignments to suffix and namewhich would here assume the values "isqrt_loop" and "64P" in light of our client application from Lesson 3. In general, the string returned by getLibs can name multiple libraries with ";" as a delimiter; and, in cases where a particular package has no libraries to contribute, getLibs can return an empty string "" or else the special value null.
Moving up the page, the switch statement beginning at line 4 discriminates amongst the set of possible values currently held by Settings.optimizevalues of type OptType specified earlier at line 3 of Settings.xdcand then appropriately assigns the local variable name. As for the binding of Settings at line 2 of getLibs, we've accessed the XDCscript object representing this module using a «package-object».«module-name» idiom, where pkg (alias this) here references the charlie.sqrtlib package object.
As an alternative, we could have called xdc.useModule('charlie.sqrtlib.Settings') at line 2 to retrieve the corresponding module object, though somehow leveraging the package object already available to getLibs seems more self-contained in this example.
Completing the story now, the assignment to suffix at line 3 starts with the object bound to the prog argument of getLibs and then eventually navigates to a findSuffix function defined on targets; taking the current package object as its argument, findSuffix reflects on all targets used when building this package and returns the suffix "most compatible" with the target selected for this program configuration. Internally, findSuffix comprehends the rather rich backward-compatibility relationships that often exist amongst targetsfor instance, "newer" targets (like ti.targets.C64P) can often link libraries compiled with "older" targets (like ti.targets.C62).
To test your understanding, the value of this within the body of the findSuffix function would here reference an XDCscript object corresponding to the ti.targets.C64P targetthe same meta-module we've configured earlier within the config.bld script prepared at the producer's site and executed prior to building the charlie.sqrtlib package.
The xdc.IPackage interface
Besides getLibs, package producers can elect to implement other meta-functions in package.xs called at different points within the program configuration processfrom when the package first enters the current configuration through final generation of the linker.cmd output file.
- init
- called upon importing this package into the current configuration, usually via xdc.useModule
- close
- called when the client's script completes its contribution to the current configuration
- validate
- called before generation of output files begins, giving the package one last opportunity to issue errors/warnings
- exit
- called after the current configuration has been successfully validated, immediately before generation
- getSects
- called during generation, to elicit contributions to linker.cmd beyond the libraries returned by getLibs
Like virtually everything within the world of RTSC, this set of functions ultimately belongs to a larger programmatic entity specified within an XDCspec source filein this case, a RTSC interface named xdc.IPackage. Following the same pattern introduced earlier with the charlie.sqrtlib.Settings module, the special xdc packagebundled with the XDCtools productindeed contains an XDCspec source file named IPackage.xdc.
xdc/package.xdc | |
1 | package xdc { interface IPackage; } |
xdc/IPackage.xdc | |
2 3 | metaonly interface IPackage { ... function close(); function exit(); function getLibs(prog); function getSects(); function init(); function validate(); } |
Here again, line 1 of xdc/package.xdc first introduces IPackage within the scope of the xdc package per se, followed then with a more comprehensive specification in IPackage.xdc; and not unlike Settings.xdc, the metaonly keyword at line 2 implies that none of the xdc.IPackage features specified here have a presence within the target-program during execution. Note also how the function keyword in the XDCspec declaration at line 3 mirrors the syntax of its XDCscript implementation back in package.xs. Needless to say, the "real" xdc.IPackage.xdc interface specification bundled with the XDCtools product contains considerably more detail than shown here.
Similar to the modules we've already encountered, a RTSC interface defines a programmatic contract that aggregates a related set of constants, types, parameters, and functions. But unlike a RTSC modulewhich couples a client-visible specification with a distinct supplier-proprietary implementation at any point in timea RTSC interface can simultaneously support multiple implementations. Said a little differently, any package producer can elect to furnish a specific implementation of the xdc.IPackage functions within their package.xs fileeffectively superseding default implementations otherwise invoked during the program configuration process.
In the same vein, the xdc.bld.ITarget interface specifies a collection of features shared by all RTSC targets; reviewing the current config.bld script, you'll recall that ti.targets.C64P and gnu.targets.Mingw each have an assignable rootDir property. In general, RTSC (meta-)modules like ti.targets.C64P can inherit client-visible features specified elsewhere within a RTSC (meta-)interface, can extend these features on a per-module basis, and can override default parameter values or function implementations as appropriate.
See also
Writing getLibs() | Guidelines for package getLibs() functions |
xdc.IPackage | Client documentation for xdc.IPackage |
[printable version] | offline version generated on 04-Aug-2010 21:08 UTC |