LIB$INITIALIZE example code v. DECC$ARGV_PARSE_STYLE

Post Reply

Topic author
sms
Master
Posts: 370
Joined: Fri Aug 21, 2020 5:18 pm
Reputation: 0
Status: Offline

LIB$INITIALIZE example code v. DECC$ARGV_PARSE_STYLE

Post by sms » Tue Aug 15, 2023 2:18 am

Code: Select all

ITS $ cc /version
VSI C V7.4-001 on OpenVMS IA64 V8.4-2L3

ITS $ cxx /version
VSI C++ V7.4-006 on OpenVMS IA64 V8.4-2L3


   "VSI C++ V7.4-006 Release Notes for OpenVMS Integrity servers"
(SYS$HELP:CXX.RELEASE_NOTES) includes an example program intended to
show how "To use the LIB$INITIALIZE feature explicitly in either
C or C++".  A (very) slightly edited version of that example is included
below as "lix.c".  The comments therein say:

/* Compile with either C or C++ on Alpha or I64, link and run.
** The output is:
**    In some_init_function.
**    In some_other_init_function.
**    In main.
*/

   CC is happy enough:

its $ cc lix.c /obj = lix_cc
its $ link lix_cc 
its $ run lix_cc
In some_init_function.
In some_other_init_function.
In main.

   CXX complains, but the executable seems to work:

its $ cxx lix.c /obj = lix_cxx

extern void (* const unused_global_variable_2[])() =
.....................^
%CXX-W-ALIGNNOTSTD, Alignment specifed for extern model is less than the
          alignment required for a global variable of this size under the
          Itanium Software Conventions.  Access to this variable may cause
          alignment faults.
at line number 30 in file ITS$DKA0:[SMS.VSI.lix]lix.c;7
its $ cxxlink lix_cxx
%ILINK-W-COMPWARN, compilation warnings
        module: LIX 
        file: ITS$DKA0:[SMS.VSI.lix]lix_cxx.OBJ;1 
its $ run lix_cxx
In some_init_function.
In some_other_init_function.
In main.


   "seems to work" is the critical phrase here.

   So far as I know, the only good reason to expend the effort to use
LIB$INITIALIZE instead of just invoking an initialization function in
main() is to get DECC$ARGV_PARSE_STYLE set in time to be effective. 
Sadly, it looks as if no one actually tried this with this example code.

   When I modified the example program to do this one useful task, I was
disappointed.  (Also confused, frustrated, exasperated, and a few other
things in turn.)  In "lix2.c", I expanded "some_init_function()" to use
the usual decc$feature_set_value() (et al.) functions to set
DECC$ARGV_PARSE_STYLE:

its $ show proc /pars
[...]
Parse Style: Extended

its $ cc lix2.c /obj = lix2_cc    
its $ link lix2_cc
its $ mcr sys$disk:[]lix2_cc UPPERlower
In some_init_function.
 FEAT: >DECC$ARGV_PARSE_STYLE<
 Feature init init state = -1, value = 0.
 Feature new  init state = 2, value = 1.
In some_other_init_function.
In main.
 argv[ 1]: >upperlower<

   The new code clearly gets executed, but, just as clearly, it has no
effect on the way argv[] is handled.  There was no difference using CXX,
except for the warnings:

its $ cxx lix2.c /obj = lix2_cxx

extern void (* const unused_global_variable_2[])() =
.....................^
%CXX-W-ALIGNNOTSTD, Alignment specifed for extern model is less than the
          alignment required for a global variable of this size under the
          Itanium Software Conventions.  Access to this variable may cause
          alignment faults.
at line number 34 in file ITS$DKA0:[SMS.VSI.lix]lix2.c;8
its $ cxxlink lix2_cxx
%ILINK-W-COMPWARN, compilation warnings
        module: LIX2 
        file: ITS$DKA0:[SMS.VSI.lix]lix2_cxx.OBJ;1 
its $ mcr sys$disk:[]lix2_cxx UPPERlower
In some_init_function.
 FEAT: >DECC$ARGV_PARSE_STYLE<
 Feature init init state = -1, value = 0.
 Feature new  init state = 2, value = 1.
In some_other_init_function.
In main.
 argv[ 1]: >upperlower<


   Defining the logical name before running the program _does_ work, of
course:

ITS $ define /user_mode DECC$ARGV_PARSE_STYLE 1
ITS $ mcr sys$disk:[]lix2_cxx.exe UPPERlower
In some_init_function.
 FEAT: >DECC$ARGV_PARSE_STYLE<
 Feature init init state = 1, value = 1.
 Feature new  init state = 2, value = 1.
In some_other_init_function.
In main.
 argv[ 1]: >UPPERlower<


   After extensive bumbling, I found that disabling some of the printf()
diagnostics in some_init_function() (in "lix3.c") was helpful:

its $ cc lix3.c /obj = lix3_cc
its $ link lix3_cc
its $ mcr sys$disk:[]lix3_cc UPPERlower
 Feature new  init state = 2, value = 1.
Leaving some_init_function.
In some_other_init_function.
In main.
 argv[ 1]: >UPPERlower<

   Enabling them restores the bad behavior:

its $ cc lix3.c /obj = lix3d_cc /def = DIAG=1
its $ link lix3d_cc
its $ mcr sys$disk:[]lix3d_cc UPPERlower
In some_init_function.
 FEAT: >DECC$ARGV_PARSE_STYLE<
 Feature init init state = -1, value = 0.
 Feature new  init state = 2, value = 1.
Leaving some_init_function.
In some_other_init_function.
In main.
 argv[ 1]: >upperlower<


   A naive user might guess that doing I/O using printf() _before_
setting DECC$ARGV_PARSE_STYLE causes some CRTL initialization to occur
which closes the door on any possibility of getting
DECC$ARGV_PARSE_STYLE set in time to be effective.  If so, then that
might be a fact worthy of documentation.

   Another disappointment is that this change appears to be insufficient
to wring the desired result from CXX:

its $ cxx lix3.c /obj = lix3_cxx

extern void (* const unused_global_variable_2[])() =
.....................^
%CXX-W-ALIGNNOTSTD, Alignment specifed for extern model is less than the
          alignment required for a global variable of this size under the
          Itanium Software Conventions.  Access to this variable may cause
          alignment faults.
at line number 34 in file ITS$DKA0:[SMS.VSI.lix]lix3.c;5
its $ cxxlink lix3_cxx
%ILINK-W-COMPWARN, compilation warnings
        module: LIX3 
        file: ITS$DKA0:[SMS.VSI.lix]lix3_cxx.OBJ;1 
its $ mcr sys$disk:[]lix3_cxx UPPERlower
 Feature new  init state = 2, value = 1.
Leaving some_init_function.
In some_other_init_function.
In main.
 argv[ 1]: >upperlower<


   So:
   
   1. The LIB$INITIALIZE example program in the CXX release notes has
      some problems:
      A. CXX warnings.
      B. Excessive diagnostic I/O (I'd guess) which nicely reveals the
         program activity, but renders it useless in the one case where
         it's truly valuable.
      C. It failed to show me how to get DECC$ARGV_PARSE_STYLE set in
         time to be effective in a C++ program.  (Which is how I got
         started on this ordeal in the first place.)

   Helpful (tested) advice would be appreciated.

   My example programs should be attached.
Attachments
lix.c
(1.77 KiB) Downloaded 113 times
lix2.c
(3.26 KiB) Downloaded 106 times
lix3.c
(3.4 KiB) Downloaded 105 times
Last edited by sms on Tue Aug 15, 2023 8:16 am, edited 1 time in total.


hb
Valued Contributor
Posts: 80
Joined: Mon May 01, 2023 12:11 pm
Reputation: 0
Status: Offline

Re: LIB$INITIALIZE example code v. DECC$ARGV_PARSE_STYLE

Post by hb » Tue Aug 15, 2023 1:55 pm

Sounds reasonable to ask for documentation on what is initialized in the CRTL when a printf is executed.

As mentioned elsewhere, for C++ the initialization of the CRTL is done in the init code of a shareable image, here CXXL$LANGRTL. (Don't ask me why.) You need to set the CRTL feature before the CXXL$LANGRTL's init code runs. This means, you need your own shareable image - consisting only of init code - which is activated before CXXL$LANGRTL. Sounds difficult, but it's not.

Split the lix3 source code into lix4.c

Code: Select all

#include <stdio.h>              /* printf() */

int main( int argc, char **argv)
{
  printf("In main.\n");
  if (argc > 1)
  {
    printf( " argv[ 1]: >%s<\n", argv[ 1]);
  }
}

/* Compile with either C or C++ on Alpha or I64, link and run.
** The output is:
**    In some_init_function.
**    In some_other_init_function.
**    In main.
*/
... and lix4s.c

Code: Select all

/* Example to set up LIB$INITIALIZE usage by creating a reference
** to the LIB$INITIALIZE function, and an initialized list of
** functions to be called in the LIB$INITIALIZE psect.
*/

#include <errno.h>              /* errno */
#include <stdio.h>              /* printf() */
#include <unixlib.h>            /* decc$feature_get_index(), et al. */

#ifdef __cplusplus
extern "C" {
#endif

/* Declarations for initialization functions. */
extern void some_init_function(void);
extern void some_other_init_function(void);
/* etc, e.g. other declarations might come from header files */

/* Use 32-bit pointers */
#if __INITIAL_POINTER_SIZE
# pragma pointer_size save
# pragma pointer_size 32
#endif

/* Create a reference to the LIB$INITIALIZE function. */
extern void LIB$INITIALIZE(void);
extern void (*unused_global_variable_1)(void) = LIB$INITIALIZE;

/* Create an array of pointers to the init functions in the special
** LIB$INITIALIZE section.
*/
#pragma extern_model save
#pragma extern_model strict_refdef "LIB$INITIALIZE" gbl,noexe,nowrt,noshr,long
extern void (* const unused_global_variable_2[])() =
{
  some_init_function
  , some_other_init_function
/* etc, other functions to be called by LIB$INITIALIZE() */
};
#pragma extern_model restore

#if __INITIAL_POINTER_SIZE
# pragma pointer_size restore
#endif

#ifdef __cplusplus
}
#endif
/* End of example to set up LIB$INITIALIZE */

/* Begin executable test of LIB$INITIALIZE setup. */
#ifdef __cplusplus
extern "C" {
#endif

extern void some_init_function(void)
{
  int feat_index;
  int feat_value;
  int feat_value_init;
  int feat_value_max;
  int feat_value_min;
  int feat_value_orig;

#define FEAT "DECC$ARGV_PARSE_STYLE"

#ifdef DIAG
  printf("In some_init_function.\n");
  printf( " FEAT: >%s<\n", FEAT);
#endif /* def DIAG*/

  feat_index = decc$feature_get_index( FEAT);
  if (feat_index < 0)
  {
    printf( " Error in decc$feature_get_index().  ndx = %d, errno = %d.\n",
     feat_index, errno);
  }
  else
  {
    feat_value = decc$feature_get_value( feat_index,
      __FEATURE_MODE_CURVAL);
    feat_value_min = decc$feature_get_value( feat_index,
      __FEATURE_MODE_MINVAL);
    feat_value_max = decc$feature_get_value( feat_index,
     __FEATURE_MODE_MAXVAL);
    feat_value_init = decc$feature_get_value( feat_index,
     __FEATURE_MODE_INIT_STATE);

#ifdef DIAG
    printf( " Feature init init state = %d, value = %d.\n",
     feat_value_init, feat_value);
#endif /* def DIAG*/

    feat_value_orig = decc$feature_set_value( feat_index,
     __FEATURE_MODE_CURVAL, 1);

    if (feat_value_orig < 0)
    {
      printf( " Error in decc$feature_set_value().  errno = %d.\n",
       errno);
    }
    else
    {
      feat_value = decc$feature_get_value( feat_index,
        __FEATURE_MODE_CURVAL);
      feat_value_init = decc$feature_get_value( feat_index,
       __FEATURE_MODE_INIT_STATE);
      printf( " Feature new  init state = %d, value = %d.\n",
       feat_value_init, feat_value);
    }
  }

  printf("Leaving some_init_function.\n");
#ifdef DIAG
#endif /* def DIAG*/
}

extern void some_other_init_function(void)
{
  printf("In some_other_init_function.\n");
}

#ifdef __cplusplus
}
#endif
Compile, link the main program without init code or init code linked into the main image:

Code: Select all

$ cxx lix4.c
$ link lix4
$ mc []lix4 UPPERlower
In main.
 argv[ 1]: >upperlower<
$
$ cxx lix4s.c

extern void (* const unused_global_variable_2[])() =
.....................^
%CXX-W-ALIGNNOTSTD, Alignment specifed for extern model is less than the
          alignment required for a global variable of this size under the
          Itanium Software Conventions.  Access to this variable may cause
          alignment faults.
at line number 34 in file DISK$WORK:[HB]LIX4S.C;2
$ link lix4,lix4s
%ILINK-W-COMPWARN, compilation warnings
        module: LIX4S 
        file: DISK$WORK:[HB]LIX4S.OBJ;1 
$ mc []lix4 UPPERlower
 Feature new  init state = 2, value = 1.
Leaving some_init_function.
In some_other_init_function.
In main.
 argv[ 1]: >upperlower<
$ 
... and yes, you do not need CXXLINK on IA64.

Link with a shareable image

Code: Select all

$ link/share lix4s
%ILINK-W-COMPWARN, compilation warnings
        module: LIX4S 
        file: DISK$WORK:[HB]LIX4S.OBJ;1
$ link lix4,tt:/opt
lix4s/share
 Exit 
%ILINK-W-COMPWARN, compilation warnings
        shareable image: DISK$WORK:[HB]LIX4S.EXE;1
$ def/user lix4s sys$disk:[]lix4s
$ mc []lix4 UPPERlower
 Feature new  init state = 2, value = 1.
Leaving some_init_function.
In some_other_init_function.
In main.
 argv[ 1]: >UPPERlower<
$ 
And yes, using a shareable image also works for a C program. Unfortunately, compiling the main with C++ on x86 and linking with the shareable image does not yet work. (I haven't tried this, but I assume, that a single C++ module in a program prevents this from working.)

PS: Sorry, I was too lazy to download the sources from VMS to attach them as files to this forum. So you see some big "code" boxes. But I avoided putting all of my text and the code into one box. So it should be easy to read.


Topic author
sms
Master
Posts: 370
Joined: Fri Aug 21, 2020 5:18 pm
Reputation: 0
Status: Offline

Re: LIB$INITIALIZE example code v. DECC$ARGV_PARSE_STYLE

Post by sms » Tue Aug 15, 2023 10:42 pm

Code: Select all

> [...] Sounds difficult, but it's not.

   Given a good recipe, even I seem to be able to make it work.  Thanks. 

   It even seems to work if one builds the initializer with CC, and the
main program with CXX, which would avoid those pesky %CXX-W-ALIGNNOTSTD
complaints.  (But an early printf() still spoils things, as I'd
expected.)

   The two-part-ness (separate main program and initializer shareable
image) is more annoying than a one-piece executable, however.

   I do very little with shareable images, so I know nothing, but I
gather that the image activator (or someone), by default, looks for such
a shareable image in SYS$SHARE, so, to make this scheme work for a peon
user (who lacks permission to write in SYS$SHARE), it's pretty much
compulsory to use a logical name of some kind to provide directions to
some different (peon-writeable) location for it.  "my-program_SHR", for
example?

> ... and yes, you do not need CXXLINK on IA64.

   Not ever, or not for these simple example programs?  HELP CXXLINK on
IA64 still has non-null content, so I inferred that it was still useful. 
I did notice that CXXLINK seemed to have vanished from x86_64. 
Eventually, I should run the experiment on Alpha, too.

   Now that I might have some tenuous grasp on this stuff, I'll see if I
can move from the example code to the actual program of interest.

> [...] Unfortunately, compiling the main with C++ on x86 and linking
> with the shareable image does not yet work. [...]

   But there's hope for the future?

> PS: Sorry, I was too lazy [...]

   Not a problem.  Thanks again.

User avatar

arne_v
Master
Posts: 368
Joined: Fri Apr 17, 2020 7:31 pm
Reputation: 0
Location: Rhode Island, USA
Status: Offline
Contact:

Re: LIB$INITIALIZE example code v. DECC$ARGV_PARSE_STYLE

Post by arne_v » Tue Aug 15, 2023 11:23 pm

sms wrote:
Tue Aug 15, 2023 10:42 pm
I do very little with shareable images, so I know nothing, but I
gather that the image activator (or someone), by default, looks for such
a shareable image in SYS$SHARE, so, to make this scheme work for a peon
user (who lacks permission to write in SYS$SHARE), it's pretty much
compulsory to use a logical name of some kind to provide directions to
some different (peon-writeable) location for it. "my-program_SHR", for
example?
Yes.

Try:

$ SHOW LOG *SHR*

and you will likely find lots of such logicals.

Depending on what you have installed.

OpenSSL, Java, Rdb, SQLite, OSU HTTPD, PHP, Python etc..
Arne
arne@vajhoej.dk
VMS user since 1986


Topic author
sms
Master
Posts: 370
Joined: Fri Aug 21, 2020 5:18 pm
Reputation: 0
Status: Offline

Re: LIB$INITIALIZE example code v. DECC$ARGV_PARSE_STYLE

Post by sms » Wed Aug 16, 2023 2:22 am

Code: Select all

> $ SHOW LOG *SHR*

   Thanks, but I anticipated you.  I tried "*SHR*" and "*SHARE*".  (And
found a high SHR:SHARE ratio.)


Topic author
sms
Master
Posts: 370
Joined: Fri Aug 21, 2020 5:18 pm
Reputation: 0
Status: Offline

Re: LIB$INITIALIZE example code v. DECC$ARGV_PARSE_STYLE

Post by sms » Thu Aug 24, 2023 12:07 am

Code: Select all

> [...] Unfortunately, compiling the main with C++ on x86 and linking
> with the shareable image does not yet work. [...]

   It seems to work for me (in at least one case):

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

V87 $ unrar t ITS$DKA0:[SMS]PPMDI1.RAR

UNRAR 5.91a  freeware      Copyright (c) 1993-2020 Alexander Roshal


                              vvvvvvvvvv--- Same as command line.
Testing archive ITS$DKA0:[SMS]PPMDI1.RAR

Testing     read_me.txt                                               OK 
[...]

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

V87 $ unrar t ITS$DKA0:[SMS]ppmdi1.rar

UNRAR 5.91a  freeware      Copyright (c) 1993-2020 Alexander Roshal


                              vvvvvvvvvv--- Same as command line.
Testing archive ITS$DKA0:[SMS]ppmdi1.rar

Testing     read_me.txt                                               OK 
[...]

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

   The sad part of this is that this particular program is generally
indifferent to the case of commands and options on its command line,
which I realized only too late.


   Now, if anyone is  looking for more whiny CXX complaints (referring to
the "OpenVMS x86-64 VSI C++ Release Notes Version: 230731"), ...

> All message IDs should be given to CXX as they are in double quotes to
> preserve the case. This is true for the keyword "all" as well.

   If the C++ compiler preserved the case of _its_ command line, would I
be able to omit the quotation marks in, say:
       /warning = disable = ("dangling-else", "switch")
?

   Are there any messages which differ only in case, making a
case-insensitive comparison defective (now) or dangerous (some day)?

> The compiler does not automatically upcase external names like all
> other OpenVMS compilers. [...]

   The advantage of being "not [...] like all other OpenVMS compilers"
in this respect escapes me.  Especially when it complicates my
multi-architecture builders, where I now need to specify /NAMES
explicitly everyplace, or else add architecture-specific qualifiers on
x86_64.

   And, of course, a LIB$INITIALIZE code example which CXX could
compile without warnings would be nice, too.  (Even better, a scheme
which didn't need the separate shared image, of course.)

   Defining more of those Predefined_Macros in CXX on x86_64 would be
nice:

ITS $ run [.IA64L]DEC_VER.EXE
 __VMS_VERSION: >V8.4-2L3<.
 __VMS_VER    = 80421222.
 __DECC_VER   = 70490001.
 __DECCXX_VER = 70490005.
 __CRTL_VER   = 80500000.

V87 $ run [.X86_64L]DEC_VER.EXE
 __VMS_VERSION: (undefined).
 __VMS_VER    = 2147483647.
 __DECC_VER   = 70430785.
 __DECCXX_VER = (undefined).
 __CRTL_VER   = 90210000.

   (__DECC_VER is obtained from a C module; the others from C++.)

   Presumably someday CXX on x86_64 will have a single VMS-style
version number for identification?


jreagan
VSI Expert
Master
Posts: 141
Joined: Tue Dec 01, 2020 8:40 am
Reputation: 0
Status: Offline

Re: LIB$INITIALIZE example code v. DECC$ARGV_PARSE_STYLE

Post by jreagan » Thu Aug 24, 2023 6:52 pm

We're looking into LIB$INITIALIZE with C++ for those examples.

Post Reply