A Ada Interface
Total Page:16
File Type:pdf, Size:1020Kb
A Ada interface AUGUSTA ADA (1815–1852), COUNTESS OF LOVELACE AND DAUGHTER OF LORD BYRON, ASSISTANT AND BIOGRAPHER TO CHARLES BABBAGE, AND THE WORLD’S FIRST COMPUTER PROGRAMMER. The Ada programming language [Ada95] defines a standard interface to routines written in other languages, and the GNU Ada translator, gnat, supports that interface. The standard Ada floating-point data types Float, Long_Float, and Long_Long_Float correspond directly to the C data types float, double, and long double. The Ada integer data types Integer, Long_Integer, and Long_Long_Integer are defined to be 32-bit, 32-bit, and 64-bit signed values, respectively, by the gnat compiler. At the time of writing this, this author has access only to one Ada compiler family, gnat, running on IA-32, IA-64, and AMD64 systems, so interplatform portability of the Ada interface to the mathcw library cannot yet be extensively checked. Nevertheless, any changes needed for other platforms are expected to be relatively small, and related to the mapping of integer types. Ada is a complex and strongly typed language, with a large collection of packages, several of which must be imported into Ada programs in order to use library functions. It is traditional in Ada to separate the specification of a package from its implementation, and with the gnat compiler, the two parts are stored in separate files with extensions .ads (Ada specification) and .adb (Ada body). For example, commercial software vendors can supply the specification source files and implementation object library files to customers, without revealing the implementation source code. Ada specification files therefore are similar in purpose to C header files. The interface to the mathcw library is defined as an Ada package specification in the file mathcw.ads. Because the implementation is in the C language, there is no need for a separate body file. A.1 Building the Ada interface Before looking at the source code of the Ada interface, it is useful to see how it is built and used in a small test program. Initially, we have just three hand-coded files in the ada subdirectory: %cdada %ls Makefile mathcw.ads test.adb The Makefile contains the rules for the build process, the second file contains the Ada specification, and the last file contains the test program. Ada is unusual in that it is a requirement of the language that the compiler manage source-file dependencies, so that it is impossible to compile and link a program with interface inconsistencies. The GNU gnatmake tool satisfies that mandate, managing compilation of files in the correct order, and then linking them into an executable program. That tool requires a lengthy list of options that are recorded in the Makefile. They include options that supply the installed location of the mathcw library, which can be either a static library, or a shared library. The make utility manages the build, which looks like this on a GNU/LINUX system: % make test gnatmake -gnaty test.adb -L/usr/local/lib -aO/usr/local/lib -largs -lm -Xlinker -R/usr/local/lib -lmcw gcc -c -gnaty test.adb © Springer International Publishing AG 2017 911 N.H.F. Beebe, The Mathematical-Function Computation Handbook, DOI 10.1007/978-3-319-64110-2 912 Appendix A. Ada interface gcc -c -gnaty mathcw.ads gnatbind -aO./ -aO/usr/local/lib -I- -x test.ali gnatlink -L/usr/local/lib -lm -Xlinker -R/usr/local/lib -lmcw test.ali Only the gnatmake command is specified in the Makefile. That program examines the source-code file, test.adb, and determines that both that file and the mathcw.ads file must be compiled by gcc, which it then automatically invokes. Next, it runs gnatbind to perform various required consistency checks. Finally, it runs gnatlink to link the object files and libraries recorded in the test.ali file (output by gcc) into the target executable program, test. After the make steps, the ls utility displays a list of all of the files in the directory: %ls Makefile mathcw.ali test test.ali mathcw.ads mathcw.o test.adb test.o Sites that use Ada extensively are likely to have a standard set of directories in which to store interface files, such as mathcw.ads, and in such a case, that file would be installed in one of those directories. However, there are no widely used conventions for the names of directories for locally installed Ada packages, so the Makefile cannot provide a system-independent install target. For simplicity, here we just store the interface and the test program in the same directory. The final step is to run the test program: % ./test Test of Ada interface to MathCW library x MathCW.erff () MathCW.erfcf () -4.00E+00 -1.00000E+00 2.00000E+00 -3.75E+00 -1.00000E+00 2.00000E+00 ... 3.75E+00 1.00000E+00 1.13727E-07 4.00E+00 1.00000E+00 1.54173E-08 x MathCW.erf () MathCW.erfc () -4.00E+00 -9.99999984582742E-01 1.99999998458274E+00 -3.75E+00 -9.99999886272743E-01 1.99999988627274E+00 ... 3.75E+00 9.99999886272743E-01 1.13727256569797E-07 4.00E+00 9.99999984582742E-01 1.54172579002800E-08 x MathCW.erfl () MathCW.erfcl () -4.00E+00 -9.99999984582742100E-01 1.99999998458274210E+00 -3.75E+00 -9.99999886272743430E-01 1.99999988627274343E+00 ... 3.75E+00 9.99999886272743430E-01 1.13727256569796653E-07 4.00E+00 9.99999984582742100E-01 1.54172579002800189E-08 Here, we trimmed trailing zeros from the reported x values to make the output fit the page. A.2 Programming the Ada interface The public part of the interface specification in mathcw.ads begins like this, introducing four mathematical constants that are also present in the standard Ada numerics package: with Interfaces.C; package MathCW is A.2. Programming the Ada interface 913 PI : constant := 3.14159_26535_89793_23846_26433_83279_50288_41971; PI_2 : constant := PI / 2.0; Sqrt_Two : constant := 1.41421_35623_73095_04880_16887_24209_69807_85696; Log_Two : constant := 0.69314_71805_59945_30941_72321_21458_17656_80755; The constants are specified with sufficient precision for 128-bit floating-point arithmetic, and illustrate the useful Ada practice of separating digit groups with underscores to improve readability. That feature is sadly lacking from almost all other programming languages, and is trivial to implement in a compiler. The constants have no declared type; instead, they are converted as needed with a type wrapper, such as Float (PI). The constants are followed by a large block of function declarations that define the names, argument types, and return values of all of the functions in the mathcw library that can be accessed from Ada programs: -- ================ Standard MathCW names ================ function Acosf (X : Float) return Float; function Acoshf (X : Float) return Float; function Adxf (X : Float; N : Integer) return Float; ... function Urcw3f return Float; function Urcw4f return Float; function Urcwf return Float; ... function Acos (X : Long_Float) return Long_Float; function Acosh (X : Long_Float) return Long_Float; function Adx (X : Long_Float; N : Integer) return Long_Float; ... function Urcw3 return Long_Float; function Urcw4 return Long_Float; function Urcw return Long_Float; function Acosl (X : Long_Long_Float) return Long_Long_Float; function Acoshl (X : Long_Long_Float) return Long_Long_Float; function Adxl (X : Long_Long_Float; N : Integer) return Long_Long_Float; ... function Urcw3l return Long_Long_Float; function Urcw4l return Long_Long_Float; function Urcwl return Long_Long_Float; Notice that Ada functions without arguments lack the empty parentheses that are required in C. Next, the interface defines synonyms with the traditional names used in the Ada numerics library: -- ======= Standard Ada names with C-like suffixes ======= function Arccosf (X : Float) return Float; function Arcsinf (X : Float) return Float; function Arctanf (X : Float) return Float; ... Unfortunately, the match between Ada and C is imperfect in several areas: I The source code of Ada programs is case insensitive. The Ada convention for spelling is that keywords are lowercase, function names are capitalized, and variables are uppercase. The gnatmake option -gnaty that we use requests fastidious style checking so that deviations from those conventions can be identified and corrected. One possibly surprising rule is that a function name must be separated from its parenthesized argument list by at least one space, contrary to centuries-old mathematical practice. 914 Appendix A. Ada interface I Ada has a power operator, **, but C does not. I Ada treats the ceiling, floor, and round operations as type properties, rather than as functions, although their use is quite similar. For example, the Ada code Float’Ceiling (X) corresponds to the C code ceilf(x). Similarly, Float’Rounding (X) corresponds to roundf(x): both round halfway cases away from zero, indepen- dent of the current rounding direction. Ada’s Float’Unbiased_Rounding (X) rounds halfway cases to the nearest even integer, like C’s rintf(x) when the rounding direction is set to the IEEE 754 default. I The Ada absolute-value operation uses a function-like operator, Abs (x). I Ada provides generic names for the elementary functions. For example, as long as the appropriate library packages are included, the call Sqrt (x) selects a version of the square-root function that is appropriate for the type of the argument expression. I Functions that return additional values by storing values into locations given by pointer arguments, such as C’s frexpf(x,&n), have no direct analogue in Ada. However, they are easily handled with arguments declared with the in out keyword pair, indicating that the arguments are assigned values in the function, and those new values are visible to the caller on return from the function. I Ada provides no access to the IEEE 754 exception flags, precision control, or rounding modes. Indeed, there is no mention of IEEE 754, and only three brief references to the IEC 60559:1989 Floating-Point Standard, in the Ada 95 Reference Manual, along with one remark about a possible future Ada binding to that standard.