Building a shared library that depends on a shared library produced by GraalVM's native-image

I’m working on a project where we have a C++ shared library which is (effectively) an API wrapper around our Java library, which is compiled down to C using GraalVM’s native-image tool.

The library is cross-platform, targeting Linux, macOS and Windows. Our existing build system gets GraalVM to build the shared library object plus header files. I then need to include that when I build the C++ source of the wrapping shared library.

We haven’t been using CMake, and I want to move away from our scratch build scripts to something more maintainable.

It’s not obvious to me how to include the Graal-generated library.

My initial approach was to use this in my CMakeLists.txt (targeting 3.27):

set(LIBSAXON_SO "libname-1.2.3.so")
if(APPLE)
    set(LIBSAXON_SO "libname-1.2.3.dylib")
endif()
add_library(libname SHARED IMPORTED)
set_property(TARGET libname PROPERTY
        IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/path_to/graalvm-generated-lib/${LIBNAME_SO}")
target_sources(libname INTERFACE
        FILE_SET HEADERS
        BASE_DIRS path_to/graalvm-generated-lib
        FILES path_to/graalvm-generated-lib/graal_isolate.h
        path_to/graalvm-generated-lib/graal_isolate_dynamic.h
        path_to/graalvm-generated-lib/libname-1.2.3.h
        path_to/graalvm-generated-lib/libname-1.2.3_dynamic.h

I’m not especially fond of this. There’s an awful lot of hard-coded versions and platform-specific conditionals in there (and it doesn’t even deal with Windows). Is there a pattern for handling this kind of thing (probably akin to using a commercially-supplied pre-compiled library) that I’ve missed and people would recommend?

Thanks, Matt

Instead of a conditional platform-specific variable for the library binary file name you could use the find_library() function. That should take care of assigning appropriate prefixes/suffixes/extensions to the base library name.

Then instead of manually composing the list of public headers you could use a GLOB, which is usually not very much recommended, but here it would be justified, I think.

Finally, in general, for finding a library that doesn’t have a CMake config, you could write your own custom Find* module, perhaps using this one as (a bit convoluted) example. Having this module, your consuming projects will only need to do this:

#list(APPEND CMAKE_MODULE_PATH "/path/to/your/cmake/modules")
find_package(SAXON REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE ${SAXON_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE SAXON::SAXON)

find_library() was a great idea, thank you. Looking at that, along with find_path() to get the path to the headers so I could use that variable in target_include_directories() has made things much simpler.

I realised that the library file naming was non-standard, and changing that also helped with keeping things straightforward.

Thanks again!

1 Like