diff --git a/.cmake/Modules/FindLibUsb.cmake b/.cmake/Modules/FindLibUsb.cmake index 77b6e09..f0f6e54 100644 --- a/.cmake/Modules/FindLibUsb.cmake +++ b/.cmake/Modules/FindLibUsb.cmake @@ -3,8 +3,8 @@ # LibUsb_LIBRARIES : The libraries to link against # LibUsb_INCLUDE_DIRS : The directories to include # -# pkg-config is used when available and CMAKE_SHARED_LINKER_FLAGS -# is filled with additianal flags reported by it. +# pkg-config is used when available and CMAKE_SHARED_LINKER_FLAGS +# is filled with additional flags reported by it. # # When no pkg-config is found then the library is searched within the # standard directories. diff --git a/.gitignore b/.gitignore index 705954b..d291403 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ .settings .project +.vscode target +/build +/.vs +/out/build/x64-Debug diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e7bf8a..61156ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.14) project(usb4java C) -set(PROJECT_VERSION 1.2.1) +set(PROJECT_VERSION 1.3.1) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/.cmake/Modules/") find_package(JNI REQUIRED) diff --git a/README.md b/README.md index c471aae..ba882df 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ This is the source code of the JNI wrapper for libusb. usb4java -already includes pre-compiled libraries for the following platforms: +already includes prebuilt libraries for the following platforms: * linux-x86 -* linux-x86_64 +* linux-x86-64 * linux-arm -* windows-x86 -* windows-x86_64 -* osx-x86 -* osx-x86_64 +* linux-armel +* linux-aarch64 +* win32-x86 +* win32-x86-64 +* darwin-x86-64 +* darwin-arm-64 If you need the library on an other platform then you can easily compile it yourself. On a Unix-compatible operating system you only need the Java JDK, @@ -19,7 +21,7 @@ library with the following commands: $ cd build $ cmake .. $ make - + When compilation was successful then you can find the library in the `build/src` directory. diff --git a/build/README.md b/build/README.md deleted file mode 100644 index 8fee50c..0000000 --- a/build/README.md +++ /dev/null @@ -1,7 +0,0 @@ -This directory contains the build scripts used by the usb4java CI server to -automatically generate the native libraries shipped with usb4java. - -If you want to build your own native library for a platform which is not -supported by usb4java out-of-the-box then this is the wrong place for you. -Follow the instructions in the README.md file in the root directory of the -project instead. diff --git a/build/linux.sh b/build/linux.sh deleted file mode 100755 index 76dd345..0000000 --- a/build/linux.sh +++ /dev/null @@ -1,78 +0,0 @@ -# ============================================================================ -# Build script for Linux. -# -# The script automatically compiles the binary for the local architecture and -# creates the corresponding JAR file in the target folder. -# -# Requirements: cmake, make, curl, jar -# ============================================================================ - -# Fail on all errors -set -e - -# Software versions -LIBUSB_VERSION=1.0.19 -EUDEV_VERSION=3.1.2 - -# Determine directories -cd "$(dirname $0)/.." -PROJECT_DIR="$(pwd)" -TARGET_DIR="$PROJECT_DIR/target" -ROOT_DIR="$TARGET_DIR/root" - -# Clean up target directory -rm -rf "$TARGET_DIR" - -# Determine OS and architecture -OS=linux -case "$(arch)" in - "x86_64") - ARCH=x86_64 - ;; - "i"[3456]"86") - ARCH=x86 - ;; - "armv"*) - ARCH=arm - ;; - *) - echo "Unknown platform: $(arch)" - exit 1 -esac -echo "Building for platform $OS-$ARCH" - -# Download and build eudev -mkdir -p "$TARGET_DIR/eudev" -cd "$TARGET_DIR/eudev" -curl -L "http://dev.gentoo.org/~blueness/eudev/eudev-$EUDEV_VERSION.tar.gz" \ - | tar xvz --strip-components=1 -./configure --disable-shared --enable-static --with-pic --prefix="" \ - --enable-split-usr --disable-manpages --disable-kmod \ - --disable-gudev --disable-selinux --disable-blkid -make install-strip DESTDIR="$ROOT_DIR" - -# Download and build libusb -mkdir -p "$TARGET_DIR/libusb" -cd "$TARGET_DIR/libusb" -curl -L "http://downloads.sf.net/project/libusb/libusb-1.0/libusb-$LIBUSB_VERSION/libusb-$LIBUSB_VERSION.tar.bz2" \ - | tar xvj --strip-components=1 -CFLAGS="-I$ROOT_DIR/include" \ -LDFLAGS="-L$ROOT_DIR/lib" \ -./configure --disable-shared --enable-static --with-pic --prefix="" -make install-strip DESTDIR="$ROOT_DIR" - -# Build libusb4java -mkdir -p "$TARGET_DIR/libusb4java" -cd "$TARGET_DIR/libusb4java" -cmake "$PROJECT_DIR" \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="" \ - -DLibUsb_INCLUDE_DIRS="$ROOT_DIR/include/libusb-1.0" \ - -DLibUsb_LIBRARIES="$ROOT_DIR/lib/libusb-1.0.a;$ROOT_DIR/lib/libudev.a" \ - -DLibUsb_LDFLAGS="-pthread -lrt" -make install/strip DESTDIR="$ROOT_DIR" - -# Create the JAR file -mkdir -p "$TARGET_DIR/classes/org/usb4java/$OS-$ARCH" -cp "$ROOT_DIR/lib/libusb4java.so" "$TARGET_DIR/classes/org/usb4java/$OS-$ARCH" -jar cf "$TARGET_DIR/libusb4java-$OS-$ARCH.jar" -C "$TARGET_DIR/classes" org diff --git a/build/osx.sh b/build/osx.sh deleted file mode 100755 index 0b480fc..0000000 --- a/build/osx.sh +++ /dev/null @@ -1,67 +0,0 @@ -# ============================================================================ -# Build script for Mac OS X. -# -# The script automatically compiles the multi-binary for x86 and x86_64 and -# creates the corresponding JAR file in the target folder. -# -# Requirements: cmake, make, curl, jar -# ============================================================================ - -if [ $# -ne 1 ] -then - echo "Syntax: $0 " - exit 1 -fi - -# Fail on all errors -set -e - -# Software versions -LIBUSB_VERSION=1.0.19 - -# Determine directories -cd "$(dirname $0)/.." -PROJECT_DIR="$(pwd)" -TARGET_DIR="$PROJECT_DIR/target" -ROOT_DIR="$TARGET_DIR/root" - -# Clean up target directory -rm -rf "$TARGET_DIR" - -# Determine OS and architecture -OS=osx -ARCH="$1" -case "$ARCH" in - x86) - OSX_ARCH=i386 - ;; - *) - OSX_ARCH="$ARCH" -esac -echo "Building for platform $OS-$ARCH" - -# Download and build libusb -mkdir -p "$TARGET_DIR/libusb" -cd "$TARGET_DIR/libusb" -curl -L "http://downloads.sf.net/project/libusb/libusb-1.0/libusb-$LIBUSB_VERSION/libusb-$LIBUSB_VERSION.tar.bz2" \ - | tar xvj --strip-components=1 -CFLAGS="-I$ROOT_DIR/include -arch $OSX_ARCH" \ -LDFLAGS="-L$ROOT_DIR/lib" \ -./configure --disable-shared --enable-static --with-pic --prefix="$ROOT_DIR" -make install-strip - -# Build libusb4java -mkdir -p "$TARGET_DIR/libusb4java" -cd "$TARGET_DIR/libusb4java" -PKG_CONFIG_PATH="$ROOT_DIR/lib/pkgconfig" cmake "$PROJECT_DIR" \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="" \ - -DCMAKE_OSX_ARCHITECTURES=$OSX_ARCH \ - -DLibUsb_USE_STATIC_LIBS=true -make install/strip DESTDIR="$ROOT_DIR" - -# Create the JAR file -OS=osx -mkdir -p "$TARGET_DIR/classes/org/usb4java/$OS-$ARCH" -cp "$ROOT_DIR/lib/libusb4java.dylib" "$TARGET_DIR/classes/org/usb4java/$OS-$ARCH" -jar cf "$TARGET_DIR/libusb4java-$OS-$ARCH.jar" -C "$TARGET_DIR/classes" org diff --git a/dists/README.md b/dists/README.md new file mode 100644 index 0000000..6d15955 --- /dev/null +++ b/dists/README.md @@ -0,0 +1,11 @@ +This directory contains the build scripts used by the usb4java CI server to +automatically build the native libraries shipped with usb4java. + +If you want to build your own native library for a platform which is not +supported by usb4java out-of-the-box then this might be the wrong place for +you. Follow the instructions in the README.md file in the root directory of +the project instead. + +The bundle script can be used to create a distribution bundle ready to be +uploaded to Sonatype Nexus. It requires already build and deployed SNAPSHOT +versions of all the native JARs. diff --git a/dists/bundle b/dists/bundle new file mode 100755 index 0000000..85a9ae8 --- /dev/null +++ b/dists/bundle @@ -0,0 +1,53 @@ +#!/bin/sh +# +# Copyright (C) 2018 Klaus Reimer +# See LICENSE.md for licensing information. +# + +# Exit on errors +set -e + +# Go to project root directory +cd "$(dirname $0)/.." + +# Get version from pom.xml +VERSION=$(sed -nE '0,//s/.*(.*?)<\/version>.*/\1/p' pom.xml) + +# Determine SNAPSHOT version +SNAPSHOT_VERSION=$(echo $VERSION | sed s/-SNAPSHOT//)-SNAPSHOT + +# Prepare bundle directory +rm -rf target/bundle/ +mkdir -p target/bundle + +# Download latest snapshot platform JARs +PLATFORMS=" + linux-x86 + linux-x86-64 + linux-arm + linux-armel + linux-aarch64 + win32-x86 + win32-x86-64 + darwin-x86-64 + darwin-aarch64 +" +for PLATFORM in $PLATFORMS +do + mvn dependency:copy -Dartifact=org.usb4java:libusb4java:$SNAPSHOT_VERSION:jar:$PLATFORM \ + -DoutputDirectory=target/bundle/ -Dmdep.stripVersion=true + mv target/bundle/libusb4java-$PLATFORM.jar target/bundle/libusb4java-$VERSION-$PLATFORM.jar +done + +# Copy pom to bundle directory +cp pom.xml target/bundle/libusb4java-$VERSION.pom + +# Sign all files +for FILE in target/bundle/* +do + gpg -a --detach-sig $FILE +done + +# Create bundle JAR file +cd target/bundle +jar cf ../libusb4java-$VERSION-bundle.jar * diff --git a/dists/darwin/build b/dists/darwin/build new file mode 100755 index 0000000..a11de9e --- /dev/null +++ b/dists/darwin/build @@ -0,0 +1,96 @@ +#1/bin/bash +# ============================================================================ +# Build script for Mac OS X. +# +# The script automatically compiles the binary for x86-64 and aarch64. +# Then it creates the corresponding JAR file in the target folder containing +# both architecture builds. +# The libusb sources are pulled from the GitHub tag matching the configured +# version. +# +# Requirements: cmake, make, curl, jar +# ============================================================================ + +# Fail on all errors +set -e + +# Software versions +LIBUSB_VERSION=1.0.28 + +# Determine OS +OS=darwin + +# Determine directories +cd "$(dirname $0)/../.." +PROJECT_DIR="$(pwd)" +TARGET_DIR="$PROJECT_DIR/target" +JAR_FILE=$TARGET_DIR/libusb4java-$OS.jar + +# Download libusb from GitHub and unzip +DOWNLOAD_DIR="$TARGET_DIR/downloads" + +# Clean up target directory +rm -rf "$TARGET_DIR" + +# Create download directory if not already present +mkdir -p "$DOWNLOAD_DIR" + +LIBUSB_TARBALL="v$LIBUSB_VERSION.zip" +LIBUSB_SOURCE=https://github.com/libusb/libusb/archive/$LIBUSB_TARBALL +LIBUSB_TARGET="$DOWNLOAD_DIR/$LIBUSB_TARBALL" +if [ ! -f "$LIBUSB_TARGET" ] +then + curl -C - -o "$LIBUSB_TARGET.download" -L "$LIBUSB_SOURCE" + mv -f "$LIBUSB_TARGET.download" "$LIBUSB_TARGET" +fi + +build_architecture () { + + local ARCH_ID=$1 + local ARCH=$2 + echo "Building for platform $OS-$ARCH" + local BUILD_DIR="$TARGET_DIR/build/darwin-$ARCH" + local ROOT_DIR="$BUILD_DIR/root" + + # Standard compiler and linker flags + local CFLAGS="-I$ROOT_DIR/include -arch $ARCH" + local LDFLAGS="-L$ROOT_DIR/lib" + + # Export compiler and linker flags + export CFLAGS LDFLAGS + + # Unzip libusb + mkdir -p "$BUILD_DIR" + cd "$BUILD_DIR" + unzip "$LIBUSB_TARGET" + mv "$BUILD_DIR/libusb-$LIBUSB_VERSION" "$BUILD_DIR/libusb" + cd "$BUILD_DIR/libusb" + + # Build libusb + autoreconf -i + ./configure --disable-shared --enable-static --with-pic --prefix="$ROOT_DIR" --host=$ARCH + make install-strip + + # Build libusb4java + mkdir -p "$BUILD_DIR/libusb4java" + cd "$BUILD_DIR/libusb4java" + PKG_CONFIG_PATH="$ROOT_DIR/lib/pkgconfig" cmake "$PROJECT_DIR" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="" \ + -DCMAKE_OSX_ARCHITECTURES=$ARCH \ + -DLibUsb_USE_STATIC_LIBS=true + make install/strip DESTDIR="$ROOT_DIR" + + # Create the JAR file + mkdir -p "$BUILD_DIR/classes/org/usb4java/$OS-$ARCH_ID" + cp "$ROOT_DIR/lib/libusb4java.dylib" "$BUILD_DIR/classes/org/usb4java/$OS-$ARCH_ID" + + if [ -f "$JAR_FILE" ]; then + jar uf "$JAR_FILE" -C "$BUILD_DIR/classes" org + else + jar cf "$JAR_FILE" -C "$BUILD_DIR/classes" org + fi +} + +build_architecture x86-64 x86_64 +build_architecture aarch64 arm64 diff --git a/dists/linux/Dockerfile b/dists/linux/Dockerfile new file mode 100644 index 0000000..695b9b5 --- /dev/null +++ b/dists/linux/Dockerfile @@ -0,0 +1,52 @@ +# +# Copyright (C) 2018 Klaus Reimer +# See LICENSE.md for licensing information. +# + +ARG DOCKER_ARCH +FROM $DOCKER_ARCH/debian:bookworm + +ARG OS_ARCH +ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-$OS_ARCH + +ENV LIBUSB_VERSION=1.0.28 +ENV EUDEV_VERSION=3.2.14 + +# Copy optional qemu binaries +ARG ARCH +COPY target/build/linux-$ARCH/qemu* /usr/bin/ + +# Install debian updates +RUN apt update && apt upgrade -y + +# Install required debian packages +RUN apt install -y gnome-icon-theme gcc cmake curl gperf bzip2 openjdk-17-jdk + +# Install eudev +RUN mkdir -p /tmp/eudev; \ + cd /tmp/eudev; \ + curl -L https://github.com/eudev-project/eudev/releases/download/v$EUDEV_VERSION/eudev-$EUDEV_VERSION.tar.gz | tar xvz --strip-components 1; \ + ./configure \ + --disable-shared \ + --enable-static \ + --with-pic \ + --enable-split-usr \ + --disable-manpages \ + --disable-kmod \ + --disable-selinux \ + --disable-blkid \ + --prefix=/usr/local; \ + make install-strip; \ + rm -rf /tmp/eudev + +# Install libusb +RUN mkdir -p /tmp/libusb; \ + cd /tmp/libusb; \ + curl -L https://github.com/libusb/libusb/releases/download/v$LIBUSB_VERSION/libusb-$LIBUSB_VERSION.tar.bz2 | tar xvj --strip-components 1; \ + ./configure \ + --disable-shared \ + --enable-static \ + --with-pic \ + --prefix=/usr/local; \ + make install-strip; \ + rm -rf /tmp/libusb diff --git a/dists/linux/Dockerfile.arm b/dists/linux/Dockerfile.arm new file mode 100644 index 0000000..20db99e --- /dev/null +++ b/dists/linux/Dockerfile.arm @@ -0,0 +1,54 @@ +# +# Copyright (C) 2018 Klaus Reimer +# See LICENSE.md for licensing information. +# + +FROM debian:stretch + +ENV LIBUSB_VERSION=1.0.24 + +# Install debian updates +RUN apt-get update && apt-get upgrade -y + +# Install required debian packages +RUN apt-get install -y cmake curl gperf bzip2 gcj-6-jdk git + +# Install Raspberry Pi tools +RUN cd /opt; \ + git clone --depth 1 https://github.com/raspberrypi/tools + +# Install eudev +RUN mkdir -p /tmp/eudev; \ + cd /tmp/eudev; \ + curl -L http://dev.gentoo.org/~blueness/eudev/eudev-3.2.6.tar.gz | tar xvz --strip-components 1; \ + export PATH=/opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin:$PATH; \ + ./configure \ + --host=arm-linux-gnueabihf \ + --disable-shared \ + --enable-static \ + --with-pic \ + --enable-split-usr \ + --disable-manpages \ + --disable-kmod \ + --disable-selinux \ + --disable-blkid \ + --prefix=/usr/local; \ + make install-strip; \ + rm -rf /tmp/eudev + +# Install libusb +RUN mkdir -p /tmp/libusb; \ + cd /tmp/libusb; \ + curl -L https://github.com/libusb/libusb/releases/download/v$LIBUSB_VERSION/libusb-$LIBUSB_VERSION.tar.bz2 | tar xvj --strip-components 1; \ + export PATH=/opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin:$PATH; \ + export CFLAGS=-I/usr/local/include; \ + export CPPFLAGS=-I/usr/local/include; \ + export LDFLAGS=-L/usr/local/lib; \ + ./configure \ + --host=arm-linux-gnueabihf \ + --disable-shared \ + --enable-static \ + --with-pic \ + --prefix=/usr/local; \ + make install-strip; \ + rm -rf /tmp/libusb diff --git a/dists/linux/README.md b/dists/linux/README.md new file mode 100644 index 0000000..cd28f2f --- /dev/null +++ b/dists/linux/README.md @@ -0,0 +1,86 @@ +Linux Build +=========== + +This build script automatically compiles the native libusb4java library for the given architecture. It is primarily +written to be used on a X86-64 Debian machine but may work on other systems as well. + +The first build for a specific architecture takes a long time because a matching Docker image is created first. This +image is based on Debian Stretch and is filled with all necessary tools and libraries to build libusb4java. The +Docker image is cached so the next build for the same architecture will be much faster. + + +## Requirements + +The following packages must be installed before running the build script: + + # apt install binfmt-support qemu-user-static + +[Docker] must be installed by following the official installation instructions. + +After installing Docker it is recommended to put your user into the docker group and logout and in again to apply the +change. Then you are able to use docker without root privileges. + + +## Parameters + +The first parameter of the build script defines the target platform architecture. This is for example `x86`, `x86-64`, +`arm` or `aarch64`. The architecture naming convention of usb4java follows the one of the [Java Native Access] project. + +The second parameter is optional and defines the static qemu binary which is necessary for cross compiling. + + +## Example usages + +Build a X86 (32 bit) library on a X86 or X86-64 host system: + + $ ./build x86 + +Build a X86-64 library on a X86-64 host system: + + $ ./build x86-64 + +Build a ARM-HF (32 bit) library: + + $ ./build arm /usr/bin/qemu-arm-static + +Build a AARCH64 (ARM 64 Bit) library: + + $ ./build aarch64 /usr/bin/qemu-aarch64-static + +In theory this works for many more architectures as long as there is a Debian Stretch docker image for this +architecture and the architecture is supported by qemu. New entries in the architecture mapping in the build script +might be needed in case the java architecture name differs from the Debian architecture name in the docker library. + + +## Some notes about Docker + +### Disable bridge networking + +If you don't need Docker for anything else and you don't like Docker's default behavior of creating bridge networking +devices and firewall rules then you might want to disable all this by creating the config file `/etc/docker/daemon.json` +with the following content: + + { + "bridge": "none", + "iptables": false, + "ip-masq": false, + "ip-forward": false + } + +Run `sudo systemctl restart docker` to apply the changes. The libusb4java build script uses host networking which +doesn't need bridge network devices. + + +### Cleaning up + +All the created Docker images uses a lot of disk space. You can remove them with `docker system prune -a`. + + +## Known issues + +While the build script is able to create a binary for the ARM architecture this will not work on a Raspberry +Pi 1. Would be nice to get it running, I tried for days, but I didn't succeed. That's why there is a special build +script for ARM which uses the Raspberry Pi cross compiler toolchain. + +[Java Native Access]: https://github.com/java-native-access/jna/tree/master/dist/ +[Docker]: https://docs.docker.com/install/linux/docker-ce/debian/ diff --git a/dists/linux/build b/dists/linux/build new file mode 100755 index 0000000..c2db50b --- /dev/null +++ b/dists/linux/build @@ -0,0 +1,96 @@ +#!/bin/bash +# +# Copyright (C) 2018 Klaus Reimer +# See LICENSE.md for licensing information. +# + +# Exit on errors +set -e + +# Go to base directory +cd $(dirname $0)/../.. + +# Show syntax help when called with wrong number of parameters +if [ $# -lt 1 ] || [ $# -gt 2 ] +then + echo "Syntax: $0 ARCH [QEMU]" + exit 1 +fi + +# Fetch CLI arguments and create some helper variables +ARCH=$1 +QEMU=$2 +OS=linux +TARGET=target +BUILD=$TARGET/build/$OS-$ARCH + +# Map specified architecture to a debian docker image architecture +case $ARCH in + x86-64) + DOCKER_ARCH=amd64 + OS_ARCH=amd64 + ;; + x86) + DOCKER_ARCH=i386 + OS_ARCH=i386 + ;; + aarch64) + DOCKER_ARCH=arm64v8 + OS_ARCH=arm64 + ;; + arm) + DOCKER_ARCH=arm32v7 + OS_ARCH=armhf + ;; + armel) + DOCKER_ARCH=arm32v5 + OS_ARCH=armel + ;; + *) + DOCKER_ARCH=$ARCH + OS_ARCH=$ARCH + ;; +esac + +# Create build directory +mkdir -p $BUILD + +# Copy qemu binary to build directory if specified +if [ "$QEMU" != "" ] +then + cp -f $QEMU $BUILD/ +else + # Dummy file to keep COPY in Dockerfile happy + touch $BUILD/qemu-none +fi + +# Build docker image +docker build . \ + --network host \ + -f dists/linux/Dockerfile \ + --build-arg ARCH=$ARCH \ + --build-arg DOCKER_ARCH=$DOCKER_ARCH \ + --build-arg OS_ARCH=$OS_ARCH \ + -t usb4java-build-$ARCH + +# Compile libusb4java in docker image +docker run \ + -u $(id -u $USER):$(id -g $USER) \ + --network host \ + --rm \ + -v $(pwd):/workspace \ + usb4java-build-$ARCH \ + /bin/bash -c " + cd /workspace/$BUILD; + cmake ../../.. \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX='' \ + -DLibUsb_LIBRARIES='/usr/local/lib/libusb-1.0.a;/usr/local/lib/libudev.a' \ + -DLibUsb_LDFLAGS='-pthread -lrt'; + make install/strip DESTDIR=/workspace/$BUILD + " + +# Create the JAR file +mkdir -p "$BUILD/classes/org/usb4java/$OS-$ARCH" +cp "$BUILD/lib/libusb4java.so" "$BUILD/classes/org/usb4java/$OS-$ARCH" +jar cf "$TARGET/libusb4java-$OS-$ARCH.jar" -C "$BUILD/classes" org diff --git a/dists/linux/build-all b/dists/linux/build-all new file mode 100755 index 0000000..911f0d5 --- /dev/null +++ b/dists/linux/build-all @@ -0,0 +1,26 @@ +#!/bin/bash +# +# Copyright (C) 2018 Klaus Reimer +# See LICENSE.md for licensing information. +# + +# Exit on errors +set -e + +# Go to base directory of linux build scripts +cd $(dirname $0) + +# Build X86 library +./build x86 + +# Build X86-64 library +./build x86-64 + +# Build ARM 64-bit library (ARMv8 and higher) +./build aarch64 + +# Build ARM 32-bit library (ARMv7 and higher) +./build arm + +# Build ARM 32-bit library (ARMv4T and higher) +./build armel diff --git a/dists/linux/build-arm b/dists/linux/build-arm new file mode 100755 index 0000000..4652bbe --- /dev/null +++ b/dists/linux/build-arm @@ -0,0 +1,50 @@ +#!/bin/bash +# +# Copyright (C) 2018 Klaus Reimer +# See LICENSE.md for licensing information. +# + +# Exit on errors +set -e + +# Go to base directory +cd $(dirname $0)/../.. + +# Create some helper variables +TARGET=target +BUILD=$TARGET/build/linux-arm-rpt + +# Create build directory +mkdir -p $BUILD + +# Build docker image +docker build . \ + --network host \ + -f dists/linux/Dockerfile.arm \ + -t usb4java-build-arm-rpt + +# Compile libusb4java in docker image +docker run \ + -u $(id -u $USER):$(id -g $USER) \ + --network host \ + --rm \ + -v $(pwd):/workspace \ + usb4java-build-arm-rpt \ + /bin/bash -c " + cd /workspace/$BUILD; + export PATH=/opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin:$PATH; + JAVA_HOME=/usr/lib/jvm/java-gcj-6 cmake ../../.. \ + -DCMAKE_SYSTEM_NAME=Linux \ + -DCMAKE_SYSTEM_PROCESSOR=arm \ + -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX='' \ + -DLibUsb_LIBRARIES='/usr/local/lib/libusb-1.0.a;/usr/local/lib/libudev.a' \ + -DLibUsb_LDFLAGS='-pthread -lrt'; + make install/strip DESTDIR=/workspace/$BUILD + " + +# Create the JAR file +mkdir -p "$BUILD/classes/org/usb4java/linux-arm" +cp "$BUILD/lib/libusb4java.so" "$BUILD/classes/org/usb4java/linux-arm" +jar cf "$TARGET/libusb4java-linux-arm.jar" -C "$BUILD/classes" org diff --git a/dists/win32/build-all.bat b/dists/win32/build-all.bat new file mode 100644 index 0000000..1a0ebda --- /dev/null +++ b/dists/win32/build-all.bat @@ -0,0 +1,15 @@ +@echo off + +rem Variables - General +for %%I in ("%~dp0.") do set "SCRIPT_DIR=%%~fI" +set "BUILD_BAT=%SCRIPT_DIR%\build.bat" + +rem Variables - Visual Studio +set "VSWHERE_EXE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +set "VSWHERE_OPTIONS=-latest -property installationPath -format value" +for /f "delims=" %%i in ('"%VSWHERE_EXE%" %VSWHERE_OPTIONS%') do set "VS_PATH=%%i" +set "VSDEVCMD_BAT=%VS_PATH%\Common7\Tools\VsDevCmd.bat" + +rem Main +cmd /c ""%VSDEVCMD_BAT%" && "%BUILD_BAT%"" +cmd /c ""%VSDEVCMD_BAT%" -host_arch=amd64 -arch=amd64 && set "PLATFORM=x64" && "%BUILD_BAT%"" \ No newline at end of file diff --git a/build/windows.bat b/dists/win32/build.bat similarity index 77% rename from build/windows.bat rename to dists/win32/build.bat index b6abbec..0dcaa73 100644 --- a/build/windows.bat +++ b/dists/win32/build.bat @@ -7,49 +7,49 @@ rem 64 bit or 32 bit. The script automatically compiles the binary for rem the corresponding platform and creates the JAR file in the target rem folder. rem -rem Dependencies: cmake, curl, jar and 7z must be callable via PATH. -rem Visual Studio 2013 Community must be installed. +rem Dependencies: cmake, curl, jar and 7z must be callable via PATH. +rem Visual Studio 2017 Build Tools must be installed. rem ====================================================================== rem ---------------------------------------------------------------------- rem Setup variables rem ---------------------------------------------------------------------- -set LIBUSB_VERSION=1.0.19 +set LIBUSB_VERSION=1.0.28 + set CURRENT=%cd% -set PROJECT_DIR=%~dp0.. -set OS=windows +set PROJECT_DIR=%~dp0..\.. +set OS=win32 if /i "%Platform%" == "x64" ( - set ARCH=x86_64 + set ARCH=x86-64 set LIBUSB_ARCH=MS64 ) else ( set ARCH=x86 set LIBUSB_ARCH=MS32 ) set TARGET_DIR=%PROJECT_DIR%\target -set BUILD_DIR=%TARGET_DIR%\build -set ROOT_DIR=%TARGET_DIR%\root +set BUILD_DIR=%TARGET_DIR%\build\%OS%-%ARCH% +set ROOT_DIR=%BUILD_DIR%\root rem -rem Compile libusb. +rem Compile libusb. rem We do this manually because we need the /MT option and the provided -rem build script unfortunately only works with an old Windows DDK instead +rem build script unfortunately only works with an old Windows DDK instead rem of using Visual Studio. rem set LIBUSB_NAME=libusb-%LIBUSB_VERSION% set LIBUSB_COMPRESSED_ARCHIVE=%LIBUSB_NAME%.tar.bz2 -set LIBUSB_ARCHIVE=%LIBUSB_NAME%.tar +set LIBUSB_ARCHIVE=v%LIBUSB_VERSION%.zip mkdir "%ROOT_DIR%" cd "%ROOT_DIR% -curl -L -o "%LIBUSB_COMPRESSED_ARCHIVE%" http://downloads.sourceforge.net/project/libusb/libusb-1.0/%LIBUSB_NAME%/%LIBUSB_COMPRESSED_ARCHIVE% || goto :error -7z -y x "%LIBUSB_COMPRESSED_ARCHIVE%" || goto :error +curl -L -o "%LIBUSB_ARCHIVE%" https://github.com/libusb/libusb/archive/%LIBUSB_ARCHIVE% || goto :error 7z -y x "%LIBUSB_ARCHIVE%" || goto :error cd "%LIBUSB_NAME%" mkdir build cd build -cl /nologo /c /MT /I..\libusb /I..\msvc ..\libusb\*.c ..\libusb\os\windows*.c ..\libusb\os\*windows.c +cl /DHAVE_STRUCT_TIMESPEC /nologo /c /MT /I..\libusb /I..\msvc ..\libusb\*.c ..\libusb\os\windows*.c ..\libusb\os\*windows.c lib /nologo /out:libusb.lib *.obj @@ -84,9 +84,7 @@ rem Clean up and go back to original directory rem ---------------------------------------------------------------------- cd "%CURRENT%" -rmdir /s /q "%BUILD_DIR%" -rmdir /s /q "%ROOT_DIR%" -goto :EOF +goto :end :error set ERRORCODE=%errorlevel% @@ -96,4 +94,3 @@ exit /b %ERRORCODE% :end echo Finished - diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..da23b4b --- /dev/null +++ b/pom.xml @@ -0,0 +1,137 @@ + + + 4.0.0 + + org.usb4java + libusb4java + pom + libusb4java + 1.3.1-SNAPSHOT + https://github.com/usb4java/libusb4java/ + The native JNI library used by usb4java + 2011 + + usb4java Team + http://usb4java.org/ + + + + + MIT + LICENSE.md + repo + + + + + + Discussions + usb4java+subscribe@googlegroups.com + usb4java+unsubscribe@googlegroups.com + usb4java@googlegroups.com + http://groups.google.com/group/usb4java + + + + + + kayahr + Klaus Reimer + k@ailis.de + + Developer + + +1 + http://www.ailis.de/~k/ + + + llongi + Luca Longinotti + l@longi.li + + Developer + + +1 + http://l.longi.li/ + + + + + UTF-8 + ${project.version} + + + + scm:git:git://github.com/usb4java/${project.artifactId}.git + scm:git:ssh://git@github.com/usb4java/${project.artifactId}.git + http://github.com/usb4java/${project.artifactId} + HEAD + + + + GitHub + https://github.com/usb4java/${project.artifactId}/issues + + + + 3.0.5 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.0 + + + org.apache.maven.plugins + maven-clean-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-deploy-plugin + 3.0.0-M1 + + + org.apache.maven.plugins + maven-install-plugin + 3.0.0-M1 + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-resources-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-site-plugin + 3.7.1 + + + + + + + sonatype-snapshots + Sonatype Snapshot Repository + https://oss.sonatype.org/content/repositories/snapshots + true + + + + + + sonatype-snapshots + Sonatype Snapshot Repository + https://oss.sonatype.org/content/repositories/snapshots + + + + diff --git a/src/LibUsb.c b/src/LibUsb.c index 83eeb13..5ed4d1c 100644 --- a/src/LibUsb.c +++ b/src/LibUsb.c @@ -33,9 +33,27 @@ #include "ContainerIdDescriptor.h" #include "Transfer.h" #include "HotplugCallbackHandle.h" +#include "Pollfds.h" static int defaultContextRefcnt = 0; +/** + * Validates the default context by making sure the reference counter is larger than 0. + * + * @param ENV + * The Java environment. + * @param CONTEXT + * The context. This check does nothing if a context is set. + * @param ACTION + * The action to perform after throwing an exception. + */ +#define VALIDATE_DEFAULT_CONTEXT(ENV, CONTEXT, ACTION) \ + if (!CONTEXT && !defaultContextRefcnt) \ + { \ + illegalState(ENV, "Default context is not initialized"); \ + ACTION; \ + } + /** * Version getVersion() */ @@ -130,7 +148,20 @@ JNIEXPORT void JNICALL METHOD_NAME(LibUsb, setDebug) { libusb_context *ctx = unwrapContext(env, context); if (!ctx && context) return; - libusb_set_debug(ctx, level); + libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level); +} + +/** + * void setOption(Context, int, int) + */ +JNIEXPORT void JNICALL METHOD_NAME(LibUsb, setOption) +( + JNIEnv *env, jclass class, jobject context, jint option, jint value +) +{ + libusb_context *ctx = unwrapContext(env, context); + if (!ctx && context) return; + libusb_set_option(ctx, option, value); } /** @@ -145,6 +176,7 @@ JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, getDeviceList) libusb_device **list; ssize_t result; + VALIDATE_DEFAULT_CONTEXT(env, context, return 0); VALIDATE_NOT_NULL(env, deviceList, return 0); VALIDATE_POINTER_NOT_SET(env, deviceList, "deviceListPointer", return 0); ctx = unwrapContext(env, context); @@ -597,6 +629,48 @@ JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, freeStreams) return returnValue; } +/** + * ByteBuffer devMemAlloc(DeviceHandle, int) + */ +JNIEXPORT jobject JNICALL METHOD_NAME(LibUsb, devMemAlloc) +( + JNIEnv *env, jclass class, jobject handle, jint length +) +{ + libusb_device_handle *dev_handle; + + VALIDATE_NOT_NULL(env, handle, return 0); + + dev_handle = unwrapDeviceHandle(env, handle); + if (!dev_handle) return 0; + + unsigned char *mem = libusb_dev_mem_alloc(dev_handle, length); + if (!mem) return NULL; + + jobject buffer = (*env)->NewDirectByteBuffer(env, mem, length); + return buffer; +} + +/** + * int devMemFree(DeviceHandle, ByteBuffer, int) + */ +JNIEXPORT int JNICALL METHOD_NAME(LibUsb, devMemFree) +( + JNIEnv *env, jclass class, jobject handle, jobject buffer, jint length +) +{ + libusb_device_handle *dev_handle; + + VALIDATE_NOT_NULL(env, handle, return 0); + VALIDATE_NOT_NULL(env, buffer, return 0); + + dev_handle = unwrapDeviceHandle(env, handle); + if (!dev_handle) return 0; + + unsigned char *mem = (*env)->GetDirectBufferAddress(env, buffer); + return libusb_dev_mem_free(dev_handle, mem, length); +} + /** * int kernelDriverActive(DeviceHandle, int) */ @@ -1310,6 +1384,19 @@ JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, eventHandlerActive) return libusb_event_handler_active(ctx); } +/** + * void interruptEventHandler(Context) + */ +JNIEXPORT void JNICALL METHOD_NAME(LibUsb, interruptEventHandler) +( + JNIEnv *env, jclass class, jobject context +) +{ + libusb_context *ctx = unwrapContext(env, context); + if (!ctx && context) return; + libusb_interrupt_event_handler(ctx); +} + /** * void lockEventWaiters(Context) */ @@ -1566,6 +1653,46 @@ JNIEXPORT void JNICALL METHOD_NAME(LibUsb, unsetPollfdNotifiersNative) libusb_set_pollfd_notifiers(ctx, NULL, NULL, NULL); } +/** + * Pollfds getPollfds(Context) + */ +JNIEXPORT jobject JNICALL METHOD_NAME(LibUsb, getPollfds) +( + JNIEnv *env, jclass class, jobject context +) +{ + libusb_context *ctx; + const struct libusb_pollfd **list; + jobject pollfds; + jint size; + + VALIDATE_DEFAULT_CONTEXT(env, context, return NULL); + ctx = unwrapContext(env, context); + if (!ctx && context) return NULL; + list = libusb_get_pollfds(ctx); + if (!list) return NULL; + for (size = 0; list[size]; size++) {}; + pollfds = wrapPollfds(env, list, size); + return pollfds; +} + +/** + * void freePollfds(Pollfds) + */ +JNIEXPORT void JNICALL METHOD_NAME(LibUsb, freePollfds) +( + JNIEnv *env, jclass class, jobject pollfds +) +{ + const struct libusb_pollfd **list; + + if (!pollfds) return; + list = unwrapPollfds(env, pollfds); + if (!list) return; + libusb_free_pollfds(list); + resetPollfds(env, pollfds); +} + /** * Transfer allocTransfer(int) */ diff --git a/src/Pollfd.c b/src/Pollfd.c new file mode 100644 index 0000000..923e6d5 --- /dev/null +++ b/src/Pollfd.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 Klaus Reimer (k@ailis.de) + * See LICENSE.md file for copying conditions + */ + +#include "Pollfd.h" + +jobject wrapPollfd(JNIEnv* env, const struct libusb_pollfd* pollfd) +{ + return wrapPointer(env, pollfd, CLASS_PATH("Pollfd"), "pollfdPointer"); +} + +const struct libusb_pollfd* unwrapPollfd(JNIEnv* env, jobject pollfd) +{ + return (struct libusb_pollfd *) unwrapPointer(env, pollfd, "pollfdPointer"); +} + +void resetPollfd(JNIEnv* env, jobject object) +{ + RESET_POINTER(env, object, "pollfdPointer"); +} + +/** + * int fd() + */ +JNIEXPORT jint JNICALL METHOD_NAME(Pollfd, fd) +( + JNIEnv *env, jobject this +) +{ + const struct libusb_pollfd* descriptor = unwrapPollfd(env, this); + if (!descriptor) return 0; + return (jint) descriptor->fd; +} + +/** + * int events() + */ +JNIEXPORT jshort JNICALL METHOD_NAME(Pollfd, events) +( + JNIEnv *env, jobject this +) +{ + const struct libusb_pollfd* descriptor = unwrapPollfd(env, this); + if (!descriptor) return 0; + return (jshort) descriptor->events; +} diff --git a/src/Pollfd.h b/src/Pollfd.h new file mode 100644 index 0000000..5ad0ee2 --- /dev/null +++ b/src/Pollfd.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2018 Klaus Reimer (k@ailis.de) + * See LICENSE.md file for copying conditions + */ + +#ifndef USB4JAVA_POLLFD_H +#define USB4JAVA_POLLFD_H + +#include "usb4java.h" + +jobject wrapPollfd(JNIEnv*, const struct libusb_pollfd*); +const struct libusb_pollfd* unwrapPollfd(JNIEnv*, jobject); +void resetPollfd(JNIEnv*, jobject); + +#endif diff --git a/src/Pollfds.c b/src/Pollfds.c new file mode 100644 index 0000000..46ab7c9 --- /dev/null +++ b/src/Pollfds.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018 Klaus Reimer (k@ailis.de) + * See LICENSE.md file for copying conditions + */ + +#include "Pollfds.h" +#include "Pollfd.h" + +jobject wrapPollfds(JNIEnv* env, const struct libusb_pollfd** list, int size) +{ + jobject pollfds = wrapPointer(env, list, CLASS_PATH("Pollfds"), "pollfdsPointer"); + jclass cls = (*env)->GetObjectClass(env, pollfds); + jfieldID field = (*env)->GetFieldID(env, cls, "size", "I"); + (*env)->SetIntField(env, pollfds, field, size); + return pollfds; +} + +const struct libusb_pollfd** unwrapPollfds(JNIEnv* env, jobject pollfds) +{ + return (const struct libusb_pollfd **) unwrapPointer(env, pollfds, "pollfdsPointer"); +} + +void resetPollfds(JNIEnv* env, jobject object) +{ + RESET_POINTER(env, object, "pollfdsPointer"); +} + +/** + * Pollfd get(index) + */ +JNIEXPORT jobject JNICALL METHOD_NAME(Pollfds, get) +( + JNIEnv *env, jobject this, jint index +) +{ + jclass cls; + const struct libusb_pollfd** list; + jfieldID field; + int size; + + list = unwrapPollfds(env, this); + if (!list) return NULL; + + cls = (*env)->GetObjectClass(env, this); + field = (*env)->GetFieldID(env, cls, "size", "I"); + size = (*env)->GetIntField(env, this, field); + if (index < 0 || index >= size) return NULL; + + return wrapPollfd(env, list[index]); +} diff --git a/src/Pollfds.h b/src/Pollfds.h new file mode 100644 index 0000000..0f7f7b0 --- /dev/null +++ b/src/Pollfds.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2018 Klaus Reimer (k@ailis.de) + * See LICENSE.md file for copying conditions + */ + +#ifndef USB4JAVA_POLLFDS_H +#define USB4JAVA_POLLFDS_H + +#include "usb4java.h" + +jobject wrapPollfds(JNIEnv*, const struct libusb_pollfd**, int size); +const struct libusb_pollfd** unwrapPollfds(JNIEnv*, jobject); +void resetPollfds(JNIEnv*, jobject); + +#endif