[comp.lang.fortran] archiving block data subroutines...

jeffb@aquifer.las.uiuc.edu (Jeffrey Biesiadecki) (10/22/90)

Hi -

We have a library written in Fortran77 which includes a block data
subroutine.  If we use "ar" to archive the object files of the library,
and then try to compile a program using the resulting "lib???.a" file,
everything works fine EXCEPT the block data subroutine is never executed
(that is, the initializations are not made).  If the block data object file
is linked in explicitly with the fortran compiler, then the initializations
are done.

Archiving the block data subroutine does work elsewhere (at least on computers
running BSD4.3).  It does not work on our SGI Personal Iris, (running
IRIX version 3.2 I believe - but am not positive...  I can find out if it
makes a difference).

Is this a problem with SGI's archiver, or archivers on machines running
System V-like operating systems in general?  We do not have a "ranlib"
program on the SGI;  the "ar" program creates the symbol tables that the
loader needs (we can call normal subroutines that have been archived and
it works fine).

Thanks,
Jeff

--
/******************************************************************************
** Jeff Biesiadecki           ** University of Illinois, Urbana-Champaign    **
** jeffb@aquifer.las.uiuc.edu ** Departments of Geology and Computer Science **
******************************************************************************/

burley@world.std.com (James C Burley) (10/22/90)

In article <1990Oct22.033107.5159@ux1.cso.uiuc.edu> jeffb@aquifer.las.uiuc.edu (Jeffrey Biesiadecki) writes:

   Hi -

   We have a library written in Fortran77 which includes a block data
   subroutine.  If we use "ar" to archive the object files of the library,
   and then try to compile a program using the resulting "lib???.a" file,
   everything works fine EXCEPT the block data subroutine is never executed
   (that is, the initializations are not made).  If the block data object file
   is linked in explicitly with the fortran compiler, then the initializations
   are done.

Hi back!  I know nothing about "ar" or "lib???.a" files.  But in Fortran,
there is a specification for forcing the inclusion of a BLOCK DATA program
unit in a program.  It is EXTERNAL, believe it or not.  For example:

      PROGRAM FOO
      EXTERNAL BDATA
      COMMON /X/I
      PRINT *,I
      END

      BLOCK DATA BDATA
      COMMON /X/I
      DATA I/5/
      END

Without "EXTERNAL BDATA", the block data program unit must be explicitly
linked with the program, or whatever wording to that affect is appropriate
(since the standard doesn't really talk about linking).  With it, the linker
should complain if it can't find a block data program unit named BDATA when
linking FOO, and thus should also pull it in from any library it is
searching.

Give this approach a try.  I realize it requires you to modify the code
using the block data program  unit, but that might be a good idea anyway, to
improve its portability.  However, be aware that some nonconforming
implementations of Fortran might do the wrong thing, like assume BDATA must
be a subroutine or function but NOT a block data program unit, so try testing
this approach using, say, the example above (i.e. put BDATA in a library using
"ar" and link it to FOO after compiling both).

James Craig Burley, Software Craftsperson    burley@world.std.com

silvert@cs.dal.ca (Bill Silvert) (10/22/90)

In article <1990Oct22.033107.5159@ux1.cso.uiuc.edu> jeffb@aquifer.las.uiuc.edu (Jeffrey Biesiadecki) writes:
>We have a library written in Fortran77 which includes a block data
>subroutine.  If we use "ar" to archive the object files of the library,
>and then try to compile a program using the resulting "lib???.a" file,
>everything works fine EXCEPT the block data subroutine is never executed
>(that is, the initializations are not made).  If the block data object file
>is linked in explicitly with the fortran compiler, then the initializations
>are done.

This is a common (:)) problem which arises from the fact that the linker
looks only for subroutines that are called, and since block data is not
called, it doesn't get linked.  One sure fix is to combine the block
data unit with a subroutine in one file, since the entire file with
both units will then get loaded if the subroutine is called.
-- 
William Silvert, Habitat Ecology Division, Bedford Inst. of Oceanography
P. O. Box 1006, Dartmouth, Nova Scotia, CANADA B2Y 4A2.  Tel. (902)426-1577
UUCP=..!{uunet|watmath}!dalcs!biomel!bill
BITNET=bill%biomel%dalcs@dalac	InterNet=bill%biomel@cs.dal.ca

ddh@hare.cdc.com (Dan Horsfall) (10/22/90)

In article <BURLEY.90Oct22050633@world.std.com> burley@world.std.com (James C Burley) writes:
> In article <1990Oct22.033107.5159@ux1.cso.uiuc.edu> jeffb@aquifer.las.uiuc.edu (Jeffrey Biesiadecki) writes:
> 
>    We have a library written in Fortran77 which includes a block data
>    subroutine.  If we use "ar" to archive the object files of the library,
>    and then try to compile a program using the resulting "lib???.a" file,
>    everything works fine EXCEPT the block data subroutine is never executed
>    (that is, the initializations are not made).  If the block data object file
>    is linked in explicitly with the fortran compiler, then the initializations
>    are done.
> 
Keep in mind here a terminology issue: block data subprograms are not 
executable.  They by definition contain no executable code.  They cannot
be "called".

> Hi back!  I know nothing about "ar" or "lib???.a" files.  But in Fortran,
> there is a specification for forcing the inclusion of a BLOCK DATA program
> unit in a program.  It is EXTERNAL, believe it or not.  For example:
> 
>       PROGRAM FOO
>       EXTERNAL BDATA
>       COMMON /X/I
>       PRINT *,I
>       END
> 
>       BLOCK DATA BDATA
>       COMMON /X/I
>       DATA I/5/
>       END
> 
> Without "EXTERNAL BDATA", the block data program unit must be explicitly
> linked with the program, or whatever wording to that affect is appropriate
> (since the standard doesn't really talk about linking).  With it, the linker
> should complain if it can't find a block data program unit named BDATA when
> linking FOO, and thus should also pull it in from any library it is
> searching.
> 

I beg to differ.  EXTERNAL for linking in block data routines is a "fairly
common" extension, but is NOT standard.  Here's the problem at the loader
level:

Block data subprograms contain no executable code.  Thus, they do not contain
an entry point.  A while back, some compiler writers figured out that if they
added an entry point to a block data routine (which actually makes it
executable, tho usually the supporting code is an instant _return).  Now,
having an entry point makes it resolvable by other routines that declare
the same symbol as an external reference.  How to do this in a manner that
doesn't actually execute the code?  Declare the symbol EXTERNAL in some
other routine.

Not all vendors support this mechanism, but this doesn't mean they are 
nonconforming.  MIPS is one of these; mips makes the sgi box; James
Burley's otherwise exemplary solution doesn't apply  to you.  What
you gotta do is force load your block data routines the same way you
force load your main program to start the loading process, e.g.:
   f77 -o xxx  main.o bdata.o libx.a

( In our case here, we use  f77 -o xxx  *.o *.a, and make sure that the
  right *.o's are available.  Kludge, but the only solution.)

--
   Horse
                                       +    Control Data Corporation      
   Dan Horsfall     +1-612-482-4622    +    4201 Lexington Ave North      
   Internet   ddh@dash.udev.cdc.com    +    Arden Hills MN 55126 USA      

doog@travis.ssd.csd.harris.com (Doug Scofield) (10/22/90)

)From article <>, by burley@world.std.com (James C Burley):
)) In article <> jeffb@aquifer.las.uiuc.edu (Jeffrey Biesiadecki) writes:
))
)) [ user wishes linker to pull block data from library ]
)
) [ suggests using the EXTERNAL keyword to cause an external reference, ]
) [ which would in theory include the block data subprogram             ]
)
) ... However, be aware that some nonconforming
) implementations of Fortran might do the wrong thing ...

Actually, implementations may do whatever they want in this case.  
Block data subprogram names are defined to be global to the 
execution unit (16.1), and block data names are allowed in EXTERNAL
statements (8.7), but no functional use is described.  In fact, this
is explicitly stated in (B16): 

     The name of a block data subprogram has no explicit use within 
     the FORTRAN language.  It is available for documentation and 
     for possible use within a computer environment.

This "possible use" would include what you require.  An innocuous
global definition of the block data name would be required in the 
block data object, and a global reference would be generated within 
the source object.  Some vendors may be hesitant to do the latter, 
as it requires generating a dummy reference for every unused 
EXTERNAL name.

--
doug scofield                    doog@ssd.csd.harris.com  (preferred)
harris computer systems                  uunet!hcx1!doog

system@alchemy.chem.utoronto.ca (System Admin (Mike Peterson)) (10/23/90)

In article <1990Oct22.033107.5159@ux1.cso.uiuc.edu> jeffb@aquifer.las.uiuc.edu (Jeffrey Biesiadecki) writes:
>We have a library written in Fortran77 which includes a block data
>subroutine.  If we use "ar" to archive the object files of the library,
>and then try to compile a program using the resulting "lib???.a" file,
>everything works fine EXCEPT the block data subroutine is never executed
>(that is, the initializations are not made). ...

You can make this work properly on most normal systems (Sun, DEC/Ultrix,
Cray/UNICOS, IBM RS/6000, SGI) by:
- giving the BLOCK DATA routine a unique name.
- putting an 'EXTERNAL blockdataname' statement in the subroutine(s)
  that want the COMMON block to be loaded.

Note that this technique will NOT work reliably on Apollo systems :-(.
-- 
Mike Peterson, System Administrator, U/Toronto Department of Chemistry
E-mail: system@alchemy.chem.utoronto.ca
Tel: (416) 978-7094                  Fax: (416) 978-8775

vjs@rhyolite.wpd.sgi.com (Vernon Schryver) (10/23/90)

In article <27320@shamash.cdc.com>, ddh@hare.cdc.com (Dan Horsfall) writes:
>                                 ...   mips makes the sgi box ...
>    Horse
>                                        +    Control Data Corporation      
>    Dan Horsfall     +1-612-482-4622    +    4201 Lexington Ave North      
>    Internet   ddh@dash.udev.cdc.com    +    Arden Hills MN 55126 USA      


The preceding was probably a typo, but ...

MIPS does not make IRIS's.  Silicon Graphics Computer Systems, Inc. makes
IRIS's.  MIPS makes their own boxes.  I'm not even sure which of the
several silicon foundaries SGI is using for the MIPS R3000 that is probably
in whichever SGI box is being mentioned.  I don't think MIPS is in the
silicon business any more.  I think it's been years since any IRIS
contained any hardware manufactured by MIPS.

It is or at least has been true that packing cases leave Mtn.View loading
docks with labels that do not mention SGI but do say "Cyber".

It is true SGI ships modified versions of MIPS compilers for some but not
all languages.

MIPS &co. are great guys with good machines and all that, but everyone
working at SGI knows they are not as great as SGI.



Vernon Schryver,    vjs@sgi.com

milind@agni.cc.nd.edu (Milind Saraph) (10/23/90)

|>
|>Hi -
|>
|>(stuff deleted)
|>
|>Archiving the block data subroutine does work elsewhere (at least on
computers
|>running BSD4.3).  It does not work on our SGI Personal Iris, (running
|>IRIX version 3.2 I believe - but am not positive...  I can find out if it
|>makes a difference).
|>
|>Is this a problem with SGI's archiver, or archivers on machines running
|>System V-like operating systems in general?  We do not have a "ranlib"
|>program on the SGI;  the "ar" program creates the symbol tables that the
|>loader needs (we can call normal subroutines that have been archived and
|>it works fine).
|>
|>Thanks,
|>Jeff
|>
|>--
|>/*********************************************************************
**********
|>** Jeff Biesiadecki           ** University of Illinois,
Urbana-Champaign    **
|>** jeffb@aquifer.las.uiuc.edu ** Departments of Geology and Computer
Science **
|>**********************************************************************
*********/
                              
This has certainly been a problem on Stellar and Ardent machines (SYS-V like
OS).

-- milind

dik@cwi.nl (Dik T. Winter) (10/23/90)

In article <1990Oct22.130143.29775@cs.dal.ca> bill%biomel@cs.dal.ca writes:
 >                                 One sure fix is to combine the block
 > data unit with a subroutine in one file, since the entire file with
 > both units will then get loaded if the subroutine is called.

Probably sure within this context (Unix systems).  Certainly not sure in
general.  I know of at least one (non Unix) system where this will fail.
In short: there is no solution that will work everywhere, except explicitly
loading the block data subprogram.
--
dik t. winter, cwi, amsterdam, nederland
dik@cwi.nl

burley@world.std.com (James C Burley) (10/23/90)

In article <27320@shamash.cdc.com> ddh@hare.cdc.com (Dan Horsfall) writes:

   In article <BURLEY.90Oct22050633@world.std.com> burley@world.std.com (James C Burley) writes:

   > [...] in Fortran,
   > there is a specification for forcing the inclusion of a BLOCK DATA program
   > unit in a program.  It is EXTERNAL, believe it or not.  For example:
   > 
   >       PROGRAM FOO
   >       EXTERNAL BDATA
   >       COMMON /X/I
   >       PRINT *,I
   >       END
   > 
   >       BLOCK DATA BDATA
   >       COMMON /X/I
   >       DATA I/5/
   >       END
   > 
   > Without "EXTERNAL BDATA", the block data program unit must be explicitly
   > linked with the program, or whatever wording to that affect is appropriate
   > (since the standard doesn't really talk about linking).  With it, the linker
   > should complain if it can't find a block data program unit named BDATA when
   > linking FOO, and thus should also pull it in from any library it is
   > searching.
   > 

   I beg to differ.  EXTERNAL for linking in block data routines is a "fairly
   common" extension, but is NOT standard.  [...]

I beg to differ right back, with a clarification of what I said above: use
of EXTERNAL for specifying a BLOCK DATA program unit name IS standard.
How this affects program linking is NOT standard, because (as I said above)
the standard doesn't really talk about linking.  I believe if you look into
the history of the F77 standard, you'll find that the reason Page 8-9 lines 30
and 31 allow block data subprogram names in the EXTERNAL statement was to
accommodate systems allowing linking of libraries that needed a means to
allow procedures in a library to specify that they also needed a corresponding
BLOCK DATA program unit from that same library.  (Another posting suggests
that if one procedure is needed from a compiled file, all procedures and
BLOCK DATA subprograms will be retrieved from the library originally specified
by that file; that statement is incorrect, since in Fortran each program unit
is independent from each other and many systems take advantage of that fact
by treating them separately.  And certainly the standard doesn't specify any
concept referred to as a "source file" containing more than one program unit.)

It stands to reason, therefore, that anyone designing a new Fortran system
and wishing to be standard-conforming would support both the letter and the
spirit of the standard.  Since the 77 standard could not possibly specify
how programs were to be put together from program units in terms of "linking",
"loading", or whatever, without many problems, it also could not explicitly
say that "EXTERNAL BDATA" means "make sure BLOCK DATA BDATA subprogram is
in the program image along with its initializations".  But any responsible
developer would interpret it that way when providing the facility for placing
Fortran subprograms in libraries.  (Of course, "responsible" here is a
subjective term!)

So, if Apollo, for example, doesn't do this, it can be said their systems
do not effectively implement the 77 standard across their "range" of their
system, unless they disavow the use of their library packaging for Fortran.
Further, if specifying "BLOCK DATA BDATA" is not permitted, either resulting
in a compile-time message or a link-time message that there is no such
subroutine or function named BDATA when, in fact, there is a BLOCK DATA
program unit present named BDATA, then their system does not conform to even
the letter of the ANSI FORTRAN 77 standard.

All readers should note that the Fortran standards, both 77 AND 90, DISALLOW
initialization (via DATA or, for 90, via initial values specified on type-
declaration statements) of entities in common blocks except within BLOCK
DATA subprograms, and there only for named common blocks (i.e. you can't
provide initial values for entities in blank common).  In other words, the
following very effective solution is, unfortunately, nonstandard, even though
I believe it will work on every single machine that supports Fortran to any
reasonable extent (i.e. here's a recommendation, though it isn't standard):

      PROGRAM MINE  !Or subroutine or function.
      INTEGER NOTHING
      COMMON /NOTHING/ NOTHING
      ...other specification statements...
      IF (NOTHING.EQ.12345) GOTO 99999  !Never happens.
      ...regular executable stuff...
      STOP  !Or RETURN, as appropriate.
99999 CALL DOES_NOTHING  !Nobody goes here.
      END

      SUBROUTINE DOES_NOTHING  !Instead of BLOCK DATA DOES_NOTHING.
      INTEGER NOTHING
      COMMON /NOTHING/ NOTHING
      ...other stuff you want to put in a BLOCK DATA...
      DATA NOTHING/0/  !Make sure it isn't 12345.
      ...other DATA statements you'd put in a BLOCK DATA...
      END

For every distinct BLOCK DATA subprogram you want, make a procedure out of
it instead, giving it, of course, a unique name, and give it a special common
area all its own with its own unique name, along with a unique variable.
Then initialize that variable to zero via a DATA statement.  Include no
executable code in the procedure.

Then the main program (or procedure that wants the BLOCK DATA included, if
you can find one that doesn't need to be super-optimal) tests each of the
special variables for common areas and jumps to statements that call the
procedures that represent the BLOCK DATAs.  The CALLs never happen because
the variables are never equal to the values tested.

By doing this, you prevent almost any optimizing compiler (except a truly
global optimizing compiler) from deciding that the calls will never happen
and thus not emitting requests to the linker to include the corresponding
procedures.  (And, for a global optimizing compiler, it'd have to reference
the procedures anyway, and thus include the initializations they perform,
which is all you want.)

If you're sure your Fortran implementation either doesn't do such nifty
optimization, or that at least it still emits a request to link a procedure
whose only reference(s) in a program unit have effectively been eliminated
due to dead code removal, then you can drop the "IF...GO TO" statements that
reach the useless CALLs.  For a main program, this makes little difference,
but for a library of often-used procedures, it can allow the procedures to
still run at the speed at which they would have had your Fortran implementation
obeyed the letter and the spirit of the standard.

Again, the above solution is NONSTANDARD because a procedure (subroutine or
function) cannot use DATA to specify initial values for variables in common
blocks -- that is what BLOCK DATA is for, and that is why any implementation
that does not fully implement "EXTERNAL BDATA" meaning "make sure you've
got a [subroutine, function, or] block data subprogram linked in with the
program" is, in my opinion, not standard-conforming.

However, the above solution will work on any system I can imagine, as long as
it accepts the nearly ubiquitous extension allowing DATA for variables in
common from within subroutines or functions.  If your system does not allow
that, I bet it doesn't allow Fortran libraries in the first place, or that it
does EXTERNAL correctly!  (Or the developers were truly obnoxious/ignorant/
underpaid :-).

James Craig Burley, Software Craftsperson    burley@world.std.com

sjc@key.COM (Steve Correll) (10/26/90)

In article <1990Oct22.033107.5159@ux1.cso.uiuc.edu>, jeffb@aquifer.las.uiuc.edu (Jeffrey Biesiadecki) writes:
> We have a library written in Fortran77 which includes a block data
> subroutine.  If we use "ar" to archive the object files of the library,
> and then try to compile a program using the resulting "lib???.a" file,
> everything works fine EXCEPT the block data subroutine is never executed
>...
> Is this a problem with SGI's archiver, or archivers on machines running
> System V-like operating systems in general? 

Yes, most Unix System V Release 3 linkers behave differently than most BSD4.3
linkers, in a fashion that is sufficient to explain your problem.

Suppose there is a .o file in the archive library which does not define any
symbol which the linker has seen previously, except for one: an uninitialized
common block. Should the linker bind that .o file into the program on the basis
of that common block alone, even though the .o file does not affect the meaning
of that common block?

Most BSD linkers answer "yes" and most SVR3 linkers answer "no".

The answer _can_ affect the meaning of the program. To sidestep arguments about
the Fortran standard for the moment, consider (sorry) a C example:

file main.c:

  int c;	/* Think of this as uninitialized common */
  main()
    {
    return com1();
    }

file com1.c:

  int c;	/* Think of this as uninitialized common */
  int d = 5;	/* Think of this as initialized common */
  com1()
    {
    return c + d;
    }

file com2.c:

  int c = 6;	/* Think of this as initialized common within blockdata */

Now do the following in /bin/sh:

  cc -c main.c
  cc -c com1.c
  cc -c com2.c
  ar cr lx.a com1.o com2.o
  cc -o main main.o lx.a
  ./main
  echo $?

Most BSD systems will print "11" and most SVR3 systems will print "5" (because
uninitialized common is 0 on Unix systems). If you say:

  nm main

on most BSD systems, both "c" and "d" will have storage class "DATA",
indicating that they have been initialized because com2.o was bound. On most
SVR3 systems, "c" will have storage class "BSS", indicating that it is
uninitialized because com2.o was not bound.

Now as for arguments about the Fortran 77 standard:

James Craig Burley writes:
> ...I believe if you look into
> the history of the F77 standard, you'll find that the reason Page 8-9 lines 30
> and 31 allow block data subprogram names in the EXTERNAL statement was to
> accommodate systems allowing linking of libraries that needed a means to
> allow procedures in a library to specify that they also needed a corresponding
> BLOCK DATA program unit from that same library.
> ...It stands to reason, therefore, that anyone designing a new Fortran system
> and wishing to be standard-conforming would support both the letter and the
> spirit of the standard...any responsible developer would interpret it that
> way...

I am acquainted with language-independent compiler optimizers which delete
unreferenced global imports, causing EXTERNAL BDATA to vanish without a trace.
Perhaps you are not accustomed to such aggressive optimization. Clearly it's
a matter of taste, but around here we tend to regard complaints about such
deletions with the same sympathy we extend to complaints about our not
allocating unSAVEd local variables in memory: if the standard doesn't say you
can rely on it, please don't.

Consider that the Fortran 77 standard says (2.12) that when a procedure
_reference_ is _executed_, the procedure must be "available" (the Fortran 77
circumlocution to avoid talking about "linking"). Can anyone find a provision
in the standard which says that the appearance of a procedure name in an
EXTERNAL statement requires the procedure to be "available"? I can't. In its
absence, I can imagine a perverse user arguing that the following program is
standard-conforming even if X is not available:

	EXTERNAL X
	END

and complaining that a processor which refuses to construct an executable
program in the absence of X fails to conform to Fortran 77!
-- 
sjc@key.com or ...{sun,pyramid}!pacbell!key!sjc 		Steve Correll

burley@world.std.com (James C Burley) (10/26/90)

In article <2208@key.COM> sjc@key.COM (Steve Correll) writes:

   James Craig Burley writes:
   > ...I believe if you look into
   > the history of the F77 standard, you'll find that the reason Page 8-9 lines 30
   > and 31 allow block data subprogram names in the EXTERNAL statement was to
   > accommodate systems allowing linking of libraries that needed a means to
   > allow procedures in a library to specify that they also needed a corresponding
   > BLOCK DATA program unit from that same library.
   > ...It stands to reason, therefore, that anyone designing a new Fortran system
   > and wishing to be standard-conforming would support both the letter and the
   > spirit of the standard...any responsible developer would interpret it that
   > way...

   I am acquainted with language-independent compiler optimizers which delete
   unreferenced global imports, causing EXTERNAL BDATA to vanish without a trace.
   Perhaps you are not accustomed to such aggressive optimization. Clearly it's
   a matter of taste, but around here we tend to regard complaints about such
   deletions with the same sympathy we extend to complaints about our not
   allocating unSAVEd local variables in memory: if the standard doesn't say you
   can rely on it, please don't.

   Consider that the Fortran 77 standard says (2.12) that when a procedure
   _reference_ is _executed_, the procedure must be "available" (the Fortran 77
   circumlocution to avoid talking about "linking"). Can anyone find a provision
   in the standard which says that the appearance of a procedure name in an
   EXTERNAL statement requires the procedure to be "available"? I can't. In its
   absence, I can imagine a perverse user arguing that the following program is
   standard-conforming even if X is not available:

	   EXTERNAL X
	   END

   and complaining that a processor which refuses to construct an executable
   program in the absence of X fails to conform to Fortran 77!
   -- 
   sjc@key.com or ...{sun,pyramid}!pacbell!key!sjc 		Steve Correll

I am accustomed to extremely aggressive optimization, both that which has
been implemented and that which I've only thought about.

The program you show above, "EXTERNAL X;END", is indeed standard-conforming
even if X is not available, because X is not necessarily a procedure: in fact
it appears the standard requires that it must be a BLOCK DATA subprogram.
(Because in the main program unit, it is not referenced as a subroutine or
function, and a BLOCK DATA subprogram is the only alternative.)  Unfortunately,
the standard does not appear to specify the effect of specifying a BLOCK DATA
subprogram name in an EXTERNAL statement.  So it appears that your mythical
user complaining about a processor refusing to construct an executable
program in the absence of X indeed has a point: it is a valid program, and
X need not be present, even though I would argue a reasonable implementation
should complain that there is no BLOCK DATA X (via an error message from,
perhaps, a multi-language linker requiring the user to look up the message
in the Fortran book to yield the explanation that perhaps a BLOCK DATA X
is missing).

However, as I pointed out in my original posting, the only reasonably way
for an implementation to deal with "EXTERNAL FOO" where FOO is not referenced
anywhere else in the same program unit is for it to assume FOO is a BLOCK DATA
program unit and to ensure that, if it indeed turns out that FOO is found to
be a BLOCK DATA program unit, its initial values for variables in COMMON are
used for the program.  If FOO turns out to be a subroutine or function, an
implementation is free to ignore it, if it is capable of doing that while
still dealing with the possible BLOCK DATA FOO case instead.

Now, you can play language lawyer games -- like the company that said their
implementation was standard-conforming even though the STOP statement did
not in fact stop the program, because the standard didn't actually specify
what happens the moment after the program is "stopped" -- and say that an
implementation is standard-conforming that totally ignores EXTERNAL FOO
where FOO is otherwise unreferenced in the program unit.

However, if you are taking things this literally from a standards
perspective, then please note that there is NO STANDARD WAY to initialize
variables in common!  According to the standard, that can ONLY be done
via BLOCK DATA.  And a system that provides some mechanism whereby BLOCK DATA
can be ignored (the "library problem" that started all this), and yet
refuses to honor a clear accommodation in the standard to deal with the
problem, fails to honor the spirit of the standard, just as does one that,
when running a program saying "PRINT *,2.0*3.0", outputs "2.0" because
the standard doesn't actually specify precision requirements.

After all, if subroutines and functions need only be "available" when they
are actually "referenced" at run time, then (unless there's some wording to
override this assumption in the standard that I can't remember seeing offhand),
the same goes for BLOCK DATA in a system that implements everything using
libraries.  Yet there is NO WAY to "reference" a BLOCK DATA subprogram except
via the "EXTERNAL FOO" construct.

(And note that your reference to complaints about unSAVEd variables not
being SAVEd is, in my opinion, an invalid comparison in this context.
The spirit of the standard regarding BLOCK DATA is as I state above; whereas
the standard clearly states that you can't depend on the value of an
unSAVEd variable between procedure invocations.  People complaining about
a system not honoring the EXTERNAL FOO convention for ensuring the linking-in
of a BLOCK DATA FOO residing in a library have a very legitimate gripe,
language-lawyer games notwithstanding.  People who complain about unSAVEd
variables not retaining their values between procedure invocations are just
plain wrong; but note that many implementations nevertheless provide command-
line qualifiers to effectively force the SAVEing of all appropriate
variables, so given that so many implementations bend over backwards to
accommodate incorrect or very old code, why not deal with the relatively
trivial case of EXTERNAL FOO possibly referring to a necessary BLOCK DATA FOO?)

James Craig Burley, Software Craftsperson    burley@world.std.com

jerry@violet.berkeley.edu (Jerry Berkman) (11/22/90)

In article <BURLEY.90Oct23041048@world.std.com> burley@world.std.com (James C Burley) writes:
...
==All readers should note that the Fortran standards, both 77 AND 90, DISALLOW
==initialization (via DATA or, for 90, via initial values specified on type-
==declaration statements) of entities in common blocks except within BLOCK
==DATA subprograms, and there only for named common blocks (i.e. you can't
==provide initial values for entities in blank common).  In other words, the
==following very effective solution is, unfortunately, nonstandard, even though
==I believe it will work on every single machine that supports Fortran to any
==reasonable extent (i.e. here's a recommendation, though it isn't standard):

==      SUBROUTINE DOES_NOTHING  !Instead of BLOCK DATA DOES_NOTHING.
==      INTEGER NOTHING
==      COMMON /NOTHING/ NOTHING
==      ...other stuff you want to put in a BLOCK DATA...
==      DATA NOTHING/0/  !Make sure it isn't 12345.
==      ...other DATA statements you'd put in a BLOCK DATA...
==      END

==... the above solution will work on any system I can imagine, as long as
==it accepts the nearly ubiquitous extension allowing DATA for variables in
==common from within subroutines or functions.

==James Craig Burley, Software Craftsperson    burley@world.std.com

This is flagged as an error by VS FORTRAN which is IBM's mainframe FORTRAN
compiler.  Also by WATFOR77 on our IBM mainframe.

There is probably no easy way which works on all systems to get block data's
to load.  Some UNIX systems will load a block data in a library if it is in
the same source file as another program segment being loaded, some UNIX systems
will not.  All the non-UNIX systems I have used would not.

	- Jerry Berkman, U.C. Berkeley, jerry@violet.berkeley.edu

3003jalp@ucsbuxa.ucsb.edu (Applied Magnetics) (11/27/90)

In article <1990Nov22.074157.15813@agate.berkeley.edu> jerry@violet.berkeley.edu (Jerry Berkman) writes:

>...
>There is probably no easy way which works on all systems to get block data's
>to load.  Some UNIX systems will load a block data in a library if it is in
>the same source file as another program segment being loaded, some UNIX systems
>will not.  All the non-UNIX systems I have used would not.
>	- Jerry Berkman, U.C. Berkeley, jerry@violet.berkeley.edu

Our IBM mainframe with VS Fortran will do it.  The loader granularity
for libraries (TXTLIB's) is at the object file level (TEXT).  If an
archived object file contains a subprogram you need and a block data,
both get loaded.  (This is with VM/XA and CMS).

I agree that there is no universal solution.  Just for the heck of it,
here is yet another way to violate the standard:

C    <Never call this routine!  Just leave it near your main.
      SUBROUTINE KABOOM
      CALL BD
      END
C    <This BD is no subroutine.  It's the block data.  Tee hee.
C    <Hope this will fool the loader.

Anybody out there have a loader that refuses to cooperate?

--Pierre Asselin, R&D, Applied Magnetics Corp.

shank@buphy.BU.EDU (Jim Shank) (11/27/90)

In article <1990Nov22.074157.15813@agate.berkeley.edu> jerry@violet.berkeley.edu (Jerry Berkman) writes:

>>...
>>There is probably no easy way which works on all systems to get block data's
>>to load.  Some UNIX systems will load a block data in a library if it is in
>>the same source file as another program segment being loaded, some UNIX systems
>>will not.  All the non-UNIX systems I have used would not.
>>	- Jerry Berkman, U.C. Berkeley, jerry@violet.berkeley.edu

>I agree that there is no universal solution.  Just for the heck of it,
>here is yet another way to violate the standard:

>C    <Never call this routine!  Just leave it near your main.
>      SUBROUTINE KABOOM
>      CALL BD
>      END
>C    <This BD is no subroutine.  It's the block data.  Tee hee.
>C    <Hope this will fool the loader.

I always thought the way to do this was to declare the Block Data
subprogram EXTERNAL in the main routine:


        PROGRAM MAIN


        EXTERNAL BLKDAT


        . 
        .
        .
        STOP

This forces the linker to include the Block data subprogram.
      

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (11/27/90)

In article <7388@hub.ucsb.edu>, 3003jalp@ucsbuxa.ucsb.edu (Applied Magnetics) writes:
> C    <Never call this routine!  Just leave it near your main.
>       SUBROUTINE KABOOM
>       CALL BD
>       END
> C    <This BD is no subroutine.  It's the block data.  Tee hee.
> C    <Hope this will fool the loader.
> 
> Anybody out there have a loader that refuses to cooperate?

I know that the Burroughs compilers used different names for
COMMON blocks (e.g. "/ABLOCK/") and subroutines (e.g. "ABLOCK").
That caught quite a lot of mistakes.  I imagine that a Fortran
compiler could do the same for block data, e.g. "*BD*".  That
would give you trouble.  It's a compiler choice, not a loader
one.
-- 
I am not now and never have been a member of Mensa.		-- Ariadne.

burley@pogo.ai.mit.edu (Craig Burley) (11/27/90)

In article <69366@bu.edu.bu.edu> shank@buphy.BU.EDU (Jim Shank) writes:

   I always thought the way to do this was to declare the Block Data
   subprogram EXTERNAL in the main routine:


	   PROGRAM MAIN


	   EXTERNAL BLKDAT


	   . 
	   .
	   .
	   STOP

   This forces the linker to include the Block data subprogram.

Not according to the standard, but yes, I agree this is the most
standard-conforming way to deal with things, both from the user's and
the implementor's point of view.

The problem is that systems that "extend" Fortran by providing certain
weird nonstandard things like source files that contain multiple program
units and, in this case, libraries from which only program units referenced
by the program currently being linked/loaded are actually loaded, fail to
take into account and thus implement in an obvious and standard-acceptable
way certain Fortran facilities like BLOCK DATA.  (Yes, I know these are very
common things, but their behaviors aren't even discussed in the standard.)

As I've pointed out before, the ONLY standard way to pre-initialize (DATA)
variables in common areas is to: use named commons; and initialize them via
DATA in BLOCK DATA program units.  A system that provides libraries and yet
does not implement in the expected way the standard extension (that by the
way in the standard has NO explanation I can find) you showed in the above
example by ensuring that any BLOCK DATA FOO in a library is loaded/linked if
at least one other program unit that is loaded/linked contains an EXTERNAL
FOO statement is, in my opinion, not a complete implementation of Fortran.

It may be an ANSI-conforming implementation, but that's a different question.
For example, an implementation may be ANSI-conforming as long as all your
program units are in a single source file, but not if you put them in
separate source files even though that implementation handles multiple sources
(and thus objects) in a load/link command for other languages.  Even though
it appears to handle Fortran this way also, and works in many cases, the
fact that, say, linkage involving user-defined procedures having the same
names as intrinsics does not work still wouldn't prevent the implementation
from being ANSI-conforming as long as the problem didn't exist in SOME
method of writing Fortran code (in my example, one big source file with all
the program units, hence one big object module).

So a system that had such a problem could be ANSI-conforming but, in my
opinion, would not be complete Fortran in terms of the natural combination
of its capabilities (multiple source files + ANSI Fortran support should =
ANSI Fortran support using multiple source files).

That is why I assert that systems failing to load/link BLOCK DATA FOO from
a library when at least one load/linked program unit says EXTERNAL FOO are
not complete Fortran, because they a) have libraries, b) may conform to ANSI
FORTRAN 77, but c) do not conform to ANSI FORTRAN 77 in the natural way when
libraries are used in certain standard ways.

Such systems require the programmer either to use nonstandard constructs within
their programs (which in itself should be a clear argument that these systems
are not complete Fortran) or use extraordinary facilities like special
specifications when loading/linking or generating the library (which is
redundant since there's an ANSI feature provided that should be usable; and
if the programmer does not know this and uses the extraordinary facilities, he
or she might well be producing nonportable code without knowing it).

Note that this does not mean I necessarily have a beef with a Fortran system
implementation (or implementor) that fails to deal with this feature, IF the
implementor has no control over the loader/linker (i.e. it comes from another
vendor and is highly inflexible or primitive).

However, I DO have a beef with people who say "we can't have EXTERNAL FOO force
FOO to be loaded/linked since it might not be a BLOCK DATA (and we can't tell
the difference when we need to) and we don't want to put anything in the
executable image that is not actually referenced except possibly via EXTERNAL".
This is WRONG.  They certainly CAN force FOO to be loaded/linked, because a)
I doubt many programs ever use EXTERNAL without actually referencing the name,
and b) assuming they provide some nonstandard or nonportable means to solve the
BLOCK DATA problem, they should instead solve it according to the standard
and relegate designations like "I know I said EXTERNAL FOO, perhaps, but I
don't really need it if I don't actually reference it" to the realm of
nonstandard and nonportable behavior.

I hold this position simply because failing to optimally omit an EXTERNALed
procedure from a loaded/linked program that doesn't actually reference it has
no effect on the correctness of a program, and hence can be relegated to the
category of problems solved via nonstandard and nonportable means.  On the
other hand, failing to load/link an EXTERNALed BLOCK DATA in a loaded/linked
program definitely CAN and most often WILL affect the correctness of the
program.  Anyone holding the opposite position in light of these facts
(assuming these are facts, i.e. I'm not simply mistaken about something)
should, in my opinion, not be writing compilers, linkers, operating systems,
and so on -- anything that has a "standard" of sorts for it.  Nor should they
be selling or manufacturing such products.  They don't have the temperment
for it -- they'd do better at end-user applications, where saving a bit of
space or time at the expense of full generality might be ok as long as they
know when they don't need full generality.  Myself, I think I have not yet
developed the temperment for end-user programming: i.e. this is not a
criticism of one's person, but of whether they're in the right field of
labor within the software industry.  There's plenty of room for all of us!

James Craig Burley, Software Craftsperson    burley@ai.mit.edu

3003jalp@ucsbuxa.ucsb.edu (Applied Magnetics) (11/28/90)

The following is from Harbison and Steele, "C a Reference Manual", 1st
ed. section 4.8.  Emphasis mine.

...It is a well-known deficiency in C that defining and referencing
occurrences of external declarations are difficult to distinguish.  In
general, compilers use one of three complicated schemes to determine
when a top level declaration is a defining occurrence.
...
4.8.2 The FORTRAN "named COMMON" Solution
  This scheme is so named because it is related to the way multiple
references to a FORTRAN COMMON block are merged into a single defining
occurrence in some FORTRAN implementations.
...At link time, all external declarations for the same identifier (in
all C object files) are combined and a single defining occurrence is
conjured, NOT NECESSARILY ASSOCIATED WITH ANY PARTICULAR FILE.  If any
declaration specified an initializer, that initializer is used to
initialize the data object.  (If several declarations did, the results
are unpredictable.)
  This solution is the most painless for the programmer, the most
demanding on system software and the most likely to lead to confusion
on the part of people reading a program.  It is hypothesized that the
presence of a linker on the PDP-11 that handled these COMMON
declarations lured early C implementors into depending on this
capability

End of quote.  THAT's the problem.  We're all stuck with loaders that
recognize 1) REFERENCED external symbols, which must be resolved by
loading additional defining modules, 2) DEFINED external symbols, which
must not conflict among themselves and are loaded to resolve the former
kind, and finally 3) COMMON external symbols, which are collected
during the loading phase and finally fused together without loading
anything else.

I assume that the COMMON symbol semantics originated at IBM.  The ANSI
F.77 standard itself explicitly declines to address those issues (sect.
1.3.2).   Your implementation can do what it wants to you.

In the future, I think that I will keep my block datas in SOURCE form
and require the programmer to INCLUDE a copy exactly once in his
source file.  The INCLUDE statement was discussed eralier in this
group.  It's not ANSI, but it's MIL-something.  Almost all compilers
have some form of it.  They're all different, of course, but the
functionality is there, so you can port.

--Pierre Asselin, R&D, Applied magnetics Corp.  I speak for me.