Commit e0f5b5bb authored by j4cbo's avatar j4cbo

Merge pull request #140 from pwais/pwais_linux_build

djinni for linux
parents babbe4b1 27e29479
......@@ -31,3 +31,6 @@ djinni-output-temp/
# intellij-plugin build artifact
intellij-plugin/djinni.jar
# profiling output
callgrind.out.*
......@@ -40,7 +40,10 @@ example_android: GypAndroid.mk
@echo "Apks produced at:"
@python example/glob.py example/ '*.apk'
test:
example_localhost: ./deps/java
cd example && make localhost
test: ./deps/java
make -C test-suite
.PHONY: example_android example_ios test djinni clean all
.PHONY: example_android example_ios example_localhost test djinni clean all
......@@ -150,6 +150,10 @@ somewhere in your code:
System.loadLibrary("YourLibraryName");
// The name is specified in Android.mk / build.gradle / Makefile, depending on your build system.
If you package your native library in a jar, you can also use `com.dropbox.djinni.NativeLibLoader`
to help unpack and load your lib(s). See the [Localhost README](example/localhost/README.md)
for details.
When a native library is called, JNI calls a special function called `JNI_OnLoad`. If you use
Djinni for all JNI interface code, include `support_lib/jni/djinni_main.cpp`; if not,
you'll need to add calls to your own `JNI_OnLoad` and `JNI_OnUnload` functions. See
......
# Third-party Software Credits, Attributions, and Licenses
Some files in this directory are provided by third parties and governed by their respective
licenses as described below.
## Hamcrest Core
* Local Path: `test/hamcrest-core-1.3.jar`
* [Binary Distribution](http://central.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar)
* [License](https://github.com/hamcrest/JavaHamcrest/blob/master/LICENSE.txt) (BSD)
## JUnit
* Local Path: `test/junit-4.11.jar`
* [Binary Distribution](http://central.maven.org/maven2/junit/junit/4.11/junit-4.11.jar)
* [License](https://github.com/junit-team/junit/blob/master/LICENSE-junit.txt) (Eclipse Public License)
## JSR305
* Local Path: `jsr305-3.0.0.jar`
* [Binary Distribution](http://central.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.0/jsr305-3.0.0.jar)
* [License](https://code.google.com/p/jsr-305/source/browse/trunk/ri/LICENSE) (BSD)
\ No newline at end of file
all: android ios
all: android ios localhost
android: example.djinni
@make -C .. GypAndroid.mk
......@@ -6,4 +6,7 @@ android: example.djinni
ios: example.djinni
@make -C .. ./build_ios/example/libtextsort.xcodeproj
.PHONY: android ios
localhost: example.djinni
cd localhost && ant compile jar run
.PHONY: android ios localhost
TextSort
--------
This folder contains an example project using djinni. The application contains a multiline text
view, and when the button "Sort" is hit, sorts the lines in that view.
view, and when the button "Sort" is hit, sorts the lines in that view. There is also a
command-line version of the demo.
Interface Stucture
------------------
......@@ -25,6 +26,12 @@ cd djinni_root_dir;
make example_ios
```
**Quick Start Command-line**
```
cd djinni_root_dir;
make example_localhost
```
**Details**
This example project utilizes [gyp](https://code.google.com/p/gyp/) to generate project files for
each platform. So, before running any of the example code the first time you will need to run `make ios`
......@@ -52,6 +59,10 @@ cd djinni_root_rit/example;
xcodebuild -workspace objc/TextSort.xcworkspace -scheme TextSort -configuration 'Debug' -sdk iphoneos
```
Command-line / Localhost Version
--------------------------------
See the [Localhost README](localhost/README.md)
Making Changes to Djinni file
-----------------------------
The Djinni file used in this example is `example.djinni`. After modifying this file, you can run
......
......@@ -9,8 +9,12 @@ sort_order = enum {
}
sort_items = interface +c {
# For the iOS / Android demo
sort(order: sort_order, items: item_list);
static create_with_listener(listener: textbox_listener): sort_items;
# For the localhost / command-line demo
static run_sort(items: item_list): item_list;
}
textbox_listener = interface +j +o {
......
......@@ -15,9 +15,13 @@ class SortItems {
public:
virtual ~SortItems() {}
/** For the iOS / Android demo */
virtual void sort(sort_order order, const ItemList & items) = 0;
static std::shared_ptr<SortItems> create_with_listener(const std::shared_ptr<TextboxListener> & listener);
/** For the localhost / command-line demo */
static ItemList run_sort(const ItemList & items);
};
} // namespace textsort
......@@ -8,11 +8,16 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
public abstract class SortItems {
/** For the iOS / Android demo */
public abstract void sort(@Nonnull SortOrder order, @Nonnull ItemList items);
@CheckForNull
public static native SortItems createWithListener(@CheckForNull TextboxListener listener);
/** For the localhost / command-line demo */
@Nonnull
public static native ItemList runSort(@Nonnull ItemList items);
private static final class CppProxy extends SortItems
{
private final long nativeRef;
......
......@@ -41,4 +41,13 @@ CJNIEXPORT jobject JNICALL Java_com_dropbox_textsort_SortItems_createWithListene
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
CJNIEXPORT jobject JNICALL Java_com_dropbox_textsort_SortItems_runSort(JNIEnv* jniEnv, jobject /*this*/, jobject j_items)
{
try {
DJINNI_FUNCTION_PROLOGUE0(jniEnv);
auto r = ::textsort::SortItems::run_sort(::djinni_generated::NativeItemList::toCpp(jniEnv, j_items));
return ::djinni::release(::djinni_generated::NativeItemList::fromCpp(jniEnv, r));
} JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */)
}
} // namespace djinni_generated
......@@ -47,6 +47,13 @@ static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for th
} DJINNI_TRANSLATE_EXCEPTIONS()
}
+ (nonnull TXSItemList *)runSort:(nonnull TXSItemList *)items {
try {
auto r = ::textsort::SortItems::run_sort(::djinni_generated::ItemList::toCpp(items));
return ::djinni_generated::ItemList::fromCpp(r);
} DJINNI_TRANSLATE_EXCEPTIONS()
}
namespace djinni_generated {
auto SortItems::toCpp(ObjcType objc) -> CppType
......
......@@ -10,9 +10,13 @@
@interface TXSSortItems : NSObject
/** For the iOS / Android demo */
- (void)sort:(TXSSortOrder)order
items:(nonnull TXSItemList *)items;
+ (nullable TXSSortItems *)createWithListener:(nullable id<TXSTextboxListener>)listener;
/** For the localhost / command-line demo */
+ (nonnull TXSItemList *)runSort:(nonnull TXSItemList *)items;
@end
......@@ -33,4 +33,10 @@ void SortItemsImpl::sort(sort_order order, const ItemList & items) {
this->m_listener->update(ItemList(lines));
}
ItemList SortItems::run_sort(const ItemList & items) {
auto lines = items.items;
std::sort(lines.begin(), lines.end(), std::less<std::string>());
return ItemList(lines);
}
}
cmake_minimum_required(VERSION 2.8)
project(textsort C CXX)
##
## Options
##
set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib"
CACHE PATH "Installation directory for libraries (default: prefix/lib).")
##
## Global Dependencies
##
find_package(JNI)
if (NOT JNI_FOUND)
message(
FATAL_ERROR
"Could not find JNI. Did you install a JDK? Set $JAVA_HOME to override")
endif()
##
## Shared Library
##
set(support_dir ../../support-lib/jni)
set(textsort_include_dirs ../generated-src/jni/ ../generated-src/cpp/ ../handwritten-src/cpp/)
file(
GLOB_RECURSE support_srcs
${support_dir}/*.cpp)
file(
GLOB_RECURSE textsort_srcs
../generated-src/jni/*.cpp
../generated-src/cpp/*.cpp
../handwritten-src/cpp/*.cpp)
set(textsort_common_flags "-Wall -Werror -std=c++1y")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${textsort_common_flags}")
if(UNIX OR APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
endif()
set(textsort_srcs ${support_srcs} ${textsort_srcs})
add_library(TextSortNative SHARED ${textsort_srcs})
include_directories(
TextSortNative
${textsort_include_dirs}
${support_dir}
${JNI_INCLUDE_DIRS})
target_link_libraries(TextSortNative ${JNI_LIBRARIES})
install(
TARGETS TextSortNative
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}")
FROM ubuntu:utopic-20150625
RUN apt-get update
RUN apt-get -y install git build-essential clang cmake
RUN apt-get install -y openjdk-8-jdk ant
ENV CXX clang++
# Select Java 8
RUN update-java-alternatives -s java-1.8.0-openjdk-amd64
RUN rm /usr/lib/jvm/default-java
RUN ln -s /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/default-java
Localhost Demo
--------------
This demo simply sorts some random strings and prints
the results to the terminal as so:
```
$ ant compile jar run
...
Sep 07, 2015 6:12:10 PM com.dropbox.djinni.NativeLibLoader loadLibrary
INFO: Loaded /var/folders/zj/w8zq8xmd4m9f__rdl4rmqhyr0000gn/T/libTextSortNative.dylib3424746480331627703dylib
Sep 07, 2015 6:12:10 PM com.dropbox.textsort.SortTest main
INFO: Input strings:
96901
70751
93099
10224
21918
Sep 07, 2015 6:12:10 PM com.dropbox.textsort.SortTest main
INFO: Output strings:
10224
21918
70751
93099
96901
```
This demo also serves to document how to build a native library using djinni
and ship it inside a jar (and include djinni's small set of dependencies).
Running locally
---------------
Run `ant compile jar run` to compile and run.
Running in Linux via Docker
---------------------------
To demo running in linux, `run_in_docker.sh ant clean compile jar run` to run inside
a Docker container, or just `run_in_docker.sh` to drop into a Dockerized
shell. The root of this djinni repo will be mounted at `/opt/djinni`.
Build Details
-------------
This demo packages the native library in the application jar and uses the
djinni support class `com.dropbox.djinni.NativeLibLoader` to unpack and
load the library at runtime. This approach should work well for the
majority of use cases but has several known caveats:
* The app might not have access to temp space at runtime. In this case,
you must install the library locally and can use the system
property `djinni.native_libs_dirs` to tell djinni where to find your
library.
* The native library might have many other system dependencies. In this
case, you must either include those shared libraries in the jar,
link/compile them into the app native library, or somehow
ensure the dependencies exist on the target system (e.g. run your
app in a container).
* `NativeLibLoader` does not currently support filtering libraries by
host architecture. In this scenario, you might consider building
a fat library using `lipo` and `libtool`.
Note that `NativeLibLoader` is an entirely optional dependency. You can
omit it from your app and build and include only djinni generated code.
However, you will need to invoke `System.load()` or `System.loadLibrary()`
manually.
<?xml version="1.0"?>
<project>
<target name="compile">
<mkdir dir="build"/>
<mkdir dir="build/local"/>
<exec executable="cmake" failonerror="true" dir="build">
<!-- Verbose helps make debugging compiler issues easier -->
<arg value="-DCMAKE_VERBOSE_MAKEFILE=ON"/>
<!-- Make CMake configure Makefile install target to install locall
(to ./build/local) to make the shared library easier to reference
in java -->
<arg value="-DCMAKE_INSTALL_PREFIX:PATH=${basedir}/build/local"/>
<arg value=".."/>
</exec>
<exec executable="make" failonerror="true" dir="build">
<arg value="-j12"/>
</exec>
<exec executable="make" failonerror="true" dir="build">
<arg value="install"/>
</exec>
<mkdir dir="build/classes"/>
<javac destdir="build/classes" includeantruntime="false" encoding="UTF-8" debug="on"
classpath="../../deps/java/jsr305-3.0.0.jar"
srcdir="../../support-lib/java/:../generated-src:./handwritten-src/java" />
</target>
<target name="jar">
<jar destfile="build/jar/DjinniTextSort.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="com.dropbox.textsort.SortTest"/>
</manifest>
<!-- Copy the native lib(s) to the canonical jar path resources/djinni_native_libs
so that com.dropbox.djinni.NativeLibLoader will find them on startup -->
<zipfileset dir="${basedir}/build/local/lib" prefix="resources/djinni_native_libs">
<include name="lib*"/>
</zipfileset>
<zipgroupfileset dir="${basedir}" includes="*.jar" />
</jar>
</target>
<target name="run">
<java jar="build/jar/DjinniTextSort.jar" fork="true"/>
</target>
<target name="clean">
<delete dir="build"/>
</target>
</project>
package com.dropbox.textsort;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.dropbox.djinni.NativeLibLoader;
public class SortTest {
private static SecureRandom random = new SecureRandom();
private static final Logger log =
Logger.getLogger(SortTest.class.getName());
public static String randomString() {
return new BigInteger(130, random).toString(10).substring(0, 5);
}
public static void main(String[] args) throws Exception {
NativeLibLoader.loadLibs();
// Create some random strings to sort below
ArrayList<String> strs = new ArrayList<String>();
for (int i = 0; i < 5; ++i) {
strs.add(randomString());
}
log.log(Level.INFO, "Input strings:\n" + String.join("\n", strs));
// Sort them!
ItemList sorted = SortItems.runSort(new ItemList(strs));
log.log(
Level.INFO,
"Output strings:\n" + String.join("\n", sorted.getItems()));
}
}
#! /usr/bin/env bash
set -eux
# Build docker container
docker build -t djinni-demo .
djinni_root=`cd ../../; pwd`
# Run!
if [ $# -eq 0 ]; then
docker run --rm -it -v $djinni_root:/opt/djinni -w /opt/djinni djinni-demo bash
else
docker run --rm -v $djinni_root:/opt/djinni -w /opt/djinni/example/localhost djinni-demo $@
fi
//
// Copyright 2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package com.dropbox.djinni;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
/**
* Utilities for loading native libraries containing djinni interfaces
* and records. To load libraries in your application at startup,
* simply place them:
* * inside the jar containing this code at the (jar-relative)
* path `djinniNativeLibsJarPath`
* * somewhere on the host filesystem and use the `djinniNativeLibsSysProp`
* system property to provide path(s)
*
* Then execute:
* <code>
* NativeLibLoader.loadLibs()
* </code>
* to load the libraries (e.g. in your main() or a class static initializer).
*/
public class NativeLibLoader {
/**
* Canonical directory in a jar containing (djinni-adapted) native libraries
*/
public static final String djinniNativeLibsJarPath =
"resources/djinni_native_libs";
/**
* Load native libraries with djinni support from the (comma-separated)
* path(s) provided in this system property
*/
public static final String djinniNativeLibsSysProp =
"djinni.native_libs_dirs";
private static final Logger log =
Logger.getLogger(NativeLibLoader.class.getName());
private NativeLibLoader() { }
// Load native libs from canonical locations
public static void loadLibs() throws URISyntaxException, IOException {
// Try to load from Jar
loadLibsFromJarPath(djinniNativeLibsJarPath);
// Try to load from system
String localPaths = System.getProperty(djinniNativeLibsSysProp);
if (localPaths != null) {
log.log(Level.FINE, "Loading local native libs");
for (String localPath : localPaths.split(",")) {
loadLibsFromLocalPath(Paths.get(localPath));
}
}
}
// Load native lib(s) from the given `localPath` - a file or directory
public static void loadLibsFromLocalPath(Path localPath) throws IOException {
File localFile = localPath.toFile();
if (!localFile.exists()) { return; }
if (localFile.isDirectory()) {
log.log(Level.FINE, "Loading all libs in " + localFile.getAbsolutePath());
Stream<Path> streamPaths = Files.walk(localFile.toPath(), 1);
for (Path p : (Iterable<Path>)streamPaths::iterator) {
File f = p.toFile();
if (f.isFile()) {
loadLibrary(f.getAbsolutePath());
}
}
streamPaths.close();
} else {
loadLibrary(localFile.getAbsolutePath());
}
}
// Load a directory of libs from a jar resource path
public static void loadLibsFromJarPath(String jarPath)
throws URISyntaxException, IOException {
// Do we have a valid path?
URL libsURL =
NativeLibLoader.class
.getClassLoader()
.getResource(djinniNativeLibsJarPath);
if (libsURL == null) { return; }
// Are we actually referencing a jar path?
if (!libsURL.toURI().getScheme().equals("jar")) { return; }
log.log(Level.FINE, "Loading libs from jar path " + jarPath);
// Walk the directory and load libs
FileSystem fs =
FileSystems.newFileSystem(libsURL.toURI(), Collections.emptyMap());
Path myPath = fs.getPath(jarPath);
for (Path p : (Iterable<Path>)Files.walk(myPath, 1)::iterator) {
loadLibFromJarPath(p);
}
fs.close();
}
// Load a single native lib from a jar resource with path `libPath`
public static void loadLibFromJarPath(Path libPath) throws IOException {
// System libraries *must* be loaded from the filesystem,
// so we must copy the lib's data from the jar to a tempfile
InputStream libIn =
NativeLibLoader.class.getResourceAsStream(libPath.toString());
if (libIn == null) { return; } // Invalid `libPath`
// Name the tempfile
String libName = libPath.getName(libPath.getNameCount() - 1).toString();
// Name the tempfile after the lib to ease debugging
String suffix = null;
int extPos = libName.lastIndexOf('.');
if (extPos > 0) { suffix = libName.substring(extPos + 1); }
// Try to suffix the tempfile with the lib's suffix so that other
// tools (e.g. profilers) identify the file correctly
File tempLib = File.createTempFile(libName, suffix);
tempLib.deleteOnExit();
log.log(
Level.FINE,
"Copying jar lib " + libPath + " to " + tempLib.getAbsolutePath());
try {
Files.copy(libIn, tempLib.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (SecurityException e) {
throw new RuntimeException(
"SecurityException while trying to create tempfile: " +
e.getMessage() + "\n\n If you cannot grant this process " +
"permissions to create temporary files, you need to install " +
"the native libraries manually and provide the installation " +
"path(s) using the system property " + djinniNativeLibsSysProp);
}
loadLibrary(tempLib.getAbsolutePath());
}
private static void loadLibrary(String abspath) {
System.load(abspath);
log.log(Level.INFO, "Loaded " + abspath);
}
}
.PHONY: all objc java
.PHONY: all objc java linux
FORCE_DJINNI := $(shell ./run_djinni.sh >&2)
all: objc java
all: objc java linux
objc:
cd objc; xcodebuild -sdk iphonesimulator -project DjinniObjcTest.xcodeproj -scheme DjinniObjcTest test
java:
cd java && ant test
cd java && ant compile test
linux:
cd ..; ./test-suite/java/docker/run_dockerized_test.sh
......@@ -5,13 +5,17 @@ run under Java (standalone JUnit runner) and iOS (via XCode iPhone simulator).
Djinni Files
----------
The djinni files are located in djinni/ . all.djinni is a list of import for all files you would
like to be generated. After input files are changed, run ./run_djinni.sh to regenerate files.
The djinni files are located in `djinni/`. all.djinni is a list of import for all files you would
like to be generated. After input files are changed, run `./run_djinni.sh` to regenerate files.
Testing
-------
Run 'make java' or 'make objc' to test the given environment.
Run `make java` or `make objc` to test the given environment. Building the Java
native test library requires CMake to support cross-platform builds; to install,
try `brew install cmake` or `sudo port install cmake`.
You may need to have Xcode open for the simulator portion of the objc
tests to complete successfully. Try opening the app if you see a
failure connecting to the simulator.
To test Java generated code in linux environments, run `make linux`.
......@@ -11,7 +11,7 @@ SetRecord TestHelpers::get_set_record() {
"StringA",
"StringB",
"StringC"
}, {} };
}, std::unordered_set<int32_t>{} };
}
bool TestHelpers::check_set_record(const SetRecord & rec) {
......
package com.dropbox.djinni.test;
import com.dropbox.djinni.NativeLibLoader;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.junit.runner.JUnitCore;
public class AllTests extends TestSuite {
......@@ -21,8 +24,8 @@ public class AllTests extends TestSuite {
return mySuite;
}
static {
System.loadLibrary("DjinniTestNative");
public static void main(String[] args) throws Exception {
NativeLibLoader.loadLibs();
JUnitCore.main("com.dropbox.djinni.test.AllTests");
}
}
cmake_minimum_required(VERSION 2.8)
project(djinni-test-suite C CXX)
##
## Options
##
set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib"
CACHE PATH "Installation directory for libraries (default: prefix/lib).")
##
## Global Dependencies
##
find_package(JNI)
if (NOT JNI_FOUND)
message(
FATAL_ERROR
"Could not find JNI. Did you install a JDK? Set $JAVA_HOME to override")
endif()
##
## Test Suite Shared Library
##
set(support_dir ../../support-lib/jni)
set(test_include_dirs ../generated-src/jni/ ../generated-src/cpp/ ../handwritten-src/cpp/)
file(
GLOB_RECURSE support_srcs
${support_dir}/*.cpp)
file(
GLOB_RECURSE test_suite_srcs
../generated-src/jni/*.cpp
../generated-src/cpp/*.cpp
../handwritten-src/cpp/*.cpp)
set(test_suite_common_flags "-g -Wall -Werror -std=c++1y")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${test_suite_common_flags}")
if(UNIX OR APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
endif()
set(test_lib_srcs ${support_srcs} ${test_suite_srcs})
add_library(DjinniTestNative SHARED ${test_lib_srcs})
include_directories(
DjinniTestNative
${test_include_dirs}
${support_dir}
${JNI_INCLUDE_DIRS})
target_link_libraries(DjinniTestNative ${JNI_LIBRARIES})
install(
TARGETS DjinniTestNative
ARCHIVE DESTINATION "${LIB_INSTALL_DIR}"
LIBRARY DESTINATION "${LIB_INSTALL_DIR}")
SUPPORT_DIR := ../../support-lib/jni
DYLIB := libDjinniTestNative.dylib
# Hacky - dummies cancel out .. to make sure objs are all under obj/
OBJ_DIR := obj/dummy/dummy
CPP_SRCS := $(SUPPORT_DIR)/djinni_support.cpp \
$(SUPPORT_DIR)/djinni_main.cpp \
$(wildcard ../generated-src/jni/*.cpp) \
$(wildcard ../generated-src/cpp/*.cpp) \
$(wildcard ../handwritten-src/cpp/*.cpp) \
CPP_OBJS := $(patsubst %,$(OBJ_DIR)/%,$(CPP_SRCS:.cpp=.o))
CPPFLAGS := -std=c++1y -I../generated-src/{jni,cpp} -I$(SUPPORT_DIR) -I/System/Library/Frameworks/JavaVM.framework/Headers -I../handwritten-src/cpp -g -Wall -Werror
$(OBJ_DIR)/%.o: %.cpp
@mkdir -p $(dir $@)
$(CXX) -MMD $(CPPFLAGS) -c $< -o $@
@./fixdep.sh $(@:.o=.d) > $(@:.o=.P)
default:
@echo "Use 'ant' (or 'ant clean') instead of invoking make directly."
@exit 1
$(DYLIB): $(CPP_OBJS)
clang++ $(CPPFLAGS) $(CPP_OBJS) -dynamiclib -o $@
clean:
rm -rf obj $(CPP_OBJS) $(CPP_OBJS:.o=.d) $(CPP_OBJS:.o=.P) $(DYLIB)*
-include $(CPP_OBJS:.o=.P)
<?xml version="1.0"?>
<project name="Djinni-test" default="test">
<target name="test" description="blah">
<exec executable="make" failonerror="true">
<project name="Djinni-test">
<target name="compile">
<mkdir dir="build"/>
<mkdir dir="build/local"/>
<exec executable="cmake" failonerror="true" dir="build">
<!-- Verbose helps make debugging compiler issues easier -->
<arg value="-DCMAKE_VERBOSE_MAKEFILE=ON"/>
<!-- Make CMake configure Makefile install target to install locall
(to ./build/local) to make the shared library easier to reference
in java -->
<arg value="-DCMAKE_INSTALL_PREFIX:PATH=${basedir}/build/local"/>
<arg value=".."/>
</exec>
<exec executable="make" failonerror="true" dir="build">
<arg value="-j12"/>
<arg value="libDjinniTestNative.dylib"/>
</exec>
<mkdir dir="classes"/>
<javac destdir="classes">
<classpath path="hamcrest-core-1.3.jar:junit-4.11.jar:jsr305-3.0.0.jar"/>
<exec executable="make" failonerror="true" dir="build">
<arg value="install"/>
</exec>
<mkdir dir="build/classes"/>
<javac destdir="build/classes" includeantruntime="false" encoding="UTF-8" debug="on">
<classpath>
<fileset dir="../../deps/java/"><include name="*.jar"/></fileset>
<fileset dir="../../deps/java/test"><include name="*.jar"/></fileset>
</classpath>
<src path="../../support-lib/java/"/>
<src path="../generated-src"/>
<src path="../handwritten-src"/>
</javac>
<java classname="org.junit.runner.JUnitCore" fork="true" failonerror="true">
<classpath path="hamcrest-core-1.3.jar:junit-4.11.jar:classes"/>
</target>
<target name="test">
<java classname="com.dropbox.djinni.test.AllTests" fork="true" failonerror="true">
<classpath>
<fileset dir="../../deps/java/"><include name="*.jar"/></fileset>
<fileset dir="../../deps/java/test"><include name="*.jar"/></fileset>
<pathelement path="${basedir}/build/classes"/>
</classpath>
<jvmarg value="-Xcheck:jni"/>
<arg value="com.dropbox.djinni.test.AllTests"/>
<sysproperty key="djinni.native_libs_dirs" value="${basedir}/build/local/lib"/>
</java>
</target>
<target name="jar">
<jar destfile="build/jar/DjinniTestSuite.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="com.dropbox.djinni.test.AllTests"/>
</manifest>
<zipfileset dir="${basedir}/build/local/lib" prefix="resources/djinni_native_libs">
<include name="lib*"/>
</zipfileset>
<zipgroupfileset dir="../../deps/java" includes="*.jar" />
<zipgroupfileset dir="../../deps/java/test" includes="*.jar" />
</jar>
</target>
<target name="run-jar">
<java jar="build/jar/DjinniTestSuite.jar" fork="true"/>
</target>
<target name="clean">
<delete dir="classes"/>
<exec executable="make" failonerror="true">
<arg value="clean"/>
</exec>
<delete dir="build"/>
</target>
</project>
Djinni Linux Tests
------------------
This directory contains a suite of tools for testing djinni (JNI only)
on Linux. The suite helps ensure the portability of djinni and
(self-)document compatible platforms.
Quickstart
----------
You need to have [Docker](https://docker.com) installed. To execute all
tests, run `./test-suite/java/docker/run_dockerized_test.sh` from the root of the
djinni repository.
Adding a Platform
-----------------
1. Create a subdirectory named after the platform (e.g. `my_platform`).
2. If you can create a Docker image for your platform,
simply create a `Dockerfile` in the subdirectory that:
* Builds an image with djinni dependencies (e.g. Java, a C++ compiler)
* Expects djinni in `/opt/djinni/`
* Has a `CMD` to runs the test script:
`/opt/djinni/test-suite/java/docker/build_and_run_tests.sh`
3. You can test the new platform using:
`./test-suite/java/docker/run_dockerized_test.sh ./test-suite/java/docker/my_platform`
#!/bin/sh
# Build and run djinni tests. Intended to be run
# from inside a Docker container
set -e
set -x
cd /opt/djinni/test-suite/java
ant -v clean compile test
ant -v jar run-jar
ant clean
FROM centos:6
# Get Java 8 (64-bit)
RUN yum install -y java-1.8.0-openjdk-devel
# Get other build utils
RUN yum install -y cmake wget tar
# djinni requires llvm with libstdc++ 4.9 features,
# e.g. experimental/optional, so we need a modern
# compiler. Let's get gcc 4.9 from Scientific Linux Cern
RUN yum install -y wget
WORKDIR /etc/yum.repos.d
RUN wget http://linuxsoft.cern.ch/cern/scl/slc6-scl.repo
RUN yum -y --nogpgcheck install devtoolset-3-gcc devtoolset-3-gcc-c++
# Make devtoolset's gcc accessible
ENV PATH /opt/rh/devtoolset-3/root/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Select Java 8
RUN echo 1 | update-alternatives --config java
RUN echo 1 | update-alternatives --config javac
# Get modern ant
WORKDIR /opt
RUN wget http://archive.apache.org/dist/ant/binaries/apache-ant-1.9.3-bin.tar.gz
RUN tar xvfvz apache-ant-1.9.3-bin.tar.gz -C /opt
ENV ANT_HOME /opt/apache-ant-1.9.3/bin/ant
RUN ln -s /opt/apache-ant-1.9.3/bin/ant /usr/bin/ant
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.51-1.b16.el6_7.x86_64
VOLUME /opt/djinni
CMD /opt/djinni/test-suite/java/docker/build_and_run_tests.sh
FROM debian:jessie
# Use Java 8 backport
RUN echo "deb http://http.debian.net/debian jessie-backports main" >> /etc/apt/sources.list
RUN apt-get update
RUN apt-get -y install build-essential clang llvm cmake
RUN apt-get install -y openjdk-8-jdk ant
# Select Java 8
RUN update-java-alternatives -s java-1.8.0-openjdk-amd64
RUN rm /usr/lib/jvm/default-java
RUN ln -s /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/default-java
ENV CXX clang++
VOLUME /opt/djinni
CMD /opt/djinni/test-suite/java/docker/build_and_run_tests.sh
#! /usr/bin/env bash
set -eux
djinni_root=`pwd`
if [ ! -e $djinni_root/test-suite/java/docker/run_dockerized_test.sh ]; then
echo "Please run this script from the root djinni directory"
exit 1
fi
# Which Docker images are we to build & run ?
img_dirs=()
if [ $# -eq 0 ]; then
for f in ./test-suite/java/docker/*; do
[[ -d $f ]] && img_dirs+=("$f")
done
else
img_dirs+=("$@")
fi
for img_dir in "${img_dirs[@]}"; do
if [ ! -e $img_dir/Dockerfile ]; then
continue
fi
img_name="djinni_test."`basename $img_dir`
(
cd $img_dir && docker build -t $img_name .
docker run --rm -v $djinni_root:/opt/djinni $img_name
)
done
FROM ubuntu:trusty
RUN apt-get update
RUN apt-get -y install build-essential clang-3.5 cmake
RUN apt-get -y install software-properties-common
# djinni requires some libstdc++ 4.9 features, e.g. experimental/optional
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update
RUN apt-get install -y libstdc++-4.9-dev
# TODO: replace with official openjdk-8-jdk once they post the backport
RUN add-apt-repository ppa:openjdk-r/ppa && apt-get update
RUN apt-get install -y openjdk-8-jdk ant
# Select Java 8
RUN update-java-alternatives -s java-1.8.0-openjdk-amd64
RUN rm /usr/lib/jvm/default-java
RUN ln -s /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/default-java
ENV CXX clang++
RUN ln -s /usr/bin/clang++-3.5 /usr/bin/clang++
VOLUME /opt/djinni
CMD /opt/djinni/test-suite/java/docker/build_and_run_tests.sh
FROM ubuntu:utopic-20150625
RUN apt-get update
RUN apt-get -y install build-essential clang cmake
RUN apt-get install -y openjdk-8-jdk ant
ENV CXX clang++
# Select Java 8
RUN update-java-alternatives -s java-1.8.0-openjdk-amd64
RUN rm /usr/lib/jvm/default-java
RUN ln -s /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/default-java
VOLUME /opt/djinni
CMD /opt/djinni/test-suite/java/docker/build_and_run_tests.sh
#!/bin/sh
# See http://scottmcpeak.com/autodepend/autodepend.html
if [ $# -ne 1 ]
then
echo "Usage: $0 depfile.d"
exit 1
fi
sed -e 's|.*:|'"${1%.d}"'.o:|' < "$1"
sed -e 's/.*://' -e 's/\\$//' < "$1" | fmt -1 | sed -e 's/^ *//' -e 's/$/:/'
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment