118 cedaAddJni

Example:

    pythonPackageName = pypizza
    cppJniLib = pizza_jni
    javaJniJar = PizzaJni
    generateJniPythonScript = ${CMAKE_CURRENT_SOURCE_DIR}/generate_pizza_jni_wrappers.py
    cppLibs = "MyCompany::Time;MyCompany::Shapes;MyCompany::Pizza"

function(cedaAddJni pythonPackageName cppJniLib javaJniJar generateJniPythonScript cppLibs)
    if (BUILD_SHARED_LIBS)
        cedaPrepareUseJni()

        # Path to witness file which is touched after all the .java and .cpp JNI files have been
        # created by the python script
        set(generate_jni_files_witness ${CMAKE_CURRENT_BINARY_DIR}/generated_jni_files_witness)

        # Paths for where the generated .cpp and .java files will be written
        set(cppFolderPath ${CMAKE_CURRENT_BINARY_DIR}/cpp)
        set(javaFolderPath ${CMAKE_CURRENT_BINARY_DIR}/java)

        # These directories must be created at configure time, because the python script doesn't create them
        file(MAKE_DIRECTORY ${cppFolderPath})
        file(MAKE_DIRECTORY ${javaFolderPath})

        # JniFiles.cmake is a generated file which is checked into the source tree in the repo, and only updated
        # when it changes.
        #
        # It sets the variable 'jniCppFiles' to a list of relative paths of the generated JNI cpp files.
        #
        # This is done so we have the list of paths to the generated files at configure time, making it possible
        # for this CMakeLists.txt file to provide the list of paths to the generated files in the call to
        # add_library (see below) for the jni library.
        #
        # This avoids the need for an ExternalProject
        # as discussed here: CMake Compiling Generated Files
        if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/JniFiles.cmake)
            include(${CMAKE_CURRENT_SOURCE_DIR}/JniFiles.cmake)
        else()
            message("ERROR : ${CMAKE_CURRENT_SOURCE_DIR}/JniFiles.cmake doesn't exist - run the build to create it then reconfigure")
            set(jniCppFiles run-build-and-reconfigure.cpp)
            set(jniJavaFiles run-build-and-reconfigure.java)
        endif()

        # Calculate jnifullPathCppFiles to be a list of full paths to the generated cpp files by prepending
        # ${cppFolderPath} to each relative path in ${jniCppFiles}
        set(jnifullPathCppFiles "")
        foreach(f ${jniCppFiles})
            list(APPEND jnifullPathCppFiles ${cppFolderPath}/${f})
        endforeach()

        set(jnifullPathJavaFiles "")
        foreach(f ${jniJavaFiles})
            list(APPEND jnifullPathJavaFiles ${javaFolderPath}/${f})
        endforeach()

        # Without this add_library() may balk at configure time if the generated files don't exist yet
        # (since they are only created at build time).
        set_source_files_properties(${jnifullPathCppFiles} PROPERTIES GENERATED 1)
        set_source_files_properties(${jnifullPathJavaFiles} PROPERTIES GENERATED 1)

        if (NOT TARGET ${pythonPackageName})
            # When the target platform is for static libraries or it's Android we don't build the python package,
            # so declaring a dependency on it with DEPENDS (see add_custom_command below) would produce an error
            # when ninja runs (ninja would say there is no rule to build it).
            # Instead it is assumed the python package has already been built and installed on the host platform
            # so there is no need to declare a dependency on it.
            set(pythonPackageName "")
        endif()

        # Add command to run the python script ${generateJniPythonScript} to generate the JNI files.
        add_custom_command(
            OUTPUT ${generate_jni_files_witness}
            BYPRODUCTS ${jnifullPathCppFiles} ${jnifullPathJavaFiles}
            DEPENDS ${generateJniPythonScript} ${pythonPackageName}
            COMMENT "Running ${generateJniPythonScript} ${javaFolderPath} ${cppFolderPath}"
            COMMAND ${Python_EXECUTABLE} ${generateJniPythonScript} ${javaFolderPath} ${cppFolderPath}
            COMMAND ${CMAKE_COMMAND} -DCPP_PATH=${cppFolderPath} -DJAVA_PATH=${javaFolderPath} -DOUPUT_PATH=${CMAKE_CURRENT_SOURCE_DIR}/JniFiles.cmake -P ${Ceda_CMAKE}/GlobJniFiles.cmake
            COMMAND ${CMAKE_COMMAND} -E touch ${generate_jni_files_witness})

        add_custom_target(GenScriptTarget_${javaJniJar} DEPENDS ${generate_jni_files_witness})

        if (TARGET pyceda)
            add_dependencies(GenScriptTarget_${javaJniJar} pyceda)
        endif()

        add_library(${cppJniLib} SHARED ${jnifullPathCppFiles})

        cedaAddDependentProject(${cppJniLib})
        cedaSetDefaultsForTarget(${cppJniLib})

        target_include_directories(${cppJniLib} PRIVATE ${JNI_INCLUDE_DIRS})

        target_link_libraries(${cppJniLib} Ceda::cxUtils Ceda::cxObject Ceda::cxPersistStore Ceda::cxJava ${cppLibs})

        ###################################################################################################
        # Create ${javaJniJar}.jar

        include(UseJava)

        set(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.8" "-target" "1.8")

        # This command creates the file ${javaJniJar}.jar.
        set(CMAKE_JNI_TARGET TRUE)
        add_jar(${javaJniJar} SOURCES ${jnifullPathJavaFiles})

        # Make sure the .java files are generated before they are compiled into a jar file
        add_dependencies(${javaJniJar} GenScriptTarget_${javaJniJar})
    else()
        message("Creating JNI bindings unsupported when building static libraries")
    endif()
endfunction()