From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 Path: border1.nntp.dca3.giganews.com!backlog3.nntp.dca3.giganews.com!border3.nntp.dca.giganews.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed.hal-mli.net!feeder3.hal-mli.net!newsfeed.hal-mli.net!feeder1.hal-mli.net!peer03.iad.highwinds-media.com!news.highwinds-media.com!feed-me.highwinds-media.com!peer03.am1!peering.am1!npeersf04.am4!fx24.fr7.POSTED!not-for-mail From: Brian Drummond Subject: Re: Exclude parts of a package Newsgroups: comp.lang.ada References: <52a0de7e$0$23162$2c885b36@post.eweka.nl> User-Agent: Pan/0.139 (Sexual Chocolate; GIT bf56508 git://git.gnome.org/pan2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-ID: <2Kiou.15508$bz3.2509@fx24.fr7> NNTP-Posting-Host: 62.49.20.82 X-Complaints-To: abuse@demon.net X-Trace: 1386330110 62.49.20.82 (Fri, 06 Dec 2013 11:41:50 UTC) NNTP-Posting-Date: Fri, 06 Dec 2013 11:41:50 UTC Date: Fri, 06 Dec 2013 11:41:50 GMT X-Received-Body-CRC: 2106972092 X-Received-Bytes: 5824 X-Original-Bytes: 6033 Xref: number.nntp.dca.giganews.com comp.lang.ada:184101 Date: 2013-12-06T11:41:50+00:00 List-Id: On Thu, 05 Dec 2013 21:13:50 +0100, Felix Krause wrote: > In C, I have the possibility to switch parts of my code on or off with > preprocessor defines. What would be the Ada way to do something like > that? > > I know that I can use scenario variables with gprbuild. This works well > if I want to include or exclude whole packages (because I can include or > exclude certain files), but it does not work if I just want to exclude > certain subroutines from a package. > > Take for example OpenCLAda: The user of the library should be able to > choose which version of the OpenCL API he wants to use (1.0, 1.1, …). > This choice should result in subroutines added in newer versions not > being available. I would tend to avoid the preprocessor - even the Gnat one - if at all possible. The basic idea is to separate out variant functionality into different packages for each revision - maybe OpenCL_1_0, OpenCL_1_1, etc. Then with/use a base package, OpenCL, in all your application code. When you come to build the program, you create the package OpenCL appropriately : it can be as simple as: with OpenCL_1_1; package Open_CL renames OpenCL_1_1; -------------------------------------------------------------------- In the MSP430 Ada compiler this approach is extended to support 450+ different varieties of the MSP430 embedded processor, each with a different set of peripherals, and the peripherals themselves vary, not just in register addresses but also functionality (e.g. 8 and 16 bit timers). If the OpenCL variants are in different categories such as math precision, number of cores, etc this sub-package approach may be useful. A worked example: Device selection is in package CPU.ads : with MSP.msp430g2553; package CPU renames MSP.msp430g2553; (Everything else - CPUs and peripherals are child packages of package MSP) package MSP is pragma Pure; type Byte is Array(0 .. 7) of Boolean; Pragma Pack(Byte); For Byte'Size use 8; ... end MSP; The specific CPU package, MSP.msp430g2553; looks like with MSP.cpu_5; with MSP.adc10; with MSP.port1_r_3; ... with MSP.ta3_1; with MSP.vectors_18; package MSP.msp430g2553 is pragma Preelaborate; package cpu renames MSP.cpu_5; package adc10 renames MSP.adc10; package port1_r renames MSP.port1_r_3; ... package ta3 renames MSP.ta3_1; package vectors renames MSP.vectors_18; end MSP.msp430g2553; as you can see, it selects the 5th variant of the CPU, the 3rd variant of Port 1 (a GPIO port) and the 18th variant of the interrupt vector table. It turns out that there are 19 variants of package MSP.cpu, 5 of port1_r, and 84 variants of the interrupt vector table. A vector table package looks like: with Interfaces; use Interfaces; -- make unsigned_n visible package MSP.vectors_18 is pragma Preelaborate; port1_vector : constant unsigned_16 := 16#4#; port2_vector : constant unsigned_16 := 16#6#; adc10_vector : constant unsigned_16 := 16#A#; timer0_a0_vector : constant unsigned_16 := 16#12#; timer1_a1_vector : constant unsigned_16 := 16#18#; ... nmi_vector : constant unsigned_16 := 16#1C#; reset_vector : constant unsigned_16 := 16#1E#; end MSP.vectors_18; And finally a fragment of an application : ----------------------------- with CPU; procedure Watch is package Timer renames CPU.ta3; subtype TickCount is Interfaces.Unsigned_16; OneMinute : constant TickCount := 1024*60; begin Timer.ccr0 := OneMinute - 1; ... and so on. ----------------------------- Now I can change package CPU with MSP.msp430g2202; package CPU renames MSP.msp430g2202; and recompile. If I have used any facilities missing in the new CPU, I find out at compile time. If the timer interrupt vector has been renamed timer_a0_vector (as it has in some other CPUs) it is reported as undeclared. Then the CPU package MSP.msp430g2202 tells me which variant of the interrupt vector package I am using, package vectors renames MSP.vectors_28; and MSP.vectors_28 gives me the new name. Most packages are a page or so, so fairly easy to browse. There are 450-odd CPU packages, and about 350 peripheral description packages (inc. 84 interrupt vector tables) so this gives pretty good reuse. In contrast, the C toolchain takes the preprocessor approach, and each CPU variant has its own #include file ranging from 500 to over 6000 lines; not so easy! The Ada packages are auto-generated from the original #includes, and simplify 60MB of #includes into 1.2MB of CPUs and under 5MB of peripheral packages. I'm happy without the preprocessor. If you're interested in the how, the complete example is at https://sourceforge.net/projects/msp430ada/ - Brian