windowscobolgnucobol

GnuCOBOL (cobc) calling subroutines


Using GnuCOBOL (cobc) 3.2.0 on Windows, I'm trying to write a simple COBOL program that calls a subroutine in another file, but the subroutine is not found.

foo1.cob:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. MAINPROG.

       PROCEDURE DIVISION.
       MAIN-PROCEDURE.
           PERFORM "SUB-SAY-HELLO1".
           CALL "SUB-SAY-HELLO2".
           STOP RUN.

        SUB-SAY-HELLO1.
           DISPLAY "HELLO1".

foo2.cob:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. SUBPROG.

       PROCEDURE DIVISION.
       SUB-SAY-HELLO2.
           DISPLAY "HELLO2!".
           EXIT PROGRAM.

First I run the command

cobc -m foo2.cob

that produces foo2.dll.

Then I run the command

cobc -x foo1.cob -L c:\dev -l foo2

that produces foo1.exe.

Then I try to execute foo1.exe, and get the following output:

HELLO1
libcob: error: module 'SUB-SAY-HELLO2' not found

What do I need to do for my main program to find the sub program?


Solution

  • EDIT: I first claimed what I want to do as not possible, but that is not true. I have now found out how to do it, which is explained below.

    After more testing, and having a colleague of mine test this on the VSI VMS Integrity operating system with the native VSI COBOL compiler, it appears that what I wanted to achieve is not possible in COBOL in the way that I did it. One COBOL program cannot specify multiple subroutines that are callable separately - a single program is instead callable, and will then execute the PROCEDURE DIVISION from the top.

    In my original posted code, the

    CALL "SUB-SAY-HELLO2".
    

    can be replaced with

    CALL "SUBPROG".
    

    Which will execute just fine with the following output

    HELLO1
    HELLO2!
    

    The SUBPROG program will be executed from the top of the PROCEDURE DIVISION, stopping at EXIT PROGRAM.

    If multiple subroutines are to be declared, they need to be declared in separate programs. A COBOL file can however include multiple programs, so if the file foo2.cob above was to be changed to:

           IDENTIFICATION DIVISION.
           PROGRAM-ID. SUB-SAY-HELLO2.
    
           PROCEDURE DIVISION.
           SUB-ROUTINE.
               DISPLAY "HELLO2!".
               EXIT PROGRAM.
    
    
           IDENTIFICATION DIVISION.
           PROGRAM-ID. SUB-SAY-HELLO3.
    
           PROCEDURE DIVISION.
           SUB-ROUTINE.
               DISPLAY "HELLO3!".
               EXIT PROGRAM.
    

    The main program foo1.cob would be able to call the programs separately like this:

           IDENTIFICATION DIVISION.
           PROGRAM-ID. MAINPROG.
    
           PROCEDURE DIVISION.
           MAIN-PROCEDURE.
               PERFORM SUB-SAY-HELLO1.
               CALL "SUB-SAY-HELLO2".
               CALL "SUB-SAY-HELLO3".
               STOP RUN.
    
            SUB-SAY-HELLO1.
               DISPLAY "HELLO1".
    

    This is supported both by GnuCOBOL and VSI COBOL. There is an ENTRY statement that can also be used, which is supported by GnuCOBOL and IBM COBOL, but not VSI COBOL, which would allow for the foo2.cob program to look like this instead:

           IDENTIFICATION DIVISION.
           PROGRAM-ID. SUBPROG.
    
           PROCEDURE DIVISION.
           ENTRY "SUB-SAY-HELLO2".
               DISPLAY "HELLO2!".
               EXIT PROGRAM.
    
           ENTRY "SUB-SAY-HELLO3".
               DISPLAY "HELLO3!".
               EXIT PROGRAM.
    

    And the foo1.cob program can now call the entries in the same manner as mentioned above. This is not the approach I will use however, as my COBOL programs need to work for both GnuCOBOL and VSI COBOL.

    NOTE: If these instructions are followed in GnuCOBOL but there are still link errors because the programs/entries are not found, this might be due to preloading being required. Set the environment variable COB_PRE_LOAD to your built library, in this case (Windows example):

    set COB_PRE_LOAD=C:\dev\foo2.dll