Failure to generate relocatable package with add_jar GENERATE_NATIVE_HEADERS

When using add_jar for generating JNI headers , the option GENERATE_NATIVE_HEADERS DESTINATION rejects path prefixed into build directory and if absolute path specified writes it into INTERFACE_INCLUDE_DIRECTORIES which leads to an error in consuming project during target importing (from xxxTargets.camke)
add_jar fails if relative path to the native_headers DESTINATION specified. If DESTINATION option is omitted or if relative path specified in the DESTINATION option, then add_jar writes an absolute path into INTERFACE_INCLUDE_DIRECTORIES and cmake fails with CMake Error indicating " Target “myProjJni” INTERFACE_INCLUDE_DIRECTORIES property contains
path: “/home/myspace/myproject/include” which is prefixed in the source directory."
If DESTINATION option is set with a path inside build directory ${CMAKE_CURRENT_BINARY_DIR}…, then cmake fails with similar error invalidating path bc it is inside build directory.
If the DESTINATION is set to be under ${CMAKE_INSTALL_PREFIX} then cmake completes with no error but it writes an absolute path into export Targets.cmake file which causes consuming project import to fail.
So could you please advise how to set cmake to prevent writing an absolute path into Targets.cmake . Note, another target that depends on the native_header target created by add_jar is being installed/exported with correct relative path and Targets.cmake has prefix "${_IMPORT_PREFIX} . If native_header is not installed, then cmake fails with an error that dependent target is missing
The cmake-generated export-name xxxTargets.cmake file has absolute path

add_library(mynms::myProjJni INTERFACE IMPORTED)
set_target_properties(framework::myProjJni PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "/home/myspace/myproject/include;${_IMPORT_PREFIX}/myproject/include"
)

CMakeLists.txt:

add_jar(myProjJava
        SOURCES ${JNI_SRC}
        INCLUDE_JARS ${JNI_CLASSPATH}
        GENERATE_NATIVE_HEADERS myProjJni   
             DESTINATION  ${CMAKE_INSTALL_PREFIX}/include #fails if ${CMAKE_INSTALL_PREFIX} removed 
)

I think this might be a corner of add_jar that has not been updated for more modern CMake patterns. I suspect the code will need to do some more logic to support relative paths for DESTINATION. I’m not sure what exactly that would entail, but a merge request adding support would be welcome.

The description of the problem is quite inexact. It is perfectly possible to specify a relative path for DESTINATION option. In this case, there are relative to CMAKE_CURRENT_SOURCE_DIR.
But when a relative path is specified to property INTERFACE_INCLUDE_DIRETORIES, it is transformed in an absolute path.

The real problem is that, currently, it is not possible to specify different values for build and install for the directory where headers are generated. So the target cannot be exported.
May be it is possible, as work-around to override property INTERFACE_INCLUDE_DIRECTORIES with proper values:

set_property(TARGET java-headers-target PROPERTY INTERFACE_INCLUDE_DIRECTORIES $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/java-haeders>
  $<INSTALL_INTERFACE:include/java-headers>)

Thank you Marc, for figuring the problem from its description. Since I posted this issue, as a temporary kludge, I implemented very similar workaround: added to xxxConfig.cmake.in

set_target_properties(mynms::myProjJni PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${PACKAGE_PREFIX_DIR}/myProjJni/include")    

which fixed the import in the consuming project. This is because I thought changing INTERFACE_INCLUDE_DIRECTORIES is not recommended in general due to potential side effects as it being changed by other commands (target_include_directories , … ). The INTERFACE_INCLUDE_DIRECTORIES is a ;-separated list so I would need to get_target_property on INTERFACE_INCLUDE_DIRECTORIES and replace particular list element that is in absolute path. However this command return path with generator expression since unlike actual path written into xxxTargets.cmake. So this workaround is only a temporary workaround and I am looking for a clean solution.
As @marc.chevrier Marc indicated

Could this lack of EXPORT support be fixed/added and meanwhile add_jar documentation updated and error message changed to indicates workaround as per my approach?
Could generator expression be passed to DESTINATION so cmake does not complain but writes some variable prefix?
Could the error check for error “target INTERFACE_INCLUDE_DIRECTORIES property contains path
which is prefixed in the build directory” be changed to add check if its originated from GENERATE_NATIVE_HEADERS and then path ${CMAKE_CURRENT_BINARY_DIR} prefix allowed , and export(EXPORT could export from build tree to install tree?

Also, what needs to be done to get_target_property(var PROPERTIES INTERFACE_INCLUDE_DIRECTORIES) return var with resolved generator expression? Then function could be written to replace absolute path.

Additional comments on comments:----

as I said

which obviously means it is possible but leads to failure since it results in absolute path relative to CMAKE_CURRENT_SOURCE_DIR.

-could you please clarify what it means? I did not imply “specified to property INTERFACE_INCLUDE_DIRECTORIES” as it is changed via target commands indirectly by values of DESTINATION, INCLUDES DESTINATION, INSTALL_INTERFACE, and other options. It is actually recommended to specify those DESTINATION options as relative path for supporting relocatable packages.

  • So could you please clarify this assessment. This suggested that the issue impact is limited to a usage style (modern- target property oriented vs old - directory/filesystem manipulation) however this is a case when the feature is not working since target created by cmake (add_jar) can not be installed using install(TARGETS. I guess you just meant that they could be installed via install(DIRECTORY as an old style…
    Also generated files can not be saved into build dir which seems inconsistent with the purpose of build tree.
    Also could you please check other questions in the response to @marc.chevrier message?

@yisseamake I am afraid you misunderstand the real problem: Currently the target generated using GENERATE_NATIVE_HEADERS option cannot be exported but it is perfectly allowed to generate the headers inside the build tree (this is the default behavior) and this target can be installed (do not confuse installation and export).

And your various propositions cannot be implemented because it is not the way CMake is working (add_jar do not do any check against DESTINATION directory, this is done by CMake when export actions are generated. And generator expressions cannot be evaluated during configuration step and are only expanded during generation time (this is the main reason for generator expressions)).

Marc,

Blockquote

it is perfectly allowed to generate the headers inside the build tree (this is the default behavior)

Blockquote

  • If this is cmake required behavior, then the 1st problem as stateed in the issue description is that if DESTINATION option is removed, cmake fails with error:
    – Configuring done
    CMake Error in …/CMakeLists.txt:
    Target “myProjJni” INTERFACE_INCLUDE_DIRECTORIES property contains
    path: “/home/myspace/myproject/build/src//CMakeFiles/myProjJava.dir/native_headers”
    which is prefixed in the build directory. Here build is the ${CMAKE_CURRENT_BINARY_DIR} dir and statement looks like this:
add_jar(myProjJava
	        SOURCES ${JNI_SRC}
	        INCLUDE_JARS ${JNI_CLASSPATH}
	        GENERATE_NATIVE_HEADERS myProjJni  )

if DESTINATION option path starts from ${CMAKE_CURRENT_BINARY_DIR}, the same error is generated.
So the only value works is one that starts from ${CMAKE_INSTALL_PREFIX} which is outside source and build dir.

The 2rd problem: As indicated in the description, cmake creates record in the cmake-generated export-name xxxTargets.cmake filw with an absolute path ( see description

INTERFACE_INCLUDE_DIRECTORIES "/home/myspace/myproject/include;${_IMPORT_PREFIX}/myproject/include"

which is not appropriate for use by consuming project and it should be starting from ${_IMPORT_PREFIX) to support relocatable package.

The 3rd problem: There no any mentioning in documentation that GENERATE_NATIVE_HEADERS target is different form any other target and can’t be exported so
a) What is a workaround for Problem 2 which follows modern cmake approach?
b) Could you please explain why is it it complicated to fix cmake to allow export and maintain uniformity for targets?

A MR is currently in process for CMake 3.20 enabling the export of this target.

Great thank you