Java Preprocessor Using Eclipse

Page 1

 So, you would like to macros like  

 

#ifdef PRO_VERSION

   System.out.println("Welcome to the PRO version of this wonderful software.  :) ");

#else

   System.out.println("Sorry, you are using the lousy, crippled, and worthless version of our otherwise wonderful software. :( ");

#endif

 

The Explanation of Why I would Ever Want Icky C-style macros in my Java code

   Now, searching for a java preprocessor on the web, you will find lots of people who are simply horrified that anybody would want to put such backward, impure things in their code.   And the above could certainly be done without preprocessing.    But there are sometimes you just really really want to use IFDEF type macros.   In my case, it was because I have a really huge library which is now filled with lines which generate log data using various combinations of  String.format("blah blah %d %f", i, fx); type stuff.   Then because I was going to be running on an embedded platform, all those strings were getting generated on the heap even if the log lines weren't executing.   This was very bad.  I didn't want to remote all the log lines because I need them for debugging.    In my case this library was a big port from c# code.    I had to do a lot of checking by putting the same log lines in the C# code, running that, and then putting the same output lines in the Java code and comparing the output. 

 

 Prebop to the Rescue

 http://prebop.sourceforge.net/

Prebop is an open source java preprocessor which uses Ant and is fairly easy to integrate with Eclipse.    If you don't know what Eclipse is, then I don't see why you are reading this article.   Now if you don't know what Ant is, here is Apache's one-line description: 

Apache Ant is a Java-based build tool. In theory, it is kind of like Make, but without Make's wrinkles.

   But fear not, you will not have to learn everything about Ant.  In fact, you can use Ant in Eclipse without too much pain at all.

   So anyway, to use a preprocessor in your Eclipse Java application, you need to do the following steps:

  1.  Download Prebop zip file. 
  2.  Install the Prebop plug-in in Eclipse
  3.  Create a build.xml file in your Java project
  4.  Make sure your project builds using the build.xml file
  5.  Add some Prebop lines to your build.xml to run the preprocessor before the compiler
  6.  Run the Ant Build wizard and specify a jar file and stuff
  7.  Add some macro-like code to your source
  8.  Enjoy

Page 2

Step 1 Downloading  Prebop

 Here is the main Prebop page:   http://prebop.sourceforge.net/

 The .zip file can be downloaded from here:  http://sourceforge.net/projects/prebop/

 

Step 2 Installing Prebop in Eclipse

  Prebop is a wonderful thing, but the documentation assumes you know everything about how to install a plug-in and get an Ant build up and running.  Since I didn't know that, there is a good chance nice people such as yourself don't know this either.   Infact, if you did already know this, you probably wouldn't be reading this page.  Anyway, to install the Prebop thingy in Eclipse 3.5,  simply unpack the .ZIP file with your favorite unzipper, and place the whole folder in your "eclipse/dropins" folder.  

  For more information about installing plugins using the dropins folder, see here or here.

  Then exit Eclipse if you are already running it, and go back in.   

Verifying that Eclipse installed Prebop Successfully

  In Eclipse, click on the 'Help' menu.

  Click on the 'About Eclipse' menu item.

  Click on the button 'Installation Details'

  Click on 'Plugins' on the top tab

  Scroll down on the list and look for

PreBop Eclipse Installation Check

 

 Depending on which column you are sorting by, it may be up near the top, or further down if it is sorted by Plug-in Name.

 


Page 3

 Step 3: Create a build.xml file in your Java project

 By default, Eclipse builds your Java projects for you.    To use the preprocessor, you can instead create an XML file in your project that will direct Ant to do the building of your Java project.    The nice thing about using Ant build file is that it can be configured to not only compile the source, but also create the final output jar, run Javadoc to automatically generate Javadoc, or anything else you'd like to do.

   I learned how to make an Ant build file from Lars Vogel's page.

   If you are familiar with the Make utility, the build.xml file is kind of like makefile, but with much more sane syntax.   If you have never used Make, then no need to worry, the format is pretty simple.  If you don't know what an XML file, also don't panic.    An xml file is just a text file you can make with Notepad or any common text editor.  They are easy to read and pretty simple create.

  So, create a new Java project in your workspace.   Call it 'Hello'.   Create a class called Hello in a new package called 'mypackage'.  Put the following in for the contents of Hello.java:

 Creating Hello Class

The red shows you the important things to check so that your Hello project looks like mine.

 And the project should look like:

Hello project

 

 

 Edit  Hello.java to make it look like this:

 

package mypackage;

public class Hello {

    /**
     * @param args
     */
    public static void main(String[] args)
    {
        System.out.println("Hello, World!");
    }

}

   This highly creative and imaginative program should print Hello, World! to the console and then terminate.   To try it out, right click on the Hello project in the package explorer, and select "Debug As", and then choose 'Java Application' in the popup menu.

 

Page 4

Creating prebopBuild.xml file

   Now we want to make our own build script to use instead of the Eclipse default script.   To do this, right click on the Hello project and select new -> file.

 

Create prebopBuild.xml

When you first create the file, it will be in Design mode, so we want it to be source mode where you can type directly:

 Source Mode

 The xml file text should be:

<?xml version="1.0"?>
<project name="Hello" default="compile" basedir=".">
    <!-- Sets variables which can later be used. -->
    <!-- The value of a property is accessed via ${} -->
    <property name="src" location="src" />
    <property name="build" location="bin" />


    <!-- Creates the  build, docs and dist directory-->
    <target name="makedir">
        <mkdir dir="${build}" />
    </target>


    <!-- Compiles the java code -->
    <target name="compile" depends="makedir">
        <javac srcdir="${src}" destdir="${build}" />
    </target>
</project>


Page 5

After filling in the text for the xml file, it is time to fill in the Ant configuration settings for this build file.   To get to this dialog, right click on the prebopBuild.xml file in the project explorer, and select the Ant build... with the three dots, or the 'External Tools Configuration.. below.

 

Run As

 

 Verifty the Main tab settings look like this.

 

Build File Config

 

 We don't want to build the entire work space, so have it only build this project.

 

 refresh settings

 And build only this project, not the entire workspace.

 Build only this project

 In the Targets tab, we choose the default action to compile.  We do not check clean or makefile.  The ant buildfile itself will do the Mkdir step before doing the build, so we don't need to check it here.

 Compile

 

On the Classpath tab, we must add the preprocessor.jar external jar.  The steps to get the right jar file added are numbered in the image below.

 

 Adding Prebop Jars

 

This next step is very important.  If you do not change the from the default value of 'Separate JRE' to "Run in the same JRE as the workspace", then preprocessor task will not run when we added it.   I.E. you will get an error like:  "Problem: failed to create task or type preprocess"

 

Run in Same JRE

 


Page 6:

Now the project should build by running the Ant script.    Now it is time to tell Eclipse to use this Ant script (instead of it's own method) to build the project by default.  Right-click on the Hello project and select 'Properties' which is probably all the way on the bottom.   On the left, choose 'Builders'.

 

Project Properties Builders

Uncheck 'Java Builder' and check our new prebopBuild.xml script.   Now by default, our script will be compiling the project.

NOTE:

  If the script doesn't work and you see an error message about the JAVA_HOME not being set, then you need to set the environment variable to JAVA_HOME up on your computer.   On my system JAVA_HOME has the value shown highlighted in blue below:

 

JAVA_HOME env variable

 

Assuming that building works, it is now time to add a step for cleaning the build.   Edit the prebopBuild.xml file so it has the extra section for the 'clean' target:

 

<?xml version="1.0"?>
<project name="Hello" default="compile" basedir=".">
    <!-- Sets variables which can later be used. -->
    <!-- The value of a property is accessed via ${} -->
    <property name="src" location="src" />
    <property name="build" location="bin" />

    <!-- Creates the  build, docs and dist directory-->
    <target name="clean">
        <delete dir="${build}" />
    </target>


    <!-- Creates the  build, docs and dist directory-->
    <target name="makedir">
        <mkdir dir="${build}" />
    </target>


    <!-- Compiles the java code -->
    <target name="compile" depends="makedir">
        <javac srcdir="${src}" destdir="${build}" />
    </target>

</project>

What we have done is to add a new capability of what the build file can do.   It can now clean as well as build.   But now the settings for the build must be updated.

 

Adding the 'clean' target to the settings

 Note the order must be clean, then compile.  Otherwise your executables will be deleted right after they are created.

 And now, apply these changes, then go to the Project Properties, and back to the Builders page.   Then click on the prebopBuild.xml file, then the 'Edit' button.   This will bring up a dialog which looks identical to the External Tools Configuration dialog, but it is a little different.

 

Edit launch add clean target

If your 'Targets' tab does not look this screen, make sure you are actually looking at the Edit Launch Configuration Properties and not the 'Edit Configuration and Launch'.   I do not quite understand the difference, but you bring the dialogs up differently.

   The line 'During a Clean' which is in read is asking you to specify which target to use for a generic Clean operation.   We want the one called 'clean'.

   Once the target has been set for the 'Clean' operation, the project will once again show up in the list when you go to clean projects.

 

Page 7:

Now that we have got an Ant script building the project, we can now use the Preprocessor.   Remember what we set out to accomplish in Part 1 of this article?

 

#ifdef PRO_VERSION

   System.out.println("Welcome to the PRO version of this wonderful software.  :) ");

#else

   System.out.println("Sorry, you are using the lousy, crippled, and worthless version of our otherwise wonderful software. :( ");

#endif

 

 Ok, well we won't have something that looks just like that, but we'll come pretty close.

 

The preprocessor will read in a source file, and then modify the source and write it out somewhere else.   Then we compile that modified file based on some variables which define.   First we must add some code to our build script so it creates a folder to put the modified source code in, and deletes it when cleaned.

 

Making the build file create different temporary source folders for the 'Pro' and 'Lite' version,

(and also different output folders).

 

  Change the prebopBuild.xml file to create two new source folders in the temp directory of the system.   One is for the 'lite' version, the other is for the 'pro' version.  In addition, we will now have two build folders for the output .class files,  bin/lite and bin/pro. 

 

<?xml version="1.0"?>
<project name="Hello" default="compile" basedir=".">
    <!-- Sets variables which can later be used. -->
    <!-- The value of a property is accessed via ${} -->
    <property name="src" location="src" />
   
    <!-- We are going to temporarily write source code outside of the workspace -->
    <property name="tmpfolder" value="/tmp/Hello" />
    <property name="src_lite" value="${tmpfolder}/src_lite"/>
    <property name="src_pro" value="${tmpfolder}/src_pro"/>   
   
    <property name="build" location="bin" />
    <property name="build_lite" value="${build}/lite"/>
    <property name="build_pro" value="${build}/pro"/>   

    <!-- Creates the  build, docs and dist directory-->
    <target name="clean">
        <delete dir="${tmpfolder}" />
        <delete dir="${build}" />
    </target>

    <!-- Creates the  build, docs and dist directory-->
    <target name="makedir">
        <mkdir dir="${src_lite}" />
        <mkdir dir="${src_pro}" />
        <mkdir dir="${build_lite}" />
        <mkdir dir="${build_pro}" />
    </target>
   
    <!-- Copies source files from src folder to src_lite and src_pro folder -->
    <target name="copysource">
    <copy todir="${src_lite}"> <fileset dir="src"/> </copy>
    <copy todir="${src_pro}"> <fileset dir="src"/> </copy>
    </target>


    <!-- Compiles the java code -->
    <target name="compile" depends="makedir, copysource">
        <javac srcdir="${src_lite}" destdir="${build_lite}" />
        <javac srcdir="${src_pro}" destdir="${build_pro}" />
    </target>

</project>
 

   So when the user now selects 'Build' then the compile target gets executed.   Looking at that final target section, we see that 'compile' depends on the targets 'makedir' and 'copysource'.   So we need to execute the targets 'makedir' first, then 'copysource' before we proceed.     

 

  The target 'makedir' now creates 4 new folders.   It creates two source folders in the tmp directory which is outside the workspace.  I did this to prevent either Eclipse or myself from getting confused by duplicate packages and source files.   It also now creates two folders in the 'bin' output folder.   One for the 'lite' version, and another for the 'pro' version.

   Then the copysource target executes.   It simply copies all the source files from the src folder (and its subfolders) into the tmp folders.

  Finally, the 'Compile' target can run.   It compiles the source from the first tmp dir (/tmp/Hello/lite/*.java) and builds the class files in the bin/lite folder.  It repeats the compile from the /tmp/Hello/pro folder into the /bin/pro output folder.

 Here is what the console output from the build looks like:


 

makedir:
       [mkdir] Created dir: C:\tmp\Hello\src_lite
       [mkdir] Created dir: C:\tmp\Hello\src_pro
       [mkdir] Created dir: C:\eclipse_workspace\Hello\bin\lite
       [mkdir] Created dir: C:\eclipse_workspace\Hello\bin\pro

copysource:
        [copy] Copying 1 file to C:\tmp\Hello\src_lite
        [copy] Copying 1 file to C:\tmp\Hello\src_pro

compile:
       [javac] Compiling 1 source file to C:\eclipse_workspace\Hello\bin\lite
       [javac] Compiling 1 source file to C:\eclipse_workspace\Hello\bin\pro
BUILD SUCCESSFUL
Total time: 1 second


 

  Well whoopdeedoo, we haven't yet accomplished anything.

   And... the project no longer runs.  When we try we get this error:

 Thread [main] (Suspended (exception ClassNotFoundException))    
    URLClassLoader$1.run() line: not available [local variables unavailable]

   The reason we are getting this error is that .class output files have moved.   

  We need to change the classpath in the debug configuration so that it can find the Hello.class file.  The followin picture shows how to add the bin/lite folder to the classpath so Eclipse can find the Hello.class file to run.

 Debug Config Classpath

 

   This debug configuration should also probably have its name changed from 'Hello' to 'Hello - lite'.

So now finally, we are ready to invoke the preprocessor plugin.

Invoking the Prebop Preprocessor

   What we are going to do now is replace the 'copysource' target with a new target call  'splitsource'.   Splitsource will actually copy the source files, but modify them according to the preprocessor variables, so that the source in /tmp/Hello/pro will be different than the source code in /tmp/Hello/lite.

(... The top twenty lines or so was omitted for brevity  ...)

    <target name="splitsource"  description="preprocessor">
        <preprocess indir="${src}" outdir="${src_lite}" out="replace">
            <var name="pro" value="false"/>
            <filetype commentend="*/" commentbegin="/*" extensions="java"/>
        </preprocess>
        <preprocess indir="${src}" outdir="${src_pro}" out="replace">
            <var name="pro" value="true"/>
            <filetype commentend="*/" commentbegin="/*" extensions="java"/>
        </preprocess>
    </target>

    <!-- Compiles the java code -->
    <target name="compile" depends="makedir, splitsource">
        <javac srcdir="${src_lite}" destdir="${build_lite}" />
        <javac srcdir="${src_pro}" destdir="${build_pro}" />
    </target>

</project>

   If the project no longer builds and complains about not being able to find the 'preprocess' Ant task, then right-click on your xml file and check the configuration.   If in the JRE tab you have it set to run in a separate process, then you must change it so it run in the same JRE as the workspace.   Be advised that the default setting is incorrect.

   After making these changes and cleaning the project, the console output looks like this:

 


makedir:
       [mkdir] Created dir: C:\tmp\Hello\src_lite
       [mkdir] Created dir: C:\tmp\Hello\src_pro
       [mkdir] Created dir: C:\eclipse_workspace\Hello\bin\lite
       [mkdir] Created dir: C:\eclipse_workspace\Hello\bin\pro

splitsource:
  [preprocess] modified 0 of 1 files
  [preprocess] modified 0 of 1 files

compile:
       [javac] Compiling 1 source file to C:\eclipse_workspace\Hello\bin\lite
       [javac] Compiling 1 source file to C:\eclipse_workspace\Hello\bin\pro
BUILD SUCCESSFUL
Total time: 1 second

 


   If your console output looks like this, then the preprocessor is running.   All we need to do now is mark up the .java source code with the preprocessor commands!

Page 8:

 In the xml build file, we now have two sections with Ant task = "preprocess".   The first sets a variable called 'pro' to false and processes the source before storing it in /tmp/Hello/lite.   Then it sets 'pro' to true, and processes the source code while copying it to /tmp/Hello/pro.

 


    <target name="splitsource"  description="preprocessor">
        <preprocess indir="${src}" outdir="${src_lite}" out="replace">
            <var name="pro" value="false"/>
            <filetype commentend="*/" commentbegin="/*" extensions="java"/>
        </preprocess>
        <preprocess indir="${src}" outdir="${src_pro}" out="replace">
            <var name="pro" value="true"/>
            <filetype commentend="*/" commentbegin="/*" extensions="java"/>
        </preprocess>
    </target>


 

 So what we need to do is modify the Hello.java source doe so the preprocessor will have something to do besides copy files.

in Hello.java, replace the Main method with this one:


 

    public static void main(String[] args)
    {
        /* $if pro$
            System.out.println("Welcome to the PRO version of this wonderful software.  :) ");
         $else
            System.out.println("This is the lousy, crippled, and worthless version");
         $endif$ */
    }


  For more information about how prebop processes text, please see this document.

   There should be a Hello.class in the Pro directory which reports itself as pro.   

    Make another debug target by clicking on the run as arrow and then select Debug Configurations.   Clone the original and rename the clone debug configuration to 'Debug - Pro'.  Then go to the classpath settings and the 'Advanced' button to add the fold bin/pro to the classpath.

    Note that we could also add a build step for creating the jar files also.   To do this we would add another target to the prebopBuild.xml file:

	<!--Creates the deployable jar file  -->
	<target name="jar" depends="compile">
		<jar destfile="${output_lite}\Hello.jar" basedir="${build_lite}">
			<manifest>
				<attribute name="Main-Class" value="myPackage.Hello" />
			</manifest>
		</jar>
		<jar destfile="${output_pro}\Hello.jar" basedir="${build_pro}">
			<manifest>
				<attribute name="Main-Class" value="myPackage.Hello" />
			</manifest>
		</jar>
	</target>

NOTE:  The above assumes you have already added the lines to the xml script to create the output_lite and output_pro folders, just like we did for the source folders and the build folders.

Thank you for reading this tutorial.  I hope you found it useful.

 

The End


http://www.boldinventions.com/index.php?option=com_content&view=article&id=87:javapreprocessorusinge
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值