From be92e3783751b8bf1481dc81635e86b70977698a Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Sat, 19 Jun 2021 01:50:15 -0500 Subject: [PATCH] Add Java module The Java module will serve as a source for easing Java development within Meson. Currently it only supports generating native header files. --- docs/markdown/Java-module.md | 15 ++++ docs/markdown/snippets/java_module.md | 18 +++++ docs/sitemap.txt | 1 + docs/theme/extra/templates/navbar_links.html | 1 + mesonbuild/compilers/java.py | 9 ++- mesonbuild/modules/java.py | 76 +++++++++++++++++++ run_mypy.py | 1 + .../java/9 jdk/lib/com_mesonbuild_JdkTest.h | 21 ----- test cases/java/9 jdk/lib/meson.build | 12 ++- test cases/java/9 jdk/meson.build | 3 + .../java/9 jdk/src/com/mesonbuild/meson.build | 2 + 11 files changed, 130 insertions(+), 29 deletions(-) create mode 100644 docs/markdown/Java-module.md create mode 100644 docs/markdown/snippets/java_module.md create mode 100644 mesonbuild/modules/java.py delete mode 100644 test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.h create mode 100644 test cases/java/9 jdk/src/com/mesonbuild/meson.build diff --git a/docs/markdown/Java-module.md b/docs/markdown/Java-module.md new file mode 100644 index 000000000..9857de78b --- /dev/null +++ b/docs/markdown/Java-module.md @@ -0,0 +1,15 @@ +# Java Module + +*Added 0.60.0* + +## Functions + +### `generate_native_header()` + +This function will generate a header file for use in Java native module +development by reading the supplied Java file for `native` method declarations. + +Keyword arguments: + +- `package`: The [package](https://en.wikipedia.org/wiki/Java_package) of the +file. If left empty, Meson will assume that there is no package. diff --git a/docs/markdown/snippets/java_module.md b/docs/markdown/snippets/java_module.md new file mode 100644 index 000000000..b806aeed8 --- /dev/null +++ b/docs/markdown/snippets/java_module.md @@ -0,0 +1,18 @@ +## Java Module + +The Java module has been added to Meson. The Java module allows users to +generate native header files without needing to use a `custom_target()`. + +```meson +jmod = import('java') + +native_header = jmod.generate_native_header('File.java', package: 'com.mesonbuild') +native_header_includes = include_directories('.') + +jdkjava = shared_module( + 'jdkjava', + [native_header_includes, other_sources], + dependencies : [jdk], + include_directories : [native_header_includes] +) +``` diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 573aed694..b659a1a8a 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -44,6 +44,7 @@ index.md Gnome-module.md Hotdoc-module.md Icestorm-module.md + Java-module.md Keyval-module.md Pkgconfig-module.md Python-3-module.md diff --git a/docs/theme/extra/templates/navbar_links.html b/docs/theme/extra/templates/navbar_links.html index 904a4996e..71d4bce30 100644 --- a/docs/theme/extra/templates/navbar_links.html +++ b/docs/theme/extra/templates/navbar_links.html @@ -15,6 +15,7 @@ ("Hotdoc-module.html","Hotdoc"), \ ("i18n-module.html","i18n"), \ ("Icestorm-module.html","Icestorm"), \ + ("Java-module.html","Java") \ ("Keyval-module.html","Keyval"), \ ("Pkgconfig-module.html","Pkgconfig"), \ ("Python-3-module.html","Python 3"), \ diff --git a/mesonbuild/compilers/java.py b/mesonbuild/compilers/java.py index ab8245057..38b90ac23 100644 --- a/mesonbuild/compilers/java.py +++ b/mesonbuild/compilers/java.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os import os.path import shutil import subprocess @@ -39,10 +40,10 @@ class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler): def get_werror_args(self) -> T.List[str]: return ['-Werror'] - def get_output_args(self, subdir: str) -> T.List[str]: - if subdir == '': - subdir = './' - return ['-d', subdir, '-s', subdir] + def get_output_args(self, outputname: str) -> T.List[str]: + if outputname == '': + outputname = './' + return ['-d', outputname, '-s', outputname] def get_pic_args(self) -> T.List[str]: return [] diff --git a/mesonbuild/modules/java.py b/mesonbuild/modules/java.py new file mode 100644 index 000000000..c97912ece --- /dev/null +++ b/mesonbuild/modules/java.py @@ -0,0 +1,76 @@ +# Copyright 2021 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import pathlib +import typing as T +from mesonbuild.build import CustomTarget +from mesonbuild.compilers import detect_compiler_for +from mesonbuild.interpreterbase.decorators import FeatureNew, KwargInfo, typed_pos_args, typed_kwargs +from mesonbuild.interpreter.interpreterobjects import FileHolder +from mesonbuild.mesonlib import version_compare, MachineChoice +from . import ExtensionModule, ModuleReturnValue, ModuleState +from ..interpreter import Interpreter + +class JavaModule(ExtensionModule): + @FeatureNew('Java Module', '0.59.0') + def __init__(self, interpreter: Interpreter): + super().__init__(interpreter) + self.methods.update({ + 'generate_native_header': self.generate_native_header, + }) + + if 'java' not in interpreter.environment.coredata.compilers[MachineChoice.BUILD]: + detect_compiler_for(interpreter.environment, 'java', MachineChoice.BUILD) + self.javac = interpreter.environment.coredata.compilers[MachineChoice.BUILD]['java'] + + @typed_pos_args('generate_native_header', (str, FileHolder)) + @typed_kwargs('java.generate_native_header', KwargInfo('package', str, default=None)) + def generate_native_header(self, state: ModuleState, args: T.Tuple[T.Union[str, FileHolder]], + kwargs: T.Dict[str, T.Optional[str]]) -> ModuleReturnValue: + assert state.backend + + package = kwargs.get('package') + + file = self.interpreter.source_strings_to_files( + [a.held_object if isinstance(a, FileHolder) else a for a in args])[0] + + if package: + header = f'{package.replace(".", "_")}_{pathlib.Path(file.fname).stem}.h' + else: + header = f'{pathlib.Path(file.fname).stem}.h' + + ct_kwargs = { + 'input': file, + 'output': header, + 'command': [ + self.javac.exelist[0], + '-d', + '@PRIVATE_DIR@', + '-h', + state.subdir, + '@INPUT@', + ] + } + + target = CustomTarget(os.path.basename(header), state.subdir, state.subproject, backend=state.backend, kwargs=ct_kwargs) + # It is only known that 1.8.0 won't pre-create the directory. 11 and 16 + # do not exhibit this behavior. + if version_compare(self.javac.version, '1.8.0'): + pathlib.Path(state.backend.get_target_private_dir_abs(target)).mkdir(parents=True, exist_ok=True) + + return ModuleReturnValue(target, [target]) + +def initialize(*args: T.Any, **kwargs: T.Any) -> JavaModule: + return JavaModule(*args, **kwargs) diff --git a/run_mypy.py b/run_mypy.py index f8f22a027..fc69063ab 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -37,6 +37,7 @@ modules = [ 'mesonbuild/mintro.py', 'mesonbuild/mlog.py', 'mesonbuild/modules/fs.py', + 'mesonbuild/modules/java.py', 'mesonbuild/modules/unstable_rust.py', 'mesonbuild/modules/qt.py', 'mesonbuild/mparser.py', diff --git a/test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.h b/test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.h deleted file mode 100644 index 40083ac9b..000000000 --- a/test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.h +++ /dev/null @@ -1,21 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_mesonbuild_JdkTest */ - -#ifndef _Included_com_mesonbuild_JdkTest -#define _Included_com_mesonbuild_JdkTest -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_mesonbuild_JdkTest - * Method: jdk_test - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_com_mesonbuild_JdkTest_jdk_1test - (JNIEnv *, jclass); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/test cases/java/9 jdk/lib/meson.build b/test cases/java/9 jdk/lib/meson.build index a94776972..edffc1c6a 100644 --- a/test cases/java/9 jdk/lib/meson.build +++ b/test cases/java/9 jdk/lib/meson.build @@ -1,12 +1,16 @@ -sources = files( - 'native.c', - 'com_mesonbuild_JdkTest.c', -) +sources = [ + files( + 'native.c', + 'com_mesonbuild_JdkTest.c', + ), + native_header +] jdkjava = shared_module( 'jdkjava', sources, dependencies : [jdk], + include_directories : [native_header_includes] ) jdkjava_dep = declare_dependency( diff --git a/test cases/java/9 jdk/meson.build b/test cases/java/9 jdk/meson.build index 310ba5e2a..e5c9728f9 100644 --- a/test cases/java/9 jdk/meson.build +++ b/test cases/java/9 jdk/meson.build @@ -9,10 +9,13 @@ if build_machine.system() == 'windows' and build_machine.cpu_family() == 'x86' endif fs = import('fs') +javamod = import('java') java = find_program('java') jdk = dependency('jdk', version : '>=1.8') +# generate native headers +subdir('src/com/mesonbuild') subdir('lib') subdir('src') diff --git a/test cases/java/9 jdk/src/com/mesonbuild/meson.build b/test cases/java/9 jdk/src/com/mesonbuild/meson.build new file mode 100644 index 000000000..07daf51ef --- /dev/null +++ b/test cases/java/9 jdk/src/com/mesonbuild/meson.build @@ -0,0 +1,2 @@ +native_header = javamod.generate_native_header('JdkTest.java', package: 'com.mesonbuild') +native_header_includes = include_directories('.')