Commit c24052d9 authored by j4cbo's avatar j4cbo

Merge pull request #83 from mknejp/feature/objcpp-cmd-args

Command line arguments to control Obj-C++ generation
parents 04da0e9a 393421cf
...@@ -105,6 +105,8 @@ When the Djinni file(s) are ready, from the command line or a bash script you ca ...@@ -105,6 +105,8 @@ When the Djinni file(s) are ready, from the command line or a bash script you ca
--objc-out OBJC_OUTPUT_FOLDER \ --objc-out OBJC_OUTPUT_FOLDER \
--objc-type-prefix DB \ # Apple suggests Objective-C classes have a prefix for each defined type. --objc-type-prefix DB \ # Apple suggests Objective-C classes have a prefix for each defined type.
\ \
--objcpp-out OBJC_OUTPUT_FOLDER \
\
--idl MY_PROJECT.djinni --idl MY_PROJECT.djinni
Some other options are also available, such as `--cpp-namespace` that put generated C++ code into the namespace specified. For a list of all options, run Some other options are also available, such as `--cpp-namespace` that put generated C++ code into the namespace specified. For a list of all options, run
...@@ -158,26 +160,19 @@ you'll need to add calls to your own `JNI_OnLoad` and `JNI_OnUnload` functions. ...@@ -158,26 +160,19 @@ you'll need to add calls to your own `JNI_OnLoad` and `JNI_OnUnload` functions.
##### Includes & Build Target ##### Includes & Build Target
Generated file for Objective-C / C++ is as follows (assuming prefix is `DB`): Generated file for Objective-C / C++ is as follows (assuming prefix is `DB`):
| Type | C++ header | C++ source | Objective-C header | Objective-C source | | Type | C++ header | C++ source | Objective-C files | Objective-C++ files |
|----------------|------------------------|----------------------------|--------------------------------------------|-------------------------------------| |-----------|------------------------|----------------------------|--------------------------|-----------------------------|
| Enum | my\_enum.hpp | | ` public/`DBMyEnum.h | `private/`DBMyEnumTranslator.mm | | Enum | my\_enum.hpp | | DBMyEnum.h | |
| | | | `private/`DBMyEnumTranslator+Private.h | | | Record | my\_record[\_base].hpp | my\_record[\_base].cpp (+) | DBMyRecord[Base].h | DBMyRecord[Base]+Private.h |
| Record | my\_record[\_base].hpp | my\_record[\_base].cpp (+) | ` public/`DBMyRecord[Base].h | `private/`DBMyRecord[Base].mm | | | | | DBMyRecord[Base].mm (++) | DBMyRecord[Base]+Private.mm |
| | | | `private/`DBMyRecord[Base]+Private.h | | | Interface | my\_interface.hpp | my\_interface.cpp (+) | DBMyInterface.h | DBMyInterface+Private.h |
| Interface `+c` | my\_interface.hpp | my\_interface.cpp (+) | ` public/`DBMyInterface.h | `private/`DBMyInterfaceCppProxy.mm | | | | | | DBMyInterface+Private.mm |
| | | | ` public/`DBMyInterfaceCppProxy.h | |
| | | | `private/`DBMyInterfaceCppProxy+Private.h | |
| Interface `+o` | my\_interface.hpp | my\_interface.cpp (+) | ` public/`DBMyInterface.h | `private/`DBMyInterfaceObjcProxy.mm |
| | | | `private/`DBMyInterfaceObjcProxy+Private.h | |
(+) Generated only for types that contain constants. (+) Generated only for types that contain constants.
(++) Generated only for types with derived operations and/or constants. These have `.mm` extensions to allow non-trivial constants.
The folders `public` and `private` correspond to the options `--objc-out` and `--objc-private-out`
respecitvely, allowing you to isolate implementation headers and sources from the public files
exposed to Objective-C clients.
Add all generated files to your build target, as well as the contents of `support-lib/objc`. Add all generated files to your build target, as well as the contents of `support-lib/objc`.
Note that `+Private` headers can only be used with ObjC++ source (other headers are pure ObjC). Note that `+Private` files can only be used with ObjC++ source (other headers are pure ObjC) and are not required by Objective-C users of your interface.
## Details of Generated Types ## Details of Generated Types
### Enum ### Enum
......
...@@ -63,7 +63,8 @@ $base_dir/../src/run-assume-built \ ...@@ -63,7 +63,8 @@ $base_dir/../src/run-assume-built \
--ident-jni-class NativeFooBar \ --ident-jni-class NativeFooBar \
--ident-jni-file NativeFooBar \ --ident-jni-file NativeFooBar \
\ \
--objc-out "$temp_out/objc" \ --objc-out "$temp_out/objc" \
--objcpp-out "$temp_out/objc" \
--objc-type-prefix TXS \ --objc-type-prefix TXS \
\ \
--idl "$in" --idl "$in"
......
...@@ -51,14 +51,15 @@ object Main { ...@@ -51,14 +51,15 @@ object Main {
var cppIdentStyle = IdentStyle.cppDefault var cppIdentStyle = IdentStyle.cppDefault
var cppTypeEnumIdentStyle: IdentConverter = null var cppTypeEnumIdentStyle: IdentConverter = null
var objcOutFolder: Option[File] = None var objcOutFolder: Option[File] = None
var objcPrivateOutFolderOptional: Option[File] = None var objcppOutFolder: Option[File] = None
var objcExt: String = "mm" var objcppExt: String = "mm"
var objcHeaderExt: String = "h" var objcHeaderExt: String = "h"
var objcIdentStyle = IdentStyle.objcDefault var objcIdentStyle = IdentStyle.objcDefault
var objcTypePrefix: String = "" var objcTypePrefix: String = ""
var objcIncludePrefix: String = "" var objcIncludePrefix: String = ""
var objcIncludePrivatePrefixOptional: Option[String] = None var objcppIncludePrefix: String = ""
var objcIncludeCppPrefix: String = "" var objcppIncludeCppPrefix: String = ""
var objcppIncludeObjcPrefixOptional: Option[String] = None
var objcFileIdentStyleOptional: Option[IdentConverter] = None var objcFileIdentStyleOptional: Option[IdentConverter] = None
var objcppNamespace: String = "djinni_generated" var objcppNamespace: String = "djinni_generated"
var objcBaseLibIncludePrefix: String = "" var objcBaseLibIncludePrefix: String = ""
...@@ -122,22 +123,25 @@ object Main { ...@@ -122,22 +123,25 @@ object Main {
note("") note("")
opt[File]("objc-out").valueName("<out-folder>").foreach(x => objcOutFolder = Some(x)) opt[File]("objc-out").valueName("<out-folder>").foreach(x => objcOutFolder = Some(x))
.text("The output folder for Objective-C files (Generator disabled if unspecified).") .text("The output folder for Objective-C files (Generator disabled if unspecified).")
opt[File]("objc-private-out").valueName("<out-folder>").foreach(x => objcPrivateOutFolderOptional = Some(x))
.text("The output folder for private Objective-C header and implementation files (default: the same as --objc-out)")
opt[String]("objc-ext").valueName("<ext>").foreach(objcExt = _)
.text("The filename extension for Objective-C files (default: \"mm\")")
opt[String]("objc-h-ext").valueName("<ext>").foreach(objcHeaderExt = _) opt[String]("objc-h-ext").valueName("<ext>").foreach(objcHeaderExt = _)
.text("The filename extension for Objective-C header files (default: \"h\")") .text("The filename extension for Objective-C[++] header files (default: \"h\")")
opt[String]("objc-type-prefix").valueName("<pre>").foreach(objcTypePrefix = _) opt[String]("objc-type-prefix").valueName("<pre>").foreach(objcTypePrefix = _)
.text("The prefix for Objective-C data types (usually two or three letters)") .text("The prefix for Objective-C data types (usually two or three letters)")
opt[String]("objc-include-prefix").valueName("<prefix>").foreach(objcIncludePrefix = _) opt[String]("objc-include-prefix").valueName("<prefix>").foreach(objcIncludePrefix = _)
.text("The prefix for #import of header files from Objective-C files.") .text("The prefix for #import of header files from Objective-C files.")
opt[String]("objc-include-private-prefix").valueName("<prefix>").foreach(x => objcIncludePrivatePrefixOptional = Some(x)) note("")
.text("The prefix for #import and #include of private header files from Objective-C files (default: the same as --objc-include-prefix)") opt[File]("objcpp-out").valueName("<out-folder>").foreach(x => objcppOutFolder = Some(x))
opt[String]("objc-include-cpp-prefix").valueName("<prefix>").foreach(objcIncludeCppPrefix = _) .text("The output folder for private Objective-C++ files (Generator disabled if unspecified).")
.text("The prefix for #include of the main header files from Objective-C files.") opt[String]("objcpp-ext").valueName("<ext>").foreach(objcppExt = _)
.text("The filename extension for Objective-C++ files (default: \"mm\")")
opt[String]("objcpp-include-prefix").valueName("<prefix>").foreach(objcppIncludePrefix = _)
.text("The prefix for #import of Objective-C++ header files from Objective-C++ files.")
opt[String]("objcpp-include-cpp-prefix").valueName("<prefix>").foreach(objcppIncludeCppPrefix = _)
.text("The prefix for #include of the main C++ header files from Objective-C++ files.")
opt[String]("objcpp-include-objc-prefix").valueName("<prefix>").foreach(x => objcppIncludeObjcPrefixOptional = Some(x))
.text("The prefix for #import of the Objective-C header files from Objective-C++ files (default: the same as --objcpp-include-prefix)")
opt[String]("objcpp-namespace").valueName("<prefix>").foreach(objcppNamespace = _) opt[String]("objcpp-namespace").valueName("<prefix>").foreach(objcppNamespace = _)
.text("Namespace for C++ objects defined in Objective-C++, such as wrapper caches") .text("The namespace name to use for generated Objective-C++ classes.")
opt[String]("objc-base-lib-include-prefix").valueName("...").foreach(x => objcBaseLibIncludePrefix = x) opt[String]("objc-base-lib-include-prefix").valueName("...").foreach(x => objcBaseLibIncludePrefix = x)
.text("The Objective-C++ base library's include path, relative to the Objective-C++ classes.") .text("The Objective-C++ base library's include path, relative to the Objective-C++ classes.")
...@@ -174,8 +178,7 @@ object Main { ...@@ -174,8 +178,7 @@ object Main {
val jniBaseLibClassIdentStyle = jniBaseLibClassIdentStyleOptional.getOrElse(jniClassIdentStyle) val jniBaseLibClassIdentStyle = jniBaseLibClassIdentStyleOptional.getOrElse(jniClassIdentStyle)
val jniFileIdentStyle = jniFileIdentStyleOptional.getOrElse(cppFileIdentStyle) val jniFileIdentStyle = jniFileIdentStyleOptional.getOrElse(cppFileIdentStyle)
var objcFileIdentStyle = objcFileIdentStyleOptional.getOrElse(objcIdentStyle.ty) var objcFileIdentStyle = objcFileIdentStyleOptional.getOrElse(objcIdentStyle.ty)
val objcPrivateOutFolder = if (objcPrivateOutFolderOptional.isDefined) objcPrivateOutFolderOptional else objcOutFolder val objcppIncludeObjcPrefix = objcppIncludeObjcPrefixOptional.getOrElse(objcppIncludePrefix)
var objcIncludePrivatePrefix = objcIncludePrivatePrefixOptional.getOrElse(objcIncludePrefix)
// Add ObjC prefix to identstyle // Add ObjC prefix to identstyle
objcIdentStyle = objcIdentStyle.copy(ty = IdentStyle.prefix(objcTypePrefix,objcIdentStyle.ty)) objcIdentStyle = objcIdentStyle.copy(ty = IdentStyle.prefix(objcTypePrefix,objcIdentStyle.ty))
...@@ -231,14 +234,15 @@ object Main { ...@@ -231,14 +234,15 @@ object Main {
cppExt, cppExt,
cppHeaderExt, cppHeaderExt,
objcOutFolder, objcOutFolder,
objcPrivateOutFolder, objcppOutFolder,
objcIdentStyle, objcIdentStyle,
objcFileIdentStyle, objcFileIdentStyle,
objcExt, objcppExt,
objcHeaderExt, objcHeaderExt,
objcIncludePrefix, objcIncludePrefix,
objcIncludePrivatePrefix, objcppIncludePrefix,
objcIncludeCppPrefix, objcppIncludeCppPrefix,
objcppIncludeObjcPrefix,
objcppNamespace, objcppNamespace,
objcBaseLibIncludePrefix) objcBaseLibIncludePrefix)
......
...@@ -52,17 +52,17 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -52,17 +52,17 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
val ext = d.body.asInstanceOf[Interface].ext val ext = d.body.asInstanceOf[Interface].ext
if (ext.cpp) { if (ext.cpp) {
header.add("@class " + objcMarshal.typename(tm) + ";") header.add("@class " + objcMarshal.typename(tm) + ";")
body.add("#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(d.name))) body.add("#import " + q(spec.objcppIncludePrefix + privateHeaderName(d.name)))
} }
if (ext.objc) { if (ext.objc) {
header.add("@protocol " + objcMarshal.typename(tm) + ";") header.add("@protocol " + objcMarshal.typename(tm) + ";")
body.add("#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(d.name))) body.add("#import " + q(spec.objcppIncludePrefix + privateHeaderName(d.name)))
} }
case DRecord => case DRecord =>
val r = d.body.asInstanceOf[Record] val r = d.body.asInstanceOf[Record]
val prefix = if (r.ext.objc) "../" else "" val objcName = d.name + (if (r.ext.objc) "_base" else "")
header.add("@class " + objcMarshal.typename(tm) + ";") header.add("@class " + objcMarshal.typename(tm) + ";")
body.add("#import " + q(spec.objcIncludePrivatePrefix + prefix + privateHeaderName(d.name))) body.add("#import " + q(spec.objcppIncludePrefix + privateHeaderName(objcName)))
} }
case p: MParam => case p: MParam =>
} }
...@@ -77,8 +77,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -77,8 +77,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
def headerName(ident: String): String = idObjc.ty(ident) + "." + spec.objcHeaderExt def headerName(ident: String): String = idObjc.ty(ident) + "." + spec.objcHeaderExt
def privateHeaderName(ident: String): String = idObjc.ty(ident) + "+Private." + spec.objcHeaderExt def privateHeaderName(ident: String): String = idObjc.ty(ident) + "+Private." + spec.objcHeaderExt
def bodyName(ident: String): String = idObjc.ty(ident) + "." + spec.objcExt def bodyName(ident: String): String = idObjc.ty(ident) + "+Private." + spec.objcppExt
def privateBodyName(ident: String): String = idObjc.ty(ident) + "+Private." + spec.objcExt
override def generateInterface(origin: String, ident: Ident, doc: Doc, typeParams: Seq[TypeParam], i: Interface) { override def generateInterface(origin: String, ident: Ident, doc: Doc, typeParams: Seq[TypeParam], i: Interface) {
val refs = new ObjcRefs() val refs = new ObjcRefs()
...@@ -94,9 +93,9 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -94,9 +93,9 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
val cppSelf = cppMarshal.fqTypename(ident, i) val cppSelf = cppMarshal.fqTypename(ident, i)
refs.privHeader.add("#include <memory>") refs.privHeader.add("#include <memory>")
refs.privHeader.add("!#include " + q(spec.objcIncludeCppPrefix + spec.cppFileIdentStyle(ident) + "." + spec.cppHeaderExt)) refs.privHeader.add("!#include " + q(spec.objcppIncludeCppPrefix + spec.cppFileIdentStyle(ident) + "." + spec.cppHeaderExt))
refs.body.add("#include <vector>") refs.body.add("#include <vector>")
refs.body.add("!#import " + q(spec.objcIncludePrefix + headerName(ident))) refs.body.add("!#import " + q(spec.objcppIncludeObjcPrefix + headerName(ident)))
def writeObjcFuncDecl(method: Interface.Method, w: IndentWriter) { def writeObjcFuncDecl(method: Interface.Method, w: IndentWriter) {
val label = if (method.static) "+" else "-" val label = if (method.static) "+" else "-"
...@@ -131,7 +130,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -131,7 +130,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
}) })
if (i.ext.cpp) { if (i.ext.cpp) {
refs.body.add("!#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(ident.name))) refs.body.add("!#import " + q(spec.objcppIncludePrefix + privateHeaderName(ident.name)))
refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJICppWrapperCache+Private.h")) refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJICppWrapperCache+Private.h"))
refs.body.add("#include <utility>") refs.body.add("#include <utility>")
refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIError.h")) refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIError.h"))
...@@ -193,7 +192,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -193,7 +192,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
if (i.ext.objc) { if (i.ext.objc) {
val objcExtSelf = objcppMarshal.helperClass("objc_proxy") val objcExtSelf = objcppMarshal.helperClass("objc_proxy")
refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIObjcWrapperCache+Private.h")) refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIObjcWrapperCache+Private.h"))
refs.body.add("!#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(ident.name))) refs.body.add("!#import " + q(spec.objcppIncludePrefix + privateHeaderName(ident.name)))
writeObjcFile(bodyName(ident.name), origin, refs.body, w => { writeObjcFile(bodyName(ident.name), origin, refs.body, w => {
arcAssert(w) arcAssert(w)
...@@ -250,17 +249,17 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -250,17 +249,17 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
refs.header.add("#import <Foundation/Foundation.h>") refs.header.add("#import <Foundation/Foundation.h>")
refs.privHeader.add("!#import " + q(spec.objcIncludePrefix + headerName(objcName))) refs.privHeader.add("!#import " + q(spec.objcIncludePrefix + headerName(objcName)))
refs.privHeader.add("!#include " + q(spec.objcIncludeCppPrefix + spec.cppFileIdentStyle(ident) + "." + spec.cppHeaderExt)) refs.privHeader.add("!#include " + q(spec.objcppIncludeCppPrefix + spec.cppFileIdentStyle(ident) + "." + spec.cppHeaderExt))
refs.body.add("#import <Foundation/Foundation.h>") refs.body.add("#import <Foundation/Foundation.h>")
refs.body.add("#include <cassert>") refs.body.add("#include <cassert>")
refs.body.add("#include <utility>") refs.body.add("#include <utility>")
refs.body.add("#include <vector>") refs.body.add("#include <vector>")
refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIDate.h")) refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIDate.h"))
refs.body.add("!#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(objcName))) refs.body.add("!#import " + q(spec.objcppIncludePrefix + privateHeaderName(objcName)))
if (r.ext.objc) { if (r.ext.objc) {
refs.body.add("#import " + q(spec.objcIncludePrefix + "../" + headerName(ident))) refs.body.add("#import " + q(spec.objcppIncludeObjcPrefix + "../" + headerName(ident)))
refs.header.add(s"@class ${objcMarshal.typename(ident, r)};") refs.header.add(s"@class ${objcMarshal.typename(ident, r)};")
} }
...@@ -292,7 +291,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -292,7 +291,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
}) })
}) })
writeObjcFile(privateBodyName(objcName), origin, refs.body, w => { writeObjcFile(bodyName(objcName), origin, refs.body, w => {
wrapNamespace(w, spec.objcppNamespace, w => { wrapNamespace(w, spec.objcppNamespace, w => {
w.wl(s"auto $helperClass::toCpp(ObjcType obj) -> CppType") w.wl(s"auto $helperClass::toCpp(ObjcType obj) -> CppType")
w.braced { w.braced {
...@@ -316,7 +315,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -316,7 +315,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
} }
def writeObjcFile(fileName: String, origin: String, refs: Iterable[String], f: IndentWriter => Unit) { def writeObjcFile(fileName: String, origin: String, refs: Iterable[String], f: IndentWriter => Unit) {
createFile(spec.objcPrivateOutFolder.get, fileName, (w: IndentWriter) => { createFile(spec.objcppOutFolder.get, fileName, (w: IndentWriter) => {
w.wl("// AUTOGENERATED FILE - DO NOT MODIFY!") w.wl("// AUTOGENERATED FILE - DO NOT MODIFY!")
w.wl("// This file generated by Djinni from " + origin) w.wl("// This file generated by Djinni from " + origin)
w.wl w.wl
......
...@@ -53,14 +53,15 @@ package object generatorTools { ...@@ -53,14 +53,15 @@ package object generatorTools {
cppExt: String, cppExt: String,
cppHeaderExt: String, cppHeaderExt: String,
objcOutFolder: Option[File], objcOutFolder: Option[File],
objcPrivateOutFolder: Option[File], objcppOutFolder: Option[File],
objcIdentStyle: ObjcIdentStyle, objcIdentStyle: ObjcIdentStyle,
objcFileIdentStyle: IdentConverter, objcFileIdentStyle: IdentConverter,
objcExt: String, objcppExt: String,
objcHeaderExt: String, objcHeaderExt: String,
objcIncludePrefix: String, objcIncludePrefix: String,
objcIncludePrivatePrefix: String, objcppIncludePrefix: String,
objcIncludeCppPrefix: String, objcppIncludeCppPrefix: String,
objcppIncludeObjcPrefix: String,
objcppNamespace: String, objcppNamespace: String,
objcBaseLibIncludePrefix: String) objcBaseLibIncludePrefix: String)
...@@ -166,9 +167,11 @@ package object generatorTools { ...@@ -166,9 +167,11 @@ package object generatorTools {
new JNIGenerator(spec).generate(idl) new JNIGenerator(spec).generate(idl)
} }
if (spec.objcOutFolder.isDefined) { if (spec.objcOutFolder.isDefined) {
createFolder("Objective-C[++]", spec.objcOutFolder.get) createFolder("Objective-C", spec.objcOutFolder.get)
createFolder("Objective-C[++] private", spec.objcPrivateOutFolder.get)
new ObjcGenerator(spec).generate(idl) new ObjcGenerator(spec).generate(idl)
}
if (spec.objcppOutFolder.isDefined) {
createFolder("Objective-C++", spec.objcppOutFolder.get)
new ObjcppGenerator(spec).generate(idl) new ObjcppGenerator(spec).generate(idl)
} }
None None
......
...@@ -65,6 +65,7 @@ $base_dir/../src/run-assume-built \ ...@@ -65,6 +65,7 @@ $base_dir/../src/run-assume-built \
--ident-jni-file NativeFooBar \ --ident-jni-file NativeFooBar \
\ \
--objc-out "$temp_out/objc" \ --objc-out "$temp_out/objc" \
--objcpp-out "$temp_out/objc" \
--objc-type-prefix DB \ --objc-type-prefix DB \
\ \
--idl "$in" --idl "$in"
......
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