GithubHelp home page GithubHelp logo

dropbox / djinni Goto Github PK

View Code? Open in Web Editor NEW
2.9K 138.0 488.0 3.77 MB

A tool for generating cross-language type declarations and interface bindings.

License: Apache License 2.0

Makefile 0.31% C++ 31.56% Java 25.11% Objective-C 9.20% Python 0.45% Shell 1.20% Scala 16.56% Objective-C++ 13.31% Lex 0.36% CMake 1.61% Swift 0.04% Dockerfile 0.28%

djinni's People

Contributors

4brunu avatar alanjrogers avatar alexcohn avatar artwyman avatar choiip avatar csimmons0 avatar ddeville avatar forderud avatar gnichola avatar greatcall-kayek avatar izacus avatar j4cbo avatar jaetzold avatar jfirebaugh avatar jonmcclung avatar konovalov-aleks avatar marcinkaszynski avatar mjmacleod avatar mknejp avatar msjarrett avatar nachosoto avatar pwais avatar skabbes avatar sschuberth avatar steipete avatar stephenwspann avatar tiwoc avatar vmaks avatar wpurdy2 avatar yageek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

djinni's Issues

Generalize exception translation

Right now, std::exception -> RuntimeException / NSException and that's it.

We want two things:

  • Define other exception mappings (C++ my_exception -> Java MyException)
  • Define exception types as records in the djinni file

Failing to build sample example on Ubuntu and Windows (using Cygwin)

Failing with following error when trying to build using: make example_android

FAILURE: Build failed with an exception.

  • Where:
    Build file '/home/prashant/Work/Djinni/example/android/app/build.gradle' line: 17

  • What went wrong:
    A problem occurred evaluating project ':app'.

    Ambiguous method overloading for method java.io.File#.
    Cannot resolve which method to invoke for [null, class java.lang.String] due to overlapping prototypes between:
    [class java.lang.String, class java.lang.String]
    [class java.io.File, class java.lang.String]

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

Please suggest

Compiling on Linux with gcc 4.9

Hi, In order to compile on Linux with gcc 4.9 I had to add #include <cstring> to djinni_support.cpp. Otherwise it couldn't find thea declaration for strrchr.

C# support?

C# support would allow for easy Windows Phone integration.

Djinni fails to run when there is a space in the current directory name

If you try to run djinni in a path with a space, it will fail:

var/lib/jenkins/jobs/foo bar/workspace/vendor/djinni/src/build: line 15: cd: /var/lib/jenkins/jobs/foo: No such file or directory
dirname: missing operand
Try dirname --help' for more information. dirname: missing operand Trydirname --help' for more information.

The fix is in src/build,:

diff --git a/src/build b/src/build
index b3ccdac..c2f7d75 100755
--- a/src/build
+++ b/src/build
@@ -12,7 +12,7 @@ while [ -h "$loc" ]; do
loc="dirname "$loc"/$link" # Relative link
fi
done
-base_dir=$(cd dirname "$loc" && pwd)
+base_dir=$(cd "$(dirname "$loc")" && pwd)

need_to_build=0
dependencies=("build.sbt" "project/plugins.sbt" "source")

c++ namespace was not generated when return interface object

for example, if run below dijinni definition with cpp-namespace option,
platform_obj = interface +o +j {
}
platform_api = interface +o +j {
Obj(): platform_obj;
}
the generated obj code will miss cpp-namespace prefix.

I am not familiar with scala, but I tried to change this file ObjcGenerator.scala with line 330 and 358:
val ret = m.ret.fold("void")(toCppType(, spec.cppNamespace))
val ret = m.ret.fold("void")(toCppType(
, spec.cppNamespace))

it seems work but I really dont know scala much, please help me to check if it's ok or not, thanks.

A buffer data type

The current way the "data" type works is only marginally useful for data streaming between languages due to all the copying involved.

I was thinking about introducing a "buffer" data type that represents memory shared between both sides of the fence without allocating and copying stuff around in every call. Both Objective-C and Java have facilities to access "unmanaged" regions of memory.

  • From C++ to
    • Java: a direct java.nio.ByteBuffer which can be created in JNI with NewDirectByteBuffer() and does not copy the content.
    • Objective-C: NSData dataWithBytesNoCopy:length:freeWhenDone: same as above (**)
  • From Java to C++: Pass in a java.nio.ByteBuffer and use GetDirectBufferAddress() and GetDirectBufferCapacity() to transform into something like std::experimental::array_view<uint8_t>.
  • From Objective-C to Java: Pass in a NSMutableData and use .length and .mutableBytes to construct the array view.

The whole point of this exercise is to avoid copying the buffer content and is intended for long-lived buffers that are shared and written to/read from on both sides to exchange bulk data. There of course must be some sort of agreement in the interface protocol about who creates the data and make sure it is not modified in a way that invalidates the memory region.

On a related note, maybe the "data" datatype should also switch to something like std::experimental::array_view<const uint8_t> to avoid the copy at least in one direction where possible.

** The only drawback here is that NSData is read-only. If mutable access is necessary the buffer has to be created on the Objective-C side with NSMutableData.

Is optional<shared_ptr<T>> necessary?

I get the intention behind specifying an optional<T> in the interface definition, stating that the passed in object reference may be nil/null in Obj-C or Java and this intention is clearly shown in the C++ side using optional<shared_ptr<T>> as argument or return type.

My problem with this is twofold:

  1. shared_ptr already has a well defined empty state. Wrapping the whole thing inside optional seems redundant.
  2. There is no indication in the Obj-C/Java interface telling a user where passing nil or null is OK or not, contrary to the C++ signature. The difference only manifests itself in the form of a runtime error if used incorrectly. Therefore whether a function accepts empty object references must be documented somewhere as one cannot infer it form the argument/return types.

My conclusion is getting rid of optional<shared_ptr<T>> and instead transform nil/null to/from empty shared_ptr<T> for interface types, regardless of whether they are defined as T or optional<T> in the Djinni file. However for plain T the generated code could handle nil/null/nullptr as errors and throw an appropriate exceptions to the offending code with an explanatory error message along the lines of "argument xxx may not be null", "return value must not be null" and so on.

Does that sound like a sensible thing to do?

f32

Hi,

at the CppCon talk you mentioned why there is only f64, something regarding inconsistent sizes across iOS architectures (it's been a while). However that only applies to CGFloat which is an alias to either float or double, depending on whether it runs on arm64 or not. The actual values of sizeof(float) and sizeof(double) always give 4 and 8, respectively. On Java the aliases jfloat and jdouble already do the right thing.

So I'm not entirely sure I understand why there is only f64.

Regards
Miro

Command line flag or other means to output only the filenames that would be generated

Something like --only-print-filenames? That'd make it way easier to use Djinni in GYP actions.

A lot of the time you can just specify one of the directories or nothing at all under outputs in a GYP action and still have the right thing happen, but if you wan to e.g. add your autogenned Objective-C headers to mac_framework_headers for a framework target, you wind up having to do two passes if you're using something like glob.py: one to generate the files, and one for the build target to pick up the list of files to copy. (This issue can also be sidestepped if you check the autogenerated files into version control, but it's kind of lame for that to be the only way to make it work.)

Windows

Running djinni on windows fails due to generating target/start.bat but trying to exec target/start from run_assemble_built

For running on cygwin, it should generate a normal "start" and exec it. Or, if it's running from a windows command prompt it should "start /WAIT start.bat". The cygwin approach seems less problematic...

Make in djinni dir fails

Hello, just started working with djinni, tried to run make and it failed.

cd example/android/ && ./gradlew app:assembleDebug

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/nt/dev/mac/lib/djinni/example/android/app/build.gradle' line: 17

* What went wrong:
A problem occurred evaluating project ':app'.
> Ambiguous method overloading for method java.io.File#<init>.
  Cannot resolve which method to invoke for [null, class java.lang.String] due to overlapping prototypes between:
    [class java.lang.String, class java.lang.String]
    [class java.io.File, class java.lang.String]
cd example/android/ && ./gradlew app:assembleDebug

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/nt/dev/mac/lib/djinni/example/android/app/build.gradle' line: 17

* What went wrong:
A problem occurred evaluating project ':app'.
> Ambiguous method overloading for method java.io.File#<init>.
  Cannot resolve which method to invoke for [null, class java.lang.String] due to overlapping prototypes between:
    [class java.lang.String, class java.lang.String]
    [class java.io.File, class java.lang.String]

Here is output of make https://gist.github.com/nt9/6115ffb92885cf4b8cd9

Would be glad if someone could give an advice :)

function / block types

list_ish = interface +c {
  map(iterator_fn: function<i64>): list_ish;
}

This would generate a block based api for objc, and a Callable (or similar one for java).

This should be flexible enough to encapsulate both synchronous and async functions.

Circular references in ObjC

Hey guys, I think #4 is resurfacing.

If I have

ClientListener = interface +j +o {
    onClientInitialized(client: Client);
}

Client = interface +c {
    static createClient(baseUrl: string, listener: ClientListener);
}

Then I get an ObjectiveC ClientListener.h file referencing Client.h and a Client.h file referencing ClientListener.h.

This was tested on ed6ef3c

Thanks!

+c interfaces returning +o +j

Hi,

the current code generation is broken for cases where a +c interface returns +j or +o interfaces.

Given:

extern = interface +j +o {...}
intern = interface +c { foo(): extern; }

On the JNI side this tries to call Extern::toJava(), which does not exist, and for Obj-C it tries to static_pointer_cast from Extern to ExternObjcProxy, which is mostly likely not the case and causes undefined behavior.

I think the easiest fix would be to disallow returning +j +o interfaces from +c. Supporting this properly would be a bit more involved I think.

Enums should be hashable

When you try to use an enum as the key in a map, the compiler complains that there is no hash function for the enum

A Barrel of Refactoring

Hey folks,

over the past month or two Djinni was used quite extensively here and we ran into a few problems, resulting in a number of refactorings, both internal (not changing the output) and external (significantly changing the output). Besides, we need something similar to #52, which at the time posed quite a challenge considering how Djinni was structured. So in preparation to make #52 (and others like #54, #46, #45) much easier to realize something had to happen.

Before doing a pull request I thought it'd be better to share these changes and get your input. So here we go:

  • Split the ObjcGenerator into ObjcGenerator and ObjcppGenerator. This makes it easier to adjust only one of them and is also how the Java/JNI generators are separated. The philosophy here is that using only ObjcGeneratoris sufficient to create all the Obj-C files necessary in the same fashion as JavaGenerator only creates Java classes, but no JNI content.
  • Introduce "Marshal" types, responsible for naming types, files, creating parameter signatures, to/from C++ conversion, etc. Now every language has its own Marshal. The xxxGenerators are responsible for the overall file structure, whereas xxxMarshals do the actual language interop. So now JNIGenerator can make use of CppMarshal to create consistent type signatures etc. (This is a crucial part to make #52 remotely possible)
  • The Obj-C support library was restructured similar to how the JNI support library works, using template translation types. This wastly simplifies the work of ObjcppGenerator.
  • Before, Djinni was generating @protocol types for both +c and +o and provided a xxCppProxy in a +Private.h include file. This was a real thorn to every Obj-C developer exposed to Djinni generated types as it didn't really follow any existing conventions on that platform. Therefore came an implementation of #25. To recap: +c types now generate an @interface acting as proxy to C++ and +o types generate a @protocol to be implemented in Objc-C. Therefore +c types are represented by T* variables and +o by id<T>. There was similar outcry in the Java camp about +j not creating a Java interface instead of class but changing the JNI side is a bit more involved.
  • Since Obj-C and Obj-C++ are now considered two separate generators, there's a new set of --objcpp-x command line arguments:
    • --objcpp-out: The output folder for private Objective-C++ files (Generator disabled if unspecified).
    • --objcpp-include-prefix: The prefix for #import of Objective-C++ header files from Objective-C++ files.
    • --objcpp-include-cpp-prefix: The prefix for #include of the main C++ header files from Objective-C++ files.
    • --objcpp-include-objc-prefix: The prefix for #import of the Objective-C header files from Objective-C++ files (default: the same as --objcpp-include-prefix)
    • --objc-ext => --objcpp-ext: The filename extension for Objective-C++ files (default: "mm")
  • Many inconsistencies about formatting and signatures are gone as that is all handled by single entities (aka Marshals).
  • Since ObjcGenerator is setup to create self-containing Obj-C records it creates its own .m files containing the comparison functions, initializers, etc. separate from Obj-C++ translators. But because Obj-C only allows compile-time constants at file scope the file must have extension .mm to support constants of record types. Same applies to interfaces.
  • The comparison operators for C++ records are generated as free friend functions to make them symmetric and follow best practices.
  • JNI fromCpp() functions now all return LocalRef<jobject> instead of jobject and local reference cleanup is handled by it form there on.
  • Generated code didn't always fully qualify the ::djinni namespace for support library stuff

There may be other small fixes but those are the really important ones. It also includes fixes for issues #69, #26, #21, #10 and implicitly includes pull requests #67, #55, #42, #41, #39, #38 .

Do these changes break existing code? Hell yes, they do.
But at least the example and test-suite all pass.
I get that this kind of bulk change is a Bad Thing™, but never was there ever a point in the past 2 months where I could have said "yes, this is a small self-contained change that can be merged back now". There was (and still is) quite the amount of redundancy and intertwining. Also the reason why I'm doing this post first.

Anyway, the branch is here https://github.com/mknejp/djinni/tree/feature/codegen-refactor so check it out if interested and see how much code it breaks. You will definitely have to add the --objcpp-out option otherwise that part is going to be missing entirely. If it's fine I'll do the pull request and hop on to #52.

async return types

I would love an automatic way to generate async results for various platforms. This allows the idiomatic async pattern to be applied on each platform.

my_slow_class = interface + c {
  do_long_operation(id: i64): async string;
}

This might generate the following:

C++

class MySlowClass {
//...
public:
    void do_long_operation(int64_t id, const function<void(string)>& on_complete); 
//...
};

Objc

@protocol DjinniMySlowClass
- (void)doLongOperation:(int64_t)id withCompletionBlock:(void (^)(NSString *))block;
@end

And maybe something with AsyncTask<Params, Progress, Result> on android.

Don't pass primitives by const&

Idiomatic c++ wouldn't pass any primitive integer types by const&. I'm happy to write this up if it aligns with the goals of the project. I propose passing the following types by value.

  • T if T is integral
  • optional<T> if T is integral
  • shared_ptr<T>

Circular definition problem in objective c

I'm trying to implement a delegate pattern:

device_discovery_delegate = interface +j +o {
device_added(device: device);
device_removed(device: device);
}

device = interface +c {
static add_delegate(delegate: device_discovery_delegate);
}

When doing this, the generated header Device.h imports DeviceDiscoveryDelegate.h which then references the protocol which is still not defined. I fixed this with this patch but I don't know if this is a good solution:

diff --git a/src/source/ObjcGenerator.scala b/src/source/ObjcGenerator.scala
index cd67a03..8d26b53 100644
--- a/src/source/ObjcGenerator.scala
+++ b/src/source/ObjcGenerator.scala
@@ -46,7 +46,7 @@ class ObjcGenerator(spec: Spec) extends Generator(spec) {
header.add("#import " + q(headerName(d.name)))
case DInterface =>
header.add("#import <Foundation/Foundation.h>")

  •        header.add("#import " + q(headerName(d.name)))
    
  •        header.add("@protocol " + idObjc.ty(d.name) + ";")
         val ext = d.body.asInstanceOf[Interface].ext
         if (ext.cpp) body.add("#import " + q(privateHeaderName(d.name + "_cpp_proxy")))
         if (ext.objc) body.add("#import " + q(privateHeaderName(d.name + "_objc_proxy")))
    

Tutorial or article describing workflow

Hello, maybe it is not the best place to ask these kind of questions and this particular question is not the best too, but could you describe basic workflow for someone who is not so experienced in build systems and xplatform build process, maybe write something like short "how-to"? Thank you :)

Example build issue - missing local.properties

Error message on Mac:

NDK is not configured. Make sure there is a local.properties file with an ndk.dir entry in the directory

Following the instructions in README.md I get these errors:

$ make android
make: *** No rule to make target `android'.  Stop.

$ make ios
make: *** No rule to make target `ios'.  Stop.

$ make example_android
...

cd example/android/ && ./gradlew app:assembleDebug

FAILURE: Build failed with an exception.

* Where:
Build file 'djinni/example/android/app/build.gradle' line: 38

* What went wrong:
A problem occurred evaluating project ':app'.
> NDK is not configured. Make sure there is a local.properties file with an ndk.dir entry in the directory djinni/example/android.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Suggestions:

Since local.properties is excluded in gitignore, creating a local.properties.sample would be a great help.

Also updating the README.md with the steps required to download and install SDK/NDK would allow prospective users to quickly compile & test.

Preexisting record types

Djinni really only needs to know how to convert record types between objc, java and c++. What if we extended the include format to take plugins like this?

@include "date.json"

djinni_type: "custom_date"
objc_type: "NSDate"
java_type: "java.util.Date"
cpp_include_path: "<chrono>"
cpp_type: "std::chrono::system_clock::time_point"
jni_type: "jobject"
// custom_date.hpp
namespace djinni {
  jobject custom_date_to_java(time_point);
  NSDate * custom_date_to_objc(time_point);
  time_point custom_date_to_cpp(jobject);
  time_point custom_date_to_cpp(NSDate *);
}

Specify new language

I want to add support for a new language but the generators are tangled up.

For example there is code referencing each language generator in the generic generator class.

I don't think this scalable are you going to make it easier to add new languages.

Deriving objc header location when extending records

When a record is specified to be extended in ObjC (using the +o flag), the deriving header location is always ../DerivingHeaderName.h (see here). Now that header is obviously a piece of handwritten code. I could not make this work while keeping the generated and handwritten source files in separate directories.

Wouldn't it be better to add an option for specifying were handwritten source files are located? Or is there some other way around this?

unused-parameter warnings on record types with no non-const fields

If you create a record without any non-const members (say, one to describe an app or library version...), the generated Objective-C constructors for it will produce unused-parameter warnings, since their arguments are never referenced. Perhaps we can just emit a "#pragma unused (varName)"?

Rationale for @protocol in +c interfaces

Hi,

I am currently in the process of trying out Djinni for our projects here. One thing that I am curious about is why the Objective-C side is using @protocol for the base type, but additionally also relies on a public @interface.

Specifically, if I have MyClass I get a @ProtoColl names MyClass and an @interface called MyClassCppProxy. Now as long as one only uses instance methods with id it's nice and all. But this totally makes object construction very inconvenient using class methods.

Example:

@protocl MyClass
+ (id<MyClass>) create;
@end

At first glance one might think you can call [MyClass create] but while this is great with static Java/C++ member functions that's not how Objective-C protocols work. One has to use [MyClassCppProxy create] instead. This is very inconvenient. First, I have to tell users about classes that I would consider a private implementation detail, and second, it means I have to tell our (overly religious) Objective-C developers to use something with "cpp" in its name...

Besides the inconvenience, there might also be a correctness issue. Right now all generated +c interfaces on the Objective-C side take id as parameter and then internally cast it to SomethingCppProxy* to get to the C++ object. But the argument may not necessarily be an instance of SomethingCppProxy. While this will most likely just crash the program I'd rather have it prevented at compile time if possible.

Both these issues would be solved if Djinni only created @interface types for +c interfaces. But I guess there is some rationale behind the current design and I would be curious to know about it.

Regards,
Miro

Java to C++ exception translation

Common workflow with djinni (I'm focused on Java only now): "Client code" (Java) --> C++ library shared code --> Platform specific interface if necessary (again Java, TextboxListenerImpl in the example).

If we call platform specific code from C++ and it throws an exception, then it is caught by jniExceptionCheck and passed back to C++ as jni_exception_pending(), but no matter what C++ code does (catches it or not), exception still exists in JVM and client code is forced to catch it (even if C++ code has already recovered).
Any reason for this? Can JNI remove exception from JVM with env->ExceptionClear() before throwing jni_exception_pending()? Then we will have to catch exception only once (in C++ code). "C++ code" does call platform specific code and it should know better how to recover in case of exception. If it is necessary we still can re-throw it to client code, but in some cases client code should not care about this.

Any thoughts?
Thank you.

Getting started documentation with dependency information

I'm very interested in experimenting with djinni for bridging C++ libraries with Java on Windows. However, I'm struggling to get started since there does not seem to be a getting started guide or list of build tool dependencies documented anywhere. Also, the documentation and makefiles already present seem very geared towards "mobile" Android/iOS platforms, with little "desktop" information to be found.

Could it be possible to extend the existing documentation with a little bit of "getting started" information for different platforms such as e.g. Windows/Linux/Android/OS-x/iOS?

Thanks in advance,
Fredrik

deriving json

Djinni should be able to autogenerate json parsing and serialization code for records/enums.

ADL prevents correct type lookup

When defining a interface +j with a record type, ADL seems to be selecting the wrong types.

record_thing = record {
    data_member: string;
}

interface_thing = interface +j +o {
  on_event(thing: record_thing);
}

Generated code with comments:

namespace djinni_generated_java_classes {

void InterfaceThing::JavaProxy::JavaProxy::on_event(const ::my_namespace::RecordThing & c_thing) {
    JNIEnv * const jniEnv = djinni::jniGetThreadEnv();
    djinni::JniLocalScope jscope(jniEnv, 10);
    djinni::LocalRef<jobject> j_thing(jniEnv, RecordThing::toJava(jniEnv, c_thing));
    // selects my_namespace::InterfaceThing NOT djinni_generated_java_classes::InterfaceThing
    const InterfaceThing & data = djinni::JniClass<InterfaceThing>::get();
    // data.method_onEvent is undefined
    jniEnv->CallVoidMethod(getGlobalRef(), data.method_onEvent, j_thing.get());
    djinni::jniExceptionCheck(jniEnv);
};

}

Cygwin uses incorrect paths

sbt fails to find sbt_launch.jar when djinni is run from cygwin

The failure in cygwin is due to incorrect paths. Java on windows requires windows-formatted paths, even when run from cygwin.

cygpath can be used to convert between the various formats.

trailing comments

When using djinni, it fails on trailing comments. Using comments not for documentation, but for commenting out methods / fields doesn't really work.

Works (because it still looks like a documentation comment)

blah = interface +c {
    # method_a();
    method_b();
}

Doesn't work but I would guess every single developer would expect it to

blah = interface +c {
    method_a();
    # method_b();
}

C++/Java interop on Linux/MacOSX

Hi, I've tried to use djinni for calling C++ from Java on both Linux and MaxOSX but I get a java.lang.UnsatisfiedLinkError exception at runtime. Is it supposed to be possible to use the C++/Java interop functionality of djinni on Linux and MaxOSX or is the implementation specific to the Android build/runtime system?

Break circular dependencies with forward declarations

if you have the CIDL file

MyClassListener = interface +c {
    onMyClassInitialized(instance: MyClass);
}

MyClass = interface +c {
    static createMyClass(listener: MyClassListener);
}

then it will fail to compile because of a circular dependency. it would be rad to detect these and break them with forward declarations.

JNI Exception check in HBinary.hpp calls forbidden JNI methods in critical section

When retrieving binary data from Java environment, fromJava method in HBinary.hpp calls jniExceptionCheck which calls further methods.

The exception check call is made between the time GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical is called, causing undefined behaviour forbidden by the JVM standard.

It also causes a hard crash on Android ART / CheckJNI with an exception:

JNI DETECTED ERROR IN APPLICATION: thread Thread[13,tid=18055,Runnable,Thread*=0xaf075000,peer=<redacted>] using JNI after critical get

Suggest removing the check call in that method since it's usually done by the callee anyway.

security exceptions in build

I am trying to compile Djinni, but am running into some Java security exceptions. If anybody has any suggestions on how to switch off these security settings, that would be great.

dhruba@dev223 ~/djinni]$ java -version
java version "1.7.0_06"
Java(TM) SE Runtime Environment (build 1.7.0_06-b24)
Java HotSpot(TM) 64-Bit Server VM (build 23.2-b09, mixed mode)

[dhruba@dev223 ~/djinni]$ uname -a
Linux 3.2.55-106_fbk22_00877_g6902630 #106 SMP Wed Apr 2 16:19:59 PDT 2014 x86_64 x86_64 x86_64 GNU/Linux

[dhruba@dev223 ~/djinni]$ src/run
Building Djinni...
java -Xms512M -Xmx1024M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M -Djava.security.manager -Djava.security.policy=/home/dhruba/local/djinni/src/support/sbt.security.policy -jar /home/dhruba/local/djinni/src/support/sbt-launch.jar -Dsbt.override.build.repos=true -Dsbt.repository.config=/home/dhruba/local/djinni/src/support/sbt.resolvers.properties compile start-script
[info] Loading project definition from /data/users/dhruba/djinni/src/project
[info] Updating {file:/data/users/dhruba/djinni/src/project/}src-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: com.typesafe.sbt#sbt-start-script;0.10.0: several problems occurred while resolving dependency: com.typesafe.sbt#sbt-start-script;0.10.0 {compile=[default(compile)]}:
[warn] java.security.AccessControlException: access denied ("java.net.SocketPermission" "xx:8080" "connect,resolve")
[warn] java.security.AccessControlException: access denied ("java.net.SocketPermission" "xx:8080" "connect,resolve")
[warn] java.security.AccessControlException: access denied ("java.net.SocketPermission" "xx:8080" "connect,resolve")
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn]
[warn] Note: Some unresolved dependencies have extra attributes. Check that these dependencies exist with the requested attributes.
[warn] com.typesafe.sbt:sbt-start-script:0.10.0 (sbtVersion=0.13, scalaVersion=2.10)
[warn]
sbt.ResolveException: unresolved dependency: com.typesafe.sbt#sbt-start-script;0.10.0: several problems occurred while resolving dependency: com.typesafe.sbt#sbt-start-script;0.10.0 {compile=[default(compile)]}:
java.security.AccessControlException: access denied ("java.net.SocketPermission" "xx.xx.xx.xx:8080" "connect,resolve")
java.security.AccessControlException: access denied ("java.net.SocketPermission" "xx.xx.xx.xx:8080" "connect,resolve")
java.security.AccessControlException: access denied ("java.net.SocketPermission" "xx.xx.xx.xx:8080" "connect,resolve")
at sbt.IvyActions$.sbt$IvyActions$$resolve(IvyActions.scala:217)
at sbt.IvyActions$$anonfun$update$1.apply(IvyActions.scala:126)
at sbt.IvyActions$$anonfun$update$1.apply(IvyActions.scala:125)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:115)
at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:115)
at sbt.IvySbt$$anonfun$withIvy$1.apply(Ivy.scala:103)
at sbt.IvySbt.sbt$IvySbt$$action$1(Ivy.scala:48)
at sbt.IvySbt$$anon$3.call(Ivy.scala:57)
at xsbt.boot.Locks$GlobalLock.withChannel$1(Locks.scala:98)
at xsbt.boot.Locks$GlobalLock.xsbt$boot$Locks$GlobalLock$$withChannelRetries$1(Locks.scala:81)
at xsbt.boot.Locks$GlobalLock$$anonfun$withFileLock$1.apply(Locks.scala:102)
at xsbt.boot.Using$.withResource(Using.scala:11)
at xsbt.boot.Using$.apply(Using.scala:10)
at xsbt.boot.Locks$GlobalLock.ignoringDeadlockAvoided(Locks.scala:62)
at xsbt.boot.Locks$GlobalLock.withLock(Locks.scala:52)
at xsbt.boot.Locks$.apply0(Locks.scala:31)
at xsbt.boot.Locks$.apply(Locks.scala:28)
at sbt.IvySbt.withDefaultLogger(Ivy.scala:57)
at sbt.IvySbt.withIvy(Ivy.scala:98)
at sbt.IvySbt.withIvy(Ivy.scala:94)
at sbt.IvySbt$Module.withModule(Ivy.scala:115)
at sbt.IvyActions$.update(IvyActions.scala:125)
at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1223)
at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1221)
at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$74.apply(Defaults.scala:1244)
at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$74.apply(Defaults.scala:1242)
at sbt.Tracked$$anonfun$lastOutput$1.apply(Tracked.scala:35)
at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1246)
at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1241)
at sbt.Tracked$$anonfun$inputChanged$1.apply(Tracked.scala:45)
at sbt.Classpaths$.cachedUpdate(Defaults.scala:1249)
at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1214)
at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1192)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
at sbt.std.Transform$$anon$4.work(System.scala:64)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
at sbt.Execute.work(Execute.scala:244)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
error sbt.ResolveException: unresolved dependency: com.typesafe.sbt#sbt-start-script;0.10.0: several problems occurred while resolving dependency: com.typesafe.sbt#sbt-start-script;0.10.0 {compile=[default(compile)]}:
[error] java.security.AccessControlException: access denied ("java.net.SocketPermission" "xx.xx.xx.xx:8080" "connect,resolve")
[error] java.security.AccessControlException: access denied ("java.net.SocketPermission" "xx.xx.xx.xx:8080" "connect,resolve")
[error] java.security.AccessControlException: access denied ("java.net.SocketPermission" "xx.xx.xx.xx:8080" "connect,resolve")

deriving parcelable

Related to #6 - there are also places where we'd like the Java versions of records to be Parcelable.

Wrap C++ -> ObjC call paths in autoreleasepool

ObjC depends on autorelease to clean up memory in a timely fashion - without an autoreleasepool, ObjC temporaries created (esp. on background threads) can stick around for a very long time.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.