Jacob Makefile Generation


Chr. Clemens Lee
 
2000-11-25


Abstract

This document describes the generation of a Makefile file for the current Jacob project. Jacob generates a Makefile for Windows as well as Unix. A Unix shell script and Windows batch file are generated in the project's bin directory as well.

Table of Contents

1   Makefile Generation
2   Generating Shell Script and Batch File
3   ToDo
Links

1   Makefile Generation

We start with the old legacy code which was not written using a literate programming approach with xml (Java code is invisible in the html output).

2   Generating Shell Script and Batch File

The generated shell script should look something like:
#! /bin/sh
#
# Script to start Jacob. (Parts are copied from jakarta-ant
# startup script.)
#
# Maybe you have to set SWING_HOME if using jdk 1.1 (see below).

if [ "$JACOB_HOME" = "" ] ; then
  # try to find JACOB

  ## resolve links - $0 may be a link to jacob's home
  PRG=$0
  progname=`basename $0`

  while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '.*/.*' > /dev/null; then
	PRG="$link"
    else
	PRG="`dirname $PRG`/$link"
    fi
  done

  JACOB_HOME=`dirname "$PRG"`/..

fi

JAVA_HOME=`which java`
JAVA_HOME=`dirname "$JAVA_HOME"`/..

if [ "$SWING_HOME" = "" ] ; then
  SWING_HOME=${JAVA_HOME}/../swing-1.1
fi

CLASSPATH=${JACOB_HOME}/classes
CLASSPATH=${CLASSPATH}:${JACOB_HOME}/lib/jacob.jar
CLASSPATH=${CLASSPATH}:${JACOB_HOME}/lib/ccl.jar
CLASSPATH=${CLASSPATH}:${JACOB_HOME}/lib/jhbasic.jar
CLASSPATH=${CLASSPATH}:${JACOB_HOME}/lib/jcf.jar
CLASSPATH=${CLASSPATH}:${JACOB_HOME}/lib/bsh-1.0.jar

# in case jdk 1.1 is used these archives are needed
# otherwise they don't do any harm
CLASSPATH=${CLASSPATH}:${JAVA_HOME}/lib/classes.zip
CLASSPATH=${CLASSPATH}:${SWING_HOME}/swingall.jar

# needed for jacob tutorial
CLASSPATH=${CLASSPATH}:${JACOB_HOME}/src

$JAVA_HOME/bin/java -classpath $CLASSPATH jacob.Main $*
It would be nice to use an xslt stylesheet to generate the shell script, but this would mean another 1-2 mb of jar files to download additionally to the rest of Jacob.

The variables that have to be defined are:

- Application name
- Upper case application name plus _HOME
- if the current project classpath contains swingall.jar

    private String _getShellScript() {

        String sAppName   = _pInit.getFileName();
        String sAppHome   = sAppName.toUpperCase() + "_HOME";
        
        // SWING_HOME
        String sSwingHome = "${JAVA_HOME}/../swing-1.1.1fcs";
        /*String sClassPath = Package.getClassPath();
        int swingIndex = sClassPath.indexOf( File.separator + "swingall.jar" );
        if ( swingIndex != -1 ) {
            sSwingHome = sClassPath.substring( 0 , swingIndex );
            sSwingHome = sSwingHome.substring( sSwingHome.lastIndexOf( File.pathSeparatorChar ) + 1 );
        }*/

        // main class
        String sMainClass = "main.class.not.Specified";
        if ( !Util.isEmpty( _sMainClass ) ) {
            sMainClass = _sMainClass;
        }

        String sRetVal = "#! /bin/sh\n"
                         + "#\n"
                         + "# Script to start "
                         + sAppName
                         + ". (Parts are copied from jakarta-ant\n"
                         + "# startup script.)\n"
                         + "#\n"
                         + "# Maybe you have to set SWING_HOME if using jdk 1.1 (see below).\n"
                         + "\n"
                         + "if [ \"$"
                         + sAppHome
                         + "\" = \"\" ] ; then\n"
                         + "  # try to find "
                         + sAppHome
                         + "\n\n"
                         + "  ## resolve links - $0 may be a link to "
                         + sAppName
                         + "'s home\n"
                         + "  PRG=$0\n"
                         + "  progname=`basename $0`\n"
                         + "\n"
                         + "  while [ -h \"$PRG\" ] ; do\n"
                         + "    ls=`ls -ld \"$PRG\"`\n"
                         + "    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n"
                         + "    if expr \"$link\" : '.*/.*' > /dev/null; then\n"
                         + "      PRG=\"$link\"\n"
                         + "    else\n"
                         + "      PRG=\"`dirname $PRG`/$link\"\n"
                         + "    fi\n"
                         + "  done\n"
                         + "\n"
                         + "  "
                         + sAppHome
                         + "=`dirname \"$PRG\"`/..\n"
                         + "fi\n"
                         + "\n"
                         + "JAVA_HOME=`which java`\n"
                         + "JAVA_HOME=`dirname \"$JAVA_HOME\"`/..\n"
                         + "\n"
                         + "if [ \"$SWING_HOME\" = \"\" ] ; then\n"
                         + "  SWING_HOME="
                         + sSwingHome
                         + "\n"
                         + "fi\n"
                         + "\n"
                         + "CLASSPATH=${" + sAppHome + "}/classes\n"
                         + "CLASSPATH=${CLASSPATH}:${" + sAppHome + "}/lib/"
                         + sAppName.toLowerCase() + ".jar\n"
                         ;

        Vector vJars = _pJacobInterface.getJars();
        Enumeration eJars = vJars.elements();
        while( eJars.hasMoreElements() ) {
            String sNextJar = (String)eJars.nextElement();
            sNextJar = sNextJar.substring( sNextJar.lastIndexOf( File.separatorChar ) + 1 );

            sRetVal += "CLASSPATH=${CLASSPATH}:${" + sAppHome + "}/lib/"
                       + sNextJar + "\n";
        }

        sRetVal += "# in case jdk 1.1 is used these archives are needed\n"
                +  "# otherwise they don't do any harm\n"
                +  "CLASSPATH=${CLASSPATH}:${JAVA_HOME}/lib/classes.zip\n"
                +  "CLASSPATH=${CLASSPATH}:${SWING_HOME}/swingall.jar\n"
                +  "\n"
                +  "\n"
                +  "$JAVA_HOME/bin/java -classpath $CLASSPATH "
                +  sMainClass
                +  " $*";

        return sRetVal;

    }
An Example of a batch file is given below. Be aware that the file needs to be saved as a Dos file in the end, but not in this method of course as this returnes only a string.
@echo off
REM Please adapt this script to your environment.

@REM Set JAVANCSS_HOME to the directory this batch file is in.
set me=%0
for %%i in (%me%) do set JAVANCSS_HOME=%%~dpi

set _JAVA_HOME_ORIG=%JAVA_HOME%
set _CLASSPATH_ORIG=%CLASSPATH%

if NOT "%JAVA_HOME%"=="" goto endif1
	REM #################### EDIT THIS ENVIRONMENT VARIABLE IF NOT ALREADY SET #################
	set JAVA_HOME=c:\jdk1.2.2
:endif1

REM #################### EDIT THIS ENVIRONMENT VARIABLE IF NOT ALREADY SET #################
set CLASSPATH=%JAVANCSS_HOME%\lib\javancss.jar;%JAVANCSS_HOME%\lib\ccl.jar;%JAVANCSS_HOME%\lib\jhbasic.jar;%CLASSPATH%

%JAVA_HOME%\bin\java -classpath %CLASSPATH% javancss.Main %1 %2 %3 %4 %5 %6 %7 %8 %9

set JAVA_HOME=%_JAVA_HOME_ORIG%
set CLASSPATH=%_CLASSPATH_ORIG%
set _JAVA_HOME_ORIG=
set _CLASSPATH_ORIG=
In this batch file the CLASSPATH and JAVA_HOME variables are changed temporarily. The problem remains that when the user Ctrl-C cancels the script the variables won't be set bacl to their original values.

The application home directory is set automatically. The only thing the user still has to set manually is the JAVA_HOME directory.

    private String _getBatchFile() {

        String sAppName   = _pInit.getFileName();
        String sAppHome   = sAppName.toUpperCase() + "_HOME";
        
        // SWING_HOME
        String sSwingHome = "%JAVA_HOME%\\..\\swing-1.1.1fcs";
        /*String sClassPath = Package.getClassPath();
        int swingIndex = sClassPath.indexOf( File.separator + "swingall.jar" );
        if ( swingIndex != -1 ) {
            sSwingHome = sClassPath.substring( 0 , swingIndex );
            sSwingHome = sSwingHome.substring( sSwingHome.lastIndexOf( File.pathSeparatorChar ) + 1 );
        }*/

        // main class
        String sMainClass = "main.class.not.Specified";
        if ( !Util.isEmpty( _sMainClass ) ) {
            sMainClass = _sMainClass;
        }

        String sRetVal = "@echo off\n"
                         + "REM Please adapt this script to your environment (if necessary).\n"
                         + "\n"
                         + "@REM Set " + sAppHome + " to the directory this batch file is in.\n"
                         + "set me=%0\n"
                         + "for %%i in (%me%) do set " + sAppHome + "=%%~dpi\n"
                         + "\n"
                         + "set _JAVA_HOME_ORIG=%JAVA_HOME%\n"
                         + "set _CLASSPATH_ORIG=%CLASSPATH%\n"
                         + "\n"
                         + "if NOT \"%JAVA_HOME%\"==\"\" goto endif1\n"
                         + "  REM #################### EDIT THIS ENVIRONMENT VARIABLE IF NOT ALREADY SET #################\n"
                         + "  set JAVA_HOME=c:\\jdk1.3\n"
                         + ":endif1\n"
                         + "\n"
                         + "REM #################### EDIT THIS ENVIRONMENT VARIABLE IF NOT ALREADY SET #################\n"
                         + "set CLASSPATH=%" + sAppHome + "%\\lib\\" + sAppName.toLowerCase() + ".jar;%CLASSPATH%\n"
                         ;

        Vector vJars = _pJacobInterface.getJars();
        Enumeration eJars = vJars.elements();
        while( eJars.hasMoreElements() ) {
            String sNextJar = (String)eJars.nextElement();
            sNextJar = sNextJar.substring( sNextJar.lastIndexOf( File.separatorChar ) + 1 );

            sRetVal += "set CLASSPATH=%" 
                    +  sAppHome 
                    +  "%\\lib\\" 
                    +  sNextJar 
                    +  ";%CLASSPATH%\n";
        }
        sRetVal += "set CLASSPATH=%"
                +  sAppHome
                +  "%\\classes;%CLASSPATH%\n"
                +  "\n"
                +  "%JAVA_HOME%\\bin\\java -classpath %CLASSPATH% "
                +  sMainClass
                +  " %1 %2 %3 %4 %5 %6 %7 %8 %9\n"
                +  "REM %JAVA_HOME%\\bin\\javaw -classpath %CLASSPATH% "
                +  sMainClass
                +  " %1 %2 %3 %4 %5 %6 %7 %8 %9\n"
                +  "\n"
                +  "set JAVA_HOME=%_JAVA_HOME_ORIG%\n"
                +  "set CLASSPATH=%_CLASSPATH_ORIG%\n"
                +  "set _JAVA_HOME_ORIG=\n"
                +  "set _CLASSPATH_ORIG=\n"
                ;

        return sRetVal;

    }
    private void _createScriptFiles() {

        if ( Util.isEmpty( _sMainClass ) ) {
            return;
        }
        
        String sBatchFile    = _getBatchFile  ();
        String sShellScript  = _getShellScript();

        String sFullProjPath = _pInit.getFilePath();

        // create bin directory and check before
        String sBinDir = FileUtil.concatPath( sFullProjPath
                                              , "bin"       );
        if ( FileUtil.existsFile( sBinDir ) ) {
            throw new ApplicationException( "Could not create directory\n'"
                                            + sBinDir
                                            + "'\nbecause there exist already a file with the same name!" );
        }
        if ( !FileUtil.existsDir( sBinDir ) ) {
            FileUtil.md( sBinDir );
        }

        String sFileName          = _pInit.getFileName().toLowerCase();

        String sShellFullFileName = FileUtil.concatPath( sBinDir,
                                                         sFileName );
        String sBatFullFileName   = sShellFullFileName + ".bat";
        try {
            FileUtil.writeDosFile( sBatFullFileName  , sBatchFile   );
            FileUtil.writeFile   ( sShellFullFileName, sShellScript );
        } catch(Exception e) {
            throw new ApplicationException
                   ("Error: either file \n" + sBatFullFileName +
                    "\nor file\n" + sShellFullFileName +
                    " could not be created!");
        }
      
    }

3   ToDo

Prevent that the user does not loose his custom shell script or batch file. Maybe simply add a complete description of what Jacob will overwrite so the user is aware of what is going on. Of course this pollutes the warning dialog. Maybe he/she can turn that warning message off for the future. This flag should be saved with the project. It is a flag that can only flip once. Maybe once no Makefile etc. was detected it will return to its original state.

Links

Clemens' Java Page:  http://www.kclee.com/clemens/java/
Clemens' Home Page:  http://www.kclee.com/clemens/


clemens@kclee.com,    last revised:   $date: $