Using SYS$ routines with C++
-
Topic author - Active Contributor
- Posts: 38
- Joined: Thu Nov 19, 2020 7:15 am
- Reputation: 0
- Location: Basingstoke, UK
- Status: Offline
- Contact:
Using SYS$ routines with C++
Hi all,
I want to write some C++ code that calls system services and have used CXX to compile and CXXLINK to link the image. This works fine if there are no calls to SYS$ etc, if there are then I get undefined symbols from the linker.
So, my question is.... what do I need to add to the CXXLINK command to get the SYS$ routines included? Do I need a .OPT file, and if so, then what goes in it?
Thanks!
Gary
I want to write some C++ code that calls system services and have used CXX to compile and CXXLINK to link the image. This works fine if there are no calls to SYS$ etc, if there are then I get undefined symbols from the linker.
So, my question is.... what do I need to add to the CXXLINK command to get the SYS$ routines included? Do I need a .OPT file, and if so, then what goes in it?
Thanks!
Gary
-
- Site Admin
- Valued Contributor
- Posts: 96
- Joined: Tue May 21, 2019 6:56 am
- Reputation: 0
- Status: Offline
Re: Using SYS$ routines with C++
Hi Gary,
Please provide the exact error that you are getting from the linker. Also, if that's not too much to ask, could you show the exact piece of code that the linker complains about?
Thank you,
Maxim Megalinskiy
VSI Training Team
Please provide the exact error that you are getting from the linker. Also, if that's not too much to ask, could you show the exact piece of code that the linker complains about?
Thank you,
Maxim Megalinskiy
VSI Training Team
Run to the bedroom, In the suitcase on the left You'll find my favorite axe.
-
Topic author - Active Contributor
- Posts: 38
- Joined: Thu Nov 19, 2020 7:15 am
- Reputation: 0
- Location: Basingstoke, UK
- Status: Offline
- Contact:
Re: Using SYS$ routines with C++
Hi Maxim,
Here's an example of a simple use of SYS$SETPRN....
Code: Select all
/* This program shows a call to system service SYS$SETPRN. */
#include <ssdef.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <descrip.h>
#define PROCNAMELEN 15
int SYS$SETPRN( struct dsc$descriptor_s* );
int main(int argc, char** argv)
{
int ret;
struct dsc$descriptor_s name_desc;
const char *name = "Gary R"; /* Define default process name */
char nameBuff[PROCNAMELEN+1];
strcpy( nameBuff , name );
name_desc.dsc$w_length = strlen(name); /* Length of name WITHOUT null terminator */
name_desc.dsc$a_pointer = nameBuff; /* Put address of string buffer in descriptor */
name_desc.dsc$b_class = DSC$K_CLASS_S; /* String descriptor class */
name_desc.dsc$b_dtype = DSC$K_DTYPE_T; /* Data type: ASCII string */
cout << "Setting process name to " << name << endl;
ret = SYS$SETPRN(&name_desc);
switch ( ret )
{
case SS$_NORMAL:
{
printf("Process name set to %s\n", nameBuff );
break;
}
case SS$_DUPLNAM:
{
fprintf(stderr, "Duplicate name detected %s\n", nameBuff );
break;
}
default:
{
fprintf(stderr, "Failed to set process name to %s - unexpected error %d!!\n", nameBuff,ret );
break;
}
}
return ret;
}
Compile & link it:
$ CXX setp
$ CXXLINK setp
%ILINK-W-NUDFSYMS, 1 undefined symbol:
%ILINK-I-UDFSYM, int SYS$SETPRN(dsc$descriptor_s *)
%ILINK-W-USEUNDEF, undefined symbol int SYS$SETPRN(dsc$descriptor_s *) referenced
source code name: "SYS$SETPRN(dsc$descriptor_s*)"
section: .text
offset: %X0000000000000140 slot: 2
module: SETP
file: MYROOT:[dev.cxx]setp.OBJ;2
OK, so, I declared SYS$SETPRN as taking a pointer to a dsc$descriptor_s struct ($DESCRIPTOR) as I guessed that's what it needed.
Can you tell me how I should declare the SYS$SETPRN routine, and how to link it in via CXXLINK?
I can get it to work no problem when coding it as a C program.
Thanks!
Gary
Re: Using SYS$ routines with C++
Code: Select all
> Can you tell me how I should declare the SYS$SETPRN routine, and how to
> link it in via CXXLINK?
its $ cxx setp2
its $ cxxlink setp2
its $ run setp2
Setting process name to Gary R
Process name set to Gary R
its $ gdiff setp.cxx setp2.cxx
12c12,13
< int SYS$SETPRN( struct dsc$descriptor_s* );
---
> /* int SYS$SETPRN( struct dsc$descriptor_s* ); */
> #include <starlet.h>
ITS $ cxx /version
HP C++ V7.4-005 on OpenVMS IA64 V8.4
Note that <starlet.h> also does things like:
#define sys$setprn SYS$SETPRN
which allows you to avoid the unsightly/tasteless upper-case "SYS$"
names.
Last edited by sms on Thu Nov 19, 2020 9:33 am, edited 1 time in total.
-
Topic author - Active Contributor
- Posts: 38
- Joined: Thu Nov 19, 2020 7:15 am
- Reputation: 0
- Location: Basingstoke, UK
- Status: Offline
- Contact:
Re: Using SYS$ routines with C++
Great, works fine.
So the thing I was missing was the #include <starlet.h>
Simple when you know how?![Smile :)](./images/smilies/icon_e_smile.gif)
So the thing I was missing was the #include <starlet.h>
Simple when you know how?
![Smile :)](./images/smilies/icon_e_smile.gif)
Re: Using SYS$ routines with C++
Code: Select all
> So the thing I was missing was the #include <starlet.h>
More providing your own (mismatched) prototype, I'd say. I do
approximately nothing with C++, so I know nothing, but I gather that C++
takes those things seriously. (Note the arg type in the %ILINK
complaints. It's not complaining about plain-old "SYS$SETPRN".) If you
extract <starlet.h> from the text library
("SYS$LIBRARY:SYS$STARLET_C.TLB"?), you'll see things like:
#ifdef __NEW_STARLET
int sys$setprn(
void *prcnam);
#else /* __OLD_STARLET */
int sys$setprn(__unknown_params);
#endif /* #ifdef __NEW_STARLET */
Neither of which has an argument list which looks like yours.
Again, I know nothing, but I'd guess that that "void *" is related to
its accepting all/many descriptor types, mentioning all of which would
be worse.
Re: Using SYS$ routines with C++
You are using CXXLINK, which is just a wrapper around the VMS linker. On IA64 this is no longer necessary. The only "advantage" is that you do not see the C++ mangled symbols in any linker message. However, directly using the VMS linker may make your problem more obvious:
The C++ compiler mangled your extern declaration of SYS$SETPRN. But in SYS$PUBLIC_VECTORS (which by default is included in a link and that's the place where all the system services are defined) there is only the symbol SYS$SETPRN. So there is no match with you mangled symbol.
Including starlet.h is probably the right thing, but sometimes the prototypes are not very helpful. At least a void* will not cause a compiler diagnostic if you pass a non-descriptor address.
What you will find in starlet.h is an extern "C" wrapper around all the system service declarations. You can do that in your source as well:
Then you have the expected check of the parameters and the linker can resolve the symbol.
Code: Select all
$ link setprn
%ILINK-W-NUDFSYMS, 1 undefined symbol:
%ILINK-I-UDFSYM, CX3$Z10SYS$STPRNP16DSC$D04URF6I
%ILINK-W-USEUNDEF, undefined symbol CX3$Z10SYS$STPRNP16DSC$D04URF6I referenced
source code name: "SYS$SETPRN(dsc$descriptor_s*)"
section: .text
offset: %X00000000000001B0 slot: 2
module: SETPRN
file: DISK$WORK:[MW]SETPRN.OBJ;1
$
Including starlet.h is probably the right thing, but sometimes the prototypes are not very helpful. At least a void* will not cause a compiler diagnostic if you pass a non-descriptor address.
What you will find in starlet.h is an extern "C" wrapper around all the system service declarations. You can do that in your source as well:
Code: Select all
--- SETPRN.CXX;-1 2020-11-21 08:45:25 -0500
+++ SETPRN.CXX 2020-11-21 09:02:58 -0500
@@ -9,7 +9,7 @@
#define PROCNAMELEN 15
-int SYS$SETPRN( struct dsc$descriptor_s* );
+extern "C" int SYS$SETPRN( struct dsc$descriptor_s* );
int main(int argc, char** argv)