| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| |
| |
| = NetBeans 4.x Project & Build System How-To |
| :jbake-type: wiki |
| :jbake-tags: wiki, devfaq, needsreview |
| :markup-in-source: verbatim,quotes,macros |
| :jbake-status: published |
| :syntax: true |
| :description: NetBeans 4.x Project & Build System How-To |
| :icons: font |
| :source-highlighter: pygments |
| :toc: left |
| :toc-title: |
| :experimental: |
| :author: Jesse Glick |
| |
| |
| [[Overview]] |
| == Overview |
| |
| This guide should give developers of NetBeans modules (extensions) a basic idea |
| of how to write new project types for NetBeans 4.x, as well as use certain |
| importants parts of the project and build system functionality from other kinds |
| of modules. |
| |
| The reader is assumed to be familiar with the basics of developing NetBeans |
| modules: how to compile Java sources against API-providing modules, make the |
| JAR, write the manifest and XML layer, register services in global lookup, etc. |
| |
| For background, the reader is encouraged to first look at the [design.html |
| general design document] which explains how the different pieces of the |
| architecture work together to provide the user functionality. |
| |
| Quick architectural summary: |
| |
| 1. The NetBeans IDE (starting with version 4.0) organizes user work into projects. Each project corresponds to exactly one project folder on disk. (A given disk folder may be a project folder or not; you cannot have two projects in one folder.) |
| . A project owns all files inside its project folder or subfolders (except when a subfolder is itself another project folder, which is allowed); it might also own files located elsewhere on disk, to permit a user to keep IDE-specific configuration separate from existing “pristine” sources. |
| . There are different types of projects available, according to what modules you have installed. Different project types may behave very differently, or look almost alike, depending on their intent. |
| . A project defines what appears beneath its node in the *Projects* tab—sometimes called its logical view. It can also define a customizer action, usually opening a properties dialog. |
| . A project can be opened or closed via the GUI. It can also be loaded though not open; an open project is however always loaded. A project can be garbage collected if it is closed; attempting to refer to it again (via its project directory) will automatically load it again. |
| . A project may list subprojects, other projects it somehow depends on. This is used mainly when opening a project using the *Open Project* action. |
| . The IDE defines certain generic actions such as *Build* which can be invoked on a project, which have corresponding commands, simple strings like `build`. Some actions can be sensitive to the selected file. Often Apache Ant is used as a build tool to produce a final program or other delierable from sources, but this is not required. |
| . Interaction between project implementations and other functionality in the IDE is normally done using queries, a pattern whereby a client can ask a concrete question (e.g. ClassPath.getClassPath(someJavaFile, ClassPath.COMPILE)) and possibly receive an answer; query implementations are registered (using `Lookup.default`) by any modules, and asked in turn. For queries mentioned here, usually the query implementation may be registered in the project (using `Project.lookup`) rather than globally, and the project associated with the file mentioned in the question (e.g. FileOwnerQuery.getOwner(someJavaFile) in the last example) will be asked to provide an answer. |
| . Though project type providers are allowed a great deal of leeway in how they implement the project SPIs, there is a fairly extensive SPI support suite which assumes that the project uses Ant as a build tool, and defines a number of convenience implementations optimized towards this system. |
| |
| NOTE: all API classes and interfaces are referred to by simple name. You can look up the Javadoc for any of these classes quickly using the link:https://bits.netbeans.org/dev/javadocallclasses.html[master class index] for the NetBeans APIs. |
| |
| |
| [[How_to_Write_a_Project_Type_.28Generally.29]] |
| == How to Write a Project Type (Generally) |
| |
| This section discusses general things you need to do in order to write a new project type. Later on we will discuss more concrete suggestions for Ant-based projects using the standard infrastructure. |
| |
| Generally a project type should be contained in a module dedicated to implementing that project type. _Do not expose any APIs from this module._ If other modules need special information about your project’s structure not available through the existing APIs, you can define new APIs _in separate API modules_ that both the clients and your project type depend on. This rule helps enforce a clean architecture on the system and ensures that other project types could mimic some of the behavior of your project type if they needed to. |
| |
| An interesting tutorial on writing a (non-Ant-based) project type from scratch is available: link:http://openide.netbeans.org/povraytutorial/[Tim Boudreau’s POV-Ray tutorial] |
| |
| |
| [[Decide_on_a_Project_Layout]] |
| === Decide on a Project Layout |
| |
| The first step for any kind of project type is to decide what the project will look like! You should have a clear idea of what files will reside in the project directory (or perhaps externally), using what file names, what the contents should be, what files will be updated by the IDE’s GUI, what by text editing, how future updates will affect file formats, etc. |
| |
| If you use the standard Ant-based infrastructure (below), some of these decisions are made for you. |
| |
| Most project types will define an `AntBasedProjectType` and keep basic project metadata in `''$projdir''/nbproject/project.xml` (below). If you do not do this, e.g. if you need to support a third-party project layout (such as Apache Maven uses), then you will need to implement `ProjectFactory` yourself to recognize and load projects using your format. A project factory should be designed to be able to quickly reject candidate directories which are _not_ in your layout. (Positive identification of your projects can be a little slower.) |
| |
| |
| [[Write_the_Project_Object]] |
| === Write the Project Object |
| |
| Every project is represented by a `Project` object, which is created by your factory. Its only mandatory behavior is to be able to report the project directory it is associated with. Other than that, all of its behavior is controlled by its `Lookup`, basically a bag of optional capabilities. Usually `org.openide.util.lookup.Lookups` can be used to make a `Lookup` with a fixed list of entries. |
| |
| _All outside code_ should interact with your project via interfaces found in its lookup. Outside code can check to see if a given project has a capability, and if so, use it. _Never make your `Project` implementation class publicly accessible._ Whatever capabilities you wish to expose, do so from the lookup—you can define additional interfaces to expose to clients (public or semi-public, in API-exposing modules) and add implementations to your lookup (in non-public classes in your project type module) if you need to. Beware that the project infrastructure reserves the right to hide the original `Project` your factory creates and expose only a wrapper to outside callers, so it would never be correct to try to cast a `Project` object to an implementation class, even if you could access that implementation class. |
| |
| |
| [[What_to_Put_in_Lookup]] |
| === What to Put in Lookup |
| |
| Since all the project’s behavior is controlled by its lookup, the question becomes: what interfaces should I implement? There is a suggested list in the Javadoc for `Project.getLookup()`. Here is an overview of major kinds of interfaces and why you might need them. |
| |
| |
| [[General_Appearance]] |
| === General Appearance |
| |
| Almost all project types will want to define their general appearance and behavior in the IDE’s GUI. |
| |
| `ProjectInformation`:: Lets you control the display name and icon of the project. Typically all projects of a given type will share an icon, but there may be badging etc. applied as well, and it is possible to have basically different icons depending on project metadata. |
| `LogicalViewProvider`:: Controls the display in the *Projects* tab. You can show whatever subnodes you like, according to the project’s semantics. Typically you will show important source roots (try `PackageView` in the case of Java package roots), or important files. You can also show nodes which do not directly correspond to individual files—e.g. an EJB project shows EJB and web services nodes which are derived from combinations of source files and deployment descriptor information.The root node for the project should usually have a name and icon matching that given in `ProjectInformation`. The precise context menu will vary by project type, so look at existing project types to keep consistency. Many of these items can be created easily using `CommonProjectActions` and `ProjectSensitiveActions`.Remember that you need to include the `Project` in the lookup of the root node, or project-sensitive actions will not generally work.Note: the *Files* tab is not under a project’s direct control. It always shows top-level “generic” source groups (acc. to `Sources`—see below) from the project as top-level nodes, beneath which there is a plain directory tree (filtered according to `VisibilityQuery`). In most cases there is one node per project—the project directory—but projects using external source roots may display additional nodes. |
| `CustomizerProvider`:: Implements the *Project Properties* action in the *File* menu (also `CommonProjectAction.customizeProjectAction`). Usually this action should open a dialog containing general GUI configuration for the project, according to its needs. Of course the project may expose additional UI for customization, if appropriate, using context menu items on the project node, subnodes in the logical view, etc. |
| |
| |
| [[File_Structure_and_Templates]] |
| === File Structure and Templates |
| |
| Most project types will wish to define some aspects of how their source directories are laid out, what they contain, and what may be added to them. |
| |
| `Sources`:: Basic information about what directories are contained in the project. Technically optional—the default assumption is that the project contains just an untyped project directory—but recommended.Generic source roots refer to top-level directories containing project files. The contents of the *Files* tab is determined by these.Typed source roots refer to particular directories (which should be inside, or equal to, some generic source root) used for particular purposes. For example, roots of type `JavaProjectConstants.SOURCES_TYPE_JAVA` refer to Java package roots. Some templates need to be placed in source roots of a certain type; for example, the wizard for adding a Java source file requires a source root of type `SOURCES_TYPE_JAVA`. |
| `SharabilityQueryImplementation`:: Optionally lets the project declare that certain folders (or, perhaps, files) are not intended for sharing with other users, typically in a version control system. If your project type defines a build folder, or a folder containing private data (such as file paths on the developer’s local disk), marked in unsharable. The IDE’s VCS integration can use this information to avoid trying to commit such folders to VCS. Other IDE features may use this information too, for example to avoid searching in build folders. |
| `RecommendedTemplates`:: Optionally define categories of file templates that this project type should allow to be added. For example, a J2ME-oriented project type would probably want to exclude Swing forms and servlets, but permit MIDlets. |
| `PrivilegedTemplates`:: Defines a set of specific templates that are likely to be important to users of the project type. Used to create the default *New* submenu in the project’s context menu. |
| |
| |
| [[Building_and_Other_Actions]] |
| === Building and Other Actions |
| |
| Most project types will have some kind of actions which can be performed on the project: build it, run some program it represents, etc. |
| |
| `ActionProvider`:: A simple interface used to specify how certain “standard” |
| actions like *Build* should behave when applied to your project (e.g. from the |
| IDE’s toolbar). Such actions might run an Ant target, for example.Note that you |
| do not need to include mappings in `ActionProvider` which will be used only |
| from GUI your module provides itself. For example, you can add context menu |
| items to your project’s node that perform additional actions without going |
| through `ActionProvider.` This interface exists to permit GUI coöperation |
| between your project and the rest of the IDE. `FileBuiltQueryImplementation`:: |
| If some files have a source representation and can be somehow processed |
| individually into “built” or “compiled” versions, you want to add a |
| `FileBuiltQueryImplementation` to represent this fact. Currently only `*.java` |
| files make use of `FileBuiltQuery`, to show an out-of-date badge, though nodes |
| for other file types could be extended to do so in the future as well. |
| |
| |
| [[Java-Specific_Behavior]] |
| === Java-Specific Behavior |
| |
| Several queries are used to permit integration of various Java editing and browsing features in the IDE with the project system. Any projects which deal with Java sources should try to implement these queries. |
| |
| `ClassPathProvider`:: Important query used to specify the class path used for a Java file or source root. Without this query, much important functionality will be broken, e.g. completion in the source editor and refactoring. See its Javadoc for details on usage. |
| `SourceLevelQueryImplementation`:: Also important—instructs the editor, parser, and other IDE components what Java source level to use for a file. For example, assertions will only be recognized if the level is at least `1.4`, and generics only if at least `1.5`. |
| `SourceForBinaryQueryImplementation`:: Also an important query, as it is needed for source stepping when debugging, interproject dependencies, and other purposes. If your project’s Java sources are ever compiled to some build directory, and perhaps packed into JARs after that, you must implement this query in order for other parts of the IDE to understand where to find sources corresponding to the build product. |
| `JavadocForBinaryQueryImplementation`:: Important if you ever produce or bundle Javadoc in your project. This query enables Javadoc search to work correctly when someone is depending on classes from your project. |
| `UnitTestForSourceQueryImplementation`:: Helpful to implement in case you have unit tests in your project (typically in JUnit format). The JUnit support module will then be able to properly configure some wizards and actions. |
| |
| |
| [[Project_Dependencies]] |
| === Project Dependencies |
| |
| `SubprojectProvider`:: If you have a formal way of representing “subprojects” of your project—which might be projects physically packaged into your project, or located inside it on disk, or just used by it at build time, etc.—you can enumerate them with this interface. This is optional and is currently only used for the subproject list in the *Open Project* dialog (subprojects may be opened automatically) and for `CommonProjectActions.openSubprojectsAction`. |
| |
| |
| [[Miscellaneous]] |
| === Miscellaneous |
| |
| `ProjectOpenedHook`:: You can perform various kinds of special actions when your project is being opened or closed _in the GUI_. Remember that your project can be loaded in memory without being open, and is expected to function reasonably anyway. The Javadoc mentions various typical actions you might perform here. |
| `AuxiliaryConfiguration`:: Strongly recommended to implement if possible. Permits foreign code to store extra metadata inside your project, in XML format. Used for example to store files open in the editor from a project, and editor bookmarks. |
| `CacheDirectoryProvider`:: Also recommended to implement though not yet in use. Permits foreign code to store cache files associated with your project. |
| |
| |
| [[How_to_Write_an_Ant-Based_Project_Type]] |
| == How to Write an Ant-Based Project Type |
| |
| While a project can be written directly to the bare SPIs such as `ProjectFactory` and various interfaces (such as `SubprojectsProvider`) placed into project lookup, you may wish to reuse the basic Ant-based project infrastructure used by most IDE project types. This support SPI conveys several major benefits: |
| |
| * You do not need your own `ProjectFactory`; any folder containing a file `nbproject/project.xml` containing a project type identifier you choose will be recognized as yours. The project load and save cycle is managed for you. |
| * There is support for storing project metadata in structured ways, such as in `nbproject/project.xml` or `nbproject/project.properties`. For properties-based storage it is possible to load and evaluate multiple properties files in a rich way, and listen to dynamic changes in properties-based configuration. |
| * There is direct support for managing Ant builds (of course). You can have build script(s) generated based on `project.xml` and an XSLT stylesheet you provide. This is usually used to make an `nbproject/build-impl.xml` file containing default build steps and imported from an editable `build.xml`. |
| * There are default implementations of various queries and other interfaces needed for your lookup, such as `Sources`, loading configuration from properties files (shared by the Ant script) where appropriate. |
| * It is possible to manage references to files (such as libraries) or other projects in a structured way, with a predefined storage format, automatic synchronization to properties files, enumeration of subprojects, and a default GUI for resolving broken references. |
| |
| The following sections describe what steps you need to take in order to write an Ant-based project type, in addition to or instead of steps taken for general project types. |
| |
| For a complete example of an Ant-based project type you may wish to look at the implementation of the “general Java project” type, located in netbeans.org CVS under `java/j2seproject/` (link:http://www.netbeans.org/source/browse/java/j2seproject/[browse online]). |
| |
| |
| [[Deciding_on_a_Source_Layout]] |
| === Deciding on a Source Layout |
| |
| Ant-based projects always have an `nbproject` subdirectory in the project directory with a file `nbproject/project.xml` which identifies the project and can contain some metadata. Typically there are several other files in standard locations. See the [design.html#project-layout design document] for an overview of the general Ant-based project layout if you are not yet familiar with it, and study some actual project in the IDE such as a plain Java library project. |
| |
| Now think about layout details specific to your project type. Perhaps you want to add another properties file for some unforeseen reason; this is up to you (almost all of the Ant-based project infrastructure classes will work happily with such a setup, except perhaps for `ReferenceHelper`, described below). Certainly you will want to decide what kinds of source files reside where and in what structure. For example, for a plain Java project, the specifics of the structure are: |
| |
| 1. main Java sources in `${src.dir}`, default `${basedir}/src` or an external root; may be more than one such source directory |
| . (optional) unit test sources in `${test.src.dir}`, default `${basedir}/test` or an external root; again, may be more than one such directory |
| . (optional) JAR manifest in `${manifest.file}`, default `${basedir}/manifest.mf` |
| . `${build.dir}` (default `${basedir}/build`) holds various transient build products (e.g. compiled classes not yet packed into a JAR) |
| . `${dist.dir}` (default `${basedir}/dist`) holds the finished JAR as well as any generated Javadoc. Furthermore, you need to decide what project metadata you will store. This includes the structure of `project.xml` (and perhaps `private.xml` if you need to use it for anything), as well as a list of recognized keys and their semantics for `project.properties` and/or `private.properties`. For example, for a plain Java project, `project.xml` can specify: |
| .. the project name |
| .. a list of source roots (giving in each case the name of the Ant property specifying its actual location) |
| .. the minimum Ant version needed to build (probably `1.6`) |
| .. (optional) an explicit platform marker indicating that the build should refer to a particular JDK |
| |
| These decisions are codified in an XML schema for the `project.xml` file (link:http://www.netbeans.org/ns/j2se-project/2.xsd[example]). Currently the schema is not used for runtime validation, but that is expected to change; in the meantime, you are strongly recommended to define a schema to make sure you have clearly defined what can and cannot be stored in `project.xml`. |
| |
| Your project type does not directly control the whole `project.xml` file. Rather, the Ant-based infrastructure will manage loading, parsing, and saving it, using APIs to be described below; and you only control one section of it, called the primary configuration data. You need to select an XML element name and namespace that will identify this block. For example, general Java projects use an element `<data xmlns="link:http://www.netbeans.org/ns/j2se-project/2[http://www.netbeans.org/ns/j2se-project/2]">`. The target namespace for your XML schema should be this namespace: your schema will validate this block only, not the complete file. |
| |
| You also need to define a primary configuration data block name for `private.xml` in the `nbproject/private/` folder, whether or not you plan to write anything to this file. For example, general Java projects use `<data xmlns="link:http://www.netbeans.org/ns/j2se-project-private/1[http://www.netbeans.org/ns/j2se-project-private/1]">`. You can just define an empty schema for this block that allows no content (link:http://www.netbeans.org/ns/j2se-project-private/1.xsd[example]), or you can store real information here—some information about the project that should not be shared with other users and is not easily kept in properties files. |
| |
| Also related to `project.xml`, you need to pick a project type identifier. This is just a short string—it could be the code name base of your module—which uniquely identifies your project type. This will be stored in the `<type>` element at the top of `project.xml`. |
| |
| A Java project can likewise use a number of different Ant properties, such as `src.dir`, `main.class`, `javac.classpath`, `run.jvmargs`, etc. *(XXX link to spec when available)* You will need to decide what properties your project type will recognize and what the values should mean, while working on the build script (below). |
| |
| |
| [[Writing_a_Prototypical_Build_Script]] |
| === Writing a Prototypical Build Script |
| |
| Make a prototype of a real project—it does not need to be loadable by the IDE as a project yet, just have realistic source files and be buildable by Ant (either from the command line or through the IDE using e.g. the *Favorites* node). Write an empty `build.xml`: |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| <project name="x" default="choose-something" basedir="."> |
| <import file="nbproject/build-impl.xml"/> |
| </project> |
| ---- |
| |
| And write an `nbproject/build-impl.xml` that does the various build steps you would like the project to do. Generally it should load some properties files first, e.g. |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| <project name="x-impl" basedir=".."> <!-- note basedir is project directory --> |
| <target name="-pre-init"><!-- placeholder --></target> |
| <target name="-init-private" depends="-pre-init"> |
| <property file="nbproject/private/private.properties"/> |
| </target> |
| <target name="-init-user" depends="-init-private"> |
| <property file="${user.properties.file}"/> |
| </target> |
| <target name="-init-project" depends="-init-user"> |
| <property file="nbproject/project.properties"/> |
| </target> |
| <target name="-init" depends="-init-project"> |
| <!-- maybe some other stuff... --> |
| </target> |
| <!-- now normal targets... --> |
| </project> |
| ---- |
| |
| Note that it is conventional to begin the names of “internal” targets that should not be run directly (only as dependencies) with a hyphen (-). |
| |
| Think about which targets the user should override in `build.xml` for what purpose. It is nice to put in “placeholder” targets which by default do nothing but which can easily be overridden to insert some custom steps at a certain point in the build. |
| |
| |
| [[Selecting_Ant_Tasks]] |
| ==== Selecting Ant Tasks |
| |
| Which Ant tasks are available to you? Naturally you are free to use any standard Ant task which comes with the Ant distribution and does not require a special library to run. (Make sure you decide which version of Ant your scripts will require at a minimum—generally this will be the version currently shipped with the IDE. Later versions should work as well.) However some other tasks may require a bit of special setup. In particular: |
| |
| Bundled optional tasks requiring special libraries:: Some tasks come with Ant but require a special library in order to run. In the current design of Ant, these can only be run if the IDE includes the library directly in Ant’s main classpath. For example, the `<junit>` task runs inside the IDE without any user setup because the `org.netbeans.modules.junit` module requests that `junit.jar` be added to Ant’s classpath. Other modules may request such classpath additions by implementing `AutomaticExtraClasspathProvider`. |
| Non-bundled custom tasks:: You may wish to have your project’s build script run some Ant tasks which do not ship with Ant. (Do so only when really required, because it is annoying to users to have their build infrastructure depend on special things.) Some module (perhaps your project type module, perhaps not) must supply the task definition JAR(s): |
| |
| |
| 1. Make sure the task JAR, as well as any special libraries it may need, is installed in the IDE distribution by including it in the module’s NBM file. |
| . Define a project library of type `j2se` and place it in the `org-netbeans-api-project-libraries/Libraries/` folder of your module XML layer. Example definition (see the Project Libraries API for more details): |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| <?xml version="1.0" encoding="UTF-8"?> |
| <!DOCTYPE library PUBLIC |
| "-//NetBeans//DTD Library Declaration 1.0//EN" |
| "link:http://www.netbeans.org/dtds/library-declaration-1_0.dtd[http://www.netbeans.org/dtds/library-declaration-1_0.dtd]"> |
| <library version="1.0"> |
| <name>mytasks</name> |
| <type>j2se</type> |
| <localizing-bundle>org.netbeans.modules.thismodule.Bundle</localizing-bundle> |
| <volume> |
| <type>classpath</type> |
| <resource>jar:nbinst://org.my.module.name/ant/extra/mytasks-1.2.3.jar!/</resource> |
| </volume> |
| </library> |
| ---- |
| |
| |
| |
| . Now `build.properties` in the user directory will be populated with the actual path to the library, so you can use it in your build script: |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| <target name="-init-taskdefs" depends="-init"> |
| <!-- Assumes 1.6-style antlib is present: --> |
| <taskdef resource="org/netbeans/mytasks/antlib.xml" uri="antlib:org.netbeans.mytasks"> |
| <classpath> |
| <pathelement path="${libs.mytasks.classpath}"/> |
| </classpath> |
| </taskdef> |
| </target> |
| <target name="use-taskdefs" depends="-init-taskdefs"> |
| <mytask xmlns="antlib:org.netbeans.mytasks" someattr="true"/> |
| </target> |
| ---- |
| |
| You could also manually update `build.properties` using `PropertyUtils` to define some other property name not using the `libs._name_.classpath` format, e.g. when your project type module is restored or a project of your type is opened. Using the library manager is easier because `build.properties` is managed for you.If you wrote the task(s) for this purpose, you are _strongly recommended_ to make task source code available as open source (e.g. under the Sun Public License), so that users retain full control over all software actually used to perform their builds (besides the JDK). |
| |
| In-VM tasks present in existing modules:: NetBeans has the ability to run special Ant tasks which interact with other parts of the IDE (and cannot be run outside the IDE). A few commonly required tasks ship with the IDE; if you want to use them, declare a dependency on the module which defines them. You can refer to the tasks by simple name, but when using Ant 1.6+ it is preferable to use the correct “antlib” namespace. (Note that when prototyping a build script you can use the IDE’s code completion for attributes and subelements of these tasks.) |
| Web browser integration (`antlib:org.netbeans.modules.browsetask)`:: `<nbbrowse>` lets you open the IDE’s configured web browser on a given URL (or file). |
| JPDA debugger integration (`antlib:org.netbeans.modules.debugger.jpda.ant`):: `<nbjpdastart>` asks the IDE’s debugger to start listening on a new JPDA port, and define an Ant property with the port so you can launch a Java process which will connect to that port as a client. `<nbjpdaconnect>` connects to an existing port; more useful for server applications. `<nbjpdareload>` reloads Java classes using “fix & continue” technology. |
| Custom in-VM tasks:: You can also define your own in-VM tasks and use them the same way as the predefined ones. See the link:https://bits.netbeans.org/dev/javadocAntModuleAPI/org/apache/tools/ant/module/spi/package-summary.html#register-defs[Ant SPI] for details. |
| |
| |
| [[Parametrizing_Build_Scripts]] |
| === Parametrizing Build Scripts |
| |
| Some project types have several variants for `build-impl.xml`, parametrized somehow. For example, plain Java projects behave a little differently depending on whether you are building and running against the “default platform” (the IDE’s own JDK) or an explicit JDK. The former case might look like (excluding irrelevant details): |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| |
| <target name="compile"> |
| <javac srcdir="..." destdir="..." classpath="..."/> |
| </target> |
| ---- |
| |
| whereas the latter case might look like: |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| |
| <target name="compile"> |
| <javac srcdir="..." destdir="..." classpath="..." fork="true" executable="..."/> |
| </target> |
| ---- |
| |
| The rule of thumb here is simple. _If some aspect of the build can be parametrized using Ant properties in a straightforward way using the Ant tasks you have available, do so._ For example, there is no need to create a different `build-impl.xml` just to change the build directory; this can be done using a property: |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| |
| <target name="compile"> |
| <javac srcdir="..." destdir="${build.classes.dir}" classpath="..."/> |
| </target> |
| ---- |
| |
| But in other cases, this is not possible. For example, Ant’s `<junit>` task can take a `jvm` attribute to specify an explicit JDK to run against. If you include this attribute, you have to set the JDK. When using the default platform, this attribute must not be there; when using an explicit platform, it must be there. Therefore `build-impl.xml` needs to be a bit different in these two cases (unless you included both versions in different targets and switched between them at runtime, though this can cause bloat in the build script). Build prototype scripts using all the variants you expect to encounter and verify that they all work the way you want. |
| |
| Now to go back to `project.xml` for a moment: whatever variations in `build-impl.xml` you wish to support must be codified as metadata in `project.xml`. For example, a plain Java project can include an `<explicit-platform>` element or not; the presence or absence of this element determines which `build-impl.xml` variant is produced. |
| |
| |
| [[Writing_Stylesheets]] |
| === Writing Stylesheets |
| |
| When you are satisfied with the `build-impl.xml` you have drafted (perhaps in multiple variants), it is time to write an link:http://www.w3c.org/TR/xslt[XSLT stylesheet] which produces it. The input to the stylesheet is the `project.xml` file and the output is the build script. Typically you will just copy most of the prototype build script verbatim into the stylesheet as the default content. You will also want to examine the `project.xml` input at least for a project name, and optionally also for any other information you need to construct different build script variants. For example, with a `project.xml` looking like this: |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| |
| <project xmlns="link:http://www.netbeans.org/ns/project/1[http://www.netbeans.org/ns/project/1]"> |
| <type>org.netbeans.modules.myprojecttype</type> |
| <configuration> |
| <data xmlns="link:http://www.netbeans.org/ns/my-project-type/1[http://www.netbeans.org/ns/my-project-type/1]"> |
| <name>Test Project</name> |
| <style>first</style> <!-- whatever this means to you --> |
| </data> |
| </configuration> |
| </project> |
| ---- |
| |
| You might have a stylesheet like this: |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| |
| <xsl:stylesheet version="1.0" |
| xmlns:xsl="link:http://www.w3.org/1999/XSL/Transform[http://www.w3.org/1999/XSL/Transform]" |
| xmlns:p="link:http://www.netbeans.org/ns/project/1[http://www.netbeans.org/ns/project/1]" |
| xmlns:xalan="link:http://xml.apache.org/xslt[http://xml.apache.org/xslt]" |
| xmlns:myproj="link:http://www.netbeans.org/ns/my-project-type/1[http://www.netbeans.org/ns/my-project-type/1]" |
| exclude-result-prefixes="xalan p myproj"> |
| <xsl:output method="xml" indent="yes" encoding="UTF-8" xalan:indent-amount="4"/> |
| <xsl:template match="/"> |
| <xsl:comment><![CDATA[ |
| *** GENERATED FROM project.xml - DO NOT EDIT *** |
| *** EDIT ../build.xml INSTEAD *** |
| ]]></xsl:comment> |
| <xsl:variable name="name" select="/p:project/p:configuration/myproj:data/myproj:name"/> |
| <xsl:variable name="codename" select="translate($name, ' ', '_')"/> |
| <project name="{$codename}-impl" basedir=".."> |
| <!-- ... --> |
| <target name="shows-variants"> |
| <xsl:variable name="style" select="/p:project/p:configuration/myproj:data/myproj:style"/> |
| <xsl:choose> |
| <xsl:when test="$style = 'first'"> |
| <do-one-thing-in-ant/> |
| </xsl:when> |
| <xsl:when test="$style = 'second'"> |
| <do-another-thing-in-ant/> |
| </xsl:when> |
| <xsl:otherwise> |
| <!-- error --> |
| </xsl:otherwise> |
| </xsl:choose> |
| </target> |
| </project> |
| </xsl:template> |
| </xsl:stylesheet> |
| ---- |
| |
| _Remember_ that { and } in attribute values have a special meaning in XSLT: if you want to use braces literally, e.g. for Ant property references, double them, e.g. |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| |
| <!-- this is in XSLT: --> |
| <target name="something"> |
| <mkdir dir="${{build.classes.dir"/> |
| <!-- ... --> |
| </target> |
| ---- |
| |
| You will also want a stylesheet to generate `build.xml`, though typically this is quite simple: |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| <xsl:stylesheet version="1.0" |
| xmlns:xsl="link:http://www.w3.org/1999/XSL/Transform[http://www.w3.org/1999/XSL/Transform]" |
| xmlns:project="link:http://www.netbeans.org/ns/project/1[http://www.netbeans.org/ns/project/1]" |
| xmlns:myproj="link:http://www.netbeans.org/ns/my-project-type/1[http://www.netbeans.org/ns/my-project-type/1]" |
| xmlns:xalan="link:http://xml.apache.org/xslt[http://xml.apache.org/xslt]" |
| exclude-result-prefixes="xalan project myproj"> |
| <xsl:output method="xml" indent="yes" encoding="UTF-8" xalan:indent-amount="4"/> |
| <xsl:template match="/"> |
| <xsl:comment> You may freely edit this file. See commented blocks below for </xsl:comment> |
| <xsl:comment> some examples of how to customize the build. </xsl:comment> |
| <xsl:comment> (If you delete it and reopen the project it will be recreated.) </xsl:comment> |
| <xsl:variable name="name" select="/project:project/project:configuration/myproj:data/myproj:name"/> |
| <xsl:variable name="codename" select="translate($name, ' ', '_')"/> |
| <project name="{$codename}"> |
| <xsl:attribute name="default">default</xsl:attribute> |
| <xsl:attribute name="basedir">.</xsl:attribute> |
| <description>Builds, tests, and runs the project <xsl:value-of select="$name"/>.</description> |
| <import file="nbproject/build-impl.xml"/> |
| <xsl:comment><![CDATA[ |
| You could add descriptions of overridable targets here, or just link to online help... |
| ]]></xsl:comment> |
| </project> |
| </xsl:template> |
| </xsl:stylesheet> |
| ---- |
| |
| You can fine-tune the XSLT for your build scripts, as well as the `project.xml` format and the list of Ant properties you want to recognize, _without writing one line of NetBeans module source code_. (Just run `project.xml` through your stylesheets to see the output, using any XSLT tool, such as that built into the NetBeans IDE.) All you are doing at this stage is defining some metadata for the project and verifying that Ant scripts generated from it do indeed build and run an example project the way you want. |
| |
| |
| [[Writing_the_Project_Type_Skeleton]] |
| === Writing the Project Type Skeleton |
| |
| Now it is time to begin writing the project type provider module proper. First you will need an implementation of `AntBasedProjectType` which registers your project type in the system. (Place this implementation in default lookup, e.g. using the `META-INF/services/` section of your module JAR.) The project type class does not do much except report the project type identifier, and the local name and namespace used for the shared and private primary configuration data blocks (in `project.xml` and `private.xml`). The `createProject` method must create a particular project object; it is passed an `AntProjectHelper` object which gives you access to a variety of different Ant-based project functionality in a convenient way. You can immediately throw an `IOException` in case there is something badly wrong with the project on disk; a future version of NetBeans should also let you perform XML validation on `project.xml` at this time (cf. #42686). |
| |
| You will need a separate class for the `Project` implementation, which will usually hold onto the instance of `AntProjectHelper` and use it to service requests. |
| |
| Another common thing to set up in your project’s constructor is a property evaluator, which can load the current values of various properties from `project.properties`, `private.properties`, and `build.properties`, using Ant’s property evaluation semantics, and notify you of changes even in specific properties. A `PropertyEvaluator` instance is also a required parameter for many convenience factory methods and constructors in the Ant-based project support. Many projects can just call `AntProjectHelper.getStandardPropertyEvaluator()` to load properties from these three files in the usual way. If you have other property files your build script loads, or default values set in the build script, you can make a custom evaluator using factory methods in `PropertyUtils`—but beware that `ReferenceHelper` expects the standard semantics (so that it can store relative paths in `project.properties` and absolute paths in `private.properties`) and so may not work appropriately if you have a very different property loading model. |
| |
| The project should create a `Lookup` containing its particular abilities and return this from the `getLookup()` method. Normally `Lookups.fixed` is adequate for this purpose. In principle a project’s lookup could change dynamically, but this is not normally required. More information on what to put in the lookup can be found below. |
| |
| |
| [[Handling_Build_Script_.28Re-.29generation]] |
| === Handling Build Script (Re-)generation |
| |
| The normal way that `build.xml` and `build-impl.xml` are created is that these files are automatically generated whenever they are missing; and regenerated when they are out of date relative to the current XSLT stylesheet and `project.xml`, _but_ not modified by the user. (`private.xml` is not considered: since it is per-user, the shared build script cannot be changed according to its contents.) Note that `build-impl.xml` is not _supposed_ to be modified by the user, but at least if it is, those modifications will never be clobbered. `build.xml` can be modified, so if it is, it will not be regenerated; however it is not likely to need regeneration often or at all. |
| |
| To configure the normal (re-)generation semantics, make sure your project’s lookup contains: |
| |
| |
| |
| . A `ProjectXmlSavedHook`, used when `project.xml` is modified and saved. |
| . A `ProjectOpenedHook`, used when the project is opened. |
| |
| The Javadoc for `GeneratedFilesHelper.refreshBuildScript` describes the recommended parameters that should be passed to it from these two hooks. Remember that your XSLT stylesheets should be packaged in the module JAR so they can be passed to this method. |
| |
| Other kinds of behavior are possible; check the `GeneratedFilesHelper` Javadoc for more information. You could also produce Ant build scripts using some method other than XSLT transformations (e.g. manual DOM manipulation), but `GeneratedFilesHelper` will not currently (#42735) help you determine whether the scripts are modified or out of date if you do this, so you would need to write this logic yourself. |
| |
| |
| [[Populating_the_Project_Lookup]] |
| === Populating the Project Lookup |
| |
| *PENDING* |
| |
| |
| [[Creating_a_Properties_Dialog]] |
| == Creating a Properties Dialog |
| |
| *PENDING* |
| |
| |
| [[Handling_Upgrades]] |
| == Handling Upgrades |
| |
| *PENDING* |
| |
| |
| [[How_to_Use_Project-Related_APIs_from_Other_Modules]] |
| == How to Use Project-Related APIs from Other Modules |
| |
| *PENDING* |
| |
| |
| [[Some_Interesting_Things_which_are_Impossible]] |
| == Some Interesting Things which are Impossible |
| |
| There is no general API for accessing project settings from the outside, and anyway it comes in various forms depending on the particular project type. For example, J2SE projects currently let you configure a main class, a working directory, etc. These things make no sense for web applications. Conversely, context root is critical for a web application but senseless for a J2SE project. There are no plans to ever have a general API for accessing this kind of project configuration from the outside. |
| |
| Someday there may be an SPI for plugging in natures (behaviors for a project), in response to accumulated feedback and experience from people trying to do this sort of thing (e.g. the JFluid project); currently there are no plans for it. The project type is currently expected to directly handle all of the significant build/run scenarios which it could support, such as running, debugging, and unit testing. |
| |
| Currently the JFluid module accomplishes its profiler integration for a fixed list of known project types by relying on knowledge of the disk layout and file formats of those project types, and either running the app directly based on settings read in this way, or generating auxiliary Ant scripts in `nbproject/` which can launch the app with specialized parameters in addition to the normal properties-file-based settings. |
| |
| Note that you can use e.g. `ClassPath.getClassPath(FileObject)` to find various classpaths which the project claims it uses to build or run the app. How the project actually builds or runs the app is its own business; the API-exposed information is intended for use in code completion, refactoring, and similar development-time-only features, and is intentionally the bare minimum information required for these features. For example, getting the classpath for a _particular_ source root contained in the project is exposed, since the editor and refactoring features need this. Getting the main class of the project (if there is such a thing) is not exposed, since they do not. |
| |
| |
| [NOTE] |
| ==== |
| |
| The content in this page was kindly donated by Oracle Corp. to the Apache Software Foundation. |
| |
| This page was exported from link:http://wiki.netbeans.org/BuildSystemHowTo[http://wiki.netbeans.org/BuildSystemHowTo] , that was last modified by NetBeans user Jglick on 2010-02-19T17:17:47Z. |
| |
| This document was automatically converted to the AsciiDoc format on 2020-03-12, and needs to be reviewed. |
| ==== |