Tuesday, October 24, 2006

How to mix Java and C++ code in a singe Eclipse project

Recently I got an interesting task to build a component in Java and C++ (with similar interface) and able to run on Linux and Windows also (in the future on potential other platforms).

First I created 2 separate Eclipse project, but I didn't liked the idea at all since I want to use the same CVS tree, same config and 3rd party components, so it's really 1 project not 2.

The other problem was, I need native Windows build (thanks to C++ name mangling, yeah I know I should use C), while Eclipse Managed C++ project support mainly the Cygwin build.

Finally I come up with 1 single project with Ant build and using cpptask for the C++ compilation, but I still wasn't happy! I lost the name completition/intellisense correct error highlighting and automatic repair functions. However you can get this back with the manually editing the Eclipse project files. We don't need to run, you will see this 2 minutes later.

So here is what you need

How C++ building works with Eclipse anyway?

Before we jump to the conclusion let's take 1 step back and take a quick look on how C++ building working on Eclipse at very high level (lot of other article covered this).

If you are on Windows all you need is to download and install Cygwin and the most important: set up your path correctly! Assume the default install directory for Cygwin you need to add the following:
C:\cygwin\bin
Ok, let's verify is it working, so just open a command window and type make, if you see the following you can take a coffee :) (Otherwise directed medication section comes focusing on the error.)
C:\>make
make: *** No targets specified and no makefile found. Stop.
Now we can create a managed C++ project and Eclipse and it takes care everything, compile, build, name competition and so on.

Hey, we want native build!

Ok, first we need a native compiler. VC++ 2005 (it's free for 30 day and anyway we will just use the command line interface for the cl.exe and the link.exe so it will be free for us in our whole life:), or not) and we need the Platform SDK also.
If it's not working I can imagine 2 scenario:
  1. your disk is full :) seriously just the Platform SDK is 1GB

  2. the most likely: your path is incorrect
Your path should like like this:
C:\>echo %PATH%
C:\Program Files\Microsoft Visual Studio 8\VC\BIN;
C:\cygwin\bin;
C:\WINDOWS\system32;
C:\WINDOWS;C:\WINDOWS\System32\Wbem;
C:\Program Files\Microsoft Visual Studio 8\Common7\IDE;
C:\Program Files\Microsoft Visual Studio 8\Common7\Tools;
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin;
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727;
C:\Program Files\Microsoft Visual Studio 8\VC\VCPackages;
C:\Program Files\Microsoft Platform SDK\Bin\.;
C:\Program Files\Microsoft Platform SDK\Bin\WinNT\.
Let's assume this solved your problem, but here is the deal: cygwin/bin/link.exe is needed for the Cygwin make and link.exe is the official linker for Visual Studio
c/Program Files/Microsoft Visual Studio 8/VC/BIN/link

Since I need native build, my path looks like as above: VC in the front and Cygwin is just comming after that.

If we don't want to use the make, what we can do?

Create your build.xml (for the Ant build), e.g. and add you CC task for C++ compilation like this

<target name="build-lib-release">

<cc subsystem="console" objdir="${obj.dir}" debug="false" outtype="shared" name="${compiler}" exceptions="true" rtti="false" optimize="speed" runtime="dynamic" outfile="${lib.dir}">

<linker name="msvc" if="is-win32"/>

<fileset dir="${src.dir}/cxx" includes="*.cxx" />

<includepath path="${include.dir}"/>

<libset libs="stdc++" if="is-g++"/>

<libset libs="dl" if="is-g++"/>

<libset libs="pthread" if="is-g++"/>

<libset libs="m" if="is-g++"/>

<libset libs="ws2_32" if="is-win32"/>

<defineset define="HAVE_PTHREADS" if="is-g++"/>

<defineset define="WIN32" if="is-win32"/>

<defineset define="_WIN32" if="is-win32"/>

</cc>

</target>

More about the CC task

Ensure that cpptask is on the Ant classpath and right click on the build.xml Run as -> Ant build.

Create the blended project and hack the configuration files

To have a correct mixed C++ and Java project, let's start a project from the scratch:
New->General->Project

Add the source code, e.g src/java is the Java part and src/cxx is the C++, you can build a nice Ant builder task now using the properties, but the Java intellisense not working.

You can add an Ant Builder in the Project->Properties, but after that you need to add manually the Java Builder to the .project file :

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>whatever</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project>/.externalToolBuilders/New_Builder.launch</value>
</dictionary>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

To able to edit the .project file you need to close the Eclipse application, since it will write back the original by default.

By adding the javabuilder manually to the .project file we are almost get a standard Java project, but one piece is still missing: our java source code is in the src/java and not in the project root/something directory (Eclipse will interpret the java directory as part of the package name by default)

We can fix it easily by editing the Project->Properties->Java build path->Source->Source folders on build path (sometimes you need to delete and recreate) and just specify src/java. You need to modify the Default output folder (where the object takes place) to <projectname>/src/java also.













Add the CDT compilation/build

The easiest way if you create an empty Managed C++ project and copy the following items to your project directory:
  • .settings directory
  • .cdtbuild file
  • .cdtproject file
Plus, you need to merge the .project files, so you will get this:

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>whatever</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project>/.externalToolBuilders/New_Builder.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
</natures>
</projectDescription>

Now the C/C++ Build appears in the project settings, so it can be modified via the UI and able to be used for debugging and development and we can use the Ant CC task for the final native build.

At this point of time we have 3 builder in the project (Ant, Java, C/C++) and we can take the advantage of easy debugging editing of Eclipse. Ok let's import the module to the CVS and checkout from there as an Eclipse CVS project.

Need more help?

0 Comments:

Post a Comment

<< Home