diff --git a/modules/ECMCargo.cmake b/modules/ECMCargo.cmake new file mode 100644 --- /dev/null +++ b/modules/ECMCargo.cmake @@ -0,0 +1,144 @@ +#.rst: +# ECMCargo +# -------- +# +# Functions for integrating Cargo workspaces into CMake. +# +# :: +# +# ecm_add_cargo_workspace(DIRECTORY +# NAME +# [STATIC_LIBNAME ] +# [DYNAMIC_LIBNAME ] +# [VENDOR_TARBALL ] +# [VENDOR_CONFIG ] +# [FEATURES ] +# +# One variable will be exported when calling this function: ${NAME}_artifacts_dir, +# which points to the directory containing artifacts from Cargo. +# +# ``DIRECTORY`` +# ============= +# Path to the directory containg the root ``Cargo.toml`` for a Cargo workspace. +# +# ``NAME`` +# ======== +# The name to use when exporting CMake variables for this Cargo workspace. +# +# ``VENDOR_TARBALL`` +# ================== +# A path to look for a vendor tarball containing vendored dependencies for the Cargo workspace. +# When providing this, you must provide a ``VENDOR_CONFIG``. If the file that ``VENDOR_TARBALL` +# expects does not exist, the project will be built with crates.io as normal without +# any warnings or errors. This is intentional, as some distributions prefer to vendor +# and others do not. +# +# ``VENDOR_CONFIG`` +# ================= +# The path to a Cargo configuration file generated by ``cargo vendor`` to use when +# a vendor tarball is present. This must be present if ecm_add_cargo_workspace is +# expecting a vendor tarball. +# +# ``STATIC_LIBNAME`` and ``DYNAMIC_LIBNAME`` +# ========================================== +# The name of the library file to export to CMake as a library. +# +# ``FEATURES`` +# ============ +# Project features to enable. This argument will be passed verbatim to the ``--features`` +# flag on Cargo. +# + +#============================================================================= +# Copyright 2020 Carson Black +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +include(CMakeParseArguments) + +function(ecm_add_cargo_workspace) + set(options GUI) + + set(oneValueArgs DIRECTORY NAME VENDOR_TARBALL VENDOR_CONFIG STATIC_LIBNAME DYNAMIC_LIBNAME) + set(multiValueArgs FEATURES) + + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + find_program(Cargo NAMES cargo) + + string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build) + if(cmake_build STREQUAL debug) + set(rust_target_dir target/debug/) + set(rust_build_flags) + else() + set(rust_target_dir target/release/) + set(rust_build_flags --release) + endif() + + if("${ARG_FEATURES}") + list(APPEND ${rust_build_flags} --features ${ARG_FEATURES}) + endif() + + add_custom_target( + "${ARG_NAME}_artifacts" + COMMAND ${Cargo} build ${rust_build_flags} + WORKING_DIRECTORY "${ARG_DIRECTORY}" + ) + + if(ARG_VENDOR_TARBALL) + if (NOT ARG_VENDOR_CONFIG) + message(FATAL_ERROR "\"VENDOR_CONFIG\" not provided for ecm_add_cargo_workspace") + endif() + if (EXISTS "${CMAKE_SOURCE_DIR}/${ARG_VENDOR_TARBALL}") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xvf ${CMAKE_SOURCE_DIR}/${ARG_VENDOR_TARBALL} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/${ARG_DIRECTORY} + ) + configure_file( + ${CMAKE_SOURCE_DIR}/${ARG_VENDOR_CONFIG} + ${CMAKE_SOURCE_DIR}/${ARG_DIRECTORY}/.cargo/config + COPYONLY + ) + endif() + endif() + + if(ARG_STATIC_LIBNAME AND ARG_DYNAMIC_LIBNAME) + message(FATAL_ERROR "You cannot configure both a dynamic library and a static library from a single Cargo workspace") + elseif(ARG_STATIC_LIBNAME) + set(lib "${CMAKE_CURRENT_SOURCE_DIR}/${ARG_DIRECTORY}/${rust_target_dir}/${ARG_STATIC_LIBNAME}${CMAKE_STATIC_LIBRARY_SUFFIX}") + add_library(${ARG_NAME} STATIC IMPORTED GLOBAL) + set_target_properties(${ARG_NAME} PROPERTIES IMPORTED_LOCATION ${lib}) + add_dependencies(${ARG_NAME} ${ARG_NAME}_artifacts) + + elseif(ARG_DYNAMIC_LIBNAME) + set(lib "${CMAKE_CURRENT_SOURCE_DIR}/${ARG_DIRECTORY}/${rust_target_dir}/${ARG_DYNAMIC_LIBNAME}${CMAKE_SHARED_LIBRARY_SUFFIX}") + add_library(${ARG_NAME} SHARED IMPORTED GLOBAL) + set_target_properties(${ARG_NAME} PROPERTIES IMPORTED_LOCATION ${lib}) + add_dependencies(${ARG_NAME} ${ARG_NAME}_artifacts) + + endif() + + set("${ARG_NAME}_artifacts_dir" "${CMAKE_CURRENT_SOURCE_DIR}/${ARG_DIRECTORY}/${rust_target_dir}" PARENT_SCOPE) +endfunction()