Using SWIG-generated files in another project

I am attempting to use SWIG to generate a C# wrapper for some C++ code, and then use that generated code in another C# project. Right now, I’m just trying to get things working in an example project. Starting with the CMake example on the SWIG website (http://www.swig.org/Doc3.0/Introduction.html#Introduction_build_system), I updated it a bit to try and match the latest CMake documentation (https://cmake.org/cmake/help/latest/module/UseSWIG.html), as well as removed the Python parts in favour of C# equivalents.

Now I’m looking at

cmake_minimum_required(VERSION 3.17)

project(example
    LANGUAGES CSharp
)

find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})

include_directories(${CMAKE_CURRENT_SOURCE_DIR})

set(CMAKE_SWIG_FLAGS "")
set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}/example_out)

set_source_files_properties(example.i PROPERTIES CPLUSPLUS ON)
swig_add_library(example
    TYPE SHARED
    LANGUAGE csharp
    SOURCES example.i example.c
)

If anyone’s trying to get this to work locally, I also needed to change example.i from the SWIG website to directly #include "example.c", rather than use externs.

This does generate a C# wrapper, and outputs it to ${CMAKE_CURRENT_BINARY_DIR}/example_out. The problem then is, that I need to reference these output files from another project. One approach would be

get_property(EXAMPLE_OUT_DIR TARGET ${PROJECT_NAME} PROPERTY SWIG_SUPPORT_FILES_DIRECTORY)

file(GLOB OUT_SRC
    CONFIGURE_DEPENDS
    "${EXAMPLE_OUT_DIR}/*.cs"
)

add_library(newlib SHARED ${OUT_SRC} tmp.cs)
add_library(mylibs::newlib ALIAS newlib)
set_property(TARGET newlib PROPERTY DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1")
set_property(TARGET newlib PROPERTY VS_DOTNET_REFERENCES
    "Microsoft.CSharp"
)

The properties being there to force this project to be a C# project (which is necessary for setting it as a reference for another C# project), and tmp.cs being an empty file to get this to run before anything’s been generated (since the generation from SWIG happens at build time).

Even with CONFIGURE_DEPENDS, though, this still requires compiling twice, and then touching the CMakeLists to get a further C# project to recognise that the wrappers have been added to it.
Example C# project for consuming this:

cmake_minimum_required(VERSION 3.17)

project(thing_using_example
    LANGUAGES CSharp)
include(CSharpUtilities)

set(SOURCES
    ThingUsingExample.cs
)

add_executable(${PROJECT_NAME} ${SOURCES})
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1")
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_GLOBAL_ROOTNAMESPACE "ThingUsingExample")
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_GLOBAL_Prefer32Bit "false")
set(CMAKE_CSharp_FLAGS "${CMAKE_CSharp_FLAGS} /langversion:6")
add_dependencies(${PROJECT_NAME} mylibs::newlib)

My question is: what is the right way to create a library, consisting of files generated at build time, the names of which are not known in advance? Right now I’m leaning towards replacing the swig_add_library with a custom command, but I’m sure there’s a cleaner/nicer way.

In case anyone comes across this in the future, the solution I ended up going with was to follow the pattern given here: https://stackoverflow.com/a/52714922

Basically, to have SWIG run through execute_process; add the wrapped headers and the SWIG interface files as CMake dependencies, by adding them to CMAKE_CONFIGURE_DEPENDS; and then glob the output directory, and add the globbed files to a new C# project.

I don’t think swig_add_library is designed to be used in such a way, so this is probably about as clean of an answer as is out there (as of this post).

Is there an example of what you implemented out in the wild?

Unfortunately not. I also recall that this solution didn’t really end up satisfying for some reason. My team ended up converting to Visual Studio projects before I worked out the kinks, though.