Return-Path: Delivered-To: apmail-ant-dev-archive@www.apache.org Received: (qmail 86541 invoked from network); 27 Apr 2010 16:04:53 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 27 Apr 2010 16:04:53 -0000 Received: (qmail 53073 invoked by uid 500); 27 Apr 2010 16:04:52 -0000 Delivered-To: apmail-ant-dev-archive@ant.apache.org Received: (qmail 53010 invoked by uid 500); 27 Apr 2010 16:04:51 -0000 Mailing-List: contact dev-help@ant.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Help: List-Post: List-Id: "Ant Developers List" Reply-To: "Ant Developers List" Delivered-To: mailing list dev@ant.apache.org Received: (qmail 53002 invoked by uid 99); 27 Apr 2010 16:04:51 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 27 Apr 2010 16:04:51 +0000 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests=FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_PASS,UNPARSEABLE_RELAY X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: local policy) Received: from [76.13.13.43] (HELO smtp104.prem.mail.ac4.yahoo.com) (76.13.13.43) by apache.org (qpsmtpd/0.29) with SMTP; Tue, 27 Apr 2010 16:04:45 +0000 Received: (qmail 47318 invoked from network); 27 Apr 2010 16:04:24 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.com; h=Message-ID:Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:Reply-To:From:To:Subject:Date:X-Mailer:Thread-Index:X-MimeOLE; b=avNLbGyq0n7iEU+lVCqijBKI0257p0SVrgcQsMpVFYTg3feWPAfIbZdrkIhnJEcEx1jDCM482/xQsFItH3PzDWw2WumrLwd1cF//HAYbwycRimINDS2lIz074XJ1q1jXHY4tqRBZALA8f4QhPxLb1Vvp4x1elRdGIpwks/cxWEo= ; Message-ID: <317148.47287.qm@smtp104.prem.mail.ac4.yahoo.com> Received: from cpe-74-78-136-109.twcny.res.rr.com (voytechs@74.78.136.109 with login) by smtp104.prem.mail.ac4.yahoo.com with SMTP; 27 Apr 2010 09:04:23 -0700 PDT X-Yahoo-SMTP: 9Rci58eswBB1W9vCSzR.IcgIbZ5l X-YMail-OSG: CcfU1asVM1kvKl305jm2Kv4aXZrxCWu4lTAYDo5lM2kVjt2mnavyxuR.iiZw.7cY_P5Uy8hU.XNcW09rvZKuCOoShTiL3DBLPpVk9uora30NN2M2_FGNwHQVZyosdoaA1BGVFhhUCv95AOFLCCrYmdu0lVcqAkZHGbQY47ZpVMVGv6MUmhw.2lHrYx1TpvBHdNYI8CfCllLk.mWYgQtX0Rtmi3H6l3buSHnQlY9TsusDXT9ff8lkMJZFgEHddXyx6qBJ9bz9Oo3Hpnu7Bk1L83aNxQ-- X-Yahoo-Newman-Property: ymail-3 Reply-To: From: "Mark Bednarczyk" To: Subject: Writing new task: javani Date: Tue, 27 Apr 2010 12:04:23 -0400 X-Mailer: Microsoft Office Outlook, Build 11.0.5510 Thread-Index: AcrmI011cBVmjj4rSrKdT3NFtvxYzg== X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.5579 I'm writing a new task "javani" and want to see if there was any duplicate effort with what I'm proposing. Summary: The task named 'javani' is a java preprocessor for generating wrapper functions in C. Its input is a compiled java classfile, and its output either a C or header file to be compiled, or both. The task expands on what existing 'javah' task performs by generating C wrapper functions which automate some common tasks usually performed manually using JNI C programming interface. The task can generate source C code (both C and header files), which needs to be further compiled by a C compiler. The task can be instructed to generate 2 types of output: 1) A header file, which provides C declarations for functions and JNI to java mappings 2) A C source file containing wrapper functions which can be used to call on any java method from C. The code generator takes care of maintaining/caching JNI method and field IDs. Typically stub and wrapper C functions do not mix and are thus output to different C files. Stub files only need to be generated once, while wrapper functions can be regenerated every time ant build compiles the code. Easily create wrapper functions for any java class (including standard JRE classes). This saves the time of trying to manually lookup and cache JNI field and method IDs. You call on C functions only supplying the JNIEnv and jobject or jclass parameters and any other parameters declared in the java method signature. Here is an example java class: package org.jnetsoft.jni.stub; public class MyClass { public void method1() { } public int method2(char c, byte b, short s, int i, long l, String str) {return 0;} private int field1; } And wrapper functions generated: -------------------------------------------------------------------------- #include #include "org_jnetsoft_jni_stub_MyClass.h" org_jnetsoft_jni_stub_MyClass_class_t org_jnetsoft_jni_stub_MyClass_class; /* * Class: org.jnetsoft.jni.stub.MyClass * Method: onClassLoad * Signature: ()V */ JNIEXPORT void JNICALL Java_org_jnetsoft_jni_stub_MyClass_onClassLoad (JNIEnv *env, jclass clazz) { org_jnetsoft_jni_stub_MyClass_class_t *c = &org_jnetsoft_jni_stub_MyClass_class; memset(c, sizeof(org_jnetsoft_jni_stub_MyClass_class_t), 0); c->clazz = (*env)->NewGlobalRef(env, clazz); c->method1 = (*env)->GetMethodID(env, clazz, "method1", "()V"); c->method2 = (*env)->GetMethodID(env, clazz, "method2", "(CBSIJLjava/lang/String;)I"); c->field1 = (*env)->GetFieldID(env, clazz, "field1", "I"); } /* * Class: org.jnetsoft.jni.stub.MyClass * Method: onClassUnload * Signature: ()V */ JNIEXPORT void JNICALL Java_org_jnetsoft_jni_stub_MyClass_onClassUnload (JNIEnv *env, jclass clazz) { org_jnetsoft_jni_stub_MyClass_class_t *c = &org_jnetsoft_jni_stub_MyClass_class; (*env)->DeleteGlobalRef(env, c->clazz); } /* * Class: org.jnetsoft.jni.stub.MyClass * Method: method1 * Types: () * Signature: ()V */ void org_jnetsoft_jni_stub_MyClass_method1 (JNIEnv *env, jobject obj) { (*env)->CallVoidMethod(env, obj, org_jnetsoft_jni_stub_MyClass_class.method1); } /* * Class: org.jnetsoft.jni.stub.MyClass * Method: method2 * Types: (char, byte, short, int, long, String, ) * Signature: (CBSIJLjava/lang/String;)I */ jint org_jnetsoft_jni_stub_MyClass_method2 (JNIEnv *env, jobject obj, jchar arg1, jbyte arg2, jshort arg3, jint arg4, jlong arg6, jobject arg7) { return (*env)->CallIntMethod(env, obj, org_jnetsoft_jni_stub_MyClass_class.method2, arg1, arg2, arg3, arg4, arg6, arg7); } [truncated...] -------------------------------------------------------------------------- And so forth. The code generator is working already (as seen above), I started putting it into an ANT task and figured this would be a good time to check the community. The generator has no external dependencies and is pure java. The current code generator can also generate C "stub" functions for all declared 'native' methods in java class, but that functionality would be ommitted from the task. The long 'namespace' prefix for every function can be overwritten with any user specified one. For example in the above sample, the namespace prefix used 'org_jnetsoft_jni_stub' could be replaced by 'javani' task to user supplied one such as 'stub' thus greatly shortening the function and ID names making them more convenient to utilize in user's code. Here is a typical scenario I would envision for usage with this task. A programmer would choose which java calls need to be made on java classes from native C or C++ code. He would add a list of those classes to his ANT build script, through a refid or some other list of classes (typically an external .properties file). The build process would proceed in roughly the following order: 1) compile user java code to classfiles 2) invoke javah to generate stub header files for all native java functions (as normally done) 3) invoke javani to generate wrapper functions and header files for all classes and java methods which are expected to be invoked from user's native code. User would declare those classes in a list. 4) compile with a C compiler all the newly generated wrapper functions and output to a build area. 5) compile normal user native (C/C++) code. The code at this stage can reference and rely on any wrapper functions and generated header files. I use this process in practice with my projects and it works rather well. Steps #3 and #4 can easily be incorporated into any build process and greatly simplify java method calls from native user space. Also note that the wrapper functions can be omitted completely (with an option to 'javani' task), and the user can rely on entirely on the cached JNI method and field IDs and invoke JNI API directly using those IDs. The IDs are exported globally (declared in header files). Once initialized, the wrapper functions are simply a convenience. The method and field IDs can be utilized directly by the user if preferred over additional overhead of wrapper functions. There are some limitations. Unlike 'javah' task, my code does not parse the binary classfile looking for constants. The task uses java reflection to inspect classes, methods and fields. Therefore any constants (static final fields) are typically optimized away by the compiler. These constants however do exist in the 'javah' generated stub header files, which can be incorporated into a build process. The 2 tasks are complimentatory to each other. This is one area, where possibly classfile parser used by 'javah' could be reused, but I haven't looked into this possibility yet. Cheers, mark... "A government big enough to give you everything you want, is strong enough to take everything you have." - Thomas Jefferson --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org For additional commands, e-mail: dev-help@ant.apache.org