LANGUAGE STUDY NOTE INTERFACE pragmas !Topic LSN on INTERFACE pragmas !reference [lots] !from Bevin Brett 92-03-16 I have decided to put a bit of time into the INTERFACE issues, to try to enhance a little the already excellent LSN that Randy and others have put together. This is an area where DIGITAL has significant experience and expertise, and a large [hundreds of thousands of lines of code] of investment to protect, some our own, and some our users. It is also an area where increased standardisation will help with the bindings issue. /Bevin ------------------------------------------------------------------------------- Executive Summary: This area is not as "unexplored territory" as Randy's LSN seemed to me to imply. There is at least one compiler already with extensive multi-language support that demonstrably works (ours), and many compilers have some support and good ideas (Verdix and Alsys are the two I am most familiar with). [Randy, I believe our compilers are proof that the current state of the art is actually very good. It is just that many implementations are a way behind the current state of the art in this area]. In particular the Verdix implementation has a nice approach to external naming, and the DEC compilers have a powerful approach to specifying the parameter passing information. We need to find a way that incorporates the best of each, is incompatible with none, and fixes any important glitches. ------------------------------------------------------------------------------- First, an overview of the DEC Ada system today. Values: There are occasions where Linker Global Symbols are used to propagate values other than addresses. To support these, DEC Ada has package System is ... function Import_Value(Symbol : String) returns Unsigned_Longword; ... end; allowing users to write things like X : Integer := Integer(System.Import_Value("SS$_NORMAL")); for example. Objects: Representation [Layout] Control We fully support 'size clauses, enumeration rep clauses, and record representation clauses. We recognise a need for clauses that specify both the sizes and spacing of array components. The biggest simple problem with representing C representations is that languages zero/nonzero booleans. The biggest complicated problems is pointers to implicitly counted vectors of components. Also note that most zero/nonzero booleans in C are stored with 'size=sizeof(int), which means that Standard.Boolean isn't always suitable as a parameter type or result type for two different reasons. The biggest simple problem with representing Fortran representations is that languages 0,-1 booleans. The biggest complicated problems hinge around when is an Ada type is Fortran common block. Other problems include when is an Ada type Fortran complex and also Row v. column major order is a relatively trivial problem that should also be solved. For Cobol and PL/I, you can expect packed decimal to also present an interesting set of issues. Import The Ada '83 way to import an object, but not initialise it, is tricky but viable. The point is to recognise that you are not declaring an object, but renaming one. We recommend that programmers do this by with System, Unchecked_Conversion; package Import_Example is type Imported_Type is ... type Access_Imported_Type is access Imported_Type; for Access_Imported_Type'storage_size use 0; function "+" is new System.Unchecked_Conversion( System.Unsigned_Longword, Access_Imported_Type); ... X : Imported_Type renames "+"(System.Import_Value("This_Global_Symbol")).all; end; Importing AND initialising is accomplished with an Import_Object pragma, or by an address attribute. X : Imported_Type; for X use at [address_expression]; -- or X : Imported_Type; pragma Import_Object(X, [external_designator]); +-------------------------------------------------------------- | IMPORTANT ASIDE : I WOULD GREATLY PREFER A SYNTAX THAT WAS ! ! X at address_expression : [constant] tm [:= expression]; ! ! ! because this would get the evaluation of the expression ! done at the correct time. +-------------------------------------------------------------- Note we support both Identifier and String forms of the external_designator, and the Identifier form does system-specific munging to get the actual string passed to the Linker. We support importing anywhere. We evaluate the address expression at the point of the object declaration, and initialise it directly. You can not import constants. "Access constant" types would let the above renaming trick work to support this case. Export DEC Ada only supports exporting objects that are not inside subprogram or task bodies. pragma Export_Object(X, [external_designator]); We also support taking 'ADDRESS of any object. You can export constants. Subprograms Your analysis of linker names v. Ada identifiers, calling conventions v. merely the language name, and data representation was good as far as it went. However, when trying to build strongly typed, then, yet easy-to-use bindings you get examples like this... Keysym *XGetKeyboardMapping( display, first_keycode, keycode_count, keysyms_per_keycode_return); Display *display; KeyCode first_keycpde; int keycode_count; int *keysyms_per_keycode_return; Which leads to procedure Get_Keyboard_Mapping( Display : in Access_Display_Type; First_Keycode : in KeyCode_Type; Keycode_Count : in Integer; Keysyms_per_Keycode : in Access_Integer; Keysyms : in Access_Access_Keysym_Type); Instead of Keysyms_per_Keycode : in out Natural; Keysyms : out Access_Keysym_Type); Which is the desireable equivalent - provided you can get your compiler to pass by pointer, and reorder the position of the function result. We can do the former, currently we don't support the later. So, I am convinced we need to find a simple Ada 9X speak for those C parameters that are passed as pointers, but really represent in_out objects. We currently support Interface pragmas on overloaded declarations. We also support an pragma Import_Procedure(Internal_Designator, External_Designator, parameter_types => (...), result_type => ..., mechanism => (...), result_mechanism => ...); which we have had no complaints at all about our users finding confusing, although undoubtably the issues are more complex for users than for many language features. We similarly support Export_Procedure, again with a choice of mechanisms, although the choice is more restrictive than for the import case. Both are restricted to non-nested subprograms. I forget if the test is done before or after generic instantiation. In order to take 'ADDRESS of a subprogram, and get a meaningful result, we insist that the subprogram have an Export_Procedure pragma. It is permissible to specify the external_designator as "" in this pragma, which means no name is passed on to the linker, but 'ADDRESS can be used. I believe it would be acceptable to support VALUE and REFERENCE[(static_size_expression)] as the only two portable mechanisms. I believe there should probably be location => (location,...) result_location => [location] optional parameters also - the XD Ada product has something like this, I am not familiar with the details, or even exactly which names the parameters have. The exact way to specify location is going to have to be somewhat target specific.