aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Machine-files.md1
-rw-r--r--docs/markdown/snippets/jdk-system-dependency.md16
-rw-r--r--mesonbuild/dependencies/__init__.py5
-rw-r--r--mesonbuild/dependencies/dev.py56
-rw-r--r--mesonbuild/envconfig.py12
-rw-r--r--mesonbuild/environment.py5
-rw-r--r--test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.c9
-rw-r--r--test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.h21
-rw-r--r--test cases/java/9 jdk/lib/meson.build14
-rw-r--r--test cases/java/9 jdk/lib/native.c11
-rw-r--r--test cases/java/9 jdk/meson.build18
-rw-r--r--test cases/java/9 jdk/src/com/mesonbuild/JdkTest.java15
-rw-r--r--test cases/java/9 jdk/src/meson.build17
13 files changed, 193 insertions, 7 deletions
diff --git a/docs/markdown/Machine-files.md b/docs/markdown/Machine-files.md
index 39e02a6..6c0b051 100644
--- a/docs/markdown/Machine-files.md
+++ b/docs/markdown/Machine-files.md
@@ -236,6 +236,7 @@ section.
`exe_wrapper` specified in `[binaries]` to run generated executables in CMake
subprojects. This setting has no effect if the `exe_wrapper` was not specified.
The default value is `true`. (*new in 0.56.0*)
+- `java_home` is an absolute path pointing to the root of a Java installation.
### CMake variables
diff --git a/docs/markdown/snippets/jdk-system-dependency.md b/docs/markdown/snippets/jdk-system-dependency.md
new file mode 100644
index 0000000..bccd16e
--- /dev/null
+++ b/docs/markdown/snippets/jdk-system-dependency.md
@@ -0,0 +1,16 @@
+## JDK System Dependency
+
+When building projects such as those interacting with the JNI, you need access
+to a few header files located in a Java installation. This system dependency
+will add the correct include paths to your target. It assumes that either
+`JAVA_HOME` will be set to a valid Java installation, or the default `javac` on
+your system is a located in the `bin` directory of a Java installation. Note:
+symlinks are resolved.
+
+```meson
+jdk = dependency('jdk', version : '>=1.8')
+```
+
+Currently this system dependency only works on `linux`, `win32`, and `darwin`.
+This can easily be extended given the correct information about your compiler
+and platform in an issue.
diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py
index afd4adc..722ede4 100644
--- a/mesonbuild/dependencies/__init__.py
+++ b/mesonbuild/dependencies/__init__.py
@@ -21,7 +21,9 @@ from .base import ( # noqa: F401
InternalDependency, PkgConfigDependency, CMakeDependency,
find_external_dependency, get_dep_identifier, packages,
_packages_accept_language, DependencyFactory)
-from .dev import ValgrindDependency, gmock_factory, gtest_factory, llvm_factory, zlib_factory
+from .dev import (
+ ValgrindDependency, JDKSystemDependency, gmock_factory, gtest_factory,
+ llvm_factory, zlib_factory)
from .coarrays import coarray_factory
from .mpi import mpi_factory
from .scalapack import scalapack_factory
@@ -196,6 +198,7 @@ packages.update({
'llvm': llvm_factory,
'valgrind': ValgrindDependency,
'zlib': zlib_factory,
+ 'jdk': JDKSystemDependency,
'boost': BoostDependency,
'cuda': CudaDependency,
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
index 2ac91b1..e9181bd 100644
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -18,6 +18,8 @@
import glob
import os
import re
+import pathlib
+import shutil
import typing as T
from .. import mesonlib, mlog
@@ -32,6 +34,7 @@ from ..compilers.c import AppleClangCCompiler
from ..compilers.cpp import AppleClangCPPCompiler
if T.TYPE_CHECKING:
+ from ..envconfig import MachineInfo
from .. environment import Environment
@@ -505,6 +508,59 @@ class ZlibSystemDependency(ExternalDependency):
return [DependencyMethods.SYSTEM]
+class JDKSystemDependency(ExternalDependency):
+ def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
+ super().__init__('jdk', environment, kwargs)
+
+ m = self.env.machines[self.for_machine]
+
+ if 'java' not in environment.coredata.compilers[self.for_machine]:
+ environment.detect_compiler_for('java', self.for_machine)
+ self.javac = environment.coredata.compilers[self.for_machine]['java']
+ self.version = self.javac.version
+
+ if 'version' in kwargs and not version_compare(self.version, kwargs['version']):
+ mlog.error(f'Incorrect JDK version found ({self.version}), wanted {kwargs["version"]}')
+ self.is_found = False
+ return
+
+ self.java_home = environment.properties[self.for_machine].get_java_home()
+ if not self.java_home:
+ self.java_home = pathlib.Path(shutil.which(self.javac.exelist[0])).resolve().parents[1]
+
+ platform_include_dir = self.__machine_info_to_platform_include_dir(m)
+ if platform_include_dir is None:
+ mlog.error("Could not find a JDK platform include directory for your OS, please open an issue or provide a pull request.")
+ self.is_found = False
+ return
+
+ java_home_include = self.java_home / 'include'
+ self.compile_args.append(f'-I{java_home_include}')
+ self.compile_args.append(f'-I{java_home_include / platform_include_dir}')
+ self.is_found = True
+
+ @staticmethod
+ def get_methods() -> T.List[DependencyMethods]:
+ return [DependencyMethods.SYSTEM]
+
+ @staticmethod
+ def __machine_info_to_platform_include_dir(m: 'MachineInfo') -> T.Optional[str]:
+ """Translates the machine information to the platform-dependent include directory
+
+ When inspecting a JDK release tarball or $JAVA_HOME, inside the `include/` directory is a
+ platform dependent folder that must be on the target's include path in addition to the
+ parent `include/` directory.
+ """
+ if m.is_linux():
+ return 'linux'
+ elif m.is_windows():
+ return 'win32'
+ elif m.is_darwin():
+ return 'darwin'
+
+ return None
+
+
llvm_factory = DependencyFactory(
'LLVM',
[DependencyMethods.CMAKE, DependencyMethods.CONFIG_TOOL],
diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py
index f2792c5..c6a4df3 100644
--- a/mesonbuild/envconfig.py
+++ b/mesonbuild/envconfig.py
@@ -136,9 +136,9 @@ class CMakeSkipCompilerTest(Enum):
class Properties:
def __init__(
self,
- properties: T.Optional[T.Dict[str, T.Union[str, bool, int, T.List[str]]]] = None,
+ properties: T.Optional[T.Dict[str, T.Optional[T.Union[str, bool, int, T.List[str]]]]] = None,
):
- self.properties = properties or {} # type: T.Dict[str, T.Union[str, bool, int, T.List[str]]]
+ self.properties = properties or {} # type: T.Dict[str, T.Optional[T.Union[str, bool, int, T.List[str]]]]
def has_stdlib(self, language: str) -> bool:
return language + '_stdlib' in self.properties
@@ -210,13 +210,17 @@ class Properties:
assert isinstance(res, bool)
return res
+ def get_java_home(self) -> T.Optional[Path]:
+ value = T.cast(T.Optional[str], self.properties.get('java_home'))
+ return Path(value) if value else None
+
def __eq__(self, other: object) -> bool:
if isinstance(other, type(self)):
return self.properties == other.properties
return NotImplemented
# TODO consider removing so Properties is less freeform
- def __getitem__(self, key: str) -> T.Union[str, bool, int, T.List[str]]:
+ def __getitem__(self, key: str) -> T.Optional[T.Union[str, bool, int, T.List[str]]]:
return self.properties[key]
# TODO consider removing so Properties is less freeform
@@ -224,7 +228,7 @@ class Properties:
return item in self.properties
# TODO consider removing, for same reasons as above
- def get(self, key: str, default: T.Union[str, bool, int, T.List[str]] = None) -> T.Union[str, bool, int, T.List[str]]:
+ def get(self, key: str, default: T.Optional[T.Union[str, bool, int, T.List[str]]] = None) -> T.Optional[T.Union[str, bool, int, T.List[str]]]:
return self.properties.get(key, default)
class MachineInfo:
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 54f608d..fc9b703 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -881,12 +881,13 @@ class Environment:
self.binaries[for_machine].binaries.setdefault(name, mesonlib.split_args(p_env))
def _set_default_properties_from_env(self) -> None:
- """Properties which can alkso be set from the environment."""
+ """Properties which can also be set from the environment."""
# name, evar, split
opts: T.List[T.Tuple[str, T.List[str], bool]] = [
('boost_includedir', ['BOOST_INCLUDEDIR'], False),
('boost_librarydir', ['BOOST_LIBRARYDIR'], False),
('boost_root', ['BOOST_ROOT', 'BOOSTROOT'], True),
+ ('java_home', ['JAVA_HOME'], False),
]
for (name, evars, split), for_machine in itertools.product(opts, MachineChoice):
@@ -944,7 +945,7 @@ class Environment:
def is_library(self, fname):
return is_library(fname)
- def lookup_binary_entry(self, for_machine: MachineChoice, name: str) -> T.List[str]:
+ def lookup_binary_entry(self, for_machine: MachineChoice, name: str) -> T.Optional[T.List[str]]:
return self.binaries[for_machine].lookup_entry(name)
@staticmethod
diff --git a/test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.c b/test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.c
new file mode 100644
index 0000000..075e37b
--- /dev/null
+++ b/test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.c
@@ -0,0 +1,9 @@
+#include <jni.h>
+
+#include "com_mesonbuild_JdkTest.h"
+
+JNIEXPORT jint JNICALL Java_com_mesonbuild_JdkTest_jdk_1test
+ (JNIEnv *env, jclass clazz)
+{
+ return (jint)0xdeadbeef;
+}
diff --git a/test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.h b/test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.h
new file mode 100644
index 0000000..40083ac
--- /dev/null
+++ b/test cases/java/9 jdk/lib/com_mesonbuild_JdkTest.h
@@ -0,0 +1,21 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* 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
new file mode 100644
index 0000000..a947769
--- /dev/null
+++ b/test cases/java/9 jdk/lib/meson.build
@@ -0,0 +1,14 @@
+sources = files(
+ 'native.c',
+ 'com_mesonbuild_JdkTest.c',
+)
+
+jdkjava = shared_module(
+ 'jdkjava',
+ sources,
+ dependencies : [jdk],
+)
+
+jdkjava_dep = declare_dependency(
+ link_with : jdkjava,
+)
diff --git a/test cases/java/9 jdk/lib/native.c b/test cases/java/9 jdk/lib/native.c
new file mode 100644
index 0000000..0b5e718
--- /dev/null
+++ b/test cases/java/9 jdk/lib/native.c
@@ -0,0 +1,11 @@
+#include <jni.h>
+
+JNIEXPORT jint JNICALL
+JNI_OnLoad(JavaVM *vm, void *reserved)
+{
+ return JNI_VERSION_1_8;
+}
+
+JNIEXPORT void JNICALL
+JNI_OnUnload(JavaVM *vm, void *reserved)
+{}
diff --git a/test cases/java/9 jdk/meson.build b/test cases/java/9 jdk/meson.build
new file mode 100644
index 0000000..310ba5e
--- /dev/null
+++ b/test cases/java/9 jdk/meson.build
@@ -0,0 +1,18 @@
+project('jdkjava', ['c', 'java'])
+
+if build_machine.system() == 'cygwin'
+ error('MESON_SKIP_TEST: cygwin test failures')
+endif
+
+if build_machine.system() == 'windows' and build_machine.cpu_family() == 'x86'
+ error('MESON_SKIP_TEST: failing builds on 32bit Windows because a 32bit JDK isn not available in the Azure Pipelines Windows images')
+endif
+
+fs = import('fs')
+
+java = find_program('java')
+
+jdk = dependency('jdk', version : '>=1.8')
+
+subdir('lib')
+subdir('src')
diff --git a/test cases/java/9 jdk/src/com/mesonbuild/JdkTest.java b/test cases/java/9 jdk/src/com/mesonbuild/JdkTest.java
new file mode 100644
index 0000000..35c47ce
--- /dev/null
+++ b/test cases/java/9 jdk/src/com/mesonbuild/JdkTest.java
@@ -0,0 +1,15 @@
+package com.mesonbuild;
+
+public final class JdkTest {
+ private static native int jdk_test();
+
+ public static void main(String[] args) {
+ if (jdk_test() != 0xdeadbeef) {
+ throw new RuntimeException("jdk_test() did not return 0");
+ }
+ }
+
+ static {
+ System.loadLibrary("jdkjava");
+ }
+}
diff --git a/test cases/java/9 jdk/src/meson.build b/test cases/java/9 jdk/src/meson.build
new file mode 100644
index 0000000..d1b9ee3
--- /dev/null
+++ b/test cases/java/9 jdk/src/meson.build
@@ -0,0 +1,17 @@
+jdkjar = jar(
+ 'jdkjar',
+ 'com' / 'mesonbuild' / 'JdkTest.java',
+ main_class : 'com.mesonbuild.JdkTest',
+)
+
+test(
+ 'jdktest',
+ java,
+ args: [
+ '-Djava.library.path=@0@'.format(fs.parent(jdkjava.full_path())),
+ '-jar',
+ jdkjar,
+ ],
+ protocol : 'exitcode',
+ depends : [jdkjava],
+)