plugin building

This is a how-to for creating a plugin's build.xml and build.properties files. Installed directory structure and possbilities for the developer's directory structure are addressed.

On this page:

overview

The following steps are required to submit your plugin to Plugin Central where it becomes available to all jEdit users through jEdit's Plugin Manager:

  1. get build-support files from the jEdit's SourceForge repository
  2. determine the directory structure for your plugin development
  3. create build.properties file
  4. create build.xml
  5. build and test your plugin
  6. check-in your code
  7. gather information and submit plugin to Plugin Central

This document explains steps 1 through 4.

(Note: Plugin source code, if not intended to be part of the jEdit repository, is best placed in some public repository like SourceForge. In any case you need to put it somewhere the person doing the packaging can get at it. Do not expect to send it in as an attachment in an email.)

build-support files

There are currently (June 2006) three files in the build-support module.

build.properties.sample a starting point for a build.properties file should you decide to use one
plugin-build.xml required, this is used in an import task in your build.xml file
users-guide.xsl needed if you use docbook to generate your plugin's help files

To get them using a CVS client see here. Or just browse to the CVS repository, copy/paste from your browser to jEdit, and save them with the appropriate filenames.

Put them in a directory outside of your plugin tree. Its parent directory may be convenient.

plugin directory structure

If all your source files are in one directory tree (as is typical), you are in good shape. If not, the simplest solution is to use a higher-level build file to copy them there.

When your development directory structure reflects the directory structure after plugin installation in jEdit, writing your build.xml file may be trivial.

installed plugin directory structure

The default structure assumed in plugin-build.xml can be thought of as a reflection jEdit's Settings directory after a user has downloaded your plugin with its source code:

The forthcoming Xilize 3.0 plugin has a structure like this after it is installed with source code:

directory structure for development

Again using the Xilize plugin as an example, the corresponding development directory structure is given below. Note: in this case the jEdit plugin is one of several components in a larger project. The only part of this relevant to jEdit plugin development is the "xpe" directory (in green).

build.properties

Use this file to set properties used in the build process. You may also include property definitions in build.xml before the import task.

plugin-build.xml looks for and loads:

  1. build.properties — current dir
  2. ../build.properties — parent dir
  3. ${user.home}/.build.properties — note the leading . (dot) in the filename
  4. ${user.home}/build.properties — without the leading dot

the related comment in plugin-build.xml has some errors

Note:

To create a build.properties file:

  1. copy build.properties.sample from the build-suppport module to build.properties
  2. un-comment the lines you need and provide meaningful values.

See here for a listing of build.properties.sample.

plugin-build.xml contains these lines to load your property file:

    <property file="build.properties" />
    <property file="../build.properties" />
    <property file="${user.home}/.build.properties" />
    <property file="${user.home}/build.properties" />

In the next step you will connect plugin-build.xml to your build.xml file.

I would remove this from build.properties.sample:

# Location of build-support directory
# build.support=../
# build.support=/absolute/path/to/plugins/build-support

since the user is better off followng the suggestion in plugin.build.xml to do this in their build file — which is a good idea if you want jEdit's XML support when editing build.xml (otherwise the XML plugin complains):

    <property name="build.support" value="../build-support" />
    <import file="${build.support}/plugin-build.xml" />

build.xml

A plugin build.xml file can be as simple as this:

<?xml version="1.0"?>
<project name="NameOfYourPlugin" default="build" basedir=".">
    
    <property name="build.support" value="/absolute/path/to/plugins/build-support"/>
    
    <import file="${build.support}/plugin-build.xml"/>
    
</project>

Even the property definition can be eliminated if passed in on the command line or supplied through a parent ant process. However, it is convenient to leave it in the build.xml file.

The important bits here are

Using the build.properties file to set the various properties used in the build is preferrable to adding more property tasks to build.xml if only to keep the clutter down for the packaging team.

Here is the same file with comments included.

<?xml version="1.0"?>

<!-- {{{  sample plugin build.xml file

This is an example of a minimal build.xml file for a plugin.
It uses the required build-support plugin-build.xml file for building a 
jEdit plugin.

NOTE:  The project name is used in creating the file name of the plugin's 
jar file:  NameOfYourPlugin.jar

}}} -->

<project name="NameOfYourPlugin" default="build" basedir=".">

    <!-- build.support property                                        {{{ 
    
        Change the value of this property to the directory where you put 
        plugin-build.xml and the other build-support files.            }}} -->
    
    <property name="build.support" value="/absolute/path/to/plugins/build-support"/>
    
    <!-- other properties if not using build.property file             {{{
    
        To override other properties used in plugin-build.html, 
        either use a build.properties files, 
        or declare them before the followng import statement.          }}} -->
     
    <!-- don't touch the import task, it is the heart of the build process -->
    <import file="${build.support}/plugin-build.xml"/>

    <!-- path and selector overrides                                   {{{
    
        To override paths and selectors used in plugin-build.html, 
        declare them after the import statement.                       }}} -->
    
</project>

<!-- :tabSize=4:indentSize=4:noTabs=true:folding=explicit:collapseFolds=1: -->

The next section describes what happens in the import statement and how to modify/extend that behavior.

plugin-build.xml

Note: two targets in plugin-build.xml are identical:
<target name="dist.complete" depends="docs,build" />
<target name="package" depends="docs,build" />
Should not one of them be removed? Or are both necessary?

See here for a complete listing of plugin-build.xml.

plugin-build.xml defines these targets (from ant -p):

    builds the Xilize2 plugin using the required build-support plugin-build.xml

Main targets:

 build                Builds the plugin JAR file
 build.dependencies   Builds the needed plugins from the available source code.
 clean                Cleans project directories
 compile              Compile the plugin's classes
 docs                 Build the User's Guide and Javadoc documentation
 docs-xalan           Generate user documentation in hmtl format with xalan
 docs-xsltproc        Generate user documentation in hmtl format with xsltproc
 javadoc              Generates javadoc sourcecode documentation
 test                 Runs the plugin's unit tests.
 test-junit           Runs the plugin's jUnit tests.
 update.dependencies  Download the most recent source of the needed plugins from CVS
 userdocs             Builds the user documentation.
Default target: build

Fortunately you only have to be aware of a few of them — and then only if your plugin needs special handling.

A synopsis of how targets in plugin-build.xml may get called during the packaging process is:

  1. dist.complete
    • docs
      • javadocs
      • userdocs (from docbook xml sources)
    • build
      • compile
      • build.prepare
      • jar
      • build.post
  2. dist.source
    • zips source code, support files, javadocs

plugin-build.xml contains serveral targets, selectors, and a classpath for you to override in your build.xml if necessary.

targets

The targets build.prepare and build.post are present for you to override if you need to; their default implementations do nothing.

selectors

These selectors are used within the scope of the build target and can be overridden if necessary:

    <!-- This selector defines the files that will be
         compiled by the "compile" target. Define here which
         files under ${src.dir} will be compiled when the
         "compile" task is called.                          -->
    <selector id="compileFiles">
        <filename name="**/*.java" />
    </selector>

    <!-- This selector defines extra files to be included
         in the plugin's JAR file. The context of the
         selector is the plugin's directory (${basedir}),
         so it will not work for files outside the plugin
         directory. For those cases, use the "build.prepare"
         target. By default, it's empty.                    -->
    <selector id="packageFiles">
        <size value="0" when="less" />
    </selector>

    <!-- This selector defines other files that should be packaged
         in the plugin's jar file; by default it contains actions.xml,
         dockables.xml, services.xml, any files ending in ".props",
         "LICENSE" and "README". The context is "${basedir}". Override
         it if your plugin needs special treatment for these files. -->
    <selector id="extraFiles">
        <and>
            <or>
                <filename name="**/actions.xml" />
                <filename name="**/dockables.xml" />
                <filename name="**/services.xml" />
                <filename name="**/*.props" />
                <filename name="**/LICENSE" />
                <filename name="**/README" />
            </or>
            <not>
                <filename name="${build.dir}/*" />
            </not>
        </and>
    </selector>

classpath

In the following, the classpath project.class.path may be overridden if, for example, your plugin depends on other plugins. Note: this classpath is added to the default which contains jedit.jar and junit.jar.

    <!-- this is the classpath used by the "compile"
         target. Override this one if you need to. You don't
         need to reference "default.class.path" here - it's added
         automatically to the javac command.                -->
    <path id="project.class.path" />

dependencies on other plugins and libraries

If your plugin depends on other plugins an libraries, override project.class.path.

As an example, the AntFarm plugin depends the Console, ErrorList, ProjectViewer, and CommonControls plugins and the ant library (ant.jar). Here it sets the classpath in its build.xml file (remember jedit.jar and junit.jar are added by default):

   <path id="project.class.path">
        <!-- External dependencies -->
        <pathelement path="${jedit.jars}/ant.jar"/>
        <!-- Other plugin dependencies -->
        <pathelement path="${jedit.user.jars}/Console.jar"/>
        <pathelement path="${jedit.user.jars}/ErrorList.jar"/>
        <pathelement path="${jedit.user.jars}/ProjectViewer.jar"/>
        <pathelement path="${jedit.user.jars}/CommonControls.jar"/>
    </path>

plugin configuration files

this should be expanded and put on its own page

jEdit reads one or more plugin configuration files when it loads a plugin. For each JAR archive file it finds, jEdit scans its entries for certain files. By convention these are at the top-level of the plugin directory structure.

NameOfYourPlugin.props required properties to be loaded into the jEdit environment. This file must be in the plugin's top directory. See below
actions.xml optional actions the plugin makes available
dockables.xml optional dockable windows supplied by the plugin
services.xml optional services provided by the plugin
LICENSE recommended license you are supplying with your plugin
README recommended your readme file

During the plugin build, plugin-build.xml automatically collects these files and includes them in the jar with this default selector. If this behavior is not suitable for your plugin, you can override it in your build.xml.

   <selector id="extraFiles">
        <and>
            <or>
                <filename name="**/actions.xml" />
                <filename name="**/dockables.xml" />
                <filename name="**/services.xml" />
                <filename name="**/*.props" />
                <filename name="**/LICENSE" />
                <filename name="**/README" />
            </or>
            <not>
                <filename name="${build.dir}/*" />
            </not>
        </and>
    </selector>

NameOfYourPlugin.props

This file is required and must be in the plugin's top directory. It provides essential information to jEdit's plugin management system. You may have additional props file in your project and jEdit will find and load them. But to ease the task of the packagers, please put all the properties related to general plugin information, the option pane(s), and menus in this "primary" property file.

Using the Xilize plugin as an example, your plugin will likely need to define at least the following properties:

plugin.xilize.XilizePlugin.activate     = defer
plugin.xilize.XilizePlugin.name         = Xilize
plugin.xilize.XilizePlugin.author       = Andy Streich
plugin.xilize.XilizePlugin.depend.0     = jdk 1.5
plugin.xilize.XilizePlugin.depend.1     = jedit 04.02.02.00
plugin.xilize.XilizePlugin.docs         = xilizehelp.html
plugin.xilize.XilizePlugin.menu.label   = Xilize
plugin.xilize.XilizePlugin.option-pane  = xilize

Note the use of xilize.XilizePlugin in each of the property names. Every regular plugin must contain one class that extends either org.gjt.sp.jedit.EditPlugin or org.gjt.sp.jedit.EBPlugin. For Xilize, this is XilizePlugin whose fully qualified name (package and class name) is xilize.XilizePlugin.

See the javadoc for EditPlugin for details.

notes

ant command line

You can modify the build.support property in your build.xml file to point to wherever you put plugin-build.xml and users-quide.xsl.

Alternately define it on the ant command line with something like

ant -Dbuild.support=/home/andy/wdev/x/lib/jEditBuildSupport

or define it in build.properties and run ant with a command like this

ant -propertyfile build.properties

ant-contrib

Plugin Central's packaging process uses ant-contrib.jar, you can safely ignore it. From a comment in plugin-build.xml:

Some tasks require the ant-contrib library available from http://ant-contrib.sourceforge.net. If you have the library, specify a property named ant-contrib.jar with the location of the library. The tasks that need ant-contrib are the tasks related to plugin dependencies.

JUnit support

From a comment in plugin-build.xml.

For JUnit support, make sure you have the ant-junit.jar library in Ant's lib directory. Specify the location of the junit jar file using the property junit.jar.

docbook

this should be completed and put on its own page