Skip to content

Commit

Permalink
add new --jni-generate-main parameter (#49)
Browse files Browse the repository at this point in the history
* add new commandline parameter `--jni-generate-main` to resolve the currently discussed issue on how to provide a default JNI_OnLoad & JNI_OnUnload implementation without the user having to know about the internals.

The paramater, if true, generates a file `djinni_jni_main.cpp` that includes the `djinni/jni/djinni_jni_main.hpp` header provided by djinni-support-lib. That way by default the user automatically gets a default JNI_OnLoad implementation if he builds a shared library from all sources.

This is a breaking change because it generates a new type of file. This requires the upcoming djinni-support-lib v1.0.0, that comes with the required header file, to work properly.
  • Loading branch information
jothepro authored May 7, 2021
1 parent 26e1812 commit 2438082
Show file tree
Hide file tree
Showing 21 changed files with 67 additions and 13 deletions.
1 change: 1 addition & 0 deletions docs/cli-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ djinni \
| `--jni-include-cpp-prefix <prefix>` | The prefix for `#includes` of the main header files from JNI C++ files. |
| `--jni-namespace ...` | The namespace name to use for generated JNI C++ classes. |
| `--jni-base-lib-include-prefix ...` | The JNI base support library's include path (default: `djinni/jni/`). |
| `--jni-generate-main <true/false>` | Generate a source file (`djinni_jni_main.cpp`) that includes the default `JNI_OnLoad` & `JNI_OnUnload` implementation from the support library. (default: `true`) |

### Objective-C

Expand Down
14 changes: 9 additions & 5 deletions docs/generated-code-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ The following headers / code will be generated for each defined type:

(+) Generated only for types that contain constants.

Additionally `djinni_jni_main.cpp` is generated to provide a default implementation for `JNI_OnLoad` and `JNI_OnUnload`, if `--jni-generate-main=true`.

Add all generated source files to your build target, and link the C++ code against the [djinni-support-lib](https://github.com/cross-language-cpp/djinni-support-lib).

### Our JNI approach
JNI stands for [Java Native Interface](http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html), an extension of the Java language to allow interop with
native (C/C++) code or libraries.


For each type, built-in (`list`, `string`, etc.) or user-defined, Djinni produces a translator
class with a `toJava` and `fromJava` function to translate back and forth.

Expand All @@ -39,12 +40,15 @@ class Main {
If you package your native library in a jar, you can also use the [`NativeLibLoader`](https://github.com/cross-language-cpp/djinni-support-lib/blob/main/java/com/dropbox/djinni/NativeLibLoader.java)
to help unpack and load your lib(s).

When a native library is called, JNI calls a special function called [`JNI_OnLoad`](https://github.com/cross-language-cpp/djinni-support-lib/blob/main/djinni/jni/djinni_main.cpp#L23).
Any library loaded from Java should provide the functions `JNI_OnLoad` and `JNI_OnUnload`.
They are called by JNI when the library is loaded/unloaded.

If your app doesn't use JNI except through Djinni, include [`djinni/jni/djinni_main.cpp`](https://github.com/cross-language-cpp/djinni-support-lib/blob/main/djinni/jni/djinni_main.cpp).
It defines default `JNI_Onload` and `JNI_OnUnload` functions for Djinni.
Djinni uses these functions to initialize & cleanup internal structures.
The generated file `djinni_jni_main.cpp` includes a default implementation of `JNI_Onload` and `JNI_OnUnload` functions
provided by the support library.

If your app also includes a non-Djinni JNI interface, you'll need to define your own `JNI_OnLoad` and `JNI_OnUnload` functions.
If you are building a library that does not use JNI except through Djinni, this default should work well for you.
If want to provide your own implementation of `JNI_Onload` and `JNI_OnUnload`, the generation of `djinni_jni_main.cpp` can be disabled by setting `--jni-generate-main=false`.

## Objective-C / C++ Project

Expand Down
2 changes: 1 addition & 1 deletion docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ Add the generator as a build requirement in `conanfile.txt`:

```text
[build_requires]
djinni-generator/0.3.1
djinni-generator/1.0.0
```
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
src/it/resources/result/all_datatypes/cpp-headers/all_datatypes.hpp
src/it/resources/result/all_datatypes/java/AllDatatypes.java
src/it/resources/result/all_datatypes/jni/djinni_jni_main.cpp
src/it/resources/result/all_datatypes/jni-headers/all_datatypes.hpp
src/it/resources/result/all_datatypes/jni/all_datatypes.cpp
src/it/resources/result/all_datatypes/objc-headers/ITAllDatatypes.h
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// AUTOGENERATED FILE - DO NOT MODIFY!
// The file included here provides default JNI_OnLoad and JNI_OnUnload implementations.
// Disable the generation of this file with `--jni-generate-main=false`.
#include "djinni/jni/djinni_jni_main.hpp"
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
src/it/resources/result/my_client_interface/cpp-headers/my_client_interface.hpp
src/it/resources/result/my_client_interface/java/MyClientInterface.java
src/it/resources/result/my_client_interface/jni/djinni_jni_main.cpp
src/it/resources/result/my_client_interface/jni-headers/my_client_interface.hpp
src/it/resources/result/my_client_interface/jni/my_client_interface.cpp
src/it/resources/result/my_client_interface/objc-headers/ITMyClientInterface.h
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// AUTOGENERATED FILE - DO NOT MODIFY!
// The file included here provides default JNI_OnLoad and JNI_OnUnload implementations.
// Disable the generation of this file with `--jni-generate-main=false`.
#include "djinni/jni/djinni_jni_main.hpp"
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
src/it/resources/result/my_cpp_interface/cpp-headers/my_cpp_interface.hpp
src/it/resources/result/my_cpp_interface/cpp/my_cpp_interface.cpp
src/it/resources/result/my_cpp_interface/java/MyCppInterface.java
src/it/resources/result/my_cpp_interface/jni/djinni_jni_main.cpp
src/it/resources/result/my_cpp_interface/jni-headers/my_cpp_interface.hpp
src/it/resources/result/my_cpp_interface/jni/my_cpp_interface.cpp
src/it/resources/result/my_cpp_interface/objc-headers/ITMyCppInterface.h
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// AUTOGENERATED FILE - DO NOT MODIFY!
// The file included here provides default JNI_OnLoad and JNI_OnUnload implementations.
// Disable the generation of this file with `--jni-generate-main=false`.
#include "djinni/jni/djinni_jni_main.hpp"
1 change: 1 addition & 0 deletions src/it/resources/expected/my_enum/generated-files.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
src/it/resources/result/my_enum/cpp-headers/my_enum.hpp
src/it/resources/result/my_enum/java/MyEnum.java
src/it/resources/result/my_enum/jni/djinni_jni_main.cpp
src/it/resources/result/my_enum/jni-headers/my_enum.hpp
src/it/resources/result/my_enum/objc-headers/ITMyEnum.h
src/it/resources/result/my_enum/objcpp/ITMyEnum+Private.h
Expand Down
4 changes: 4 additions & 0 deletions src/it/resources/expected/my_enum/jni/djinni_jni_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// AUTOGENERATED FILE - DO NOT MODIFY!
// The file included here provides default JNI_OnLoad and JNI_OnUnload implementations.
// Disable the generation of this file with `--jni-generate-main=false`.
#include "djinni/jni/djinni_jni_main.hpp"
1 change: 1 addition & 0 deletions src/it/resources/expected/my_flags/generated-files.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
src/it/resources/result/my_flags/cpp-headers/my_flags.hpp
src/it/resources/result/my_flags/java/MyFlags.java
src/it/resources/result/my_flags/jni/djinni_jni_main.cpp
src/it/resources/result/my_flags/jni-headers/my_flags.hpp
src/it/resources/result/my_flags/objc-headers/ITMyFlags.h
src/it/resources/result/my_flags/objcpp/ITMyFlags+Private.h
Expand Down
4 changes: 4 additions & 0 deletions src/it/resources/expected/my_flags/jni/djinni_jni_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// AUTOGENERATED FILE - DO NOT MODIFY!
// The file included here provides default JNI_OnLoad and JNI_OnUnload implementations.
// Disable the generation of this file with `--jni-generate-main=false`.
#include "djinni/jni/djinni_jni_main.hpp"
1 change: 1 addition & 0 deletions src/it/resources/expected/my_record/generated-files.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
src/it/resources/result/my_record/cpp-headers/my_record.hpp
src/it/resources/result/my_record/cpp/my_record.cpp
src/it/resources/result/my_record/java/MyRecord.java
src/it/resources/result/my_record/jni/djinni_jni_main.cpp
src/it/resources/result/my_record/jni-headers/my_record.hpp
src/it/resources/result/my_record/jni/my_record.cpp
src/it/resources/result/my_record/objc-headers/ITMyRecord.h
Expand Down
4 changes: 4 additions & 0 deletions src/it/resources/expected/my_record/jni/djinni_jni_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// AUTOGENERATED FILE - DO NOT MODIFY!
// The file included here provides default JNI_OnLoad and JNI_OnUnload implementations.
// Disable the generation of this file with `--jni-generate-main=false`.
#include "djinni/jni/djinni_jni_main.hpp"
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ src/it/resources/result/using_custom_datatypes/cpp-headers/custom_datatype.hpp
src/it/resources/result/using_custom_datatypes/cpp-headers/other_record.hpp
src/it/resources/result/using_custom_datatypes/java/CustomDatatype.java
src/it/resources/result/using_custom_datatypes/java/OtherRecord.java
src/it/resources/result/using_custom_datatypes/jni/djinni_jni_main.cpp
src/it/resources/result/using_custom_datatypes/jni-headers/custom_datatype.hpp
src/it/resources/result/using_custom_datatypes/jni/custom_datatype.cpp
src/it/resources/result/using_custom_datatypes/jni-headers/other_record.hpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// AUTOGENERATED FILE - DO NOT MODIFY!
// The file included here provides default JNI_OnLoad and JNI_OnUnload implementations.
// Disable the generation of this file with `--jni-generate-main=false`.
#include "djinni/jni/djinni_jni_main.hpp"
14 changes: 7 additions & 7 deletions src/it/scala/djinni/GeneratorIntegrationTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class GeneratorIntegrationTest extends IntegrationTest with GivenWhenThen {
Cpp(),
CppHeaders("my_enum.hpp"),
Java("MyEnum.java"),
Jni(),
Jni("djinni_jni_main.cpp"),
JniHeaders("my_enum.hpp"),
ObjC(),
ObjCHeaders("ITMyEnum.h", "bridging-header.h"),
Expand All @@ -40,7 +40,7 @@ class GeneratorIntegrationTest extends IntegrationTest with GivenWhenThen {
Cpp(),
CppHeaders("my_flags.hpp"),
Java("MyFlags.java"),
Jni(),
Jni("djinni_jni_main.cpp"),
JniHeaders("my_flags.hpp"),
ObjC(),
ObjCHeaders("ITMyFlags.h"),
Expand All @@ -54,7 +54,7 @@ class GeneratorIntegrationTest extends IntegrationTest with GivenWhenThen {
Cpp("my_record.cpp"),
CppHeaders("my_record.hpp"),
Java("MyRecord.java"),
Jni("my_record.cpp"),
Jni("my_record.cpp", "djinni_jni_main.cpp"),
JniHeaders("my_record.hpp"),
ObjC("ITMyRecord.mm"),
ObjCHeaders("ITMyRecord.h", "bridging-header.h"),
Expand All @@ -69,7 +69,7 @@ class GeneratorIntegrationTest extends IntegrationTest with GivenWhenThen {
Cpp("my_cpp_interface.cpp"),
CppHeaders("my_cpp_interface.hpp"),
Java("MyCppInterface.java"),
Jni("my_cpp_interface.cpp"),
Jni("my_cpp_interface.cpp", "djinni_jni_main.cpp"),
JniHeaders("my_cpp_interface.hpp"),
ObjC("ITMyCppInterface.mm"),
ObjCHeaders("ITMyCppInterface.h", "bridging-header.h"),
Expand All @@ -83,7 +83,7 @@ class GeneratorIntegrationTest extends IntegrationTest with GivenWhenThen {
Cpp(),
CppHeaders("my_client_interface.hpp"),
Java("MyClientInterface.java"),
Jni("my_client_interface.cpp"),
Jni("my_client_interface.cpp", "djinni_jni_main.cpp"),
JniHeaders("my_client_interface.hpp"),
ObjC(),
ObjCHeaders("ITMyClientInterface.h", "bridging-header.h"),
Expand All @@ -97,7 +97,7 @@ class GeneratorIntegrationTest extends IntegrationTest with GivenWhenThen {
Cpp(),
CppHeaders("all_datatypes.hpp"),
Java("AllDatatypes.java"),
Jni("all_datatypes.cpp"),
Jni("all_datatypes.cpp", "djinni_jni_main.cpp"),
JniHeaders("all_datatypes.hpp"),
ObjC("ITAllDatatypes.mm"),
ObjCHeaders("ITAllDatatypes.h", "bridging-header.h"),
Expand All @@ -112,7 +112,7 @@ class GeneratorIntegrationTest extends IntegrationTest with GivenWhenThen {
Cpp(),
CppHeaders("custom_datatype.hpp", "other_record.hpp"),
Java("CustomDatatype.java", "OtherRecord.java"),
Jni("custom_datatype.cpp", "other_record.cpp"),
Jni("custom_datatype.cpp", "other_record.cpp", "djinni_jni_main.cpp"),
JniHeaders("custom_datatype.hpp", "other_record.hpp"),
ObjC("ITCustomDatatype.mm", "ITOtherRecord.mm"),
ObjCHeaders("ITCustomDatatype.h","ITOtherRecord.h", "bridging-header.h"),
Expand Down
9 changes: 9 additions & 0 deletions src/main/scala/djinni/JNIGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ class JNIGenerator(spec: Spec) extends Generator(spec) {
def writeJniHppFile(name: String, origin: String, includes: Iterable[String], fwds: Iterable[String], f: IndentWriter => Unit, f2: IndentWriter => Unit = (w => {})) =
writeHppFileGeneric(spec.jniHeaderOutFolder.get, spec.jniNamespace, spec.jniFileIdentStyle)(name, origin, includes, fwds, f, f2)

if(spec.jniGenerateMain) {
createFile(spec.jniOutFolder.get, "djinni_jni_main." + spec.cppExt, w => {
w.wl("// AUTOGENERATED FILE - DO NOT MODIFY!")
w.wl("// The file included here provides default JNI_OnLoad and JNI_OnUnload implementations.")
w.wl("// Disable the generation of this file with `--jni-generate-main=false`.")
w.wl(s"#include " + q(spec.jniBaseLibIncludePrefix + "djinni_jni_main.hpp"))
})
}

class JNIRefs(name: String, cppPrefixOverride: Option[String]=None) {
var jniHpp = mutable.TreeSet[String]()
var jniCpp = mutable.TreeSet[String]()
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/djinni/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ object Main {
var jniFileIdentStyleOptional: Option[IdentConverter] = None
var jniBaseLibClassIdentStyleOptional: Option[IdentConverter] = None
var jniBaseLibIncludePrefix: String = "djinni/jni/"
var jniGenerateMain: Boolean = true
var cppHeaderOutFolderOptional: Option[File] = None
var cppExt: String = "cpp"
var cppHeaderExt: String = "hpp"
Expand Down Expand Up @@ -185,6 +186,8 @@ object Main {
.text("The namespace name to use for generated JNI C++ classes.")
opt[String]("jni-base-lib-include-prefix").valueName("...").foreach(x => jniBaseLibIncludePrefix = x)
.text("The JNI base support library's include path (default: djinni/jni/).")
opt[Boolean]("jni-generate-main").valueName("<true/false>").foreach(x => jniGenerateMain = x)
.text("Generate a source file (djinni_jni_main.cpp) that includes the default JNI_OnLoad & JNI_OnUnload implementation from the djinni-support-lib. (default: true)")
note("\nObjective-C")
opt[File]("objc-out").valueName("<out-folder>").foreach(x => objcOutFolder = Some(x))
.text("The output folder for Objective-C files (Generator disabled if unspecified).")
Expand Down Expand Up @@ -427,6 +430,7 @@ object Main {
jniClassIdentStyle,
jniFileIdentStyle,
jniBaseLibIncludePrefix,
jniGenerateMain,
cppExt,
cppHeaderExt,
objcOutFolder,
Expand Down
1 change: 1 addition & 0 deletions src/main/scala/djinni/generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ package object generatorTools {
jniClassIdentStyle: IdentConverter,
jniFileIdentStyle: IdentConverter,
jniBaseLibIncludePrefix: String,
jniGenerateMain: Boolean,
cppExt: String,
cppHeaderExt: String,
objcOutFolder: Option[File],
Expand Down

0 comments on commit 2438082

Please sign in to comment.