问题
I have a simple java class using Pi4J that contains a main method. I want to build and deploy it to a Raspberry Pi. I'm using java 8 on a windows 10 and my IDE is NetBeans 8.1. If the project is set up to be a normal (non-Maven) Java Application and set up to deploy to the Raspberry Pi via the NetBeans build configurations as shown here, the project will build normal and FTP over the jar and then run it with no issues. I would like to do the same but using Maven. The problem is that the code that is being ran has C code native to the ARM's architecture of the Pi and the Maven plugin I'm using seems to run the jar on my local box first in which the C code will crash throwing the Exception
SEVERE: Unable to load [libpi4j.so] using path: [/lib/libpi4j.so] java.lang.IllegalArgumentException: The path has to be absolute, but found: \lib\libpi4j.so at com.pi4j.util.NativeLibraryLoader.loadLibraryFromClasspath(NativeLibraryLoader.java:120) at com.pi4j.util.NativeLibraryLoader.load(NativeLibraryLoader.java:92) at com.pi4j.wiringpi.Gpio.(Gpio.java:174) at com.pi4j.io.gpio.RaspiGpioProvider.(RaspiGpioProvider.java:51) at com.pi4j.io.gpio.GpioFactory.getDefaultProvider(GpioFactory.java:106) at com.pi4j.io.gpio.impl.GpioControllerImpl.(GpioControllerImpl.java:54) at com.pi4j.io.gpio.GpioFactory.getInstance(GpioFactory.java:89) at com.hadronix.pi4jsample2.ControlGpioExample.main(ControlGpioExample.java:24)
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.pi4j.wiringpi.Gpio.wiringPiSetup()I at com.pi4j.wiringpi.Gpio.wiringPiSetup(Native Method) at com.pi4j.io.gpio.RaspiGpioProvider.(RaspiGpioProvider.java:51) at com.pi4j.io.gpio.GpioFactory.getDefaultProvider(GpioFactory.java:106) at com.pi4j.io.gpio.impl.GpioControllerImpl.(GpioControllerImpl.java:54) at com.pi4j.io.gpio.GpioFactory.getInstance(GpioFactory.java:89) at com.hadronix.pi4jsample2.ControlGpioExample.main(ControlGpioExample.java:24)
If i just do a clean build, it will build fine and create the jar. However, if i choose to run the build then thats where the crash happens. This is the Maven plugin I'm using to deploy the jar to the Pi.
<!-- OPTIONALLY DEPLOY THE FINAL JAR TO THE RASPBERRY PI -->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<!-- copy the compiled JAR file to the Raspberry Pi platform platform -->
<execution>
<id>ControlGpioExample.jar</id>
<phase>install</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<taskdef resource="net/sf/antcontrib/antcontrib.properties"
classpathref="maven.plugin.classpath" />
<if>
<equals arg1="${pi.transfer.dev}" arg2="true" />
<then>
<!-- ensure the target directory exists on the Raspberry Pi -->
<sshexec host="${pi.host.dev}" port="${pi.port.dev}" username="${pi.user.dev}"
password="${pi.password.dev}" trust="true" failonerror="false"
verbose="true" command="mkdir --parents ${pi.dirCopyTo.dev}" />
<!-- copy the JAR file to the Raspberry Pi -->
<scp
file="${project.build.directory}/${project.build.finalName}.jar"
todir="${pi.user.dev}:${pi.password.dev}@${pi.host.dev}:${pi.dirCopyTo.dev}"
port="${pi.port.dev}" trust="true" verbose="true" failonerror="true">
</scp>
</then>
</if>
</tasks>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-jsch</artifactId>
<version>${ant-jsch.version}</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>${jsch.version}</version>
</dependency>
<dependency>
<groupId>ant-contrib</groupId>
<artifactId>ant-contrib</artifactId>
<version>${ant-contrib.version}</version>
</dependency>
</dependencies>
</plugin>
I'm trying to figure out how to change this plugin to not execute the code first on my local machine. I just want it to assume the jar is built, ssh into the remote Pi and copy the jar over and then run it there. Also, if someone has a completely better way while using Maven then I'm open to suggestions. Any help would be great!
Here are links to what I'm using as references link 1
Thanks in advance.
回答1:
Solved: This pom file will build an executable JAR of example use cases of Pi4J. It will then transfer the JAR to the Raspberry Pi and then execute it. In netbeans, This is done via the build command. So one button to build, deploy and run!
One thing I don't like is that it brings dependencies as packages instead of the original JAR. It also creates 2 JAR's at build time; one with and one without dependencies. Open up the Jar and see what can be done to better the structure. Feel free to optimize and give feedback.
Also, for simplicity purposes on this answer, I put my RASPBERRY PI PROPERTIES in this pom file. However, those should be in a controlled user home location in a settings.xml file or something.
Note: Pi4J has a C code native ARM dependencies which prevent it from running on non ARM architectures and must be sent to Pi.
<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>com.company</groupId>
<artifactId>Swarm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- DEFAULT RASPBERRY PI PROPERTIES -->
<pi.host>192.168.1.20</pi.host>
<pi.port>22</pi.port>
<pi.user>root</pi.user>
<pi.password>root</pi.password>
<pi.deployDirectory>/home/pi/artifacts</pi.deployDirectory>
<pi.main.class>com.company.test.ControlGpioExample</pi.main.class>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.pi4j</groupId>
<artifactId>pi4j-core</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- This plugin will generate JAR MANIFEST file inside the JAR in order to make our applicationeasily runnable -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${pi.main.class}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-my-jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!--This plugin will Transfer the executable JAR file to the Pi and runs it -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<!-- ensure the target directory exists on the Raspberry Pi -->
<sshexec host="${pi.host}" port="${pi.port}" username="${pi.user}" password="${pi.password}"
trust="true" failonerror="false" verbose="true"
command="mkdir --parents ${pi.deployDirectory}"/>
<!-- copy the JAR file to the Raspberry Pi -->
<scp
file="${project.build.directory}/${project.build.finalName}-jar-with-dependencies.jar"
todir="${pi.user}:${pi.password}@${pi.host}:${pi.deployDirectory}"
port="${pi.port}" trust="true" verbose="true" failonerror="true">
</scp>
<!-- run the JAR file on the Raspberry Pi -->
<sshexec host="${pi.host}" port="${pi.port}" username="${pi.user}"
password="${pi.password}" trust="true" failonerror="false"
verbose="true"
command="java -jar ${pi.deployDirectory}/${project.build.finalName}-jar-with-dependencies.jar"/>
</tasks>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-jsch</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
来源:https://stackoverflow.com/questions/35148025/how-to-deploy-a-jar-onto-raspberry-pi-2-using-maven-plugin