As Eclipse
in Raspberry Pi
is very slow compared to a desktop computer, we will show how to create a simple hello world project
and how to transfer and debug it remotely using Eclipse
and ssh
.
1 Prepare eclipse
- Ensure console view by selecting Eclipse menu
Window -> Show View -> Console
- Open Ant view by selecting Eclipse menu
Window -> Show View -> Other -> Ant -> Ant
- Ensure Maven is installed
2 Create a maven project
- Start
Eclipse IDE
on your desktop computer - In the Package Explorer, right-click and select
New -> Other -> Maven Project
- Unselect “create a simple project (skipe archetype selection) as we will select a default archetype."
Click next
- Select
maven-archetype-quickstart
- Enter hello as artifact id
Now we have a simple application skeleton created by Maven
with a default App.java
and a default pom.xml file.
3 Modify the pom.xml file
Edit the pom.xml and add a few lines (the build section) so Maven knows that the App will be the entry point of the program.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>pi</groupId> <artifactId>hello</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>hello</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <!-- Add the maven pluggin to build --> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>pi.hello.App</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
4 Create the build.xml file
Create a build.xml ant file like the following example, changing the values of properties to match your configuration (raspberrypi, raspberryfolder, username, password).
The build file have tasks to:
- maven-install - to build the jar when code changes
- transfer - to transfer the jar file (located in target directory) to raspberry pi computer
- remote-run - to remote run java with the transfered jar
- remote-debug - to remote run java in debug mode with the transfered jar
<?xml version="1.0" encoding="UTF-8"?> <project name="hello" default="remote-run" basedir="." xmlns:artifact="antlib:org.apache.maven.artifact.ant"> <!-- Setup RASPBERRY PI properties --> <property name="raspberrypi" value="192.168.1.41" /> <property name="raspberryfolder" value="~" /> <property name="username" value="pi" /> <property name="password" value="raspberry" /> <path id="maven-ant-tasks.classpath" path="${ant.libs.dir}/maven-ant-tasks-2.1.3.jar" /> <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="antlib:org.apache.maven.artifact.ant" classpathref="maven-ant-tasks.classpath" /> <!-- Add maven install target to be run before deploy --> <target name="maven-install"> <artifact:mvn pom="pom.xml"> <arg value="install"/> </artifact:mvn> </target> <!-- Locate the prokect jar and transfer via scp to RASPBERRY PI --> <target name="transfer" depends="maven-install"> <first id="jars"> <!-- <fileset dir="target" includes="**/*-SNAPSHOT-jar-with-dependencies.jar" /> --> <fileset dir="target" includes="**/*.jar" /> </first> <pathconvert pathsep="," property="jar.path" refid="jars" /> <basename file="${jar.path}" property="jar.filename" /> <echo>">>> Found application ${jar.path}"</echo> <echo>">>> Copying application to ${raspberrypi}:${raspberryfolder}/${jar.filename}"</echo> <scp localfile="${jar.path}" todir="${username}:${password}@${raspberrypi}:${raspberryfolder}" trust="true" /> </target> <!-- Run java --> <target name="remote-run" depends="transfer"> <echo>">>> Starting ${raspberrypi}:${raspberryfolder}/${jar.filename}"</echo> <sshexec host="${raspberrypi}" username="${username}" password="${password}" trust="true" failonerror="true" usepty="true" command="java -jar ${jar.filename}" /> </target> <!-- Run java in debug mode and keep waiting for execution --> <target name="remote-debug" depends="transfer"> <echo>">>> Starting ${raspberrypi}:${raspberryfolder}/${jar.filename} in debug mode"</echo> <sshexec host="${raspberrypi}" username="${username}" password="${password}" trust="true" failonerror="true" usepty="true" command="java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=y -jar ${jar.filename}" /> </target> </project>
4.1 Run the ant file
Now you can Right click on build.xml and select Run as-> Ant build
. You should see
the Hello world output from your remote Pi.
Buildfile: /workspace/hello/build.xml maven-install: [artifact:mvn] [INFO] Scanning for projects... [artifact:mvn] [INFO] ------------------------------------------------------------------------ [artifact:mvn] [INFO] Building hello [artifact:mvn] [INFO] task-segment: [install] [artifact:mvn] [INFO] ------------------------------------------------------------------------ [artifact:mvn] [INFO] [resources:resources] [artifact:mvn] [INFO] Using 'UTF-8' encoding to copy filtered resources. [artifact:mvn] [INFO] skip non existing resourceDirectory /Users/xavierescote/Documents/workspace-pi/hello/src/main/resources [artifact:mvn] [INFO] [compiler:compile] [artifact:mvn] [INFO] Nothing to compile - all classes are up to date [artifact:mvn] [INFO] [resources:testResources] [artifact:mvn] [INFO] Using 'UTF-8' encoding to copy filtered resources. [artifact:mvn] [INFO] skip non existing resourceDirectory /Users/xavierescote/Documents/workspace-pi/hello/src/test/resources [artifact:mvn] [INFO] [compiler:testCompile] [artifact:mvn] [INFO] Nothing to compile - all classes are up to date [artifact:mvn] [INFO] [surefire:test] [artifact:mvn] [INFO] Surefire report directory: /Users/xavierescote/Documents/workspace-pi/hello/target/surefire-reports [artifact:mvn] ------------------------------------------------------- [artifact:mvn] T E S T S [artifact:mvn] ------------------------------------------------------- [artifact:mvn] Running pi.hello.AppTest [artifact:mvn] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.013 sec [artifact:mvn] Results : [artifact:mvn] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [artifact:mvn] [INFO] [jar:jar] [artifact:mvn] [INFO] Building jar: /Users/xavierescote/Documents/workspace-pi/hello/target/hello-0.0.1-SNAPSHOT.jar [artifact:mvn] [INFO] [install:install] [artifact:mvn] [INFO] Installing /Users/xavierescote/Documents/workspace-pi/hello/target/hello-0.0.1-SNAPSHOT.jar to /Users/xavierescote/.m2/repository/pi/hello/0.0.1-SNAPSHOT/hello-0.0.1-SNAPSHOT.jar [artifact:mvn] [INFO] ------------------------------------------------------------------------ [artifact:mvn] [INFO] BUILD SUCCESSFUL [artifact:mvn] [INFO] ------------------------------------------------------------------------ [artifact:mvn] [INFO] Total time: < 1 second [artifact:mvn] [INFO] Finished at: Sun Sep 11 20:16:19 CEST 2016 [artifact:mvn] [INFO] Final Memory: 25M/876M [artifact:mvn] [INFO] ------------------------------------------------------------------------ transfer: [echo] ">>> Found application /Users/xavierescote/Documents/workspace-pi/hello/target/hello-0.0.1-SNAPSHOT.jar" [echo] ">>> Copying application to 192.168.1.41:~/hello-0.0.1-SNAPSHOT.jar" [scp] Connecting to 192.168.1.41:22 [scp] done. remote-run: [echo] ">>> Starting 192.168.1.41:~/hello-0.0.1-SNAPSHOT.jar" [sshexec] Connecting to 192.168.1.41:22 [sshexec] cmd : java -jar hello-0.0.1-SNAPSHOT.jar [sshexec] Hello World! [sshexec] BUILD SUCCESSFUL Total time: 3 seconds
4.2 Modify the java file to ensure it's runnig remote
Simply change the java code to print the hostname of the computer.
public class App { public static void main( String[] args ) throws UnknownHostException { System.out.println( "Hello World! from " + java.net.InetAddress.getLocalHost().getHostName()); } }
You should see:
Hello World! from raspberrypi
5 Adding libraries to project
When libraries are need you should add them to the pom.xml dependencies and they will be included in project. For example, to add slf4j library, under the dependecies section add:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.21</version> </dependency>
But how we can pack libraries with our application to become a single jar executable before trasnfering it ?
The solution is to use the maven-assembly-plugin. In the pom.xml file, add a build entry and the pluggin reference to maven assembly.
<build> <plugins> <!-- Plugin to create a single jar that includes all dependencies --> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <addClasspath>true</addClasspath> <!-- Name the main class --> <mainClass>pi.hello.App</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
When deploy.xml is executed, it will create now two jar files:
- "target/artifact-0.0.1-SNAPSHOT.jar" - the standard artifaact jar file without dependecines.
- "target/artifact-0.0.1-SNAPSHOT-jar-with-dependencies.jar" - the new artifaact jar file with libraries included
So you need to change the deploy.xml file to selecte the second one to be copied.
<first id="jars"> <fileset dir="target" includes="**/*-SNAPSHOT-jar-with-dependencies.jar" /> </first>
5.1 Running the sample
Finally, we can run the sample. To check library is packed, we can change the main app to use the Logger.
public class App { public static void main( String[] args ) throws UnknownHostException { Logger.getLogger("PI").info("Start"); System.out.println( "Hello World! from " + InetAddress.getLocalHost().getHostName()); Logger.getLogger("PI").info("End"); } }
Finally select the deploy.xml right click and select Run as -> Ant build file
remotedebug: [echo] "Found application /Users/xavi/Documents/workspace/test/target/HelloWorld-0.0.1-SNAPSHOT-jar-with-dependencies.jar" [echo] "Copying application to 192.168.1.41:~/HelloWorld-0.0.1-SNAPSHOT-jar-with-dependencies.jar" [scp] Connecting to 192.168.1.41:22 [scp] done. [echo] "Starting 192.168.1.41:~/HelloWorld-0.0.1-SNAPSHOT-jar-with-dependencies.jar in debug mode" [sshexec] Connecting to 192.168.1.41:22 [sshexec] cmd : java -jar HelloWorld-0.0.1-SNAPSHOT-jar-with-dependencies.jar [sshexec] Sep 11, 2016 11:09:50 AM pi.hello.App main [sshexec] INFO: Start [sshexec] Hello World! from raspberrypi [sshexec] [sshexec] Sep 11, 2016 11:09:50 AM pi.hello.App main [sshexec] INFO: End BUILD SUCCESSFUL Total time: 3 seconds
6 Create a debug launch configuration
Setup a debug launch configuration has to be set up in the Eclipse IDE
In the Main Menu, go to Run -> Debug Configurations… -> Remote Java Applications
.
Create a new launch configuration there and
- select the remotehelloworld project
- select Connection Type “Socket Attach”
- enter the Raspberry Pis IP address as host
- enter the Java VMs debug port set in the Ant script

7 Perform the Remote Debug
To perform the remote debugging, do the following:
- Build the project with Maven
(right-click -> Run As -> Maven install)
- Verify that the build was successful and that the jar file has been placed into the /target folder of the project
- Add a breakpoint to the HelloWorld.java class (e.g. in the system.out line)
- Execute the remotedebug.xml
Ant
script by doing right click on remotedebug.xml Ant script and selectRun As -> Ant Build
In some cases, ant fails with a message like "Could not load a dependent class com/jcraft/jsch/Logger". In that case need to download jsch.jar into your $HOME/.ant/lib. And restart eclipse to take effect. - observe the console to see:
remotedebug: [echo] "Found application /Users/xavi/Documents/workspace/HelloWorld/target/HelloWorld-0.0.1-SNAPSHOT.jar" [echo] "Copying application to 192.168.1.54:~/HelloWorld-0.0.1-SNAPSHOT.jar" [scp] Connecting to 192.168.1.54:22 [scp] done. [echo] "Starting 192.168.1.54:~/HelloWorld-0.0.1-SNAPSHOT.jar in debug mode" [sshexec] Connecting to 192.168.1.54:22 [sshexec] cmd : java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=y -jar HelloWorld-0.0.1-SNAPSHOT.jar [sshexec] Listening for transport dt_socket at address: 8000
- Start the HelloWorld debug launch configuration.
- If everything works as expected, the Eclipse IDE will switch to the debug perspective.
It will show the Hello-World program running on the Raspberry Pi.
The programs main thread will be suspended on the breakpoint in the HelloWorld class.
-
click on debug next step and you will see Hello World output from remote application.
[sshexec] Listening for transport dt_socket at address: 8000 [sshexec] Hello World! [sshexec] BUILD SUCCESSFUL Total time: 6 seconds