A linked Unicon program consists of the "Icode" bytes that are interpreted by the Icon virtual machine, generally preceded by bootstrap code. This bootstrap code is responsible for finding the Icon code executer, then running the Icon executer so that it will interpret the "Icode" bytes that follows the bootstrap code. The bootstrap code takes one of several forms:
- Some Icon / Unicon configurations use no bootstrap code; in this case, the Icon / Unicon linker produces a file that consists of "Icode" only, and this file must be run by passing it to the Icon executer. - On some platforms, this bootstrap code is executable image code, i.e. the sort of code produced by the C linker. - On most platforms, the bootstrap code can take the form of a shell script. Depending on the OS, the script format is either Bourne shell, MS CMD file, or Rexx. The source code for writing or skipping over the bootstrap code to a linked Icon / Unicon program has been developed by multiple authors over many years. By its very nature, this facility is highly platform specific and somewhat messy. The current implementation of bootstrap code is also messier than it needs to be, as we shall soon see. The configuration of this facility depends on two macros: - The Header macro is defined when some sort of bootstrap code is to be included; and - The ShellHeader macro is defined when the bootstrap code takes the form of a shell script. - if Header is defined and ShellHeader is not defined, an executable image header is to be used. If Header and ShellHeader are defined, the kind of shell script used is determined by the OS. As a result, the current code precludes the possibility of supporting more than one script language for the bootstrap code on a given platform. This is a limitation I have already encountered: I make heavy use of the Cygwin environment, a Posix implementation for Win32 platforms. Either Bourne shell or MS CMD scripting is a viable option for Cygwin, but you cannot switch between these options by merely changing the "src/define.h" and "Makedefs" files. The details of the various forms of bootstrap codes are divided among at least 4 source files, with lots of details copied between these files. One must be careful that any changes made in this facility (including additional scripting languages) is done in tandem. There are two separate mechanisms for generating the executable image bootstrap code. The first step of generating the executable image bootstrap code is to compile, link, and strip the C program "src/icont/ixhdr.c". Then, one of two approaches are used to generate the header: - either the ixhdr executable file is run through the "src/icont/newhdr" program to turn in into a C header file "src/icont/hdr.h" that defines an array of the bytes in ixhdr; or - the ixhdr executable is copied to the ./bin directory, and icont will assume that the ixhdr can always be found in the same directory as itself. In the process of doing a new Cygwin port, I revised the bootstrap code facility to make it both cleaner and more modular. The Header / ShellHeader macros were dropped and replaced with the more appropriately named macro Bootcode. The revised version of "src/h/config.h" defines the following values for Bootcode: #define Bootcode_None 0 /* No bootstrap code */ #define Bootcode_ExecImage 1 /* Executable image code */ #define Bootcode_BourneShell 2 /* Bourne Shell code */ #define Bootcode_MsCmd 3 /* MS CMD code */ #define Bootcode_Rexx 4 /* Rexx code */ The user can specify which kind of bootstrap code to use by declaring the value of Bootcode in "src/h/define.h". For example, if I wanted to link Unicon programs as Bourne Shell files, I could include the following line in "define.h": #define Bootcode Bootcode_BourneShell If "src/h/define.h" does not define Bootcode, the revised "src/h/config.h" file will provide a default value for Bootcode, based on the platform. This scheme may sound messy, but it actually allows us to cut a lot of "#if" / "#endif" directives from the rest of the code. The new approach provides the following three functions that are used for processing the bootstrap code in a Unicon / Icon program: /* * put_bootcode - Writes boot code to outfile, sets *hdrsize to size of boot code. */ void put_bootcode( FILE* outfile, const char* iconxloc, long* hdrsize ); /* * skip_bootcode - Skips boot code in infile; * If outfile != NULL, boot code from infile is copied to outfile. * Returns 1 if successful; * if it fails, returns 0 and writes an error message to errmsg. */ int skip_bootcode( FILE* infile, FILE* outfile, char* errmsg ); /* * put_bootend - Given an outfile that starts with boot code, * writes anything required at the end of the file to complete the code. * Returns 1 if successful; * if it fails, returns 0 and writes an error message to errmsg. */ int put_bootend( FILE* outfile, char* errmsg ); I created a new source file "common/src/bootcode.c" that implements these 3 functions. The implementations of these functions depends heavily on the value of the Bootcode macro. The callers of these functions, however, does not need to use ANY macros or preprocessor directives in order to process bootstrap code. All of the gory details are encapilated in "common/src/bootcode.c", and the rest of the code can treat this facility as a black box. I am pleased to report that I can now switch between linking Unicon programs as *.exe files, *.bat files, or Bourne scripts with changing just a few lines in "define.h" and "Makedefs" (related to file extensions). The source is now cleaner. Moreover, if we ever needed to support another script language for the bootstrap code, all we need to do is defined a new "Bootcode_*" macro in "src/h/config.h" and update "src/common/bootcode.c" to handle it. Everything else would be unchanged. I have attached "src/common/bootcode.c" to this message. I would be happy to send the rest of my changes to those who request it. Is this worth including in a future version of Unicon / Icon?
bootcode.c
Description: Binary data
