diff --git a/build.gradle b/build.gradle index 3393873..a3bd4e3 100755 --- a/build.gradle +++ b/build.gradle @@ -1,208 +1,208 @@ -apply plugin: 'groovy' -apply plugin: 'cpp' - -allprojects { - apply plugin: 'java' - apply plugin: 'idea' - apply plugin: 'maven' - - repositories { - mavenCentral() - maven { url "https://gradle.artifactoryonline.com/gradle/libs-releases-local" } - } - - dependencies { - testCompile 'org.spockframework:spock-core:0.6-groovy-1.8' - } - - group = 'net.rubygrapefruit' - version = '0.2' - - sourceCompatibility = 1.5 - targetCompatibility = 1.5 - - configurations.compile.extendsFrom = [] - - tasks.withType(Upload) { - repositories { - mavenDeployer { - if (project.hasProperty('release')) { - repository(url: uri("https://gradle.artifactoryonline.com/gradle/libs-releases-local")) { - authentication(userName: artifactoryUserName, password: artifactoryPassword) - } - } else { - repository(url: uri("$rootProject.buildDir/repo")) - } - } - } - } -} - -dependencies { - groovy 'org.codehaus.groovy:groovy:1.8.7' -} - -def nativeHeadersDir = file("$buildDir/nativeHeaders") - -cpp { - sourceSets { - main - } -} - -libraries { - if (org.gradle.internal.os.OperatingSystem.current().macOsX) { - universal.spec { - baseName = 'native-platform-osx-universal' - includes(['/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/']) - args("-lcurses", "-arch", "x86_64", "-arch", "i386", "-o", outputFile) - } - } else if (org.gradle.internal.os.OperatingSystem.current().windows) { - all { - spec { - includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include"]) - includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include/win32"]) - args("/DWIN32") - } - } - - def out = new ByteArrayOutputStream() - exec { - commandLine "cl.exe", "/?" - errorOutput = out - standardOutput = new ByteArrayOutputStream() - } - def header = out.toString().readLines().head() - if (header.endsWith("for 80x86") || header.endsWith("for x86")) { - i386.spec { - baseName = 'native-platform-windows-i386' - } - } else if (header.endsWith("for x64")) { - amd64.spec { - baseName = 'native-platform-windows-amd64' - } - } else { - throw new RuntimeException("Cannot determine compiler's target architecture") - } - - } else if (org.gradle.internal.os.OperatingSystem.current().linux) { - all { - spec { - includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include"]) - includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include/linux"]) - args("-lcurses") - } - } - if (System.getProperty('os.arch') == 'i386' || project.hasProperty('multiarch')) { - i386.spec { - baseName = 'native-platform-linux-i386' - args("-m32") - } - } - if (System.getProperty('os.arch') == 'amd64' || project.hasProperty('multiarch')) { - amd64.spec { - baseName = 'native-platform-linux-amd64' - args("-m64") - } - } - } else { - baseName = "native-platform-solaris" - main.spec { - includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include"]) - includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include/solaris"]) - args("-DSOLARIS", "-lcurses") - } - } - all { - spec { - includes([nativeHeadersDir]) - } - sourceSets << cpp.sourceSets.main - } -} - -task nativeHeaders { - def outputFile = file("$nativeHeadersDir/native.h") - inputs.files sourceSets.main.output - outputs.file outputFile - doLast { - outputFile.parentFile.mkdirs() - exec { - executable org.gradle.internal.jvm.Jvm.current().getExecutable('javah') - args '-o', outputFile - args '-classpath', sourceSets.main.output.classesDir - args 'net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions' - args 'net.rubygrapefruit.platform.internal.jni.PosixFileFunctions' - args 'net.rubygrapefruit.platform.internal.jni.PosixFileSystemFunctions' - args 'net.rubygrapefruit.platform.internal.jni.PosixProcessFunctions' - args 'net.rubygrapefruit.platform.internal.jni.PosixTerminalFunctions' - args 'net.rubygrapefruit.platform.internal.jni.TerminfoFunctions' - args 'net.rubygrapefruit.platform.internal.jni.WindowsConsoleFunctions' - } - } -} - -configurations { - jni -} - -def deployer = uploadJni.repositories.mavenDeployer - -libraries.all { lib -> - def nativeJar = task("nativeJar${lib.name.capitalize()}", type: Jar) { - from lib.spec.task - baseName = lib.spec.baseName - } - lib.spec.task.dependsOn nativeHeaders - test.dependsOn lib.spec.task - artifacts { - jni nativeJar - runtime nativeJar - } - def jniPom = deployer.addFilter(lib.name) { artifact, file -> - return file == nativeJar.archivePath - } - jniPom.groupId = project.group - jniPom.artifactId = lib.spec.baseName - jniPom.version = project.version - jniPom.scopeMappings.mappings.clear() -} - -javadoc { - exclude '**/internal/**' -} - -task sourceZip(type: Zip) { - from sourceSets.main.allSource - classifier = 'sources' -} - -task javadocZip(type: Zip) { - from javadoc - classifier = 'javadoc' -} - -artifacts { - archives sourceZip - archives javadocZip -} - -def mainPom = uploadArchives.repositories.mavenDeployer.pom -mainPom.groupId = project.group -mainPom.artifactId = jar.baseName -mainPom.version = project.version -mainPom.scopeMappings.mappings.clear() -mainPom.withXml { provider -> - def node = provider.asNode() - def deps = node.appendNode('dependencies') - ['osx-universal', 'linux-amd64', 'linux-i386', 'windows-amd64', 'windows-i386'].each { platform -> - def dep = deps.appendNode('dependency') - dep.appendNode('groupId', project.group) - dep.appendNode('artifactId', "native-platform-${platform}") - dep.appendNode('version', project.version) - } -} - -task wrapper(type: Wrapper) { - gradleVersion = "1.3-20120907220018+0000" -} +apply plugin: 'groovy' +apply plugin: 'cpp' + +allprojects { + apply plugin: 'java' + apply plugin: 'idea' + apply plugin: 'maven' + + repositories { + mavenCentral() + maven { url "http://repo.gradle.org/gradle/libs-releases-local" } + } + + dependencies { + testCompile 'org.spockframework:spock-core:0.6-groovy-1.8' + } + + group = 'net.rubygrapefruit' + version = '0.2' + + sourceCompatibility = 1.5 + targetCompatibility = 1.5 + + configurations.compile.extendsFrom = [] + + tasks.withType(Upload) { + repositories { + mavenDeployer { + if (project.hasProperty('release')) { + repository(url: uri("https://gradle.artifactoryonline.com/gradle/libs-releases-local")) { + authentication(userName: artifactoryUserName, password: artifactoryPassword) + } + } else { + repository(url: uri("$rootProject.buildDir/repo")) + } + } + } + } +} + +dependencies { + groovy 'org.codehaus.groovy:groovy:1.8.7' +} + +def nativeHeadersDir = file("$buildDir/nativeHeaders") + +cpp { + sourceSets { + main + } +} + +libraries { + if (org.gradle.internal.os.OperatingSystem.current().macOsX) { + universal.spec { + baseName = 'native-platform-osx-universal' + includes(['/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/']) + args("-lcurses", "-arch", "x86_64", "-arch", "i386", "-o", outputFile) + } + } else if (org.gradle.internal.os.OperatingSystem.current().windows) { + all { + spec { + includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include"]) + includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include/win32"]) + args("/DWIN32") + } + } + + def out = new ByteArrayOutputStream() + exec { + commandLine "cl.exe", "/?" + errorOutput = out + standardOutput = new ByteArrayOutputStream() + } + def header = out.toString().readLines().head() + if (header.endsWith("for 80x86") || header.endsWith("for x86")) { + i386.spec { + baseName = 'native-platform-windows-i386' + } + } else if (header.endsWith("for x64")) { + amd64.spec { + baseName = 'native-platform-windows-amd64' + } + } else { + throw new RuntimeException("Cannot determine compiler's target architecture") + } + + } else if (org.gradle.internal.os.OperatingSystem.current().linux) { + all { + spec { + includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include"]) + includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include/linux"]) + args("-lcurses") + } + } + if (System.getProperty('os.arch') == 'i386' || project.hasProperty('multiarch')) { + i386.spec { + baseName = 'native-platform-linux-i386' + args("-m32") + } + } + if (System.getProperty('os.arch') == 'amd64' || project.hasProperty('multiarch')) { + amd64.spec { + baseName = 'native-platform-linux-amd64' + args("-m64") + } + } + } else { + baseName = "native-platform-solaris" + main.spec { + includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include"]) + includes(["${org.gradle.internal.jvm.Jvm.current().javaHome}/include/solaris"]) + args("-DSOLARIS", "-lcurses") + } + } + all { + spec { + includes([nativeHeadersDir]) + } + sourceSets << cpp.sourceSets.main + } +} + +task nativeHeaders { + def outputFile = file("$nativeHeadersDir/native.h") + inputs.files sourceSets.main.output + outputs.file outputFile + doLast { + outputFile.parentFile.mkdirs() + exec { + executable org.gradle.internal.jvm.Jvm.current().getExecutable('javah') + args '-o', outputFile + args '-classpath', sourceSets.main.output.classesDir + args 'net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions' + args 'net.rubygrapefruit.platform.internal.jni.PosixFileFunctions' + args 'net.rubygrapefruit.platform.internal.jni.PosixFileSystemFunctions' + args 'net.rubygrapefruit.platform.internal.jni.PosixProcessFunctions' + args 'net.rubygrapefruit.platform.internal.jni.PosixTerminalFunctions' + args 'net.rubygrapefruit.platform.internal.jni.TerminfoFunctions' + args 'net.rubygrapefruit.platform.internal.jni.WindowsConsoleFunctions' + } + } +} + +configurations { + jni +} + +def deployer = uploadJni.repositories.mavenDeployer + +libraries.all { lib -> + def nativeJar = task("nativeJar${lib.name.capitalize()}", type: Jar) { + from lib.spec.task + baseName = lib.spec.baseName + } + lib.spec.task.dependsOn nativeHeaders + test.dependsOn lib.spec.task + artifacts { + jni nativeJar + runtime nativeJar + } + def jniPom = deployer.addFilter(lib.name) { artifact, file -> + return file == nativeJar.archivePath + } + jniPom.groupId = project.group + jniPom.artifactId = lib.spec.baseName + jniPom.version = project.version + jniPom.scopeMappings.mappings.clear() +} + +javadoc { + exclude '**/internal/**' +} + +task sourceZip(type: Zip) { + from sourceSets.main.allSource + classifier = 'sources' +} + +task javadocZip(type: Zip) { + from javadoc + classifier = 'javadoc' +} + +artifacts { + archives sourceZip + archives javadocZip +} + +def mainPom = uploadArchives.repositories.mavenDeployer.pom +mainPom.groupId = project.group +mainPom.artifactId = jar.baseName +mainPom.version = project.version +mainPom.scopeMappings.mappings.clear() +mainPom.withXml { provider -> + def node = provider.asNode() + def deps = node.appendNode('dependencies') + ['osx-universal', 'linux-amd64', 'linux-i386', 'windows-amd64', 'windows-i386'].each { platform -> + def dep = deps.appendNode('dependency') + dep.appendNode('groupId', project.group) + dep.appendNode('artifactId', "native-platform-${platform}") + dep.appendNode('version', project.version) + } +} + +task wrapper(type: Wrapper) { + gradleVersion = "1.3-20120907220018+0000" +} diff --git a/readme.md b/readme.md index f048dd6..63994b4 100755 --- a/readme.md +++ b/readme.md @@ -1,188 +1,199 @@ - -# Native-platform: Java bindings for various native APIs - -A collection of cross-platform Java APIs for various native APIs. Supports OS X, Linux, Solaris and Windows. - -These APIs support Java 5 and later. Some of these APIs overlap with APIs available in later Java versions. - -## Available bindings - -### Generic - -* Get PID of current process. -* Get kernel name and version. -* Get machine architecture. - -### Terminal and console - -These bindings work for both the UNIX terminal and the Windows console: - -* Determine if stdout/stderr are attached to a terminal. -* Query the terminal size. -* Switch between bold and normal mode on the terminal. -* Change foreground color on the terminal. -* Move terminal cursor up, down, left, right, start of line. -* Clear to end of line. - -### File systems - -* Get and set UNIX file mode. -* Create and read symbolic links. -* List the available file systems on the machine -* Query file system mount point. -* Query file system type. -* Query file system device name. -* Query whether a file system is local or remote. - -## Supported platforms - -Currently ported to OS X, Linux and Windows, with some support for Solaris and FreeBSD. Tested on: - -* OS X 10.7.4, 10.8 (x86_64), 10.6.7 (i386) -* Ubunutu 12.04 (amd64), 8.04.4 (i386, amd64) -* Solaris 11 (x86) -* Windows 7 (x64), XP (x86) - -## Using - -Include `native-platform.jar` and `native-platform-${os}-${arch}.jar` in your classpath. From Gradle, you can do -this: - - repositories { - maven { url "https://gradle.artifactoryonline.com/gradle/libs-releases-local" } - } - - dependencies { - compile "net.rubygrapefruit:native-platform:0.1" - } - -Some sample code to use the terminal: - - import net.rubygrapefruit.platform.Native; - import net.rubygrapefruit.platform.Terminals; - import net.rubygrapefruit.platform.Terminal; - import static net.rubygrapefruit.platform.Terminals.Output.*; - - Terminals terminals = Native.get(Terminals.class); - - // check if terminal - terminals.isTerminal(Stdout); - - // use terminal - Terminal stdout = terminals.getTerminal(Stdout); - stdout.bold(); - System.out.println("bold text"); - -## Changes - -### 0.2 - -Fixes to make native library extraction multi-process safe. - -### 0.1 - -Initial release - -# Development - -## Building - -You will need to use the Gradle wrapper. Just run `gradlew` in the root directory. - -### Ubuntu - -The g++ compiler is required to build the native library. You will need the `g++` package for this. Usually this is already installed. - -You need to install the `libncurses5-dev` package to pick up the ncurses header files. Also worth installing the `ncurses-doc` package too. - -#### 64-bit machines with multi-arch support - -Where multi-arch support is available (e.g. recent Ubuntu releases), you can build the i386 and amd64 versions of the library on the -same machine. - -You need to install the `gcc-multilib` and `g++-multilib` packages to pick up i386 support. - -You need to install the `lib32ncurses5-dev` package to pick up the ncurses i386 version. - -To build, include `-Pmultiarch` on the command-line. - -### Windows - -You need to install Visual studio, and build from a Visual studio command prompt. - -### OS X - -The g++ compiler is required to build the native library. You will need to install the XCode tools for this. - -### Solaris - -For Solaris 11, you need to install the `development/gcc-45` and `system/header` packages. - -## Running - -Run `gradle installApp` to install the test application into `test-app/build/install/native-platform-test`. Or -`gradle distZip` to create an application distribtion in `test-app/build/distributions/native-platform-test-$version.zip`. - -You can run `$INSTALL_DIR/bin/native-platform-test` to run the test application. - -# Releasing - -1. Create a tag and push. -2. Build each variant: - 1. Checkout tag. - 2. `./gradlew clean test :uploadJni -Prelease -PartifactoryUserName=<> -PartifactoryPassword=<>` - * OS X universal - * Linux i386, using Ubunutu 8.04 - * Linux amd64, using Ubunutu 8.04 - * Windows x86, using VC++ 2010 - * Windows x64 -3. Build Java library and test app: - 1. Checkout tag. - 2. `./gradlew clean test :uploadArchives testApp:uploadArchives -Prelease` -4. Checkout master -5. Increment version number. - -## Testing - -* Test on IBM JVM. -* Test on Java 5, 6, 7. -* Test on Windows 7, Windows XP - -## TODO - -### Fixes - -* Windows: fix detection of shared drive under VMWare fusion and Windows XP -* Linux: detect remote filesystems. -* Solaris: fix unicode file name handling. -* Solaris: fail for unsupported architecture. -* Solaris: build 32 bit and 64 bit libraries. -* Freebsd: finish port. -* Freebsd: fail for unsupported architecture. -* Freebsd: build 32 bit and 64 bit libraries. - -### Improvements - -* Use wchar_to_java() for windows system and file system info. -* Test network file systems on Mac, Linux, Windows -* Test mount points on Windows -* Cache class, method and field lookups (in particular for String conversions). -* Determine C charset once at startup -* Change readLink() implementation so that it does not need to NULL terminate the encoded content -* Don't use NewStringUTF() anywhere -* Don't use NewString() anywhere -* Use iconv() to convert from C char string to UTF-16 when converting from C char string to Java String. -* Support for cygwin terminal -* Use TERM=xtermc instead of TERM=xterm on Solaris. -* Add diagnostics for terminal. -* Split out separate native library for terminal handling. -* Version each native interface separately. -* String names for errno values. -* Split into multiple projects. -* Convert to c. -* Use fully decomposed form for unicode file names on hfs+ filesystems. -* Extend FileSystem to deal with removable media. - -### Ideas - -* Expose platform-specific HTTP proxy configuration. Query registry on windows to determine IE settings. + +# Native-platform: Java bindings for various native APIs + +A collection of cross-platform Java APIs for various native APIs. Supports OS X, Linux, Solaris and Windows. + +These APIs support Java 5 and later. Some of these APIs overlap with APIs available in later Java versions. + +## Available bindings + +### System information + +* Get kernel name and version. +* Get machine architecture. + +### Processes + +* Get the PID of the current process. + +### Terminal and console + +These bindings work for both the UNIX terminal and the Windows console: + +* Determine if stdout/stderr are attached to a terminal. +* Query the terminal size. +* Switch between bold and normal mode on the terminal. +* Change foreground color on the terminal. +* Move terminal cursor up, down, left, right, start of line. +* Clear to end of line. + +### File systems + +* Get and set UNIX file mode. +* Create and read symbolic links. +* List the available file systems on the machine +* Query file system mount point. +* Query file system type. +* Query file system device name. +* Query whether a file system is local or remote. + +## Supported platforms + +Currently ported to OS X, Linux and Windows. Support for Solaris and FreeBSD is a work in progress. Tested on: + +* OS X 10.7.4, 10.8 (x86_64), 10.6.7 (i386) +* Ubunutu 12.04 (amd64), 8.04.4 (i386, amd64) +* Solaris 11 (x86) +* Windows 7 (x64), XP (x86) + +## Using + +Include `native-platform.jar` and `native-platform-${os}-${arch}.jar` in your classpath. From Gradle, you can do +this: + + repositories { + maven { url "http://repo.gradle.org/gradle/libs-releases-local" } + } + + dependencies { + compile "net.rubygrapefruit:native-platform:0.1" + } + +You can also download [here](http://repo.gradle.org/gradle/libs-releases-local/net/rubygrapefruit/native-platform/0.1) + +Some sample code to use the terminal: + + import net.rubygrapefruit.platform.Native; + import net.rubygrapefruit.platform.Terminals; + import net.rubygrapefruit.platform.Terminal; + import static net.rubygrapefruit.platform.Terminals.Output.*; + + Terminals terminals = Native.get(Terminals.class); + + // check if terminal + terminals.isTerminal(Stdout); + + // use terminal + Terminal stdout = terminals.getTerminal(Stdout); + stdout.bold(); + System.out.println("bold text"); + +## Changes + +### 0.2 + +Fixes to make native library extraction multi-process safe. + +### 0.1 + +Initial release. + +# Development + +## Building + +You will need to use the Gradle wrapper. Just run `gradlew` in the root directory. + +### Ubuntu + +The g++ compiler is required to build the native library. You will need the `g++` package for this. Usually this is already installed. + +You need to install the `libncurses5-dev` package to pick up the ncurses header files. Also worth installing the `ncurses-doc` package too. + +#### 64-bit machines with multi-arch support + +Where multi-arch support is available (e.g. recent Ubuntu releases), you can build the i386 and amd64 versions of the library on the +same machine. + +You need to install the `gcc-multilib` and `g++-multilib` packages to pick up i386 support. + +You need to install the `lib32ncurses5-dev` package to pick up the ncurses i386 version. + +To build, include `-Pmultiarch` on the command-line. + +### Windows + +You need to install Visual studio, and build from a Visual studio command prompt. + +### OS X + +The g++ compiler is required to build the native library. You will need to install the XCode tools for this. + +### Solaris + +For Solaris 11, you need to install the `development/gcc-45` and `system/header` packages. + +## Running + +Run `gradle installApp` to install the test application into `test-app/build/install/native-platform-test`. Or +`gradle distZip` to create an application distribtion in `test-app/build/distributions/native-platform-test-$version.zip`. + +You can run `$INSTALL_DIR/bin/native-platform-test` to run the test application. + +# Releasing + +1. Create a tag and push. +2. Build each variant: + 1. Checkout tag. + 2. `./gradlew clean test :uploadJni -Prelease -PartifactoryUserName=<> -PartifactoryPassword=<>` + * OS X universal + * Linux i386, using Ubunutu 8.04 + * Linux amd64, using Ubunutu 8.04 + * Windows x86, using VC++ 2010 + * Windows x64 +3. Build Java library and test app: + 1. Checkout tag. + 2. `./gradlew clean test :uploadArchives testApp:uploadArchives -Prelease` +4. Checkout master +5. Increment version number. + +## Testing + +* Test on IBM JVM. +* Test on Java 5, 6, 7. +* Test on Windows 7, Windows XP + +## TODO + +### Fixes + +* Windows: fix detection of shared drive under VMWare fusion and Windows XP +* Linux: detect remote filesystems. +* Solaris: fix unicode file name handling. +* Solaris: fail for unsupported architecture. +* Solaris: build 32 bit and 64 bit libraries. +* Freebsd: finish port. +* Freebsd: fail for unsupported architecture. +* Freebsd: build 32 bit and 64 bit libraries. + +### Improvements + +* Use wchar_to_java() for windows system and file system info. +* Test network file systems on Mac, Linux, Windows +* Test mount points on Windows +* Cache class, method and field lookups (in particular for String conversions). +* Determine C charset once at startup +* Change readLink() implementation so that it does not need to NULL terminate the encoded content +* Don't use NewStringUTF() anywhere +* Don't use NewString() anywhere +* Use iconv() to convert from C char string to UTF-16 when converting from C char string to Java String. +* Support for cygwin terminal +* Use TERM=xtermc instead of TERM=xterm on Solaris. +* Add diagnostics for terminal. +* Split out separate native library for terminal handling. +* Version each native interface separately. +* String names for errno values. +* Split into multiple projects. +* Convert to c. +* Use fully decomposed form for unicode file names on hfs+ filesystems. +* Extend FileSystem to deal with removable media. + +### Ideas + +* Expose platform-specific HTTP proxy configuration. Query registry on windows to determine IE settings. +* Expose native named semaphores, mutexes and condition variables (CreateMutex, CreateSemaphore, CreateEvent, semget, sem_open, etc). +* Expose infromation about network interfaces. +* Fire events when filesystems or network interfaces change in some way. +* Fire events when terminal size changes. +* Fire events when files change. +* Expose system keystores and authentication services.