0

CMake is using JNI headers in /user/local/include and not the ones at $JAVA_HOME

CMAKE File

cmake_minimum_required(VERSION 3.24.0...3.31.1)
cmake_policy(SET CMP0135 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0174 NEW)
cmake_policy(SET CMP0174 NEW)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_VERBOSE_MAKEFILE on)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  -fconstexpr-depth=1000")
project("sat_parser_bindings_java" )
set(JAVA_HOME $ENV{JAVA_HOME})
set(PATH $ENV{PATH})

include(FetchContent)
set(FETCHCONTENT_FULLY_DISCONNECTED OFF)
FetchContent_Declare(
   jni_bind_f
   URL https://raw.githubusercontent.com/google/jni-bind/refs/tags/Release-1.2.0/jni_bind_release.h 
   DOWNLOAD_NO_EXTRACT TRUE
)
FetchContent_MakeAvailable(jni_bind_f)
FetchContent_GetProperties(jni_bind_f)

set(CMAKE_JNI_TARGET TRUE)
find_package(Java 21 REQUIRED)
find_package(JNI 21 REQUIRED)

include(CMakePrintHelpers)
cmake_print_variables(CMAKE_VERSION JAVA_HOME JAVA_INCLUDE_PATH JAVA_INCLUDE_PATH2 JNI_INCLUDE_DIRS JNI_FOUND JNI_VERSION Java_VERSION )
include(UseJava)

file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java)
set(CMAKE_JNI_TARGET TRUE)

# Create a target to generate native headers
add_jar(j_parser_nh
    SOURCES ${JAVA_SOURCES} 
    INCLUDE_JARS $ENV{HOME}/.m2/repository/cz/adamh/native-utils/1.0/native-utils-1.0.jar
    GENERATE_NATIVE_HEADERS j_parser_natives)

set(resourcedir ${CMAKE_CURRENT_BINARY_DIR}/resources)

get_target_property(classdir j_parser_nh CLASSDIR)
get_target_property(nativehdrdir j_parser_natives NATIVE_HEADERS_DIRECTORY)

file(GLOB SOURCES src/main/cpp/src/*.cpp)
file(GLOB HEADERS src/main/cpp/include/*.h)

add_library(java_cpp_binding SHARED ${SOURCES})
set_target_properties(java_cpp_binding PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${resourcedir}/native/x86_64/darwin)
target_include_directories(java_cpp_binding 
    PUBLIC src/main/cpp/include
    PUBLIC ${jni_bind_f_SOURCE_DIR} 
    PUBLIC ${DataModel_SOURCE_DIR}
)

Value of properties, as printed by CMAKE:

-- Found Java: /usr/local/Cellar/openjdk@21/21.0.7/libexec/openjdk.jdk/Contents/Home/bin/java (found suitable version "21.0.7", minimum required is "21")
-- Found JNI: /usr/local/include (Required is at least version "21") found components: AWT JVM
-- CMAKE_VERSION="4.0.1" ;  
JAVA_HOME="/usr/local/Cellar/openjdk@21/21.0.7/libexec/openjdk.jdk/Contents/Home" ;  
JAVA_INCLUDE_PATH="/usr/local/include" ; 
JAVA_INCLUDE_PATH2="/usr/local/include" ;  
JNI_INCLUDE_DIRS="/usr/local/include;/usr/local/include" ; 
JNI_FOUND="TRUE" ;  
JNI_VERSION="" ; 
Java_VERSION="21.0.7"

/usr/local/include is mapped to 1.8

Using cmake 4.0.1 on MacOs Sequoia (15.4.1)

Any help would be a life saver, everything I have read says this should work. I must be missing something. This work before upgrading to cmake 4 (company requirement).

2
  • Variables CPPFLAGS and LDFLAGS have no special meaning for CMake itself. So setting them is useless. The list of variables consumed by CMake itself could be found in the documentation: cmake.org/cmake/help/latest/manual/cmake-variables.7.html Commented May 12 at 22:09
  • @Tsyvarev remove them does not fix the problem. Commented May 13 at 4:52

1 Answer 1

1

Part of the problem is caused by you having run brew link openjdk in the past. This puts the linked JVM front and center when CMake tries to find the JVM and JNI components. If it suits your workflow, brew unlink openjdk will make everything work because FindJNI.cmake will only look at your JAVA_HOME.

If you must have those files linked, read on.

The reason /usr/local/include gets picked before anything else is this find_path call in FindJNI:

 find_path(JAVA_INCLUDE_PATH jni.h
  ${JAVA_AWT_INCLUDE_DIRECTORIES}
  DOC "JNI include directory"
)

This searches common include directories first, before looking at any of the directories specified in that variable, but you can put another directory in front by defining JNI_ROOT as either a CMake variable or an environment variable. Its contents should be the same as your JAVA_HOME, so:

set(JNI_ROOT $ENV{JAVA_HOME})

in your CMakeLists.txt before you call find_package(JNI ...) will do the trick.

Sign up to request clarification or add additional context in comments.

2 Comments

You were correct this has to do with how find_path works. Setting JNI_ROOT allowed it to find jni.h correctly but not jni_md.h. I found that if I set CMAKE_FIND_USE_CMAKE_SYSTEM_PATH to OFF with out setting JNI_ROOT and ensuring JAVA_HOME was correct then found both files correctly.
That also works .. but it's a big restriction to put on your CMake system, I think. Not sure why jni_md was not found for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.