Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial JNI configuration #157

Open
wants to merge 10 commits into
base: java-interop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@

2024-07-12 Vedant Tewari <[email protected]>

2023-02-25 Ron Norman <[email protected]>
* ax_prog_java.m4: Added macro for jni check
* ax_jni_include_dir.m4: Added macro for jni check
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • combine both m4 entries to one entry (comma separate filename, include their "m4/" prefix)
  • make the configure entry more specific, like the 2020-07-19 one
  • add something like NEWS, DEPENDENCIES: updated for JNI

* configure.ac: added support for Java interoperability through JNI

2023-02-25 Ron Norman <[email protected]>

* configure.ac: Add check for sys/time.h

Expand Down
15 changes: 15 additions & 0 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ The following libraries ARE required WHEN :

JSON-C is distributed under Expat License.

5) JNI (Java Native Interface) support is used

BOTH runtime AND development components required.

Java Development Kit (JDK) 8 or later

https://openjdk.org/

The JDK is distributed under various open-source licenses depending
on the vendor and version. Common licenses include the GNU General
Public License (GPL) and the Oracle Binary Code License Agreement.

To enable JNI support, ensure that the JDK is installed on your system,
and set the appropriate environment variables (e.g., JAVA_HOME) to point
to the JDK installation directory.

See HACKING if you wish to hack the GnuCOBOL source or build directly
from version control as this includes the list of additional tools
Expand Down
10 changes: 10 additions & 0 deletions DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,13 @@ Support for GENERATE JSON is provided by *one* of the following:

JSON-C is distributed under Expat License.

JNI Support
------------

Support for JNI (Java Native Interface) is provided by:

* [Java Development Kit (JDK)](https://openjdk.java.net/) 8 or later.

The JDK is distributed under various open-source licenses depending on the vendor and version. Common licenses include the GNU General Public License (GPL) and the Oracle Binary Code License Agreement.

To enable JNI support, ensure that the JDK is installed on your system, and set the appropriate environment variables (e.g., JAVA_HOME) to point to the JDK installation directory.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please word-wrap as for SCREEN SECTION

2 changes: 1 addition & 1 deletion NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ NEWS - user visible changes -*- outline -*-


* New GnuCOBOL features

** Initial support for Java interoperability through JNI (new optional dependency JDK)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please adjust as for "JSON GENERATE" (just check in the same file searching for "json"):

  • what is available now
  • what is needed for support (I guess this will only be a dependency for runtime support, e. g. all checks in cobc work identical without that)
  • add the related configure option / flags
  • word-wrap your new content to col80

** file handling: added backends for ODBC (so far PostgrSQL, MySQL, SQLite,
MSSQL) and OCI, along with new directory COB_SCHEMA_DIR containing the
necessary internal schema files to match the file definition to the
Expand Down
4 changes: 4 additions & 0 deletions cobc/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@

2024-08-14 Nicolas Berthier <[email protected]>

* cobc.c (cobc_print_info): added note for Java interoperability

2024-08-04 David Declerck <[email protected]>

Adjustments to merge 2022-12-21:
Expand Down
6 changes: 6 additions & 0 deletions cobc/cobc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,12 @@ cobc_print_info (void)

cobc_var_print (_("JSON library"), _(WITH_JSON), 0);

#ifdef WITH_JNI
cobc_var_print (_("Java interoperability"), _("enabled"), 0);
#else
cobc_var_print (_("Java interoperability"), _("disabled"), 0);
#endif
nberth marked this conversation as resolved.
Show resolved Hide resolved

#ifdef COB_DEBUG_LOG
cobc_var_print ("DEBUG_LOG", _("enabled"), 0);
#endif
Expand Down
68 changes: 67 additions & 1 deletion cobc/codegen.c
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file and most others in cobc miss a ChangeLog entry

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
Copyright (C) 2003-2024 Free Software Foundation, Inc.
Written by Keisuke Nishida, Roger While, Ron Norman, Simon Sobisch,
Edward Hart
Edward Hart, Vedant Tewari

This file is part of GnuCOBOL.

Expand Down Expand Up @@ -147,6 +147,7 @@ static struct literal_list *literal_cache = NULL;
static struct field_list *field_cache = NULL;
static struct field_list *local_field_cache = NULL;
static struct call_list *call_cache = NULL;
static struct call_list *call_java_cache = NULL;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tab-indent please

static struct call_list *func_call_cache = NULL;
static struct static_call_list *static_call_cache = NULL;
static struct base_list *base_cache = NULL;
Expand Down Expand Up @@ -395,6 +396,22 @@ lookup_source (const char *p)
return source_id++;
}

static void
lookup_java_call(const char *p)
{
struct call_list *clp;

for (clp = call_java_cache; clp; clp = clp->next) {
if (strcmp (p, clp->call_name) == 0) {
return;
}
}
clp = cobc_parse_malloc (sizeof (struct call_list));
clp->call_name = p;
clp->next = call_java_cache;
call_java_cache = clp;
}

static void
lookup_call (const char *p)
{
Expand Down Expand Up @@ -1978,6 +1995,11 @@ output_call_cache (void)
output_local ("static cob_call_union\tcall_%s;\n",
call->call_name);
}
call_java_cache = call_list_reverse (call_java_cache);
for (call = call_java_cache; call; call = call->next) {
output_local ("static cob_java_handle*\tcall_java_%s;\n",
call->call_name);
}
func_call_cache = call_list_reverse (func_call_cache);
for (call = func_call_cache; call; call = call->next) {
output_local ("static cob_call_union\tfunc_%s;\n",
Expand Down Expand Up @@ -7068,6 +7090,45 @@ output_field_constant (cb_tree x, int n, const char *flagname)
output_newline ();
}

static void
output_java_call (struct cb_call *p)
{
if (p->args != NULL || p->call_returning != NULL) {
CB_PENDING ("Java method call with parameters or return values");
COBC_ABORT ();
Comment on lines +7119 to +7120
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please tab-indent and move down to after the variable definitions (C89 compat)

this feature itself is part of a different PR, right?

}
char* full_name = (char *)CB_LITERAL(p->name)->data; /* Assume java.prefix (enforced in `parser.y`, rule `call_body`)*/
char* class_and_method_name = full_name + 5;
char *last_dot;
char *method_name;
const char *class_name;
char* mangled;

mangled = strdup(class_and_method_name);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is allocated but never freed

for (size_t i = 0; i < strlen(mangled) + 1; i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move that size_t definition to the start of the scope (C89 compat)

mangled[i] = (mangled[i] == '.') ? '_' : mangled[i];
}

last_dot = strrchr(class_and_method_name, '.');

*last_dot = '\0';
method_name = last_dot + 1;
class_name = class_and_method_name;

lookup_java_call(mangled);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move this to directly after the mangling loop

output_line("if (call_java_%s == NULL)", mangled);
output_block_open();

output_prefix();
output_line("call_java_%s = ", mangled);
output("cob_resolve_java(\"%s\", \"%s\", \"()V\");", class_name, method_name);
output_newline ();
Comment on lines +7145 to +7147
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should all be a single outline_line -you can then also drop all output_prefix and output_newline in this function

output_prefix ();
output_line("cob_call_java(call_java_%s);\n", mangled);
output_newline();
output_block_close();
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do an exception check afterwards, as done for normal calls; also add the ON EXCEPTION/ NOT ON EXCEPTION codegen; possibly by moving those parts out of output_call() and executing them also in the 'CB_CONV_JAVA` part.


static void
output_call (struct cb_call *p)
{
Expand Down Expand Up @@ -7097,6 +7158,11 @@ output_call (struct cb_call *p)
}
system_call = NULL;

if (p->convention & CB_CONV_JAVA) {
output_java_call(p);
return;
}

#ifdef _WIN32
if (p->convention & CB_CONV_STDCALL) {
convention = "_std";
Expand Down
14 changes: 14 additions & 0 deletions cobc/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -12253,6 +12253,20 @@ call_body:

/* Check parameter conformance, if we can work out what is being called. */
if (CB_LITERAL_P ($3)) {
/* Check for "Java." prefix and set call convention */
char* s = (char *)CB_LITERAL ($3)->data;
if (strncasecmp("Java.", s, 5) == 0) {
call_conv = CB_CONV_JAVA;
}
/* Check for malformed Java method names */
GitMensch marked this conversation as resolved.
Show resolved Hide resolved
char* class_and_method_name = s + 5;
GitMensch marked this conversation as resolved.
Show resolved Hide resolved
if (strchr(class_and_method_name, '.') == NULL) {
cb_error_x ($3, _("malformed Java method name '%s', expected format 'Java.ClassName.methodName'"), s);
}
/* Check for unsupported Java method calls with parameters or return values */
if($7 != NULL || $8 != NULL) {
CB_PENDING("Java method calls with parameters or return values");
}
cb_check_conformance ($3, $7, $8);
} else if (CB_REFERENCE_P ($3)) {
cb_tree ref = cb_ref ($3);
Expand Down
1 change: 1 addition & 0 deletions cobc/tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ enum cb_tag {
#define CB_CONV_THUNK_16 (1 << 5)
#define CB_CONV_STDCALL (1 << 6)
#define CB_CONV_COBOL (1 << 15)
#define CB_CONV_JAVA (1 << 16)
#define CB_CONV_C (0)
#define CB_CONV_PASCAL (CB_CONV_L_TO_R | CB_CONV_CALLEE_STACK)

Expand Down
79 changes: 78 additions & 1 deletion configure.ac
nberth marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ AH_TEMPLATE([WITH_JSON], [JSON handler])
AH_TEMPLATE([WITH_CJSON], [Use cJSON library/source as JSON handler])
AH_TEMPLATE([WITH_JSON_C], [Use JSON-C library as JSON handler])

AH_TEMPLATE([WITH_JNI], [Support for Java calls through JNI])

AH_TEMPLATE([COB_EXPORT_DYN], [Compile/link option for exporting symbols])
AH_TEMPLATE([COB_PIC_FLAGS], [Compile/link option for PIC code])
AH_TEMPLATE([COB_DEBUG_FLAGS], [Compile/link option for debugging])
Expand Down Expand Up @@ -483,7 +485,6 @@ AC_CHECK_HEADERS([sys/types.h signal.h stddef.h], [],
# optional:
AC_CHECK_HEADERS([sys/time.h locale.h fcntl.h dlfcn.h sys/wait.h sys/sysmacros.h])


# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_BIGENDIAN
Expand Down Expand Up @@ -933,7 +934,73 @@ AS_IF([test "$with_xml2" = "yes" -o "$with_xml2" = "check"], [
LIBS="$curr_libs"; CPPFLAGS="$curr_cppflags"
])

# Check for JNI
AC_ARG_WITH([java],
[AS_HELP_STRING([--without-java],
[disable Java Interoperability])])
cob_has_jni=no
AS_IF([test "x$with_java" != "xno"], [
dnl Find `java` and $JAVA_HOME (we need the latter to locate libjvm).
dnl AX_CHECK_JAVA_HOME dnl (<- does not appear to work properly)
AX_PROG_JAVA
if test "x$JAVA_HOME" = x; then
JAVA_HOME="$( $JAVA -XshowSettings:properties -version 2>&1 >/dev/null | \
$SED -e '/^[ ]*java.home/!d' -e 's/.*=[ ]*//' )"
AC_MSG_NOTICE([Found Java home: ${JAVA_HOME}])
else
AC_MSG_NOTICE([Given Java home: ${JAVA_HOME}])
fi

dnl Note: AX_PROG_JAVAC might find a `javac` binary that does
dnl not match the version of `$JAVA` found above, so we set
dnl its path manually.
JAVAC="$JAVA_HOME/bin/javac"
AX_PROG_JAVAC_WORKS
Comment on lines +943 to +958
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure that there are multiple issues with this...

I did sent a mail to the original author of those macros to possibly sort some out...

For now I suggest to replace the first three lines with manual code using AC_CHECK_PROG[JAVA], then set JAVAC (also allow to override that) and finally call ab adjusted AX_PROG_JAVA_WORKS + AX_PROG_JAVAC_WORKS. Those need to be adjusted to not abort (no AC_MSG_ERROR) if they don't work, allowing to, depending on user-request, either a) error in configure.ac or b) warn and not enable jni depending.


AX_JNI_INCLUDE_DIR
AS_IF([test "$JNI_INCLUDE_DIRS" != ""], [
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
JNI_CPPFLAGS="$JNI_CPPFLAGS -I$JNI_INCLUDE_DIR"
done
Comment on lines +960 to +964
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only do this if JNI_CFLAGS are not set externally (and rename to JNI_CFLAGS, not because it is right but because all other [mostly pkgconfig] definitions use that)
after this part check for jni.h and skip/abort if it isn't found

for _dir in "${JAVA_HOME}/jre/lib" "${JAVA_HOME}/lib"; do
if test -d "$_dir"; then
JNI_LIBS="$JNI_LIBS -L$_dir"
fi
Comment on lines +966 to +968
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this is not true then the entries below can't either

if test -d "$_dir/server"; then
JNI_LIBS="$JNI_LIBS -L$_dir/server"
fi
if test -d "$_dir/client"; then
JNI_LIBS="$JNI_LIBS -L$_dir/client"
fi
done
Comment on lines +965 to +975
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this part should be separate and only set JNI_LIBS if they aren't set already

curr_LIBS="$LIBS"
curr_CPPFLAGS="$CPPFLAGS"
LIBS="$LIBS $JNI_LIBS -ljvm"
CPPFLAGS="$CPPFLAGS $JNI_CPPFLAGS"
AC_MSG_CHECKING([if -ljvm brings JNI symbols])
AC_LINK_IFELSE([
AC_LANG_SOURCE([[
#include <jni.h>
void main (void) {
(void) JNI_CreateJavaVM (NULL, NULL, NULL);
}
]])
], [
AC_MSG_RESULT([yes])
AC_DEFINE([WITH_JNI], [1])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this define should be outside (in the "else" part of the code below, when all checks worked)

JNI_LDFLAGS="$JNI_LIBS"
JNI_LIBS="-ljvm"
cob_has_jni=yes
], [
AC_MSG_RESULT([no])
])
LIBS="$curr_LIBS"
CPPFLAGS="$curr_CPPFLAGS"
Comment on lines +976 to +998
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this part should be outside and only run if all of the above works (java, javac, jni.h)

])
])
AS_IF([test "x$with_java" = "xyes" -a "x$cob_has_jni" != "xyes"], [
AC_MSG_ERROR([Java interoperability requested, but JNI was not found])
])

# Checks for cjson/json-c.
AC_MSG_NOTICE([Checks for JSON handler])
Expand Down Expand Up @@ -2570,6 +2637,8 @@ AM_CONDITIONAL([COB_MAKE_LMDB_LIB], [test "$cob_gen_lmdb" = "yes"])

AM_CONDITIONAL([LOCAL_CJSON],[test "$USE_JSON" = "local"])

AM_CONDITIONAL([COB_HAS_JNI], [test "$cob_has_jni" = "yes"])

unset COB_USES_GCC
unset COB_USES_GCC_NO_ICC
unset COB_USES_ICC_ONLY
Expand Down Expand Up @@ -2660,6 +2729,11 @@ AC_SUBST([OCI_CFLAGS])
AC_SUBST([BDB_CFLAGS])
AC_SUBST([LMDB_CFLAGS])

AC_SUBST([JAVAC])
AC_SUBST([JNI_LIBS])
AC_SUBST([JNI_LDFLAGS])
AC_SUBST([JNI_CPPFLAGS])
Comment on lines +2732 to +2735
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those should not be directly set to AC_SUBST but use AC_ARG_VAR instead (see BDB_LIBS for an example);
drop JNI_LDFLAGS here and above, use JNI_LIBS (and renamed JNI_CFLAGS in the Makefile)


dnl was used in bin/Makefile.am - seems not to be needed
dnl AC_SUBST([COB_EXPORT_DYN])

Expand All @@ -2683,6 +2757,7 @@ AC_SUBST([COB_HAS_OCEXTFH])
AC_SUBST([COB_HAS_CURSES])
AC_SUBST([COB_HAS_XML2])
AC_SUBST([COB_HAS_JSON])
AC_SUBST([COB_HAS_JNI])
AC_SUBST([COB_HAS_64_BIT_POINTER])
AC_SUBST([COB_PATCH_LEVEL], [$with_patch_level]) # needed for bin/cob-config

Expand Down Expand Up @@ -2804,4 +2879,6 @@ case "$USE_JSON" in
;;
esac

AC_MSG_NOTICE([ Build with Java interoperability: ${cob_has_jni}])

unset DEFINE_DL
Loading
Loading