Using Eclipse for VMS sources.

Just for coding and compiling your VMS C sources you can use Eclipse on a non-VMS system: no linking, no running nor debugging. That is you can use Eclipse out of the box and don't need any integrated or plugged in connection to a dedicated server process on the VMS system. After coding and syntax checking you have to copy the source code to the VMS system to build your application with native compilers and link it. But you can benefit from all the features in Eclipse, including syntax highlighting, syntax check - while typing, refactoring, macro expansion under your mouse, declarations and references of variables and functions at the distance of a mouse click, etc.

The whole setup may need quite some time and may require some patience and perseverance. The effort usually depends on the size and complexity of the project. But then, having an IDE as Eclipse for your sources is worth the time. Such a setup was used for all the VMS tools listed on this web site: small projects, targeting recent VMS versions Alpha/I64 and recent C compilers. Such a setup was used for another small project targeting VAX/VMS 5.5-2 and VAXC 3.2-044: 10+ source and include files. And, such a setup was used in a big VMS project targeting VMS 8.4 on I64: 320+ source and 250 include files. Here the challenge was to add a new feature to an application without ever having seen the source code prior to working on that project. Without Eclipse and its features, especially to quickly get to declarations, references and to expand macros, getting the work done would have taken much more time.

Also, getting the sources compiled on a non-VMS platform, although with VMS-supplied header files, may be a good start for a port to a non-VMS platform. Especially refactoring in Eclipse should be useful to extract OS-specific code into separate functions/modules.

All my projects were done with Eclipse running on Linux, but setting up such an environment should be possible for any other operating system for which Eclipse is available.

There are other IDEs like eCube Systems' NXTware Remote, which require an Eclipse plugin and a remote server process running on VMS. And there is Distributed NetBeans, which to my knowledge requires a remote server process as well.

What you need to do can be summarized as

Getting the public VMS supplied C header files, needs to be done once for all projects with the same VMS/C/CRTL versions as the target.

Depending on what the application uses ("standard" C, system services and RTLs, or VMS data structures) on the target VMS system extract the include files from SYS$COMMON:[SYSLIB]DECC$RTLDEF.TLB, SYS$LIB_C.TLB, SYS$STARLET_C.TLB. These cover the VMS supplied include files. There may be more, X11, network, or third party ones, etc. which may be in .TLB or .H files in SYS$COMMON:[SYSLIB] or other directories. The compile commands for or the compiler listings of your application may help to identify all the include files your application needs. You have to copy all these include files to the system with Eclipse. You may want to copy/extract the include files into separate sub-directories, named after the TLBs or whatever (third party) library they belong to. You may want to use a tool like ZIP or tar to create an archive of all the created sub-directories. (On ODS-2 ZIP makes lowercase names out of uppercase names, that may be handy here, as on other operating systems the compiler very likely expects the filenames in lowercase.)

Move the archive to your system with Eclipse and expand it in an Eclipse workspace.

Unfortunately VMS header files aren't ready for this. You need some adjustments.

Problem 1: VMS filename processing by default is case insensitive.

So including a header file, like in "#include <stdio.h>" will work although the actual file name can be/is STDIO.H or the module name is STDIO in the text library, and vice versa. Usually all these header file names are in lowercase, in the sources and other header files. Lowercase file names are expected on Linux. But on VMS there are a few header files which include with uppercase. For exaample, xab.h contains "#include <XABDEF.H>". This needs to be adjusted, in the include file or with a symbolic link.

Problem 2: VMS compilers are smart.
VMS supplied header files sometimes are generic and include other files from sub-directories, as on Unix. The VMS compiler knows about some sub-directories and looks for the header file in the same .TLB file or at the same directory level. For Eclipse and its compilers the include file has to be in the correct subdirectory. For example, pthread.h contains "# include <sys/types.h>". This needs to be adjusted, in the include file or with a symbolic link.

Problem 3: VAXC style of header file inclusion.
There are a few header files which use the old VAXC style of including other header files. For example, pool_zones.h contains "#include far_pointers". This needs to be adjusted, in the include file.

Finding such problems and fixing them can done with using standard tools like find, grep, sed and awk.

To complete step 1 some tests should be made. There shouldn't be any include file from the host environment included, here '/usr/include'. Create hello-world-type programs; on the command line tell the compiler to run the preprocessor only and to include from the VMS subdirectories. Then check whether there is still a non-VMS include file included. For gcc you can use -nostdinc to avoid searching the standard system directories for header files, like in

cc -E -I workspace/VMSincludes/rtldef -nostdinc hello.c

In case there are still header files from your host environment, your setup is not yet correct or complete. Create at least one such program for all the VMS type include files (CRTL, STARLET, LIB) or third party header files you need.

To get the VMS header files included into your project just create a symbolic link. This needs to be done per project, see step 2. It is not useful to create an Eclipse C project for the header files. However I didn't try a general project (and create a reference to that in the C projects) and/or a Eclipse variable to point to the VMS include directory.

Importing your source code is done once per project

As mentioned before, on VMS the source and header files may be all in uppercase letters. That is, there are .C and .H files. For other environments you need at least lowercase file types: .c and .h. Usually the whole filenames are in lowercase letters. So, on the VMS side, create an archive with zip or tar, extract the files in a subdirectory of your Eclipse workspace and make sure that the filenames are as expected.

In Eclipse create a new project, as 'Makefile with Existing Code'. Existing Code Location is your directory with the VMS source files. Language is C and the toolchain is Cross GCC.

In Eclipse you can change the project settings not to discover paths and symbols. This feature usually takes these settings from the build log, which your makefile produces. At this time you may have a makefile for VMS, but here you need one for Eclipse. As long as you have no stable make environment for Eclipse, taking and saving the "discovered" settings from the build makes not much sense.

If you do not change the project settings for discovery you should not expect that all of the Eclipse environment, especially the indexer, etc. are working as expected.

From the shell, cd into you project directory and create a symbolic link to the VMS include directory.

Creating an Eclipse makefile needs to be done once per project

Depending on your project, especially on the number of source and include files, this may be the biggest task for your project.

If you have a VMS makefile (for GNU make), an MMS or MMK descrip.mms you may want to use this as a base to create a makefile for Eclipse.

For Eclipse you just want to compile the sources into objects, you do not want to link. For Eclipse you need - at least - two targets: all and clean.

For this environment you need compiler flags to set the path to the VMS include files and to define or undefine VMS macros or macros of your OS environment. First, try to catch what the compiler and OS supplied macros are on VMS. This depends on your project. That is, it may depend on the HW VMS runs on and on the CC command you are using. You will find all the macros in a full compler listing. Look for something like

These macros are in effect at the start of the compilation.
----- ------ --- -- ------ -- --- ----- -- --- ------------

 __G_FLOAT=1  __DECC=1  vms=1  VMS=1  __32BITS=1  __PRAGMA_ENVIRONMENT=1 
 __CRTL_VER=80300000  __vms_version="V8.3    "  CC$gfloat=1  __X_FLOAT=1 
 vms_version="V8.3    "  __DATE__="Sep 17 2013"  __STDC_VERSION__=199901L 
 __DECC_MODE_RELAXED=1  __DECC_VER=70190015  __VMS=1  __ALPHA=1 
 VMS_VERSION="V8.3    "  __IEEE_FLOAT=0  __VMS_VERSION="V8.3    " 
 __STDC_HOSTED__=1  __TIME__="15:43:17"  __Alpha_AXP=1  __VMS_VER=80300022 
 __BIASED_FLT_ROUNDS=2  __INITIAL_POINTER_SIZE=0  __STDC__=1 
 __LANGUAGE_C__=1  __vms=1  __alpha=1  __D_FLOAT=0 

Obviously, some macros are not important: __DATE__, __TIME__. All the macros without leading underscores are not used in VMS supplied header files. However, all of the macros may be used in your sources or other header files your code depends on.

On Alpha, __G_FLOAT=1 is default if no other /float is given. __X_FLOAT=1 depends on /l_double, which by default defines 128 bit for a long double. Here I suggest to set both to 0 and enable IEEE floating point.

Example of a simple makefile:

.PHONY: all clean
CFLAGS += -nostdinc -fno-builtin \
 -I./VMSincludes/rtldef -I./VMSincludes/starlet \
 -D__G_FLOAT=0 -D__DECC=1 -D__CRTL_VER=80300000 -D__X_FLOAT=0 \
 -D__STDC_VERSION__=199901L -D__DECC_VER=70190015 \
 -D__VMS=1 -D__ALPHA=1 -D__IEEE_FLOAT=1 -D__VMS_VER=80300022 \
 -D__BIASED_FLT_ROUNDS=2 -D__INITIAL_POINTER_SIZE=0 \
 -D__vms=1 -D__alpha=1  -D__D_FLOAT=0 \
 -D__int64=__INT64_TYPE__ -D__int32=__INT32_TYPE__ -D__int16=__INT16_TYPE__ \
 -Uunix -Ulinux -U__unix -U__linux -U__unix__ -U__linux__ 
all: vmsdemo.o
clean:
      - rm vmsdemo.o

Please note, __INT64_TYPE__ was introduced after __VERSION__=="4.3.2" of gcc. For versions without that pre-defined macro, one should use -D__int64='long long int' and similar for the other __INTnn_TYPE__s.

From the shell, run your makefile. It should compile without any error (or warning) for the header files. If there are missing header files or if you see wrong ones from your OS environment, check the specified include paths. Other compiler warnings/errors for your source code need to be checked as well. For example if your code uses __VMS_VERSION to print out the VMS version you need to add that macro to your list.

If this works as expected, run your makefile from Eclipse and check its console output for errors/problems. If you need to make changes to the include path and or macros, be aware that when discovering paths and symbols is enabled, you need to clear the discovered symbols before you continue. Also undefines, -U, are not discovered. You need to delete them from the list, see step 4.

At this stage don't look at the problem tab, this may not yet work as expected.

Adjusting symbols and include paths needs to be done once per project

In Eclipse change the project settings back to discover paths and symbols, from the build log.

Also in project settings, delete all the macros you "undefine" with -U in the makefile.

Then, from Eclipse, run a build and you should be all set.

Again, if something is messed up here, you may not be able to find the declarations, macros etc, although your build as shown in the Eclipse console is fine: you may see a lot of problems in the "Problems" tab. Do a project -> clean, clear the discovery of the paths and symbols and build again - project -> build project.

If you still see errors and warnings in the source files and the problem tab, you need to re-run the indexer: right click from the selected source file and project -> indexer -> Freshen all files.

In the problems tab you can always delete all errors and warnings. But without any change in the include file path and/or symbols this will very likely not resolve the problem.

That's probably all. If there is more or you see problems, let me know.

This seems a lot, but if you have done this once you know what to do and can quickly adjust the environment for new projects.

Notes on gcc

If you include c_asm.h (directly or indirectly via pthread.h), you need to use -fno-asm or to #define asm to a non-gcc asm function, for example to DECCasm.

If your project defines __NEW_STARLET, gcc may report an error like "ISO C requires a named argument before ‘...’". You can tell gcc to allow this with -fallow-parameterless-variadic-functions.

If your project defines __NEW_STARLET, gcc may report a warning like "‘struct _glock’ declared inside parameter list [enabled by default]". As long as this is in function prototypes, this warning can be ignored, here. But you can also create a first.h and just declare these structs like "struct _glock;" and use -include first.h to fix this.

Notes on member alignments

DECC, as many other compilers, has its own pragmas to deal with environment specific options. The one which is found very often in the VMS headers is #pragma __member_alignment and its variants especially #pragma __nomember_alignment. Other compilers usually have different pragmas and usually ignore pragmas they don't know or recognize. Gcc will not act on these DECC pragmas. When compiling VMS sources, this shouldn't be a problem, as long as you don't have compile time checks in your code, to check the alignment or size of a struct. When generating code with gcc to run it, it very likely will be a problem.

In case of compile time checks for alignment and structure size, you have to use __attribute__((packed)) or the #pragma pack (1) to let gcc know about the alignment. If you are lucky - if there are no aligned members of structs in the header file - you can add a #pragma pack (push,1) and #pragma pack (pop) before and after the #include directives in your source. Otherwise you need to change your copied VMS header file and add a __attribute__((packed));

You should be aware that, although undocumented, recent DECC compilers recognize the pack pragmas as well. That is, if you want to compile and run from the same source on VMS and Linux and if it is enough to simply surround the inclusion of the header files with #pragma pack (push,1) and #pragma pack (pop), this will work with DECC and gcc.

Notes on GNU make

If you have an mms or mmk makefile, usually named descrip.mms, you may want/need to convert some of its contents. Directives for mms/mmk start with a dot, for example ".IFDEF", the same directive for GNU make is "ifdef".

The set of directives is different. There is an .IF but no equivalent in GNU make. An
.IF "$(VERBOSE)" .EQ "1"
needs to be converted to something like
ifeq "$(VERBOSE)" "1"

Mms/mmk knows a .FIRST and .LAST target, for GNU make you have to specify explicit targets and make sure they are in the right sequence.

Converting VMS file types to Unix ones is not necessary if there are suffix rules. Otherwise you can use a text processing utility like sed to replace .OBJ with .o and .EXE with no file type.

Also, mms/mmk can have predefined macro names in the recepies. For example MMS$TARGET is the name of the target, for which $@ is a synonym. GNU make only knows the "synonym".

For mms/mmk there are other predefined macros which are not derived from recipes, they are defined at the time mms/mmk is invoked. For example $(MMS) is the mms command, $(MMSQUALIFIERS) holds all (but the /DESCRIPTION) the used command qualifiers and their values, $(MMSTARGETS) holds the targets as specified on the command line. The mms dcoumentation describes these macros. (You can distinguish the command line macros from the recipe derived ones: the latter have a $ in the name.) All the command line macros need to be looked at and probably require manual conversion. For example consider $(MAKE), $(MAKEFLAGS) and $(MAKECMDGOALS).

Notes on Eclipse Kepler

By default, Kepler doesn't display the "Discovery Options". To show them in the Project Properties you have to go to Window->Preferences and in the C/C++ section, in the Property Pages Settings you can enable them.