Compiling Java programs

This chapter covers:


Overview of compiling

The JBuilder compiler has full support for the Java language, including inner classes and JAR files. You can compile from within the IDE, or from the command line using bmj (Borland Maker for Java) or bcj (Borland Compiler for Java).

A Java compiler reads Java source files, determines which additional files need to be compiled, and produces the Java program in the form of .class files containing bytecodes that are the machine code for the Java Virtual Machine (VM). Compiling produces a separate .class file for each class declaration and interface declaration in a source file. When you run the resulting Java program on a particular platform such as Windows NT, the Java interpreter for that platform runs the bytecodes contained in the .class files. The just-in-time compiler is a different type of compiler. The just-in-time compiler for a given platform rapidly converts the bytecodes from the Java VM format to the platform's machine code, as the Java program runs.

For additional general information about compiling in Java, see the overview of the compiler that comes with the Java Development Kit (JDK), javac - The Java Compiler.

The following parts of a project can be compiled:

Smart Dependencies Checking

JBuilder provides fast yet complete compiling by using Smart Dependencies Checking, which results in fewer unnecessary compiles of interdependent source files, and thus accelerates the edit/recompile cycle. When compiling, instead of deciding whether to recompile a source file based only on the time stamp of the file, JBuilder analyzes the nature of the changes you make to source files. A source file is recompiled only if it uses (or depends on) a particular element that has changed within another source file. A class uses another class when it calls a method in another class, uses (imports) a variable in another class, extends a class, or implements an interface.

When you compile source files for the first time, a dependency file is automatically created for each package, and is placed in the output directory along with the class files. The dependency file contains detailed information about which class uses which, for all the classses in that package.

Pre-generated dependency files are provided for the JDK and JBCL libraries, in the same place as the class files for those libraries.

The compiler must be able to find the dependency files; they must be in the classpath. When you compile from within the IDE, this classpath is correctly set, by default. Otherwise, you might need to run setvars.bat. See Using the Command-Line Tools: Setting environment variables for command-line tools.

Smart Dependencies Checking is used by the compiler in the IDE and by the bmj command-line compiler, but not by the bcj command-line compiler.


Types of compiling

There are two commands for compiling on the Build menu. The Make command compiles the selected node, if it has changed, and compiles any imported files, if they have changed. During routine iterations of the edit/recompile cycle, Make is the recommended command. The Rebuild command compiles the selected node and its imported files, regardless of whether they have changed, so it takes longer than Make. Rebuild ensures that the project options are applied to all classes that are referenced by the selected nodes.

The node can be a project, a package, or a .java file. Packages lower in the project tree hierarchy are built before packages higher in the hierarchy.

These commands are described in greater detail below.

The Make command

Build | Make compiles any .java files within the selected node that have outdated or nonexistent .class files. The Make command also compiles any files imported by the node that have outdated or nonexistent .class files.

The selected node can be a project, package, or .java file. Making a package or project includes all the .java files within the package or project, including those within nested packages.

Make is faster than Rebuild, once you have done the initial compiling. The Make command is generally preferred over Rebuild.

An "outdated" .class file is one that was not generated by compiling the current version of its .java source file.

The imported files that are checked and compiled include all recursively imported files (that is, imported files of imported files) except for files that are not in packages in the current project, such as files in packages that are marked "stable".

To Make a node, select the node in the Navigation pane, and choose Build | Make <node name>.

Issuing Save and then Make on a file won't necessarily cause the file to be recompiled, because the date-time stamp reflects the last edit action, not the last save. To force a recompile, either use Build | Rebuild, or make a change to the file in the editor before saving it. For example, type a space and then a backspace.

The Rebuild command

Build | Rebuild compiles all .java files within the selected node, regardless of whether their .class files are outdated. The Rebuild command also compiles the imported files, regardless of whether their .class files are outdated. Project options, such as Obfuscate, are applied to all files as they are compiled.

The selected node can be a project, package, or .java file. Rebuilding a package or project includes all the .java files within the package or project, including those within nested packages.

The imported files that are compiled include all recursively imported files (that is, imported files of imported files) except for files in the stable packages that are not part of the project.

To Rebuild a node, select the node in the Navigation pane, and choose Build | Rebuild <node name>.


Compiling a program

To compile the .java files for an application or applet:
  1. Open the project containing the program, or open a single Java file.
  2. In the Navigation pane, do one of the following:
  3. Do one of the following:

Any error messages are displayed in the status pane that is added to the AppBrowser below the Content pane. Select an error message to display the associated source code.

After a successful build, you can run and debug your program.

Checking for package/directory correspondence

JBuilder provides protective checking for duplicate class definitions in a project and for package/directory correspondence. The IDE and bmj compilers verify that the package statement in a source file corresponds to the package directory, and verify that two source files do not define the same class.

The first time you build a project, all the available .java files in a package directory will be verified and compiled. If you have temporary sources that are not compilable, you should use another extension besides .java. For example, if the project contains an old version of a file you are working on, containing another definition of the same class, you'll get a "duplicate class definition" error. This reinforces the package conventions defined in the Java Language Specification (http://www.javasoft.com:80/docs/language_specification/7.doc.html). This checking prevents subtle problems that would be difficult to locate.

If you are using a class library that is partly inconsistent and you don't have the sources to rebuild the library, you can avoid verifying all classes of the package, and check only the classes that are actually used, by specifying the -nomakestable compiler option on the command line. When you compile from within the IDE, the nomakestable option cannot be used, but you can generate a dependency file from the command line, and that dependency file will be used by the IDE.

Selectively compiling stable packages

Packages of common libraries, such as java.lang, sun.io, or borland.jbcl.control, will usually not be modified, so it is usually unnecessary to take the time to recheck them for consistency every time you compile. To prevent these libraries from being checked every time you compile, these packages are marked "stable". When all classes of a package have been successfully compiled, the package is considered "stable" and a flag is set in the dependency file. When only some classes of a package have been compiled, or if an error occurred, then the package remains marked "unstable".

Stable packages won't be checked for consistency when you compile from within the IDE, or if you specify the -nocheckstable option for the bmj command-line compiler. When compiling from the IDE, the -nocheckstable option is always implicitly specified. As a result, stable packages are not checked for being up-to-date. However, if a package is included in your project, or if at least one source file in the package is included in your project, that package will be marked "unstable" and will thus be checked at every recompilation (that is, every time you do Build|Make).

In the IDE, if a package is marked "stable" but you are editing a file of that package outside of the IDE (using a different editor), it's best to include that package in the project so it is checked for recompiling. In the IDE, the compiler does not check packages marked "stable" to see if they are up to date, unless they are part of the project.


Setting compiler options

You can specify compiler options for the current project. The options are applied to files in the project tree. The options are also applied to files referenced by these files, stopping at packages which are marked "stable" and have no classes in the project tree.

To set compiler options in the IDE:

The scope of project-wide settings

If you change the option settings, you should fully Rebuild your packages or your entire project, and not just Make them. The project options are applied to any class being rebuilt, outside the project tree as well as inside the project tree. For example, if you set obfuscation on some classes and compile them in one project, then in another project reference those same files without obfuscation, but do a Rebuild All, you will un-obfuscate them.

You cannot set compile options per file; a file can be used by two projects, both of which have different settings for compiling. Applying options on classes or packages individually is not supported, because there is no separate compilation of headers and modules in Java. If some import information is missing (such as a class file), the imported class is compiled at the same time as the importing class, using the same project-wide options.

See also:
Getting Started: Options for the command-line compiler
User's Guide online: The bmj and bcj command-line compilers

Setting the sourcepath, classpath, and outpath

JBuilder places the .class files in the OUTPATH directory, in a directory tree that matches the arrangement of the source directories. If the output directory does not exist yet, it is automatically created.

The CLASSPATH environment variable specifies the location for your .class files. The compiler needs to know where .class files are, to check whether they are outdated and need to be recompiled. The compiler looks in the SOURCEPATH for a source file, to determine whether each source file needs to be recompiled to bring the .class files up to date.

See also:
User's Guide online: The bmj and bcj command-line compilers

Adding symbolic debug Information

To add symbolic debug information at compile time:

When you compile, make, or rebuild a node, symbolic debug information will be included in the .class file.


Compiling from the command line

You can compile from the command line using the bmj or bcj commands.

bmj
bmj is the Borland Maker for Java. bmj compiles any .java files within the selected node that have outdated or nonexistent .class files. bmj also compiles any imported classes that have outdated or nonexistent .class files.

bmj looks for dependency files on the classpath, and does dependencies checking. If you specify a set of sources, some or all of those sources might not be recompiled. For example, the class files might be determined to be up to date, if they have been saved but not edited since the last compile. You can force recompilation using the -rebuild option.

To check a set (or "graph") of interdependent modules, it is sufficient to call bmj on the root source (or multiple root sources, if one is not under the other). You can specify this argument using source names, package names, class names, or a combination.

bcj
bcj is the Borland Compiler for Java. bcj compiles the specified sources, whether or not their .class files are outdated. Also compiles any directly imported .java files that do not have .class files. Imported .java files that already have .class files will not be recompiled, even if their .class files are outdated; after using bcj, some imported classes might still have outdated .class files.

bcj does not do dependencies checking, and does not use or generate a dependency file. bcj only compiles the items you specify, and only compiles the imported classes which have no .class file yet.

To see the syntax and list of options, type bmj or bcj at the command line.

You might need to run setvars.bat to set the environment variables for the command line, so the required classes are found.

See also:
Getting Started card: Options for the command-line compiler
User's Guide online: The bmj and bcj command-line compilers
User's Guide: Command-line tools: Setting environment variables for command-line tools

Switching between the command line and IDE

If you edit a file outside the IDE, be sure to include its package or at least one of that package's sources in your project, so that the package is considered "unstable", and thus is checked when you compile. Otherwise, the change will not be detected, and the source won't be recompiled.

The default setting at the command line is to check consistency for referenced classes, regardless of whether their packages are marked "stable" or "unstable". That is, the option -nocheckstable is not specified by default on the command line.


Specifying a native encoding

You can specify an encoding name such as EUCJIS to control how the compiler interprets characters beyond the ASCII character set. If no setting is specified for this option, the default native-encoding converter for the platform is used.

To set the encoding option, do one of the following:

Non-Unicode environments represent characters using different encoding systems. In the PC world, these are known as codepages; Java refers to them as native encodings. When moving data from one encoding system to another, conversion needs to be done. Since each system can have a different set of extended characters, conversion is required, to prevent loss of data.

Most text editors, including JBuilder's editor, write text out in the native encoding. For example, Japanese Windows uses the Shift-JIS format, and US Windows uses Windows Codepage 1252. Starting with JDK 1.1, javac is also able to compile "native-encoded" source code. The encoding can be specified by using the "encoding" switch. When the encoding is not specified, the compiler uses the encoding based on the user's environment. Unlike Unicode, source code written with native encoding is not directly portable to systems using other encodings. For example, if source code has been encoded in Shift-JIS (a Japanese encoding), and you are running the compiler in a US Windows environment, you must specify the Shift-JIS encoding for the compiler to read the source correctly.

The JBuilder and javac compilers are able to compile source code encoded in native encodings (also known as local codepages), which is the storage format used by most text editors, including the JBuilder editor.

Under Western European versions of Windows, including the United States version, the javac and JBuilder compilers assume the encoding of 8859_1, even though the actual encoding should be Cp1252. Cp1252 contains some characters that are not in 8859_1. If your source file contains these additional characters, they will not be correctly interpreted. In this case, you should specify Cp1252 as the encoding.

Native encodings supported


8859_1
8859_2
8859_3
8859_4
8859_5
8859_6
8859_7
8859_8
8859_9
Big5
CNS11643
Cp1250
Cp1251
Cp1252
Cp1253
Cp1254
Cp1255
Cp1256
Cp1257
Cp1258
Cp437
Cp737
Cp775
Cp850
Cp852
Cp855
Cp857
Cp860
Cp861
Cp862
Cp863
Cp864
Cp865
Cp866
Cp869
Cp874
EUCJIS
GB2312
JIS
KSC5601
MacArabic
MacCentralEurope
MacCroatian
MacCyrillic
MacDingbat
MacGreek
MacHebrew
MacIceland
MacRoman
MacRomania
MacSymbol
MacThai
MacTurkish
MacUkraine
SJIS
Unicode
UnicodeBig
UnicodeLittle
UTF8

Two encoding names have special meaning:

null
Specifies that no native-encoding conversion should be done. Each byte in the file is converted to Unicode by setting it to the lower byte of the Unicode character. The upper byte of the Unicode character is set to zero.
default
Equivalent to not specifying an encoding option. This uses the default encoding of the user's environment.

For a description of each encoding, see the JDK Internationalization Specification: Character Set Conversion: Supported Encodings (http://www.javasoft.com:80/products/jdk/1.1/intl/html/intlspec.doc7.html). The following descriptions supplement that section:

Unicode
Unicode, with big or little endian indicated by Byte-Order-Mark.
UnicodeBig
Big-Endian Unicode.
UnicodeLittle
Little-Endian Unicode.

The 16-bit Unicode format

Unicode is a universal system of representing characters using 16-bit numbers. The 16-bit Unicode character set can be supported directly, or can be represented indirectly within the 7-bit ASCII character set, using the \u escape character followed by four hexadecimal digits.

When all major operating environments directly support Unicode, this will replace the established approach, which requires conversion between different native encodings with conflicting character values. Java is one the first environments to standardize on Unicode; Unicode is the internal character set of the Java environment.

Unicode support using ASCII and '\u'

Currently, most Windows text editors, including JBuilder's editor, store and process text as 7- or 8-bit characters, rather than 16-bit Unicode characters. The ASCII character set uses a 7-bit encoding that contains the 26 letters of the English alphabet and some symbols. Almost all native encodings have ASCII as a subset, and represent it in the same way: the first 127 characters of an encoding are the ASCII character set. The ASCII character set can be considered a subset of Unicode.

To enable users to specify Unicode characters in their source code without a Unicode-enabled editor, the Java specification allows the use of the \u "Unicode escape" in an ASCII file. This usage enables extended characters to be represented by a combination of ASCII characters. This way of representing Unicode uses 6 characters to represent each non-ASCII character. To enter an ordinary ASCII character, you press the character's key on the keyboard, and to enter a non-ASCII character, you type in the Unicode escape sequence representing the character.

In this 7-bit representation of Unicode, each character beyond the ASCII character set is represented in the form \uNNNN, where NNNN are the 4 hex digits of the Unicode character. For example, the Unicode character "Latin Small Letter F with Hook", a cursive 'f' which is represented in Unicode with the hexadecimal number 0192, can be entered by typing "\u0192".

Unicode, in both the 16-bit and 7-bit forms, is in a universal format; source code in Unicode is directly portable to all platforms, in all languages.


Running applets

If you run an applet from within the IDE, the HTML file is able to find the class file, even though the class file is in a different directory. The HTML file usually resides in the myprojects tree, while the corresponding class file resides in the myclasses tree. The CODEBASE parameter in the <APPLET> tag usually does not need to be defined.

To run an applet from within the IDE:

  1. Select the HTML file that contains the APPLET tag.
  2. Choose Run|Run.

The HTML file might need to specify a package name prefix in addition to a class name:
CODE="somePackage.SomeClass.class"

See also Using the command-line tools: Running applets from the command line.