GnuCOBOL: A full featured multi-platform COBOL compiler.
"GnuCOBOL (formerly OpenCOBOL) is a free COBOL compiler. The GnuCOBOL cobc program translates COBOL source code to into C code, and then uses a local or embedded C compiler to translate the intermediate C code into executable programs. This page includes free downloads of ready-to-install copies of GnuCOBOL for Windows. These versions were built with 32-bit MinGW (Minimalist Gnu for Windows).", Arnold Trembley writes on his GnuCOBOL webpage.
The actual (mid-2025) version is GnuCOBOL 3.2, and Arnold Trembley's site hosts several binaries for Windows. They are essentially identical, except for the implementation of ISAM. If you are sure never to use indexed files, you might want to download the binary without ISAM support. Otherwise, I think that you should decide for the VBISAM version. Berkeley Database has some licensing related limitations, and VBISAM works well on my Windows 10. Thus, the file to download will, in most cases, be GC32-VBI-SP1-rename-7z-to-exe.7z.
In fact, the file isn't a 7-Zip archive, but an executable: Rename the file, changing the extension from .7z to .exe, and run it. This executable actually is a 7-Zip self-extracting archive. When asked where to extract the files, enter the directory where you want GnuCOBOL to be installed. I chose C:\Programs\gc32. The screenshot shows the content of this folder after extraction of the files has been done.
![]() |
GnuCOBOL includes the source file testgc.cob and the batch file testgc.cmd. If you want to test your COBOL installation, run the CMD file. The two screenshots show the beginning part of the batch file execution.
![]() |
![]() |
For user convenience, the GnuCOBOL distribution files include the batch file gcx.cmd, that builds the COBOL source file, entered as command line parameter. Note, that the compiler needs several environment variables set. This may be done by running the batch file set_env.cmd, before running the compilation batch file. Remember, that environment variables set in Command Prompt stay active until Command Prompt is closed. Thus, if you stay in the same Command Prompt window, run set_env.cmd once, and then run gcx.cmd in order to do your builds.
The gcx.cmd batch file runs the GnuCOBOL compiler with a whole set of options. It also includes features like detecting if the source file is fixed or free format. On the other side, there are some points that make it not really suitable for my programming environment. The major problem is that it must be launched from the GnuCOBOL installation directory, what requires to enter a full path source file name (my sources are actually stored in the directory C:\Users\allu\Programming\Cobol). Also, the .exe and .lst files will be created in the COBOL installation directory.
So I decided to write a custom batch file named gcbuild.cmd (called with the COBOL source file as command line argument), that I stored into C:\Programs. This directory is part of my PATH, thus I can launch the compilation from any directory that I want. My batch file actually does the following:
- Set the current directory to the GnuCOBOL installation directory.
- If set_env.cmd has not yet been run, run it.
- Check if the source file exist in my COBOL source file directory (if no extension has been specified, try first with .cob, then with .cbl).
- Copy the COBOL source file from my COBOL source file directory to the GnuCOBOL installation directory.
- Run gcx.cmd in order to build the program.
- Copy the .exe and .lst files to my COBOL source file directory; delete all files in the GnuCOBOL installation directory.
- Set the current directory to my COBOL source file directory.
Here is the code of gcbuild.cmd:
@echo off
set prog=%~n1
set ext=%~x1
set cobol_dir=\Programs\gc32
set source_dir=\Users\allu\Programming\Cobol
C:
cd %cobol_dir%
if [%COB_CONFIG_DIR%] == [] call set_env.cmd
if [%ext%] == [] (
if exist %source_dir%\%prog%.cob set ext=.cob
if exist %source_dir%\%prog%.cbl set ext=.cbl
)
if not exist %source_dir%\%prog%%ext% (
echo COBOL source file not found!
goto Exit
)
copy %source_dir%\%prog%%ext% %cobol_dir%
call gcx.cmd %prog%
if exist %prog%.exe (
copy %prog%.exe %source_dir%
erase %prog%.exe
)
if exist %prog%.lst (
copy %prog%.lst %source_dir%
erase %prog%.lst
)
erase %prog%%ext%
cd %source_dir%
:Exit
echo.
To test the custom COBOL environment, let's create a simple "Hello World" program.
IDENTIFICATION DIVISION.
PROGRAM-ID. hello.
PROCEDURE DIVISION.
DISPLAY "Hello, world!".
STOP RUN.
Name the program hello.cob and save it into the COBOL programming directory (C:\Users\allu\Programming\Cobol). Then, build it using
gcbuild hello
The screenshot shows the output during the execution of my batch file (including the build of hello.cob).
![]() |
The batch file set the current directory to my COBOL source file directory, where we can have a look at the files created, and run the executable hello.exe.
![]() |
Important: When you open a new Command Prompt and try to run one of the executables created by the GnuCOBOL compiler, you'll get an error message concerning some DLL(s) that haven't been found. On the development machine, this issue may be resolved by running set_env.cmd before running the program. To be able to run the program on another computer, you'll have to copy the required DLL(s) together with the executable!
Here is another simple COBOL example (hello3.cob), that asks the user for a name and displays a personal greeting message.
identification division.
program-id. hello3.
data division.
working-storage section.
77 Name pic X(25) value spaces.
77 Greeting pic X(33).
procedure division.
display 'Please, enter your name? ' no advancing.
accept Name.
if Name = spaces
move "World!" to Name
end-if.
string "Hello " delimited by size,
Name delimited by space, "!"
into Greeting.
display Greeting.
stop run.
end program hello3.
Program output:
![]() |
In the following paragraphs, I'll list some COBOL program samples to show how to implement the following features in GnuCOBOL: using the screen section for "form-like" input-output, using subprograms (call another COBOL program, or a subroutine that is part of another COBOL program), executing an internal sort, working with ISAM files. Click the following link to download the tutorial sample programs sources from my website.
Using the screen section.
The screen section allows to define label and edit field areas at a given position on the screen. Labels have static captions, edit fields may be input, or output, or both, and their content may be altered by the program or/and the user. Data input is done as on a form, filling in the different input (input-output) fields, the TAB key allowing to jump from one field to the next. Hitting ENTER will transfer the content of all these fields (the entire "form-data") to the program. Similarly, the program fills in the output (input-output) fields and displays the whole with a single display statement.
The program hello4.cob uses a COBOL screen to input user name, country and profession. It uses this information to create a personal greeting message displayed in the output fields of the COBOL screen. Here is the code:
identification division.
program-id. hello4.
data division.
working-storage section.
01 user-info.
05 user-name-in pic x(25) value spaces.
05 user-country-in pic x(25) value spaces.
05 user-profession-in pic x(25) value spaces.
05 user-name-out.
10 user-name-hello pic x(6) value spaces.
10 user-name pic x(25) value spaces.
05 user-profession pic x(25) value spaces.
05 user-country-out.
10 user-country-from pic x(5) value spaces.
10 user-country pic x(25) value spaces.
05 last-line pic x value space.
screen section.
01 screen-data.
05 value "User greeting screen" blank screen line 1 col 10
foreground-color is 15.
05 value "Name" line 4 col 10.
05 name-input line 4 col 22
pic x(25) using user-name-in.
05 value "Country" line 5 col 10.
05 country-input line 5 col 22
pic x(25) using user-country-in.
05 value "Profession" line 6 col 10.
05 profession-input line 6 col 22
pic x(25) using user-profession-in.
05 name-output-hello line 9 col 10
pic x(5) from user-name-hello.
05 name-output line 9 col 16 pic x(25) from user-name
foreground-color is 14.
05 profession-output line 10 col 10
pic x(25) from user-profession.
05 county-output-from line 11 col 10
pic x(4) from user-country-from.
05 country-output line 11 col 15
pic x(25) from user-country.
05 last-line-output line 14 col 1
pic X from last-line.
procedure division.
display screen-data.
accept screen-data.
move "Hello" to user-name-hello.
if user-name-in = spaces
move "Unknown user" to user-name
else
move user-name-in to user-name.
if user-profession-in = spaces
move "no profession" to user-profession
else
move user-profession-in to user-profession.
move "from" to user-country-from.
if user-country-in = spaces
move "an unknown country" to user-country
else
move user-country-in to user-country.
move space to last-line.
display screen-data.
stop run.
end program hello4.
The screenshots show the program execution. On the left, the display of the COBOL screen, before the user has filled in the data; on the right, after the user has send the data to the program and the program has returned the COBOL screen with the greeting message filled in.
![]() |
![]() |
Using subprograms.
If you build a COBOL program as a (dynamically loadable) module this program can be used as a subprogram of another program, i.e. being called from another program using the call statement.
Let's consider the (useless) example of a main program that calls a subprogram to display "Hello World". Let's call the main program testsubs1.cob, and the subprogram sayhello.cob.
The source of the subprogram is the same as if it was a main program except that subprograms have to be terminated with the statement exit program (instead of stop run). Here is the code of sayhello.cob:
identification division.
program-id. sayhello.
procedure division.
hello-world.
display "Hello world!".
exit program.
No special code is required in the main program. The name of the subroutine (name to be used in the call statement) has to be the name of the subprogram (name declared in the subprogram's identification division). Here is the code of testsubs1.cob:
identification division.
program-id. testsubs1.
procedure division.
call "sayhello".
stop run.
The build of this program is done in two steps:
- Compiling the subprogram as a DLL (using the compiler option -m).
- Compiling and linking the main program as an executable (using the compiler option -x), indicating the directory where the DLL is located (using the compiler option -L), as well as the name of the DLL (using the compiler option -l).
In our case:
cobc -m sayhello.cob
cobc -x testsubs1.cob -L . -l sayhello
where the dot (.) indicates the current directory (the sources of program and subprogram supposed to be both located in the actual directory).
Note: Do not forget to run set_env.cmd before starting the build!
The screenshots below show the build process: At the left, the build of the subprogram, resulting in the creation of a DLL; at the right the build of the main program, resulting in the creation of a Windows executable.
![]() |
![]() |
GnuCOBOL allows to pack several subroutines into the same subprogram. Such subroutines are declared in the procedure division, defining an entry point. This is done using an entry statement. All subroutines have to be terminated with an exit statement. In the main program, when calling a given subroutine, the name used in the call statement has to be the name as declared in the subroutine's entry point.
The main program testsubs2.cob and the subprogram sayhello2.cob are a (useless, but working and showing how to implement these calls) example of such a case.
Here is the code of the subprogram sayhello2.cob:
identification division.
program-id. sayhello2.
procedure division.
entry "hello-world-short".
display "Hello world!".
exit program.
entry "hello-world-long".
display "Hello world from GnuCOBOL!".
exit program.
And the code of the calling main program testsubs2.cob:
identification division.
program-id. testsubs2.
procedure division.
call "hello-world-short".
call "hello-world-long".
stop run.
The build is similar as before: first creating the DLL, then the executable. However, when trying to run the executable, you will (very probably) get the error
message: libcob: error: module 'hello-world-short' not found. I don't know if this could be avoided by making some changes to the code
of cobc, or if it's a kind of fatality. Anyway, there is a simple work-around: just preload the DLL (load it,
before running the program). This can be done by setting the environment variable COB_PRE_LOAD, in our case:
set COB_PRE_LOAD=.\sayhello2.dll
The screenshot shows, how I set the environment variable, and then successfully run testsubs2.exe.
![]() |
Passing arguments to a COBOL program is not exactly what we are used to in other programming languages. It involves a special section in the data division: the linkage section, a memory area accessible by both the main program and the subprogram.
Note the following:
- The argument must be declared in the linkage section of the subprogram, as well as in the working-storage section of the main program.
- The argument identifiers in the linkage section of the subprogram and the working-storage section of the main program may have different names, but they must be of exactly the same data type (e.g. having exactly the same picture).
- The argument identifier declared in the linkage section of the subprogram must be used in the usage clause of the subprogram's procedure division.
- The argument identifier declared in the working-storage section of the main program must be used in the usage clause of the main program's call statement.
- I did not succeed to pass an argument to a subprogram with several entry points. I can't say if I missed something, or if this isn't possible (?).
The main program testsubs3.cob and the subprogram sayhello3.cob are an example of passing a name to a subprogram, that uses it to display a personal greeting message.
Here is the code of the subprogram sayhello3.cob:
identification division.
program-id. sayhello3.
data division.
working-storage section.
77 Greeting pic X(33).
77 Name pic X(25) value spaces.
linkage section.
77 UName pic X(25).
procedure division using UName.
move UName to Name.
if Name = spaces
move "World!" to Name
end-if.
string "Hello " delimited by size,
Name delimited by space, "!"
into Greeting.
display Greeting.
exit program.
And the code of the calling main program testsubs3.cob:
identification division.
program-id. testsubs3.
data division.
working-storage section.
77 UserName pic X(25) value spaces.
procedure division.
display 'Please, enter your name? ' no advancing.
accept UserName.
call "sayhello3" using UserName.
stop run.
The screenshot shows the build and execution of the program.
![]() |
Executing an internal sort.
To sort your data files you can use the provided external sort program gcsort.exe, or you can do an internal sort, i.e. including the sort logic into your COBOL source file. The COBOL sort statement is a relatively simple and powerful mean to sort files, organized in records (i.e. files, where given information appears at a given position within the data item). Note the following:
- The COBOL sort statement sorts the records of an input file, creating a sorted output file, using a temporary sort file for saving intermediate data items. This special file has to be declared as sd (instead of fd) in the file section of the data division.
- The sort (ascending or descending) is done defining a sort key, i.e. sorting the data on some sub-item of the sort record.
- Defining an input procedure allows to modify the input file data, before passing them to the sort program.
- Defining an output procedure allows to modify the records returned by the sort program before writing them to the output file.
The simplest case of a sort is reading an input file, sorting it and writing the sorted records to an output file. The sample program testsort.cob shows how this works, using the file "aa.txt" as input and "aa2.txt" as output.
Here are the first 5 records of "aa.txt" (actually sorted on the amino acid name):
Alanine Ala A C3H7NO2 CH3-CH(NH2)-COOH
Arginine Arg R C6H14N4O2 HN=C(NH2)-NH-(CH2)3-CH(NH2)-COOH
Asparagine Asn N C4H8N2O3 H2N-CO-CH2-CH(NH2)-COOH
Aspartic acid Asp D C4H7NO4 HOOC-CH2-CH(NH2)-COOH
Cysteine Cys C C3H7NO2S HS-CH2-CH(NH2)-COOH
The output file "aa2.txt" should contain the same data as the input file, but the records being sorted on the 1-letter amino-acid code ("A", "R", "N", for the first 3 records). Here is the source of the program testsort.cob:
identification division.
program-id. testsort.
environment division.
input-output section.
file-control.
select INFILE assign to "aa.txt"
organization is line sequential.
select OUTFILE assign to "aa2.txt"
organization is line sequential.
select SORTFILE assign to "sort.tmp".
data division.
file section.
fd INFILE.
01 Infile-record pic x(63).
fd OUTFILE.
01 Outfile-record pic x(63).
sd SORTFILE.
01 Sortfile-record.
05 Sortfile-name pic X(13).
05 filler pic X.
05 Sortfile-code3 pic XXX.
05 filler pic X.
05 Sortfile-code1 pic X.
05 filler pic X.
05 Sortfile-formula1 pic X(10).
05 filler pic X.
05 Sortfile-formula2 pic X(32).
procedure division.
display "Sorting 'aa.txt' by 1-letter code".
display "Writing sorted amino acids to aa2.txt".
sort SORTFILE
on ascending key Sortfile-code1
using INFILE
giving OUTFILE.
stop run.
Here are the first 5 records of "aa2.txt" (the records now being sorted on the 1-letter amino acid code):
Alanine Ala A C3H7NO2 CH3-CH(NH2)-COOH
Cysteine Cys C C3H7NO2S HS-CH2-CH(NH2)-COOH
Aspartic acid Asp D C4H7NO4 HOOC-CH2-CH(NH2)-COOH
Glutamic acid Glu E C5H9NO4 HOOC-(CH2)2-CH(NH2)-COOH
Phenylalanine Phe F C9H11NO2 Ph-CH2-CH(NH2)-COOH
The sample program testsort2.cob does the same sort of the file "aa.txt", but creates an output file ("aa3.txt") where the amino acid codes are at the record beginning and the second formula has been removed. This may (relatively) easily be done using an output procedure. Here is the code.
identification division.
program-id. testsort2.
environment division.
input-output section.
file-control.
select INFILE assign to "aa.txt"
organization is line sequential.
select OUTFILE assign to "aa3.txt"
organization is line sequential.
select SORTFILE assign to "x:\sort.tmp".
data division.
file section.
fd INFILE
data record is Infile-record.
01 Infile-record pic x(63).
fd OUTFILE
data record is Outfile-record.
01 Outfile-record pic x(80).
sd SORTFILE
data record is Sortfile-record.
01 Sortfile-record.
05 Sortfile-name pic X(13).
05 filler pic X.
05 Sortfile-code3 pic XXX.
05 filler pic X.
05 Sortfile-code1 pic X.
05 filler pic X.
05 Sortfile-formula1 pic X(10).
05 filler pic X.
05 Sortfile-formula2 pic X(32).
working-storage section.
77 Sorted-data-switch pic X value 'N'.
88 No-more-records value 'Y'.
01 Data-record.
05 Data-code1 pic X.
05 filler pic X.
05 Data-code3 pic XXX.
05 filler pic X.
05 Data-name pic X(13).
05 filler pic X.
05 Data-formula pic X(10).
procedure division.
display "Sorting 'aa.txt' by 1-letter code".
display "Writing sorted amino acids to aa3.txt".
sort SORTFILE
on ascending key Sortfile-code1
using INFILE
output procedure is Sort-output-procedure.
stop run.
Sort-output-procedure.
open output OUTFILE.
return SORTFILE
at end move 'Y' to Sorted-data-switch.
perform Write-output-record
until No-more-records.
close OUTFILE.
Write-output-record.
move Sortfile-code1 to Data-code1.
move Sortfile-code3 to Data-code3.
move Sortfile-name to Data-name.
move Sortfile-formula1 to Data-formula.
write Outfile-record
from Data-record.
return SORTFILE
at end move 'Y' to Sorted-data-switch.
If we define an output procedure, the output file has to be opened, written to and closed manually. The records are retrieved from the sort program using a return ... at end ... statement.
Here are the first 5 records of "aa3.txt", created by the program testsort2.exe:
A Ala Alanine C3H7NO2
C Cys Cysteine C3H7NO2S
D Asp Aspartic acid C4H7NO4
E Glu Glutamic acid C5H9NO4
F Phe Phenylalanine C9H11NO2
Working with ISAM files.
It's already some time ago that I published a tutorial called Handling indexed-sequential files in COBOL. The tutorial examples (creating an ISAM file from a text file, sequential access to an ISAM file, random access to an ISAM file using the primary or alternate key) have been developed with Visual COBOL for Visual Studio Personal Edition on Windows 11. Trying to build them using GnuCOBOL, I got the error message that the file section was missing. My fault, I did forget it, starting the fd declarations immediately after the data division statement. Visual Cobol accepts this, but, in fact, it's a mistake, and so it's normal that GnuCOBOL does not build the program. Meanwhile, I added the file section to the code on the tutorial page, thus, if you want to learn about using indexed-sequential files in COBOL, please, have a look at the article mentioned above.
The screenshot shows the output of the program isam-list.exe.
![]() |
Using OpenCobolIDE as development environment.
If you don't like to work in Windows Command Prompt, or if you just prefer to have a nice IDE, OpenCobolIDE is without any doubt the first choice. Here is the direct link to download the installer of OpenCobolIDE 4.7.6.
The screenshot below shows the startup window of the IDE.
![]() |
You can change the application's preferences using the button in the startup window. In the Compiler tab, you can set the paths to the compiler, the library and include files, etc. All these paths are actually set. OpenCobolIDE is distributed with a copy of GnuCOBOL, in my case version 2.0.0 (as you can see after having pushed the Check Compiler button).
![]() |
There are lots of options, that you might want to review and adapt to your needs and wishes. Two options, that you should change: First, in the Compiler tab, set the Output directory to where you want the executables created to be stored; I chose my COBOL programming directory C:\Users\allu\Programming\Cobol (screenshot on the left). Second, in the Run tab, set the Working directory to where your COBOL sources are located; in my case C:\Users\allu\Programming\Cobol. You should also select the checkbox near Run in external terminal, this way avoiding possible problems with some programs, if you redirect the executable's output to the IDE (screenshot on the right).
![]() |
![]() |
The screenshot below shows the program hello4.cob (the screen section sample from the tutorial), opened in OpenCobolIDE. Source code highlighting, code navigation, and of course, the possibility to build and run the program... OpenCobolIDE is a full featured COBOL development environment!
![]() |
Syntax and other COBOL errors will be listed in the Issues tab of the Logs pane. If all went well, the message "Compilation succeeded" will be displayed.
Using the actual version of GnuCOBOL with OpenCobolIDE.
It's obvious that with GnuCOBOL 3.2 installed on our computer, using the old 2.0 version, included with OpenCobolIDE, makes no sense. And, it's really not a big deal to tell the IDE to use the compiler that we have installed at the beginning of the tutorial. All we have to do is to change the paths in Preferences > Compiler. Be just sure to change them all!
![]() |
![]() |
If you find this text helpful, please, support me and this website by signing my guestbook.