From: rankin@eql.caltech.edu (Pat Rankin)
Newsgroups: comp.os.vms
Subject: External objects in C
Followup-To: comp.os.vms
Date: 14 Dec 1992 19:35 PDT
Organization: California Institute of Technology
Distribution: world
NNTP-Posting-Host: eql.caltech.edu
News-Software: VAX/VMS VNEWS 1.41    

[was Subject: Re: Why does this code crash with ACCVIO? (summary, solution)]
In article <PRZEMEK.92Dec14171154@rrdstrad.nist.gov>,\
 przemek@rrdstrad.nist.gov (Przemek Klosowski) writes...
> Anyone cares to speculate why a separate keyword is
> needed, rather than having "external" cause linking?

     There are several different models for external objects.  The one
used by VAX C--and by GNU C for compatibility--is equivalent to Fortran
COMMON blocks, doubtlessly for greater ease in multi-language applications.
This is equivalent to using a named PSECT instead of a global symbol in
Macro32; C's globaldef/globalref is vice versa.  If you had a Fortran
BLOCK DATA module for data initialization you would have seen the same
problem, except that the other declarations of the object in Fortran would
have had to specify the proper size so the symptoms you'd see would have
been different (zeroed data with your initialization missing, rather than
ACCVIO due to wrong object size).

     This is usually only a problem with data-only object modules.  There
are several ways around it.  Suppose FOO.C has just global variables in it.
1) explicitly link the data, either as a separate object file foo.obj or
   as an explicit library reference.  link ...,mylib/libr/include=foo
   Some people seem to be unaware of the latter variant.  xxx.olb/incl=yyy
   is about the same as yyy.obj, but xxx.olb/lib/incl=yyy is more like
   yyy.obj,xxx.olb/lib.
2) don't use data-only modules; always specify an initialization routine
   even if it doesn't do anything.  Modify foo.c by adding
   `void foo_init(void) { return; }' and add a call to `foo_init()'
   in main() or some other appropriate place.  This is the method I prefer
   because it's portable and the linker will complain if I don't supply
   foo.obj (which can easily happen if relinking by hand instead of using
   a make utility).
3) like #2, but use a globaldef variable and put a globalref reference
   to it somewhere.  The somewhere could be in a header file used by all
   the modules, so is more transparent than a dummy initialization routine,
   but also non-portable.
Both the second and third choices will allow the linker to pull module foo
out of an object library without specifying the extra /include qualifier.
With #3, be careful that GNU C's optimizer doesn't omit your unreferenced
external(s) from the object module(s) though.

     DEC C for Alpha/VMS treats external objects differently by default,
and has a qualifier called "/extern_model" for controlling it.  The options
are "common_block", "relaxed_refdef", "strict_refdef", and "globalvalue".
According to the online help, there's also a variant of strict_refdef
which takes an extra name value, but I'm not sure offhand what that does.
Relaxed_refdef is the default and requires that at least one definition
exist (rather than the all `extern <type> <object>'; declarations such
as you ended up with when the linker didn't bring in your data-only
module).  Strict_refdef requires exactly one definition, which is what
portable code should have anyway.

		Pat Rankin, rankin@eql.caltech.edu
Newsgroups: comp.os.vms