When NetBeans 5.5 was released in late 2006, it radically changed its
own value proposition by offering first-class support for a language that
doesn’t run inside a JVM. The NetBeans C/C++ pack provided to C/C++ programmers
most features Java developers were already used to: advanced source editing
with syntax highlighting and code completion, built-in CVS support, hyperlinks
to navigate function declarations, a class hierarchy browser, an integrated
debugger, and integration with the make tool.
This article
focuses on how the C/C++ pack can help Java developers. Although I’m sure you
all would like to code the whole world in pure Java, reality frequently
challenges us to interface with native code, be it legacy systems, a device
vendor SDK or a high-performance math library. Also, sometimes we need to use
native code to improve the user experience, by means of tighter integration
with the underlying operating system. Wouldn’t it be better to do all this from
the same IDE we already use for Java development?
We’ll show how
to leverage NetBeans and the C/C++ Pack to develop portable native libraries
using C/C++, and how to integrate them with Java code in a way that eases
deployment in multiple platforms.
NetBeans C/C++
Pack is more than just C/C++ coding support for the Java developer. It also
suits many native code projects very well. The sidebar “Other open
source C/C++ IDEs” compares the Pack with some popular open-source
IDEs for C/C++.
Installing
NetBeans C/C++ Pack
Installing the
C/C++ Pack per se will be a no-brainer for most users. No matter if you’ve
installed the NetBeans IDE using the zip package or one of the native
installers, you only need to run C/C++ Pack’s installer and point it to your
NetBeans IDE installation directory. (Note that, although the C/C++ Pack is
mostly Java code with just one tiny native library, there’s no multiplatform
zip archive like the ones provided for the IDE.)
The installer
itself will work the same for all supported platforms: Windows, Linux and
Solaris. But configuring your environment for using C/C++ Pack may not be so
easy. Just like the core NetBeans IDE needs a compatible JDK installation, the
C/C++ Pack will require a C/C++ compiler and standard libraries and headers. So
you need to install and configure these in advance.
To meet the
Pack’s prerequisites, we’ll rely on the popular suite formed by the GNU C
Compiler (GCC), GNU Binutils, GNU Make and GNU Debugger (GDB). This is the
suite that received most of the QA effort of the C/C++ Pack developer team1, and it’s portable to Windows, Linux
and Solaris environments.
Using the same
compiler suite for all platforms greatly simplifies dealing with portable (and
even non-portable) C/C++ code, as you won’t need to spend time fighting
compiler directives, runtime library inconsistencies and language dialects.
Besides, you’ll find that in most cases the GNU toolset competes head-to-head
with other C compilers in both speed and optimization quality.
1 The only other compiler suite supported so far is the Sun Studio product for Solaris
and Linux.
Installing
the GNU toolset on Linux
Linux users
should have no problem obtaining the GNU toolset for their preferred platform.
Mine is Fedora Core 6, and as I installed a “development workstation” using
Anaconda I already had everything ready for NetBeans C/C++ Pack. Users who
didn’t install Linux development tools when configuring their systems should
have no problem using either yum, up2date, yast or apt to install the GNU toolset.
Stay clear of CD-bootable mini-distros
like Knoppix for real development work. Instead, install a full-featured distro
in a native Linux partition in your main hard disk. The few additional
gigabytes used will prove to be a small cost for all the hassle you’ll avoid.
Solaris users
will also find it easy to install the GNU toolset; there are detailed
instructions on the NetBeans Web site. But be warned: if you think you’d be
better served by the native platform C compiler (Sun Studio), think again. This
is because NetBeans C/C++ Pack’s debugger needs the GNU Debugger, and
GDB has some issues running code generated by Sun compilers. So you can use
Sun’s compiler to produce final code, but you’d better use the GNU toolchain
for development.
Installing
the GNU toolset on Windows
Windows users
won’t be able to use native C/C++ compilers from Microsoft, Borland or Intel,
and will have to stick with a Windows port of the GNU toolset. There are two
options: Cygwin
and MinGW.
The C/C++
Pack’s docs at netbeans.org provide detailed instructions for using
Cygwin, but I strongly advise you to use MinGW instead. The reason is that
Cygwin relies on a Unix emulation layer, while MinGW uses native Windows DLLs
for everything. Code compiled with Cygwin uses the standard GNU runtime library
(glibc) on an emulation of Unix system calls, and semantics like mount
points, pipes and path separators. But code compiled with MinGW will use
standard Microsoft runtime libraries such as MSVCRT.DLL.
Cygwin has its
uses, as many Linux and Unix software (specially open-source software) that has
not yet been ported to Windows is easy to run under Cygwin without
virtualization overhead. But I doubt you’d want to compromise stability and
compatibility with the native platform when developing native libraries for use
with Java applications. So MinGW is the way to go. The sidebar “Installing MinGW” provides detailed instructions.
Checking
prerequisites
Whatever your
platform of choice, you need access to the GNU toolset from your operating
system command prompt. It may be necessary to configure the system PATH before
using NetBeans C/C++ Pack. You can check that you have all prerequisites are
available before proceeding by using the commands
displayed in Figure 1. (Although this figure shows a Windows command
prompt, you’ll be able to run the same commands from either the Linux or
Solaris shells.) If you get software releases older than the ones shown,
consider upgrading your GNU toolset.
 |
Figure 1. Verifying that the GNU toolset is installed and configured correctly, and is using compatible releases. |
When pure
Java
is not enough
Now that you have NetBeans C/C++ installed
and its prerequisites configured, let’s present this article’s use case. You’re
developing a desktop Java application with cryptographic features, which saves
sensitive data such as key rings and private keys in a local file system
folder. You want to be sure that only the user who’s running the application
can read (and of course write) files to that folder.
The standard Java libraries provide methods
in the java.io.File class for checking if a
file can be read or written by the current user, but these methods don’t check
if other users can also read or write the same files. There are new methods in
Java SE 6 that deal with file permissions, and work in progress under JSR 293;
but if your application has to support Java 5 or 1.4, there’s no escaping from
native code. So our application will use native system calls to verify local
folder permissions during initialization, and refuse to start if it finds the
folder is not secure.
Java doesn’t provide an easy way to declare
external methods, like Free Pascal or Visual Basic, but it does of course
provide the Java Native Interface, a standard and portable way to call native
code from Java and vice versa. With the above use case in mind, we have to
design an abstraction that hides platform details and the corresponding native
code from the higher application layers. In the end, the apparent complexity of
dealing with JNI may actually be an advantage, because it forces us to design
the interface between Java and native code, instead of just going ahead and
invoking operating system APIs directly.
The Java wrapper code
Let’s get our feet wet. Start NetBeans,
create a Java Class Library Project, and name it “OSlib”. This project will
contain all interfaces between our hypothetical application and the native
operating system. Then create a new class named “FilePermissions”, with the
code shown in Listing 1.
Listing 1. FilePermissions.java – Utility class with a native method.
|
package org.netbeans.nbmag3.util;
import java.io.File;
public class FilePermissions {
static {
System.loadLibrary("NativeOSlib");
}
public FilePermissions() {}
// Checks if a file or folder can only
// be read/written by the current user
public static native boolean isPrivate(String path);
}
|
The native keyword, you’ll remember, means that the method’s implementation will be
provided by a native dynamic library. That library in our code is loaded by a
static initializer in the class itself.
Following Test-Driven Development practices,
I’ll create unit tests instead of creating a test application for the OS
interface. Right click Test Packages in the Projects window and select New>Test
for Existing Class to generate a skeleton for testing the native method.
Then change this skeleton to make it look like Listing 2.
Listing 2. Unit tests for FilePermissions native methods
|
FilePermissionsTest.java
-------------------------------------------------------------------------------------------------
package org.netbeans.nbmag3.util;
import java.util.Properties;
import junit.framework.*;
import java.io.File;
public class FilePermissionsTest extends TestCase {
Properties paths = null;
public FilePermissionsTest(String testName) {
super(testName);
}
protected void setUp() throws Exception {
paths = new Properties();
paths.load(this.getClass().getResourceAsStream("/paths.properties"));
}
protected void tearDown() throws Exception {}
public void testIsPrivateOk() {
String fileName = paths.getProperty("FilePermissions.test.privateOk");
assertTrue("File does not exist", new File(fileName).exists());
boolean result = FilePermissions.isPrivate(fileName);
assertEquals(true, result);
}
public void testCanReadButNotWrite() {
boolean result = FilePermissions.isPrivate(
paths.getProperty("FilePermissions.test.readButNotWrite"));
assertEquals(false, result);
}
public void testCanBeReadByOthers() {
boolean result = FilePermissions.isPrivate(
paths.getProperty("FilePermissions.test.readByOthers"));
assertEquals(false, result);
}
public void testCanBeWrittenByOthers() {
boolean result = FilePermissions.isPrivate(
paths.getProperty("FilePermissions.test.writtenByOthers"));
assertEquals(false, result);
}
}
paths.properties
-------------------------------------------------------------------------------------------------
# For testing under Linux / Unix
FilePermissions.test.privateOk = /home/fernando/privateOk
FilePermissions.test.readButNotWrite = /home/fernando/readButNotWrite
FilePermissions.test.readByOthers = /home/fernando/readByOthers
FilePermissions.test.writrenByOthers = /home/fernando/writtenByOthers
# For testing under Windows
#FilePermissions.test.privateOk = C:\\test\\privateOk
#FilePermissions.test.readButNotWrite = C:\\test\\readButNotWrite
#FilePermissions.test.readByOthers = C:\\test\\readByOthers
#FilePermissions.test.writrenByOthers = C:\\test\\writtenByOthers
|
The unit tests use a properties file (shown
in the same listing) to get each test’s target filesystem path. This way, all
file paths can be easily changed to comply with native-platform naming
conventions, without needing to recompile the tests themselves. Also, don’t
forget to create the target files and give them appropriate permissions.
If everything is fine so far, running the
tests (by selecting the FilePermissionsTest class and pressing Shift+F6) should give the output shown in Figure 2.
The UnsatisfiedLinkError exception is thrown because we haven’t yet provided the native
method implementation.
 |
Figure 2. Running JUnit tests for the unfinished native method.
|
Other open-source C/C++ IDEs |
C and C++ are of course much older than Java, and are still the
languages of choice for many high-profile open-source projects. Based on that,
on could guess there would be many other strong cross-platform and open-source
C/C++ IDEs. You’ll find that NetBeans C/C++ Pack may be the strongest one
around, however. Let’s look at some C/C++ Pack’s competitors.
DevCPP
DevCPP is very popular among Windows developers. It’s lightweight, well
supported, and, like NetBeans, relies on external make tools and C/C++
compilers. Additionally, it supports a wide variety of C/C++ compilers. Though
DevCPP is written using Borland Delphi, an attempt to port it to Linux (using
Kylix) failed. So DevCPP is not an option for cross-platform C/C++ development.
OpenWatcom
The Watcom C/C++ compiler is cross-platform but offers no Unix support;
it targets Windows and OS/2. Though not very user-friendly, it comes with an
integrated debugger and a help system. It was once the compiler of choice for
high-performance C/C++ applications, with its enhanced code optimizer and
support for all Intel processor variants. When Sybase bought Watcom, though,
the C/C++ compilers and IDEs fell into obscurity. Later the tools were released
as open-source software. Nowadays, it looks like the community project is going
well, but there’s still no support for Unix and Linux systems. This makes
OpenWatcom essentially a Windows-only IDE and not suitable for our purposes.
Anjuta
Anjuta is based on the complete GNU toolset for C/C++ development. In
addition to the tools supported by C/C++ Pack, it supports the GNU Autotools, a
set of scripts that simplifies generating Makefiles for multiple operating
systems and compilers. It’s also focused on GNOME development, so it provides
templates for GTK, Gnome and Glade applications.
While DevCPP and OpenWatcom are Windows-only, Anjuta and KDeveloper (see
next) are Unix-only. Some users have reported success running both under Cygwin,
but they are still far from providing robust support for compiling and
debugging native Windows applications.
For Unix developers, Anjuta provides integrated access to man pages and GNOME documentation. Its integrated debugger, like C/C++ Pack, relies
on GDB. The latest releases provide integration with Glade, the Gnome visual UI
builder.
KDevelop
Everything said before about Anjuta applies to KDevelop, if you just
replace GTK/Glade/GNOME with Qt/QtDesigner/KDE. Anjuta and KDevelop are strong
C/C++ IDEs for open-source desktops, but they don’t cut it as cross-platform
IDEs.
Eclipse CDT
C/C++ development support in Eclipse is almost as old as Eclipse IDE
itself, but it has not matured as fast as the support for Java. Although
currently labeled as release 4.0, Eclipse CDT doesn’t provide many features
beyond those in NetBeans C/C++ Pack (which is younger).
Also like NetBeans, Eclipse CDT doesn’t integrate yet with visual
development tools for Gnome, KDE or Windows. It has the advantage of supporting
compilers other than the GNU compilers, but this won’t be a real plus if your
goal is developing cross-platform C code.
Red Hat is developing GNU Autotools and RPM generation plug-ins which,
when they are released as production level, may become Eclipse CDT’s real
advantage over NetBeans C/C++ Pack (at least for Unix/Linux users). On the
other hand, NetBeans is the development IDE for Open Solaris, so don’t expect
it to fall short in enhancements for Unix developers.
Conclusion
The only flaw one would find in C/C++ Pack, comparing it to other
open-source alternatives for C/C++ development, is the lack of operating-system
and third-party library documentation support in the help system. That would be
also its main drawback when compared to proprietary C/C++ IDEs. But if you
evaluate alternatives for cross-platform C/C++ development, the strongest (and
only) competitor for NetBeans is also its main competitor in the Java space,
that is, Eclipse.
|
The native code project
Our unit tests are ready, but getting native
code working alongside Java code is not trivial. We’ll mock the native method
implementation so we can focus on how to build a native library that can be
called by Java code. Start by creating a C/C++ Dynamic Library Project, as
shown in Figure 3. Name the project “NativeOSlib” and clear the “Set as
main project” checkbox.
 |
Figure 3. Creating a C/C++ Project in NetBeans.
|
New C/C++ projects are created empty, except
for a generated Makefile (see Figure 4), and are structured in
virtual folders organized by file type – not by package names like Java
projects. You’ll be pleased to know that NetBeans C/C++ Pack includes a
Makefile editor (even though there’s still no support for running arbitrary
Makefile targets as there is for Ant buildfiles).
 |
Figure 4. The new C/C++ project in NetBeans’ Projects window.
|
Generating JNI Stubs
We’re ready to begin writing our C code.
First remember that all JNI-compliant native methods should use the declaration
generated by JDK’s javah tool. You could turn to the operating system
command prompt to generate the C JNI stubs, but there’s a better solution. It’s
the JNI Maker project, a plug-in module that adds a context menu for generating
JNI header files from Java classes. Just get the nbm package from jnimaker.dev.java.net and install it using NetBeans’s Update Center. After restarting the IDE, you
should see a new menu item as shown in Figure 5.
 |
Figure 5. Generating a JNI stub using the JNI Maker plug-in module.
|
Before
generating JNI stubs, make sure you’ve built the Java project. JNI Maker uses
the distribution JARs.
Now select Generate JNI Stub from the FilePermissions class’s context menu. NetBeans shows a standard File Save dialog, where you can select a folder to save the generated FilePermissions.h header file. Move into the NativeOSlib project folder and create a new src folder (C/C++ Projects do not have a default file structure with separate
source and test folders like Java projects do). Save the header file there. The
output window will look like Figure 6 if the operation is successful.
 |
Figure 6. Output from the Generate JNI Stub command.
|
JNI Maker Release 1.0 will only work
correctly under Windows, but the generated code will compile and run fine on
Unix/Linux. The project developers have been contacted about the module’s
cross-platform issues and by the time you read this there should be a new
release that will work on all platforms supported by NetBeans C/C++ Pack
Using the JNI Maker module has the same
effect as running the following command from the operating system prompt,
assuming the OSlib project folder is the current directory and NativeOSlib project folder is a sibling:
$ javah -classpath dist/OSlib.jar
-jni -o ../NativeOSlib/src/FilePermissions.h
org.netbeans.nbmag3.util.FilePermissions
Installing MinGW |
The MinGW project provides a native port of the
GNU toolset for Windows platforms. Included in the base distribution are GNU C,
C++, Objective-C, Ada, Java and Fortran compilers, plus an assembler and a
linker; there’s also support for dynamic libraries and Windows resource files.
Additional packages provide useful tools like Red Hat Source Navigator, Insight
GUI debugger and a handful of Unix ports like the wget download manager.
MinGW stands for “Minimalist GNU for Windows”.
But it’s “minimalist” only when compared to the Cygwin environment. (Cygwin
tries to emulate a full Unix shell, complete with bash scripting, user commands
and a Unix-like view of the filesystem.)
In fact, MinGW is complete to the point of
providing Win32 API header files, and many popular open-source applications
like Firefox have their Windows releases compiled using it. (Recent Cygwin
releases include many MinGW enhancements as a cross-compiling feature, showing
how Windows development is “alien” to MinGW alternatives.)
If you check the project’s website, it looks
like MinGW development has been stalled for quite a few years; the problem is
that the site was automatically generated by a script that read the project’s
SourceForge area, and developers simply got tired of catching up with sf.net’s design changes. However, MinGW is a very healthy project with active mailing
lists and frequent file releases.
There is an installer for the base distribution
named mingw-x.x.exe that downloads selected packages from SourceForge
and installs them. The same installer can be used to update an existing MinGW
installation.
Individual packages are downloaded to the same
folder where the installer was started. This allows you to later copy the
entire folder to another workstation and install MinGW there without the need
of an Internet connection. Most extra packages provide their own installers or
can simply be unpacked over an existing MinGW installation.
To satisfy C/C++ Pack’s prerequisites, you’ll
need to download and install three MinGW packages: the base distribution
itself, the GDB debugger, and the MSys distribution.
Installing
MinGW
Download MinGW-5.1.3.exe (or newer) from
the project’s current file releases at sf.net/project/showfiles.php?group_id=2435,
then launch it to see a standard Windows installer.
On the third step of the wizard (the second
screen in Figure S1) you only need to select “MinGW base tools” and
optionally “g++ compiler”. Also, the Java Compiler may be interesting to play
with, because of its ability to generate native machine code from Java sources
and bytecodes, but it’s not supported by NetBeans yet. Interestingly, the g77
(Fortran) compiler will be officially supported very soon.
After downloading all selected packages, the
installer will ask for the destination directory and unpack all packages there.
It’s left to the user to configure environment variables so that MinGW tools
can be used from the Windows command prompt.
Installing
GDB
As we’ve seen, NetBeans C/C++ Pack needs GDB to
be able to debug C programs. The MinGW distribution packages GDB as a
stand-alone installer.
At the time of writing, the latest stable MinGW
package for GDB was release 5.2.1, which won’t refresh the NetBeans debugger’s
Local Variables window correctly. To solve this, download gdb-6.3-2.exe (or newer) from MinGW Snapshot Releases to a temporary folder and run it.
Though you don’t need to install GDB over MinGW, your life will be easier if
you do, as you won’t need to add another folder to your PATH system environment
variable.
Installing
MSys
The MinGW base distribution already includes a
make tool named mingw32-make.exe, but NetBeans C/C++ Pack won’t be happy
with it. MinGW’s make tool is patched to be more compatible with other native
Windows C compilers, and NetBeans expects a Unix-style make tool. NetBeans
generated Makefiles even expect to find standard Unix file utilities such as cp and rm.
The MinGW MSys package satisfies these dependencies. It is a “Minimal System” that provides a
Unix-style shell and file utilities, and allows open-source projects based on
GNU Autotools to be easily built using MinGW.
Download msys-1.0.10.exe or newer to a
temporary folder and start it. At the final installation step, a batch script
configures the integration between MSys and MinGW. You will still have to add
the MSys programs folder to the system PATH (in my case, E:\MSys\1.0\bin),
as you did for the MinGW base distribution.
That’s it. After running three installers and
downloading about 23 MB, we are ready to develop C/C++ applications and libraries
using the NetBeans IDE and C/C++ Pack on Windows.
|
 |
|
 |
Figure S1. Screens from MinGW’s base distribution installer.
|
(The command is broken to fit the column
width, but it should be typed in a single line, of course.)
Now add the generated C header file to the
NativeOSlib project. Right click Header Files inside the NativeOSlib project folder in NetBeans’ Projects window, and select Add Existing Item.
Then browse to the file src/FilePermissions.h and open it. The code will
look like Listing 3.
Listing 3. FilePermissions.h – JNI Stub for native methods in the FilePermissions class.
|
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_netbeans_nbmag3_util_FilePermissions */
#ifndef _Included_org_netbeans_nbmag3_util_FilePermissions
#define _Included_org_netbeans_nbmag3_util_FilePermissions
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_netbeans_nbmag3_util_FilePermissions
* Method: isPrivate
* Signature: (Ljava/io/File;)Z
*/
JNIEXPORT jboolean JNICALL Java_org_netbeans_nbmag3_util_FilePermissions_isPrivate
(JNIEnv *, jclass, jobject);
#ifdef __cplusplus
}
#endif
#endif
|
Mocking native code
Due to space constraints, we won’t show you
the final C code for the FilePermissions.isPrivate() native method, but the sources available for download will provide
working implementations for both Windows and Unix (Posix) systems.
To create the C implementation file, right
click Source Files and select New>Empty C File, then type
“FilePermissions.c” as the file name and “src” as the folder name. A new node
named FilePermissions.c should be created under Source Files.
Copy the C stub function declaration from FilePermissions.h to FilePermissions.c and change it to include the header file. Also add
parameter names. The code should look like Listing 4. (Listing 3 highlights the declaration you have to copy, and Listing 4 highlights
the changes after copying.)
Listing 4. FilePermissions.h – JNI mock implementation for the FilePermissions native methods.
|
#include "FilePermissions.h"
JNIEXPORT jboolean JNICALL Java_org_netbeans_nbmag3_util_FilePermissions_isPrivate
(JNIEnv *env, jclass clazz, jstring path) {
return JNI_TRUE;
}
|
At this point, Unix and Linux users should
be ready to build the native code and run unit tests again2. But
Windows users first have to change a few project properties to make MinGW
generate Windows-compatible JNI DLLs. The sidebar “JNI and MinGW”
details these
configurations.
2 At least if you use JDK packages compatible with your distro package manager, like the IBM and BEA JDKs provided by RHEL and SuSE Enterprise, or the RPM Packages from jpackage.org. If not, you’ll have to add your JDK include folder to the GNU C compiler include directory. The configurations will be similar to the ones presented in the “JNI and MinGW” sidebar, but you won’t need to change either the linker output file name or additional compiler options.
Right click the NativeOSlib project
and select Clean and Build Project. If there are no errors, you should
see make’s output as in Figure 7.
 |
Figure 7. Building the NativeOSlib project under Linux.
|
Running unit tests again
You need to set the OSlib project’s java.library.path system property before running it, or you’ll still get UnsatisfiedLinkError exceptions. Open the project’s Properties dialog, select the Run category and change VM Options to specify the full path to the NativeOSlib project’s platform-specific native-library folder, which is inside the dist folder (see Figure 8). In Linux, this will be PROJECT_HOME/dist/Debug/GNU-Linux-x86;
in Windows, PROJECT_HOME\dist\Debug\GNU-Windows.
 |
Figure 8. Configuring the java.library.path property so unit tests can find the native code library on Linux.
|
Now run the unit tests again. The result
should be as shown in Figure 9. Since the mock native code always
returns true, some tests pass even if you have not created target test folders
or forgotten to setup their access permissions. Anyway, the first test should
fail because it takes an extra step to check if the target file path
actually exists.
 |
Figure 9. Running unit tests using a mock native implementation.
|
JNI and MinGW |
Unix and Windows native C/C++ compilers use different conventions for
mangling function names1*,
exporting global symbols from libraries and setting up stack frames. JNI on
Windows uses Microsoft conventions for Windows DLLs, while GCC uses its own
conventions for dynamic libraries. This means that if you simply try to compile
and link a dynamic library, MinGW will stick to its Unix origins and produce a
DLL that is incompatible with native Windows C/C++ compilers. The JVM won’t be
able to get native method implementations from that library and will generate
more UnsatisfiedLinkExceptions.
The solution is to add a few command-line
options when compiling C/C++ sources: ‑D_JNI_IMPLEMENTATION
-Wl,--kill-at. Open the C/C++ Dynamic Library Project
properties and expand C/C++>Command Line, then type these
options in the Additional Options text field (see Figure S1).
You also need to add your JDK include folders (JAVA_HOME\include and JAVA_HOME\include\win32) to the project properties. Open
C/C++>GNU C Compiler>General and change the Include
Directories field as shown in Figure S2.
You need one last change in the C/C++ Dynamic
Library Project properties so you can generate a JNI-compatible DLL. By
default, NetBeans chooses a library name that corresponds to Cygwin
conventions, but we need to use native Windows conventions. So you need to
enter the Linker>General category and remove the “cyg” prefix
from the Output field (Figure S3).
1“Mangling” is the process used for generating public C++ function names in object files. It’s needed because the C language doesn’t support function overloading, and, to keep backward compatibility, C++ compilers generate a function name that encodes parameter types.
|
 |
Figure S1. MinGW compiler options for generating JNI-compatible DLLs
|
|
Figure S2. Configuring JDK include folders for MinGW
|
 |
Figure S3. Changing the output file name for compliance with Windows DLL naming conventions
|
Managing platform-specific compiler
settings
NetBeans C/C++ Pack puts object files in the build and dist folders, inside subdirectories named after the
target platform, for example GNU-Linux-x86 or GNU-Windows. But it
won’t save different compiler options for each target, forcing you to have a
different project for each platform if there’s a need for platform-specific
compiler settings.
You can solve this using NetBeans C/C++
Pack’s multiple configurations feature. Open NativeOSlib’s project
properties and notice the Configuration combo box on the top of the
window (Figure 10). The default configurations are meant to save
different compiler settings for Debug and Release builds, like keeping symbol
information for Debug builds and optimizing code for Release builds. So if you
want platform-specific configurations, you may need to create Release and Debug
variants for each platform.
 |
Figure 10. Combo box for changing compiler configurations for a C/C++ project.
|
The Manage Configurations button to
the side of the combo box lets you create new configurations either from
scratch or as a copy of an existing configuration (see Figure 11).
You’ll notice I renamed the generated Debug configuration to Debug-Linux and copied it to a new configuration named Debug-Windows. Doing this
lets you change the Windows configuration to include all options needed by
MinGW for generating JNI-compatible DLLs, while keeping the default settings
for the Linux configuration.
 |
Figure 11. Creating, renaming or copying configurations.
|
NetBeans-generated Makefiles provide many
extension points (like the Ant buildfiles generated by the IDE), and they can
be used outside the IDE. For example, for building the Debug-Windows configuration you’d type the following command at the operating system prompt:
make CONF=Debug-Windows
Thus, you could have Continuous Integration
servers for many platforms, all being fed by the same CVS or Subversion source
tree. And thanks to GNU C cross-compiler features it would be possible to have
a “compile farm” that generates native binaries for multiple platforms, without
the need for multiple OS installations. For example, a Linux server could
generate both Windows and Solaris
SPARC binaries.
Conclusions
NetBeans C/C++ Pack provides a rich
environment for developing C and C++ applications and libraries. It’s useful
for Java developers that need to interface with native code and, of course, for
developing fully-native applications. Compiler configuration may pose some
challenges for Windows developers if they never tried GNU compilers before, but
the effort will certainly pay off because of the increased portability of both
code and Makefiles.
|
Fernando Lozano
(fernando@lozano.eti.br) is an independent consultant and has worked with information systems since 1991. He’s the Community Leader of the Linux Community at Java.net, webmaster for the Free Software Foundation and counselor to the Linux Professional Institute. Lozano helps many open-source projects and teaches at undergraduate and postgraduate college courses. He’s also a technical writer and book author, as well as Contributing Editor at Java Magazine (Brazil) and freelance writer for other leading IT publications. |
|