Repository: mesonbuild/meson

Issue:
JNI dependency configures incorrect include paths on macOS
**Describe the bug**
On macOS, the `jni` dependency thinks JNI headers are in `/usr/lib/jvm/jre`, which they aren't.

**To Reproduce**

```
project(
  'Test',
  'c',
  meson_version : '>=0.62',
)

jni = dependency('jni')
meson.get_compiler('c').has_header(
  'jni.h',
  dependencies : [jni],
  required : true,
)
```

```console
$ meson builddir
The Meson build system
Version: 0.63.3
Source dir: /Users/bgilbert/report
Build dir: /Users/bgilbert/report/builddir
Build type: native build
Project name: Test
Project version: undefined
C compiler for the host machine: cc (clang 12.0.0 "Apple clang version 12.0.0 (clang-1200.0.32.29)")
C linker for the host machine: cc ld64 609.8
Host machine cpu family: x86_64
Host machine cpu: x86_64
Run-time dependency jni found: YES 19.0.1

meson.build:8:24: ERROR: C header 'jni.h' not found

A full log can be found at /Users/bgilbert/report/builddir/meson-logs/meson-log.txt
$ tail -n 25 /Users/bgilbert/report/builddir/meson-logs/meson-log.txt
Run-time dependency jni found: YES 19.0.1
Running compile:
Working directory:  /Users/bgilbert/report/builddir/meson-private/tmpvzlhht5g
Command line:  cc -I/usr/lib/jvm/jre/include -I/usr/lib/jvm/jre/include/darwin /Users/bgilbert/report/builddir/meson-private/tmpvzlhht5g/testfile.c -E -P -P -O0 -Werror=implicit-function-declaration 

Code:
 
        #ifdef __has_include
         #if !__has_include("jni.h")
          #error "Header 'jni.h' could not be found"
         #endif
        #else
         #include <jni.h>
        #endif
Compiler stdout:
 

Compiler stderr:
 /Users/bgilbert/report/builddir/meson-private/tmpvzlhht5g/testfile.c:4:12: error: "Header 'jni.h' could not be found"
          #error "Header 'jni.h' could not be found"
           ^
1 error generated.


meson.build:8:24: ERROR: C header 'jni.h' not found
```

**Expected behavior**
Meson should use the `java_home(1)` command to locate the Java directory:

```console
$ /usr/libexec/java_home 
/Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home
$ JAVA_HOME=$(/usr/libexec/java_home) meson builddir
The Meson build system
Version: 0.63.3
Source dir: /Users/bgilbert/report
Build dir: /Users/bgilbert/report/builddir
Build type: native build
Project name: Test
Project version: undefined
C compiler for the host machine: cc (clang 12.0.0 "Apple clang version 12.0.0 (clang-1200.0.32.29)")
C linker for the host machine: cc ld64 609.8
Host machine cpu family: x86_64
Host machine cpu: x86_64
Run-time dependency jni found: YES 19.0.1
Has header "jni.h" with dependency jni: YES 
Build targets in project: 0

Found ninja-1.11.1 at /opt/local/bin/ninja
```

**system parameters**
* Is this a [cross build](https://mesonbuild.com/Cross-compilation.html) or just a plain native build (for the same computer)? 

native

* what operating system (e.g. MacOS Catalina, Windows 10, CentOS 8.0, Ubuntu 18.04, etc.)

macOS 10.15.7

* what Python version are you using e.g. 3.8.0

3.10.8

* what `meson --version`

0.63.3

* what `ninja --version` if it's a Ninja build

1.11.1


Discussion:
> Provides access to compiling with the Java Native Interface (JNI). The lookup will first check if `JAVA_HOME` is set in the environment, and if not will use the resolved path of `javac`. Systems will usually link your preferred JDK to well known paths like `/usr/bin/javac` on Linux for instance. Using the path from `JAVA_HOME` or the resolved `javac`, this dependency will place the JDK installation's `include` directory and its platform-dependent subdirectory on the compiler's include path.

This is documented behavior as it works today.

What is `java_home(1)`? I don't have one. Perhaps we can use /usr/lib/jvm followed by the output of `eselect java-vm` or `archlinux-java` in list mode, instead? /s
Admittedly it seems broken that the dependency was successfully found without being usable. Do you have a javac in your path? What does it do?
> What is `java_home(1)`? I don't have one.

It seems to be the standard Internet recommendation for computing `JAVA_HOME` on macOS.  [Here's](https://www.manpagez.com/man/1/java_home/) an old copy of the man page.

> Do you have a javac in your path? What does it do?

```console
$ ls -l /usr/bin/javac
lrwxr-xr-x  1 root  wheel  75 Jul 25  2021 /usr/bin/javac -> /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/javac
```

It's a regular executable, not a wrapper script, and acts like `javac`.  I'm not sure if there's some sort of alternatives mechanism under the covers, though.

Because of the way macOS lays out its filesystem, I don't think it's safe to assume that the include path can be derived from `javac`'s path.  There's no `/usr/include` or `/usr/lib/jvm` on my system.
Hi, I am the one that added support for this dependency. How did you install Java on your machine? What version of Java did you install? All OpenJDK artifacts are consistent with how they layout where the includes are relative to the binaries. Can you also provide the output of `tree $(/usr/libexec/java_home)`? If we are quick to fix it, this could probably go into 1.0.0. It is interesting that `java_home` doesn't exist on my Fedora machine. Where does it come from? Can you also provide the output of `/usr/libexec/java_home`?

Is `/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/javac` also a symlink?

Here is the code which performs the detection: https://github.com/mesonbuild/meson/blob/dd25b88f009ee47579b33dfbd167a9434cc8f2be/mesonbuild/dependencies/dev.py#L520

According to the following command line:

```
Command line:  cc -I/usr/lib/jvm/jre/include -I/usr/lib/jvm/jre/include/darwin /Users/bgilbert/report/builddir/meson-private/tmpvzlhht5g/testfile.c -E -P -P -O0 -Werror=implicit-function-declaration 
```

you do have a `/usr/lib/jvm/jre/bin/javac` on your system. No assumptions are being made.

```python
self.java_home = pathlib.Path(shutil.which(self.javac.exelist[0])).resolve().parents[1]
```

Resolves `/usr/bin/javac` and then grabs the parent directory.
> Hi, I am the one that added support for this dependency. How did you install Java on your machine? What version of Java did you install?

`/usr/libexec/java_home --request` displays a dialog box that links to [this JDK download page](https://www.oracle.com/java/technologies/downloads/#jdk19-mac).  I downloaded and ran the x64 DMG Installer.  `javac --version` reports 19.0.1.

> Can you also provide the output of `tree $(/usr/libexec/java_home)`?

<details>
<summary>Output</summary>

```
/Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home
|-- LICENSE -> legal/java.base/LICENSE
|-- README
|-- bin
|   |-- jar
|   |-- jarsigner
|   |-- java
|   |-- javac
|   |-- javadoc
|   |-- javap
|   |-- jcmd
|   |-- jconsole
|   |-- jdb
|   |-- jdeprscan
|   |-- jdeps
|   |-- jfr
|   |-- jhsdb
|   |-- jimage
|   |-- jinfo
|   |-- jlink
|   |-- jmap
|   |-- jmod
|   |-- jpackage
|   |-- jps
|   |-- jrunscript
|   |-- jshell
|   |-- jstack
|   |-- jstat
|   |-- jstatd
|   |-- jwebserver
|   |-- keytool
|   |-- rmiregistry
|   `-- serialver
|-- conf
|   |-- logging.properties
|   |-- management
|   |   |-- jmxremote.access
|   |   |-- jmxremote.password.template
|   |   `-- management.properties
|   |-- net.properties
|   |-- security
|   |   |-- java.policy
|   |   |-- java.security
|   |   `-- policy
|   |       |-- README.txt
|   |       |-- limited
|   |       |   |-- default_US_export.policy
|   |       |   |-- default_local.policy
|   |       |   `-- exempt_local.policy
|   |       `-- unlimited
|   |           |-- default_US_export.policy
|   |           `-- default_local.policy
|   `-- sound.properties
|-- include
|   |-- classfile_constants.h
|   |-- darwin
|   |   |-- jawt_md.h
|   |   `-- jni_md.h
|   |-- jawt.h
|   |-- jdwpTransport.h
|   |-- jni.h
|   |-- jvmti.h
|   |-- jvmticmlr.h
|   `-- sizecalc.h
|-- jmods
|   |-- java.base.jmod
|   |-- java.compiler.jmod
|   |-- java.datatransfer.jmod
|   |-- java.desktop.jmod
|   |-- java.instrument.jmod
|   |-- java.logging.jmod
|   |-- java.management.jmod
|   |-- java.management.rmi.jmod
|   |-- java.naming.jmod
|   |-- java.net.http.jmod
|   |-- java.prefs.jmod
|   |-- java.rmi.jmod
|   |-- java.scripting.jmod
|   |-- java.se.jmod
|   |-- java.security.jgss.jmod
|   |-- java.security.sasl.jmod
|   |-- java.smartcardio.jmod
|   |-- java.sql.jmod
|   |-- java.sql.rowset.jmod
|   |-- java.transaction.xa.jmod
|   |-- java.xml.crypto.jmod
|   |-- java.xml.jmod
|   |-- jdk.accessibility.jmod
|   |-- jdk.attach.jmod
|   |-- jdk.charsets.jmod
|   |-- jdk.compiler.jmod
|   |-- jdk.crypto.cryptoki.jmod
|   |-- jdk.crypto.ec.jmod
|   |-- jdk.dynalink.jmod
|   |-- jdk.editpad.jmod
|   |-- jdk.hotspot.agent.jmod
|   |-- jdk.httpserver.jmod
|   |-- jdk.incubator.concurrent.jmod
|   |-- jdk.incubator.vector.jmod
|   |-- jdk.internal.ed.jmod
|   |-- jdk.internal.jvmstat.jmod
|   |-- jdk.internal.le.jmod
|   |-- jdk.internal.opt.jmod
|   |-- jdk.internal.vm.ci.jmod
|   |-- jdk.internal.vm.compiler.jmod
|   |-- jdk.internal.vm.compiler.management.jmod
|   |-- jdk.jartool.jmod
|   |-- jdk.javadoc.jmod
|   |-- jdk.jcmd.jmod
|   |-- jdk.jconsole.jmod
|   |-- jdk.jdeps.jmod
|   |-- jdk.jdi.jmod
|   |-- jdk.jdwp.agent.jmod
|   |-- jdk.jfr.jmod
|   |-- jdk.jlink.jmod
|   |-- jdk.jpackage.jmod
|   |-- jdk.jshell.jmod
|   |-- jdk.jsobject.jmod
|   |-- jdk.jstatd.jmod
|   |-- jdk.localedata.jmod
|   |-- jdk.management.agent.jmod
|   |-- jdk.management.jfr.jmod
|   |-- jdk.management.jmod
|   |-- jdk.naming.dns.jmod
|   |-- jdk.naming.rmi.jmod
|   |-- jdk.net.jmod
|   |-- jdk.nio.mapmode.jmod
|   |-- jdk.random.jmod
|   |-- jdk.sctp.jmod
|   |-- jdk.security.auth.jmod
|   |-- jdk.security.jgss.jmod
|   |-- jdk.unsupported.desktop.jmod
|   |-- jdk.unsupported.jmod
|   |-- jdk.xml.dom.jmod
|   `-- jdk.zipfs.jmod
|-- legal
|   |-- java.base
|   |   |-- COPYRIGHT
|   |   |-- LICENSE
|   |   |-- aes.md
|   |   |-- asm.md
|   |   |-- c-libutl.md
|   |   |-- cldr.md
|   |   |-- icu.md
|   |   |-- public_suffix.md
|   |   `-- unicode.md
|   |-- java.compiler
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.datatransfer
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.desktop
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   |-- colorimaging.md
|   |   |-- freetype.md
|   |   |-- giflib.md
|   |   |-- harfbuzz.md
|   |   |-- jpeg.md
|   |   |-- lcms.md
|   |   |-- libpng.md
|   |   |-- mesa3d.md
|   |   `-- xwd.md
|   |-- java.instrument
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.logging
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.management
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.management.rmi
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.naming
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.net.http
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.prefs
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.rmi
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.scripting
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.se
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.security.jgss
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.security.sasl
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.smartcardio
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   `-- pcsclite.md
|   |-- java.sql
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.sql.rowset
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.transaction.xa
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- java.xml
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   |-- bcel.md
|   |   |-- dom.md
|   |   |-- jcup.md
|   |   |-- xalan.md
|   |   `-- xerces.md
|   |-- java.xml.crypto
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   `-- santuario.md
|   |-- jdk.accessibility
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.attach
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.charsets
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.compiler
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.crypto.cryptoki
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   |-- pkcs11cryptotoken.md
|   |   `-- pkcs11wrapper.md
|   |-- jdk.crypto.ec
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.dynalink
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   `-- dynalink.md
|   |-- jdk.editpad
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.hotspot.agent
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.httpserver
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.incubator.concurrent
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.incubator.vector
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.internal.ed
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.internal.jvmstat
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.internal.le
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   `-- jline.md
|   |-- jdk.internal.opt
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   `-- jopt-simple.md
|   |-- jdk.internal.vm.ci
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.internal.vm.compiler
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.internal.vm.compiler.management
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jartool
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.javadoc
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   |-- jquery.md
|   |   `-- jqueryUI.md
|   |-- jdk.jcmd
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jconsole
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jdeps
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jdi
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jdwp.agent
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jfr
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jlink
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jpackage
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jshell
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jsobject
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.jstatd
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.localedata
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   |-- LICENSE -> ../java.base/LICENSE
|   |   |-- cldr.md -> ../java.base/cldr.md
|   |   `-- thaidict.md
|   |-- jdk.management
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.management.agent
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.management.jfr
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.naming.dns
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.naming.rmi
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.net
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.nio.mapmode
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.random
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.sctp
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.security.auth
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.security.jgss
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.unsupported
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.unsupported.desktop
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   |-- jdk.xml.dom
|   |   |-- COPYRIGHT -> ../java.base/COPYRIGHT
|   |   `-- LICENSE -> ../java.base/LICENSE
|   `-- jdk.zipfs
|       |-- COPYRIGHT -> ../java.base/COPYRIGHT
|       `-- LICENSE -> ../java.base/LICENSE
|-- lib
|   |-- classlist
|   |-- ct.sym
|   |-- fontconfig.bfc
|   |-- fontconfig.properties.src
|   |-- jfr
|   |   |-- default.jfc
|   |   `-- profile.jfc
|   |-- jrt-fs.jar
|   |-- jspawnhelper
|   |-- jvm.cfg
|   |-- libattach.dylib
|   |-- libawt.dylib
|   |-- libawt_lwawt.dylib
|   |-- libdt_socket.dylib
|   |-- libextnet.dylib
|   |-- libfontmanager.dylib
|   |-- libfreetype.dylib
|   |-- libinstrument.dylib
|   |-- libj2gss.dylib
|   |-- libj2pcsc.dylib
|   |-- libj2pkcs11.dylib
|   |-- libjaas.dylib
|   |-- libjava.dylib
|   |-- libjavajpeg.dylib
|   |-- libjawt.dylib
|   |-- libjdwp.dylib
|   |-- libjimage.dylib
|   |-- libjli.dylib
|   |-- libjsig.dylib
|   |-- libjsound.dylib
|   |-- liblcms.dylib
|   |-- libmanagement.dylib
|   |-- libmanagement_agent.dylib
|   |-- libmanagement_ext.dylib
|   |-- libmlib_image.dylib
|   |-- libnet.dylib
|   |-- libnio.dylib
|   |-- libosx.dylib
|   |-- libosxapp.dylib
|   |-- libosxkrb5.dylib
|   |-- libosxsecurity.dylib
|   |-- libosxui.dylib
|   |-- libprefs.dylib
|   |-- librmi.dylib
|   |-- libsaproc.dylib
|   |-- libsplashscreen.dylib
|   |-- libsyslookup.dylib
|   |-- libverify.dylib
|   |-- libzip.dylib
|   |-- modules
|   |-- psfont.properties.ja
|   |-- psfontj2d.properties
|   |-- security
|   |   |-- blocked.certs
|   |   |-- cacerts
|   |   |-- default.policy
|   |   `-- public_suffix_list.dat
|   |-- server
|   |   |-- classes.jsa
|   |   |-- classes_nocoops.jsa
|   |   |-- libjsig.dylib
|   |   `-- libjvm.dylib
|   |-- shaders.metallib
|   |-- src.zip
|   `-- tzdb.dat
|-- man
|   `-- man1
|       |-- jabswitch.1
|       |-- jaccessinspector.1
|       |-- jaccesswalker.1
|       |-- jar.1
|       |-- jarsigner.1
|       |-- java.1
|       |-- javac.1
|       |-- javadoc.1
|       |-- javap.1
|       |-- jcmd.1
|       |-- jconsole.1
|       |-- jdb.1
|       |-- jdeprscan.1
|       |-- jdeps.1
|       |-- jfr.1
|       |-- jhsdb.1
|       |-- jinfo.1
|       |-- jlink.1
|       |-- jmap.1
|       |-- jmod.1
|       |-- jpackage.1
|       |-- jps.1
|       |-- jrunscript.1
|       |-- jshell.1
|       |-- jstack.1
|       |-- jstat.1
|       |-- jstatd.1
|       |-- jwebserver.1
|       |-- keytool.1
|       |-- kinit.1
|       |-- klist.1
|       |-- ktab.1
|       |-- rmiregistry.1
|       `-- serialver.1
`-- release

87 directories, 393 files
```
</details>

> It is interesting that `java_home` doesn't exist on my Fedora machine. Where does it come from? Can you also provide the output of `/usr/libexec/java_home`?

As far as I know, it's a Mac-specific thing.

```console
$ /usr/libexec/java_home 
/Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home
$ /usr/libexec/java_home --help
Usage: java_home [options...]
    Returns the path to a Java home directory from the current user's settings.

Options:
    [-v/--version   <version>]       Filter Java versions in the "JVMVersion" form 1.X(+ or *).
    [-a/--arch      <architecture>]  Filter JVMs matching architecture (i386, x86_64, etc).
    [-d/--datamodel <datamodel>]     Filter JVMs capable of -d32 or -d64
    [-t/--task      <task>]          Use the JVM list for a specific task (Applets, WebStart, BundledApp, JNI, or CommandLine)
    [-F/--failfast]                  Fail when filters return no JVMs, do not continue with default.
    [   --exec      <command> ...]   Execute the $JAVA_HOME/bin/<command> with the remaining arguments.
    [-R/--request]                   Request installation of a Java Runtime if not installed.
    [-X/--xml]                       Print full JVM list and additional data as XML plist.
    [-V/--verbose]                   Print full JVM list with architectures.
    [-h/--help]                      This usage information.
```


> Is `/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/javac` also a symlink?

Nope.

I was curious why CI isn't failing, and it turns out that the Java tests are disabled on macOS:

https://github.com/mesonbuild/meson/blob/dd25b88f009ee47579b33dfbd167a9434cc8f2be/run_project_tests.py#L1094

If I re-enable them and run them locally, the JNI test does indeed fail:

<details>
<summary>Output</summary>

```console
Running java tests.

 [SUCCESS]   java: 1 basic
 [SUCCESS]   java: 2 subdir
 [SUCCESS]   java: 3 args
 [SUCCESS]   java: 4 inner class
 [SUCCESS]   java: 5 includedirs
 [SUCCESS]   java: 6 codegen
 [SUCCESS]   java: 7 linking
 [SUCCESS]   java: 8 codegen custom target
  [ERROR]    java: 9 jni
During: build
Reason: Compiling source code failed.
 [SUCCESS]   java: 10 resources

Total configuration time: 64.22s
Total build time:         17.33s
Total test time:          1.76s

Total passed tests:  9
Total failed tests:  1
Total skipped tests: 0

Mesonlogs of failing tests


================================== java: 9 jni =================================
 

The Meson build system
Version: 1.0.0.rc1
Source dir: /Users/bgilbert/sw/meson/test cases/java/9 jni
Build dir: /Users/bgilbert/sw/meson/b 609b4765a3
Build type: native build
Project name: jnijava
Project version: undefined
C compiler for the host machine: cc (clang 12.0.0 "Apple clang version 12.0.0 (clang-1200.0.32.29)")
C linker for the host machine: cc ld64 609.8
Java compiler for the host machine: javac (unknown 19.0.1)
Host machine cpu family: x86_64
Host machine cpu: x86_64
Program java found: YES (/usr/bin/java)
Run-time dependency jni found: YES 19.0.1
Configuring Configured.java using configuration
Build targets in project: 3

jnijava undefined

  User defined options
    backend: ninja
    libdir : lib
    prefix : /usr

Found ninja-1.11.1 at /opt/local/bin/ninja
[1/7] Compiling Java object src/com/mesonbuild/Configured.java
[2/7] Compiling Java object '../test cases/java/9 jni/src/com/mesonbuild/JniTest.java'
[3/7] Generating src/com/mesonbuild/com.mesonbuild-native-headers with a custom command
[4/7] Compiling C object lib/libjnijava.dylib.p/com_mesonbuild_JniTest.c.o
FAILED: lib/libjnijava.dylib.p/com_mesonbuild_JniTest.c.o 
cc -Ilib/libjnijava.dylib.p -Ilib '-I../test cases/java/9 jni/lib' -Isrc/com/mesonbuild '-I../test cases/java/9 jni/src/com/mesonbuild' -I/usr/lib/jvm/jre/include -I/usr/lib/jvm/jre/include/darwin -fcolor-diagnostics -Wall -Winvalid-pch -O0 -g -MD -MQ lib/libjnijava.dylib.p/com_mesonbuild_JniTest.c.o -MF lib/libjnijava.dylib.p/com_mesonbuild_JniTest.c.o.d -o lib/libjnijava.dylib.p/com_mesonbuild_JniTest.c.o -c '../test cases/java/9 jni/lib/com_mesonbuild_JniTest.c'
../test cases/java/9 jni/lib/com_mesonbuild_JniTest.c:1:10: fatal error: 'jni.h' file not found
#include <jni.h>
         ^~~~~~~
1 error generated.
[5/7] Compiling C object lib/libjnijava.dylib.p/native.c.o
FAILED: lib/libjnijava.dylib.p/native.c.o 
cc -Ilib/libjnijava.dylib.p -Ilib '-I../test cases/java/9 jni/lib' -Isrc/com/mesonbuild '-I../test cases/java/9 jni/src/com/mesonbuild' -I/usr/lib/jvm/jre/include -I/usr/lib/jvm/jre/include/darwin -fcolor-diagnostics -Wall -Winvalid-pch -O0 -g -MD -MQ lib/libjnijava.dylib.p/native.c.o -MF lib/libjnijava.dylib.p/native.c.o.d -o lib/libjnijava.dylib.p/native.c.o -c '../test cases/java/9 jni/lib/native.c'
../test cases/java/9 jni/lib/native.c:1:10: fatal error: 'jni.h' file not found
#include <jni.h>
         ^~~~~~~
1 error generated.
[6/7] Creating JAR src/jnijar.jar
ninja: build stopped: subcommand failed.
```
</details>
Thanks for the info. Could you do some more debugging for me to understand the issue better? I don't have a mac machine at my disposal.

On this line https://github.com/mesonbuild/meson/blob/dd25b88f009ee47579b33dfbd167a9434cc8f2be/mesonbuild/dependencies/dev.py#LL548C13-L548C100

You see `Path(shutil.which(self.javac.exelist[0])).resolve().parents[1]`. Could you provide me what `self.javac.exelist` is? Then tell me what that `shutil.which` path resolves to.

I want to figure out where this `/usr/lib/jvm/jre` is coming from
> Because of the way macOS lays out its filesystem, I don't think it's safe to assume that the include path can be derived from javac's path. There's no `/usr/include` or `/usr/lib/jvm` on my system.

The two don't have anything to do with each other -- except that on systems where /usr/lib/jvm is the unofficial official way to store a set of JVMs, symlinks to the JVM will point to there, because that's where the JVM *is*.

Meson doesn't care where your JVM is stored.

> As far as I know, it's a Mac-specific thing.

Hmm, but `$JAVA_HOME` is the official, portable way to do it everywhere?

...

It seems to me like the problem is that really, javac should be set to `/Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home/bin/javac` and then everything will work? Just like it does on other OSes where you want to use `/usr/lib/jvm/{java_version}/bin/javac`, which can be a bunch of things, one of which might be linked into your $PATH, and which you can override by setting the `$JAVA_HOME` variable.
It turns out that the `/usr/lib/jvm/jre` part is my fault; I had an old `JAVA_HOME` setting in my shared `.bashrc`.  Once I remove that, `JAVA_HOME` is no longer set (i.e. the OS doesn't set it), and `jni.h` still can't be found.  Meson now sets the include paths to `/System/Library/Frameworks/JavaVM.framework/Versions/A/include` and `.../include/darwin`.  `.../Versions/A` does exist, but `jni.h` isn't anywhere in it, and there's no `include` directory there at all.

@tristan957, to answer your other questions, `self.javac.exelist` is `['javac']` and `which` resolves to `/usr/bin/javac`.
Can you debug Meson to understand where it is getting `/System/Library/Frameworks/JavaVM.framework/Versions/A` from? I would have expected to see `/Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home`
It's the `resolve()` call:

https://github.com/mesonbuild/meson/blob/dd25b88f009ee47579b33dfbd167a9434cc8f2be/mesonbuild/dependencies/dev.py#L548

`resolve()` produces `/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/javac`.  It turns out that `/System/Library/Frameworks/JavaVM.framework/Versions/Current` is a symlink to `A`.

Note that the `javac` in `/Library` is a different binary than the one in `PATH`:

```console
$ ls -l /System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/javac /Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home/bin/javac
-rwxr-xr-x  1 root  wheel  53312 Sep 14 09:11 /Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home/bin/javac
-rwxr-xr-x  1 root  wheel  38880 Oct 30  2020 /System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/javac
```

But both claim to be `javac 19.0.1`.
@bgilbert I very much appreciate your help on this :). Let me give it some thought after work today.
@bgilbert I think there is something up with your system.

This path `/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/javac` doesn't seem like what you installed when you downloaded that dmg from Oracle. This is just a guess. I don't understand where it came from.

`/Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home` seems like the path you got from Oracle.
Holy shit, macos is garbage.

https://stackoverflow.com/a/15133344/7572728

Resolving patch:
diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py
--- a/mesonbuild/dependencies/dev.py
+++ b/mesonbuild/dependencies/dev.py
@@ -22,6 +22,7 @@
 import re
 import pathlib
 import shutil
+import subprocess
 import typing as T
 
 from mesonbuild.interpreterbase.decorators import FeatureDeprecated
@@ -546,6 +547,17 @@ def __init__(self, environment: 'Environment', kwargs: JNISystemDependencyKW):
         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]
+            if m.is_darwin():
+                problem_java_prefix = pathlib.Path('/System/Library/Frameworks/JavaVM.framework/Versions')
+                if problem_java_prefix in self.java_home.parents:
+                    res = subprocess.run(['/usr/libexec/java_home', '--failfast', '--arch', m.cpu_family],
+                                         stdout=subprocess.PIPE)
+                    if res.returncode != 0:
+                        log = mlog.error if self.required else mlog.debug
+                        log('JAVA_HOME could not be discovered on the system. Please set it explicitly.')
+                        self.is_found = False
+                        return
+                    self.java_home = pathlib.Path(res.stdout.decode().strip())
 
         platform_include_dir = self.__machine_info_to_platform_include_dir(m)
         if platform_include_dir is None:
@@ -563,21 +575,11 @@ def __init__(self, environment: 'Environment', kwargs: JNISystemDependencyKW):
                 java_home_lib_server = java_home_lib
             else:
                 if version_compare(self.version, '<= 1.8.0'):
-                    # The JDK and Meson have a disagreement here, so translate it
-                    # over. In the event more translation needs to be done, add to
-                    # following dict.
-                    def cpu_translate(cpu: str) -> str:
-                        java_cpus = {
-                            'x86_64': 'amd64',
-                        }
-
-                        return java_cpus.get(cpu, cpu)
-
-                    java_home_lib = self.java_home / 'jre' / 'lib' / cpu_translate(m.cpu_family)
-                    java_home_lib_server = java_home_lib / "server"
+                    java_home_lib = self.java_home / 'jre' / 'lib' / self.__cpu_translate(m.cpu_family)
                 else:
                     java_home_lib = self.java_home / 'lib'
-                    java_home_lib_server = java_home_lib / "server"
+
+                java_home_lib_server = java_home_lib / 'server'
 
             if 'jvm' in modules:
                 jvm = self.clib_compiler.find_library('jvm', environment, extra_dirs=[str(java_home_lib_server)])
@@ -596,14 +598,26 @@ def cpu_translate(cpu: str) -> str:
 
         self.is_found = True
 
+    @staticmethod
+    def __cpu_translate(cpu: str) -> str:
+        '''
+        The JDK and Meson have a disagreement here, so translate it over. In the event more
+        translation needs to be done, add to following dict.
+        '''
+        java_cpus = {
+            'x86_64': 'amd64',
+        }
+
+        return java_cpus.get(cpu, cpu)
+
     @staticmethod
     def __machine_info_to_platform_include_dir(m: 'MachineInfo') -> T.Optional[str]:
-        """Translates the machine information to the platform-dependent include directory
+        '''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 directory 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():


Test patch:
diff --git a/run_project_tests.py b/run_project_tests.py
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -1091,7 +1091,7 @@ def __init__(self, category: str, subdir: str, skip: bool = False, stdout_mandat
         TestCategory('platform-osx', 'osx', not mesonlib.is_osx()),
         TestCategory('platform-windows', 'windows', not mesonlib.is_windows() and not mesonlib.is_cygwin()),
         TestCategory('platform-linux', 'linuxlike', mesonlib.is_osx() or mesonlib.is_windows()),
-        TestCategory('java', 'java', backend is not Backend.ninja or mesonlib.is_osx() or not have_java()),
+        TestCategory('java', 'java', backend is not Backend.ninja or not have_java()),
         TestCategory('C#', 'csharp', skip_csharp(backend)),
         TestCategory('vala', 'vala', backend is not Backend.ninja or not shutil.which(os.environ.get('VALAC', 'valac'))),
         TestCategory('cython', 'cython', backend is not Backend.ninja or not shutil.which(os.environ.get('CYTHON', 'cython'))),
diff --git a/test cases/java/9 jni/meson.build b/test cases/java/9 jni/meson.build
--- a/test cases/java/9 jni/meson.build	
+++ b/test cases/java/9 jni/meson.build	
@@ -11,10 +11,16 @@ endif
 fs = import('fs')
 javamod = import('java')
 
+cc = meson.get_compiler('c')
 java = find_program('java')
 
 jni_dep = dependency('jni', version : '>=1.8', modules: ['jvm', 'awt'])
 
+# Assert that the header can actually be found with the dependency.
+cc.has_header('jni.h', dependencies: [jni_dep])
+# Assert that the platform-specific include directory is included in the compiler arguments.
+cc.has_header('jni_md.h', dependencies: [jni_dep])
+
 # generate native headers
 subdir('src')
 subdir('lib')