comp.lang.ada
 help / color / mirror / Atom feed
* Naive question about system dependencies
@ 1994-09-15  6:32 Howard Holm
  1994-09-16 17:28 ` Tucker Taft
  0 siblings, 1 reply; 12+ messages in thread
From: Howard Holm @ 1994-09-15  6:32 UTC (permalink / raw)


I have some experience using Ada in a classroom setting, but unfortunately 
little experience using it in any real-world settings.  I was considering how 
I would go about writing a program that was intended to be used in several 
different operating system environments (e.g. OS/2 and UNIX).  If I were using 
C, I would either use compiler generated macros, if they existed, or create 
some macros in the makefile that could be used to determine which system was 
the target (i.e. #ifdef OS2).  The most likely equivalent seemed to me to be 
the System_Name constant in the System package.  However, when I checked, the 
Gnat compiler simply uses "GNAT" for that definition.  So, my question is how 
do you go about accounting for differences in GUI's and the like?  Do you have 
a build directory that you copy implementation specific low-level packages 
into and out of for each build, or do you define a search path and have a 
collection of implementation specific directories and an independent 
directory? Or, did I overlook some other language featue to address this 
question?

--------------------
Howard Holm
hholm@clark.net



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
  1994-09-15  6:32 Naive question about system dependencies Howard Holm
@ 1994-09-16 17:28 ` Tucker Taft
  1994-09-17 16:23   ` Mats Weber
  0 siblings, 1 reply; 12+ messages in thread
From: Tucker Taft @ 1994-09-16 17:28 UTC (permalink / raw)


In article <hholm.110.2E77EA6F@clark.net>, Howard Holm <hholm@clark.net> wrote:

>I have some experience using Ada in a classroom setting, but unfortunately 
>little experience using it in any real-world settings.  I was considering how 
>I would go about writing a program that was intended to be used in several 
>different operating system environments (e.g. OS/2 and UNIX).  If I were using 
>C, I would either use compiler generated macros, if they existed, or create 
>some macros in the makefile that could be used to determine which system was 
>the target (i.e. #ifdef OS2).  The most likely equivalent seemed to me to be 
>the System_Name constant in the System package.  However, when I checked, the 
>Gnat compiler simply uses "GNAT" for that definition.  So, my question is how 
>do you go about accounting for differences in GUI's and the like?  Do you have 
>a build directory that you copy implementation specific low-level packages 
>into and out of for each build, or do you define a search path and have a 
>collection of implementation specific directories and an independent 
>directory? Or, did I overlook some other language featue to address this 
>question?

Some people use the C preprocessor (or equivalent) with Ada source
code.  However, in our environment we have found it is more
maintainable to avoid using the preprocessor approach, and define
interfaces to isolate target/host independent code from target/host 
dependent code, and then have separate bodies to implement
the interface for each target/host.

Although this might seem like more work, in the long run
it vastly simplifies the process of moving to a new target
or host, and keeps the code much more readable than when
ifdef's and associated target dependences are littered around the code.

>Howard Holm
>hholm@clark.net

-Tucker Taft  stt@inmet.com



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
  1994-09-16 17:28 ` Tucker Taft
@ 1994-09-17 16:23   ` Mats Weber
  1994-09-19 12:05     ` Ted Dennison
       [not found]     ` <85B716C4188@annwfn.com>
  0 siblings, 2 replies; 12+ messages in thread
From: Mats Weber @ 1994-09-17 16:23 UTC (permalink / raw)


In article <Cw8GK2.M9y@inmet.camb.inmet.com>
stt@spock.camb.inmet.com (Tucker Taft) writes:

> Some people use the C preprocessor (or equivalent) with Ada source
> code.  However, in our environment we have found it is more
> maintainable to avoid using the preprocessor approach, and define
> interfaces to isolate target/host independent code from target/host 
> dependent code, and then have separate bodies to implement
> the interface for each target/host.

> Although this might seem like more work, in the long run
> it vastly simplifies the process of moving to a new target
> or host, and keeps the code much more readable than when
> ifdef's and associated target dependences are littered around the code.

I totally agree. We have been doing this for many Ada components
(common SQL interface for various OS's and DB vendors, common interface
to UNIX Sockets/DECnet, etc.).

In many cases, a single package specification with different bodies
solves the problem. In other cases, the private part of the package
needs to be different in different variants (this means duplication of
the spec in Ada 83, Ada 9X has significant imporvements for handling
such cases).

Using a good file naming convention helps a lot in managing the
different versions. We use something like this:

sql_interface.ads                 (common package spec)
sql_interface-oracle-vms.adb      (body for Oracle under VMS)
sql_interface-sybase-unix.adb     (body for Sybase under UNIX)

Despite the amount of code duplication, I prefer this to a preprocessor
approach.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
  1994-09-17 16:23   ` Mats Weber
@ 1994-09-19 12:05     ` Ted Dennison
  1994-09-19 14:39       ` Cyrille Comar
                         ` (2 more replies)
       [not found]     ` <85B716C4188@annwfn.com>
  1 sibling, 3 replies; 12+ messages in thread
From: Ted Dennison @ 1994-09-19 12:05 UTC (permalink / raw)


In article <35f559$mad@info.epfl.ch>, weber@lglsun.epfl.ch (Mats Weber) writes:
|> In article <Cw8GK2.M9y@inmet.camb.inmet.com>
|> Using a good file naming convention helps a lot in managing the
|> different versions. We use something like this:
|> 
|> sql_interface.ads                 (common package spec)
|> sql_interface-oracle-vms.adb      (body for Oracle under VMS)
|> sql_interface-sybase-unix.adb     (body for Sybase under UNIX)
|> 
|> Despite the amount of code duplication, I prefer this to a preprocessor
|> approach.

This won't work under GNAT. GNAT doesn't allow you to use "a good file naming 
convention", you have to use theirs.

T.E.D.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
  1994-09-19 12:05     ` Ted Dennison
@ 1994-09-19 14:39       ` Cyrille Comar
  1994-09-19 15:00       ` Norman H. Cohen
  1994-09-20  9:02       ` Stephen J Bevan
  2 siblings, 0 replies; 12+ messages in thread
From: Cyrille Comar @ 1994-09-19 14:39 UTC (permalink / raw)


dennison@romulus23.DAB.GE.COM (Ted Dennison) writes:
: In article <35f559$mad@info.epfl.ch>, weber@lglsun.epfl.ch (Mats Weber) writes:
: |> sql_interface.ads                 (common package spec)
: |> sql_interface-oracle-vms.adb      (body for Oracle under VMS)
: |> sql_interface-sybase-unix.adb     (body for Sybase under UNIX)
: |> 
: |> Despite the amount of code duplication, I prefer this to a preprocessor
: |> approach.
: 
: This won't work under GNAT. GNAT doesn't allow you to use "a good file naming
: convention", you have to use theirs.
: 
: T.E.D.

I don't understand this kind of comment... GNAT is a compiler, nothing else.
you can always write tools around it to do what you want...
In this case a 2 line script will do the job.
      gnatchop whatever_fancy_name_you_want tmp
      gcc tmp/*.ad[sb]
Or you can include the name changes in your Makefile...

It is true that the simplest approach with gnat is to use different
directories. In the previous case :

sql_interface.ads                 (common package spec)
oracle-vms/sql_interface.adb      (body for Oracle under VMS)
sybase-unix/sql_interface.adb     (body for Sybase under UNIX)

and then use either environment variables or -I (not implemented yet) to find
the right body for your spec. This is the simplest approach but it is in NO WAY
required by GNAT...
------------------------------------------------------------------------
Cyrille Comar,                                  E-mail: comar@cs.nyu.edu
Gnat Project                                    US phone: (212) 998-3489

-- 
------------------------------------------------------------------------
Cyrille Comar,                                  E-mail: comar@cs.nyu.edu
Gnat Project                                    US phone: (212) 998-3489




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
@ 1994-09-19 14:48 Bob Crispen
  0 siblings, 0 replies; 12+ messages in thread
From: Bob Crispen @ 1994-09-19 14:48 UTC (permalink / raw)


Howard Holm <hholm@clark.net> sez:

> I was considering how
>I would go about writing a program that was intended to be used in several
>different operating system environments (e.g. OS/2 and UNIX).
[snip]
>So, my question is how
>do you go about accounting for differences in GUI's and the like?

For the past several years the folks in my group have put all our
OS dependent functions into one package called OS_Services.  We've
got different package bodies for each OS.  Pretty vanilla Ada approach,
actually -- keep your PRAGMA INTERFACEs in one place, handle
variability with different package bodies, group similar functions
together in a package.  No rocket science here, and it works pretty
well.

The only question, of course, is what do the subprograms in the
specs look like?  Our two main OSes are Unix (IRIX and SunOS) and
VxWorks, so we've got a lot of commonality to begin with.  That
leaves us with two odd cases: (a) functions in the OSes that are
similar, but not quite identical and (b) functions that are unique
to a given OS.

In the first case, standardization efforts (e.g., Posix, OpenGL)
often let us decide what the "correct" function call looks like.
We then do what's necessary in the subprogram body to call the
OS function(s) that most closely approximate the function.
Sometimes that's not possible; e.g., the "incorrect" version
requires the caller to supply an argument which would be a pain
to get in the subprogram body.  Only then do we have two versions
side by side in the package spec.

When there's a wonderfully useful little function in one operating
system that isn't present in another (e.g., sysBusIntGen() in
VxWorks but not Unix) and we don't expect ever to use it on the
Unix side, we implement the body of that function on the Unix side
so it gives a warning message, raises an exception, etc.  Of course,
if it becomes necessary, we'd expend the effort to write a subprogram
body that performed that function.  But there's no reason to spend
effort on writing the body for a subprogram you'll never call.

Note that some people write packages for the ages, rather than to
solve the problems of a particular family of products.  Or they
write packages that will go out of their control.  Those folks
would disagree violently with my last statement, and with good
reason.

If I had to cope with GUIs, I think I'd probably have a separate
package for them rather than cluttering up my OS_Services package.
I do know that I prefer to use OS_Services rather than the
large number of OS bindings packages provided by the vendor wherever
I can.  Vendors change their package specs whenever they want, and
don't always provide the same functions or even bindings across
platforms.

Note that where there aren't any applicable standards or emerging
standards (and is there a domain where that isn't true any more?)
you've got to do the systems engineering to determine what the call
ought to look like to (e.g.) place a character on the screen at a
particular position, and then make the bodies do what they have to
for your particular system.

Note also that this approach doesn't require you to be stupid.  If
you're going to sell 1,000 copies of the Microsoft Windows version
to every 1 you sell on other OSes, it ought to be pretty clear what
the "correct" forms of each function are, and never mind all that
business about standards.

Finally, let me say that I've yielded to temptation to write elegant
and user-friendly calls to put in the same package alongside the
"straight" OS bindings (where the functions have the same name and
arguments as the OS function).  In my desire to be helpful, where a
socket package requires you to call socket(), then bind(), then
whatever, I provided an elegant Set_Up_Connection subprogram.

Every time I've done this, I've regretted it.  I've had to fool with
the "user-friendly" bodies to make them meet the needs of the current
program.  Lesson learned: put the user-friendly stuff in a different
package, and always supply the straight OS calls.
+-------------------------------+--------------------------------------+
| Bob Crispen                   |   Who will babysit the babysitters?  |
| crispen@foxy.hv.boeing.com    +--------------------------------------+
| (205) 461-3296                |Opinions expressed here are mine alone|
+-------------------------------+--------------------------------------+



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
  1994-09-19 12:05     ` Ted Dennison
  1994-09-19 14:39       ` Cyrille Comar
@ 1994-09-19 15:00       ` Norman H. Cohen
  1994-09-20  9:02       ` Stephen J Bevan
  2 siblings, 0 replies; 12+ messages in thread
From: Norman H. Cohen @ 1994-09-19 15:00 UTC (permalink / raw)


In article <35jupm$dkq@theopolis.orl.mmc.com>,
dennison@romulus23.DAB.GE.COM (Ted Dennison) writes: 

|> In article <35f559$mad@info.epfl.ch>, weber@lglsun.epfl.ch (Mats Weber) writes: 
|> |> In article <Cw8GK2.M9y@inmet.camb.inmet.com>
|> |> Using a good file naming convention helps a lot in managing the
|> |> different versions. We use something like this: 
|> |>
|> |> sql_interface.ads                 (common package spec)
|> |> sql_interface-oracle-vms.adb      (body for Oracle under VMS)
|> |> sql_interface-sybase-unix.adb     (body for Sybase under UNIX)
|> |>
|> |> Despite the amount of code duplication, I prefer this to a preprocessor
|> |> approach.
|>
|> This won't work under GNAT. GNAT doesn't allow you to use "a good file naming
|> convention", you have to use theirs.

T.E.D. is apparently criticizing something about which he knows nothing.
The "good file naming convention" Mats proposes is precisely the GNAT
convention for child units named SQL_Interface.Oracle.VMS and
SQL_Interface.Sybase.Unix.

--
Norman H. Cohen    ncohen@watson.ibm.com



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
  1994-09-19 12:05     ` Ted Dennison
  1994-09-19 14:39       ` Cyrille Comar
  1994-09-19 15:00       ` Norman H. Cohen
@ 1994-09-20  9:02       ` Stephen J Bevan
  2 siblings, 0 replies; 12+ messages in thread
From: Stephen J Bevan @ 1994-09-20  9:02 UTC (permalink / raw)


In article <35jupm$dkq@theopolis.orl.mmc.com> dennison@romulus23.DAB.GE.COM (Ted Dennison) writes:
   In article <35f559$mad@info.epfl.ch>, weber@lglsun.epfl.ch (Mats Weber) writes:
   |> In article <Cw8GK2.M9y@inmet.camb.inmet.com>
   |> Using a good file naming convention helps a lot in managing the
   |> different versions. We use something like this:
   |> 
   |> sql_interface.ads                 (common package spec)
   |> sql_interface-oracle-vms.adb      (body for Oracle under VMS)
   |> sql_interface-sybase-unix.adb     (body for Sybase under UNIX)
   |> 
   |> Despite the amount of code duplication, I prefer this to a preprocessor
   |> approach.

   This won't work under GNAT. GNAT doesn't allow you to use "a good
   file naming convention", you have to use theirs.

I don't believe this is quite correct.  If you want to use the above
naming convention with a compiler you have to define -somewhere- the
relationship between the interface and the particular implementation
you want to use (i.e. Oracle or Sybase).  With GNAT, all you'd have to
have is a script (perhaps generated by a config script for the given
platform) which created a link (or defined a logical on VMS) between
the sql_interface.xxx and the appropriate implementation.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
       [not found]     ` <85B716C4188@annwfn.com>
@ 1994-09-22 13:33       ` David Kehs
  1994-09-22 14:15       ` Robert Dewar
  1994-09-22 14:54       ` Norman H. Cohen
  2 siblings, 0 replies; 12+ messages in thread
From: David Kehs @ 1994-09-22 13:33 UTC (permalink / raw)


In <85B716C4188@annwfn.com> merlin@annwfn.com (Fred McCall) writes:


>One thing to be *very* wary of -- during maintenance, if you find and
>fix a bug in one variant, you'd better check all those other alternate
>bodies for the same bug and apply the same fix.  I agree with the
>difficulty of reading heavily ifdef'd sources, but they do have the
>advantage of putting all the source code in one place (which simplifies
>source control on bug fixes).

If you find yourself needing to apply the same fix in lots of different
variants, it probably means that your decomposition could stand improvement.
If the same code sequence is repeated in several variants, that sequence
should be separated out (possibly as a generic) so that you need to
keep only one copy of the source text.  Then, if a fix is needed, you'll
only have to do it in one place, and you still won't need ifdef's.

Of course, it's not always easy to pull this off in practice.

Dave Kehs
-- opinions expressed here are purely my own.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
       [not found]     ` <85B716C4188@annwfn.com>
  1994-09-22 13:33       ` David Kehs
@ 1994-09-22 14:15       ` Robert Dewar
  1994-09-23  4:34         ` R. William Beckwith
  1994-09-22 14:54       ` Norman H. Cohen
  2 siblings, 1 reply; 12+ messages in thread
From: Robert Dewar @ 1994-09-22 14:15 UTC (permalink / raw)


The whole idea in using separate bodies should be to completely avoid
code duplication. Only the code that is system dependent, and hence
NOT duplicated, i.e. the code that would go inside the range of an 
ifdef, should be in separate bodies, code outside the ifdef can be
shared.

This isn't possible to achieve completely in all cases, but you can come
very close by building appropriate abstractions, and if you have a decent
compiler which does inlining properly, there should be no efficienc y
loss from this kind of abstraction.

To emphasize, this is a design princinple which cannot always be met, but
far too much code is duplicated in situations where there has not been
nearly enough effort in attempting to meet this requirement.

Note that the disastrous thing about ifdefs is that it gets very hard to
even make sure that the module is free of syntax errors for all cases.

Suppose we have 20 ifdefs in one module, each with two settings. THen it
takes 1,000,000 compilations just to make sure that all possibilities
compile (and 1,000,000 careful test runs to make sure they all work).

If on the other hand, you have one common module, and two versions each
of 20 little modules, then you have to compile only 41 files to check
syntax correctness, and you can at least do 41 separate unit tests (the
full integration testing would of course take 1,000,000 runs, there's
no way around that, but at least it's better to have unit testing than
nothing at all).

Best of all is to try to avoid special casing in the first place. That's
cerainly the approach we try to use in GCC, where we have several hundred
possible configurations, and we are VERY unfriendly to target dependent
code, though we can't completely avoid it.

In my experience, the ability to use ifdef's is a disaster for big systems.
All to often, you get ifdefs all over the place, and the sources become
completely unmanagable.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
       [not found]     ` <85B716C4188@annwfn.com>
  1994-09-22 13:33       ` David Kehs
  1994-09-22 14:15       ` Robert Dewar
@ 1994-09-22 14:54       ` Norman H. Cohen
  2 siblings, 0 replies; 12+ messages in thread
From: Norman H. Cohen @ 1994-09-22 14:54 UTC (permalink / raw)


In article <85B716C4188@annwfn.com>, merlin@annwfn.com (Fred McCall) writes: 
|> In <35f559$mad@info.epfl.ch> weber@lglsun.epfl.ch Mats Weber writes: 
|>
|> >In many cases, a single package specification with different bodies
|> >solves the problem. In other cases, the private part of the package
|> >needs to be different in different variants (this means duplication of
|> >the spec in Ada 83, Ada 9X has significant imporvements for handling
|> >such cases).
|> >
|> >Using a good file naming convention helps a lot in managing the
|> >different versions. We use something like this: 
|> >
|> >sql_interface.ads                 (common package spec)
|> >sql_interface-oracle-vms.adb      (body for Oracle under VMS)
|> >sql_interface-sybase-unix.adb     (body for Sybase under UNIX)
|> >
|> >Despite the amount of code duplication, I prefer this to a preprocessor
|> >approach.
|>
|> One thing to be *very* wary of -- during maintenance, if you find and
|> fix a bug in one variant, you'd better check all those other alternate
|> bodies for the same bug and apply the same fix.  I agree with the
|> difficulty of reading heavily ifdef'd sources, but they do have the
|> advantage of putting all the source code in one place (which simplifies
|> source control on bug fixes).

Quite true.  That's why the design should strive to isolate the target
dependencies as much as possible.  Ideally, the multiple versions differ
only in a few very small units that define a few exported constants and
low-level subprograms differently, but invoke common code that
constitutes the bulk of the system.

--
Norman H. Cohen    ncohen@watson.ibm.com



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Naive question about system dependencies
  1994-09-22 14:15       ` Robert Dewar
@ 1994-09-23  4:34         ` R. William Beckwith
  0 siblings, 0 replies; 12+ messages in thread
From: R. William Beckwith @ 1994-09-23  4:34 UTC (permalink / raw)


Robert Dewar (dewar@cs.nyu.edu) wrote:
: The whole idea in using separate bodies should be to completely avoid
: code duplication. Only the code that is system dependent, and hence
: NOT duplicated, i.e. the code that would go inside the range of an 
: ifdef, should be in separate bodies, code outside the ifdef can be
: shared.

snip

I couldn't agree more.

When we first starting designing Screen Machine (portable GUI/CUI
product) many years ago, I missed the occassional #ifdef.  Instead
of using cpp we decided to architect the code in such a way that
we could plug in the appropriate platform/compiler specific code.

It has worked out very nicely.  Instead of the incredibly long,
complex preprocessed source files you end up creating over the
years, we ended up with an architecture that allows us to make
structural changes to our code without the typically worries of
breaking an ifdef (rats) nest.

We now maintain 153 binary products with _one_ (real busy)
porting engineer.  The current source directory heirarchy for
the library component of Screen Machine speaks for itself:

    sm
    sm/char
    sm/char/dos
    sm/char/dos/a16
    sm/char/dos/a32
    sm/char/dos/m16
    sm/char/dos/m32
    sm/char/unix
    sm/char/vax
    sm/gui
    sm/gui/Xm/unix
    sm/gui/Xm/vms
    sm/gui/Xm/r1000
    sm/gui/Xm/net
    sm/gui/win16
    sm/gui/win32
    compiler
    compiler/Alsys16
    compiler/Alsys32
    compiler/Apex
    compiler/DECAda
    compiler/IBMAda
    compiler/Merid16
    compiler/Merid32
    compiler/OCSLegacyAda
    compiler/Rational
    compiler/SunAda
    compiler/Teles16
    compiler/Teles32
    compiler/Verdix
    compiler/VMSAda
    platform
    platform/dgux_88k
    platform/aux_68k
    platform/hpux_pa
    platform/isc_intel
    platform/lynx_intel
    platform/dos_intel
    platform/osf1_alpha
    platform/delta_r1000
    platform/aix_power
    platform/sco_intel
    platform/irix_mips
    platform/solaris2_intel_
    platform/solaris2_sparc
    platform/solaris1_sparc
    platform/ultrix_mips
    platform/ultrix_vax
    platform/win31_intel
    platform/winnt_alpha_
    platform/winnt_intel
    platform/winnt_mips_
    platform/vms_alpha
    platform/vms_vax

... Bill

-- 
e-mail: Bill.Beckwith@ois.com       |    Team Ada
Objective Interface Systems, Inc.   | dist, full O-O
1895 Preston White Drive, Suite 250 | multithreading
Reston, VA  22091-5448  U.S.A.      |    built in



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~1994-09-23  4:34 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1994-09-15  6:32 Naive question about system dependencies Howard Holm
1994-09-16 17:28 ` Tucker Taft
1994-09-17 16:23   ` Mats Weber
1994-09-19 12:05     ` Ted Dennison
1994-09-19 14:39       ` Cyrille Comar
1994-09-19 15:00       ` Norman H. Cohen
1994-09-20  9:02       ` Stephen J Bevan
     [not found]     ` <85B716C4188@annwfn.com>
1994-09-22 13:33       ` David Kehs
1994-09-22 14:15       ` Robert Dewar
1994-09-23  4:34         ` R. William Beckwith
1994-09-22 14:54       ` Norman H. Cohen
  -- strict thread matches above, loose matches on Subject: below --
1994-09-19 14:48 Bob Crispen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox