@@ -324,3 +324,191 @@ function(install_rust_static_library TARGET)
324
324
DESTINATION ${ARG_INSTALL_DIR}
325
325
)
326
326
endfunction ()
327
+
328
+ # This function creates C++ bindings using the [cxx] crate.
329
+ #
330
+ # Original function found here: https://github.com/corrosion-rs/corrosion/blob/master/cmake/Corrosion.cmake#L1390
331
+ # Simplified for use as part of RustStaticLibrary module. License below.
332
+ #
333
+ # MIT License
334
+ #
335
+ # Copyright (c) 2018 Andrew Gaspar
336
+ #
337
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
338
+ # of this software and associated documentation files (the "Software"), to deal
339
+ # in the Software without restriction, including without limitation the rights
340
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
341
+ # copies of the Software, and to permit persons to whom the Software is
342
+ # furnished to do so, subject to the following conditions:
343
+ #
344
+ # The above copyright notice and this permission notice shall be included in all
345
+ # copies or substantial portions of the Software.
346
+ #
347
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
348
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
349
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
350
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
351
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
352
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
353
+ # SOFTWARE.
354
+ #
355
+ # The rules approximately do the following:
356
+ # - Check which version of `cxx` the Rust crate depends on.
357
+ # - Check if the exact same version of `cxxbridge-cmd` is installed
358
+ # - If not, create a rule to build the exact same version of `cxxbridge-cmd`.
359
+ # - Create rules to run `cxxbridge` and generate
360
+ # - The `rust/cxx.h` header
361
+ # - A header and source file for the specified CXX_BRIDGE_FILE.
362
+ # - The generated sources (and header include directories) are added to the
363
+ # `${TARGET}` CMake library target.
364
+ #
365
+ # ```cmake
366
+ # rust_cxx_bridge(<TARGET> <CXX_BRIDGE_FILE> [CRATE <CRATE_NAME>])
367
+ # ```
368
+ #
369
+ # Parameters:
370
+ # - TARGET:
371
+ # Name of the target name. The target that the bridge will be included with.
372
+ # - CXX_BRIDGE_FILE:
373
+ # Name of the file that include the cxxbridge (e.g., "src/ffi.rs").
374
+ # - CRATE_NAME:
375
+ # Name of the crate. This parameter is optional. If unspecified, it will
376
+ # fallback to `${TARGET}`.
377
+ #
378
+ function (rust_cxx_bridge TARGET CXX_BRIDGE_FILE)
379
+ fb_cmake_parse_args(ARG "" "CRATE" "" "${ARGN} " )
380
+
381
+ if (DEFINED ARG_CRATE)
382
+ set (crate_name "${ARG_CRATE} " )
383
+ else ()
384
+ set (crate_name "${TARGET} " )
385
+ endif ()
386
+
387
+ execute_process (COMMAND
388
+ ${CARGO_COMMAND} tree -i cxx --depth=0
389
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
390
+ RESULT_VARIABLE cxx_version_result
391
+ OUTPUT_VARIABLE cxx_version_output
392
+ )
393
+
394
+ if (NOT "${cxx_version_result} " EQUAL "0" )
395
+ message (FATAL_ERROR "Crate ${crate_name} does not depend on cxx." )
396
+ endif ()
397
+ if (cxx_version_output MATCHES "cxx v([0-9]+.[0-9]+.[0-9]+)" )
398
+ set (cxx_required_version "${CMAKE_MATCH_1} " )
399
+ else ()
400
+ message (
401
+ FATAL_ERROR
402
+ "Failed to parse cxx version from cargo tree output: `cxx_version_output`" )
403
+ endif ()
404
+
405
+ # First check if a suitable version of cxxbridge is installed
406
+ find_program (INSTALLED_CXXBRIDGE cxxbridge PATHS "$ENV{HOME} /.cargo/bin/" )
407
+ mark_as_advanced (INSTALLED_CXXBRIDGE)
408
+ if (INSTALLED_CXXBRIDGE)
409
+ execute_process (
410
+ COMMAND ${INSTALLED_CXXBRIDGE}
411
+ --version OUTPUT_VARIABLE cxxbridge_version_output)
412
+ if (cxxbridge_version_output MATCHES "cxxbridge ([0-9]+.[0-9]+.[0-9]+)" )
413
+ set (cxxbridge_version "${CMAKE_MATCH_1} " )
414
+ else ()
415
+ set (cxxbridge_version "" )
416
+ endif ()
417
+ endif ()
418
+
419
+ set (cxxbridge "" )
420
+ if (cxxbridge_version)
421
+ if (cxxbridge_version VERSION_EQUAL cxx_required_version)
422
+ set (cxxbridge "${INSTALLED_CXXBRIDGE} " )
423
+ if (NOT TARGET "cxxbridge_v${cxx_required_version} " )
424
+ # Add an empty target.
425
+ add_custom_target ("cxxbridge_v${cxx_required_version} " )
426
+ endif ()
427
+ endif ()
428
+ endif ()
429
+
430
+ # No suitable version of cxxbridge was installed,
431
+ # so use custom target to install correct version.
432
+ if (NOT cxxbridge)
433
+ if (NOT TARGET "cxxbridge_v${cxx_required_version} " )
434
+ add_custom_command (
435
+ OUTPUT
436
+ "${CMAKE_BINARY_DIR} /cxxbridge_v${cxx_required_version} /bin/cxxbridge"
437
+ COMMAND
438
+ ${CMAKE_COMMAND} -E make_directory
439
+ "${CMAKE_BINARY_DIR} /cxxbridge_v${cxx_required_version} "
440
+ COMMAND
441
+ ${CARGO_COMMAND} install cxxbridge-cmd
442
+ --version "${cxx_required_version} "
443
+ --root "${CMAKE_BINARY_DIR} /cxxbridge_v${cxx_required_version} "
444
+ --quiet
445
+ # todo: use --target-dir to potentially reuse artifacts
446
+ COMMENT "Installing cxxbridge (version ${cxx_required_version} )"
447
+ )
448
+ add_custom_target (
449
+ "cxxbridge_v${cxx_required_version} "
450
+ DEPENDS
451
+ "${CMAKE_BINARY_DIR} /cxxbridge_v${cxx_required_version} /bin/cxxbridge"
452
+ )
453
+ endif ()
454
+ set (
455
+ cxxbridge
456
+ "${CMAKE_BINARY_DIR} /cxxbridge_v${cxx_required_version} /bin/cxxbridge" )
457
+ endif ()
458
+
459
+ add_library (${crate_name} STATIC )
460
+ target_include_directories (
461
+ ${crate_name}
462
+ PUBLIC
463
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR} >
464
+ $<INSTALL_INTERFACE:include >
465
+ )
466
+
467
+ file (MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR} /rust" )
468
+ add_custom_command (
469
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR} /rust/cxx.h"
470
+ COMMAND
471
+ ${cxxbridge}
472
+ --header --output "${CMAKE_CURRENT_BINARY_DIR} /rust/cxx.h"
473
+ DEPENDS "cxxbridge_v${cxx_required_version} "
474
+ COMMENT "Generating rust/cxx.h header"
475
+ )
476
+
477
+ get_filename_component (filename_component ${CXX_BRIDGE_FILE} NAME )
478
+ get_filename_component (directory_component ${CXX_BRIDGE_FILE} DIRECTORY )
479
+ set (directory "" )
480
+ if (directory_component)
481
+ set (directory "${directory_component} " )
482
+ endif ()
483
+
484
+ set (cxx_header ${directory} /${filename_component} .h)
485
+ set (cxx_source ${directory} /${filename_component} .cc)
486
+ set (rust_source_path "${CMAKE_CURRENT_SOURCE_DIR} /${CXX_BRIDGE_FILE} " )
487
+
488
+ file (
489
+ MAKE_DIRECTORY
490
+ "${CMAKE_CURRENT_BINARY_DIR} /${directory_component} "
491
+ )
492
+
493
+ add_custom_command (
494
+ OUTPUT
495
+ "${CMAKE_CURRENT_BINARY_DIR} /${cxx_header} "
496
+ "${CMAKE_CURRENT_BINARY_DIR} /${cxx_source} "
497
+ COMMAND
498
+ ${cxxbridge} ${rust_source_path}
499
+ --header --output "${CMAKE_CURRENT_BINARY_DIR} /${cxx_header} "
500
+ COMMAND
501
+ ${cxxbridge} ${rust_source_path}
502
+ --output "${CMAKE_CURRENT_BINARY_DIR} /${cxx_source} "
503
+ --include "${cxx_header} "
504
+ DEPENDS "cxxbridge_v${cxx_required_version} " "${rust_source_path} "
505
+ COMMENT "Generating cxx bindings for crate ${crate_name} "
506
+ )
507
+
508
+ target_sources (${crate_name}
509
+ PRIVATE
510
+ "${CMAKE_CURRENT_BINARY_DIR} /${cxx_header} "
511
+ "${CMAKE_CURRENT_BINARY_DIR} /rust/cxx.h"
512
+ "${CMAKE_CURRENT_BINARY_DIR} /${cxx_source} "
513
+ )
514
+ endfunction ()
0 commit comments