mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-09 00:00:03 +01:00
356 lines
14 KiB
CMake
356 lines
14 KiB
CMake
# Copyright (c) 2014 SiegeLord
|
|
#
|
|
# This software is provided 'as-is', without any express or implied
|
|
# warranty. In no event will the authors be held liable for any damages
|
|
# arising from the use of this software.
|
|
#
|
|
# Permission is granted to anyone to use this software for any purpose,
|
|
# including commercial applications, and to alter it and redistribute it
|
|
# freely, subject to the following restrictions:
|
|
#
|
|
# 1. The origin of this software must not be misrepresented; you must not
|
|
# claim that you wrote the original software. If you use this software
|
|
# in a product, an acknowledgment in the product documentation would be
|
|
# appreciated but is not required.
|
|
#
|
|
# 2. Altered source versions must be plainly marked as such, and must not be
|
|
# misrepresented as being the original software.
|
|
#
|
|
# 3. This notice may not be removed or altered from any source
|
|
# distribution.
|
|
|
|
# Defines a few macros, variables and a function to help with compiling Rust
|
|
# programs/libraries and documentation with CMake.
|
|
#
|
|
# This file utilizes several global variables:
|
|
#
|
|
# RUSTC_EXECUTABLE - Filename of the rustc executable. You can fill it in using the Findrustc package.
|
|
# RUSTDOC_EXECUTABLE - Filename of the rustc executable. You can fill it in using the Findrustdoc package.
|
|
# RUSTC_FLAGS - These get passed to rustc.
|
|
# RUSTDOC_FLAGS - These flags get passed to rustdoc.
|
|
|
|
include(CMakeParseArguments)
|
|
|
|
if(NOT RUSTC_FLAGS)
|
|
set(RUSTC_FLAGS "" CACHE STRING "Flags to pass to the Rust compiler.")
|
|
endif()
|
|
mark_as_advanced(RUSTC_FLAGS)
|
|
|
|
if(NOT RUSTDOC_FLAGS)
|
|
set(RUSTDOC_FLAGS "" CACHE STRING "Flags to pass to Rustdoc.")
|
|
endif()
|
|
mark_as_advanced(RUSTDOC_FLAGS)
|
|
|
|
# Fetches the dependencies of a Rust crate with local crate root located at
|
|
# local_root_file and places them into out_var. Optionally also builds the crate.
|
|
#
|
|
# Optional arguments:
|
|
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
|
|
# DESTINATION destination - If compiling, where to place the compilation artifacts.
|
|
# COMPILE - Whether or not to produce artifacts (it won't by default).
|
|
# NOTE! This will force the compillation of this crate every time the
|
|
# project is reconfigured, so use with care!
|
|
#
|
|
# NOTE: Only the first target's dependencies are fetched!
|
|
function(get_rust_deps local_root_file out_var)
|
|
cmake_parse_arguments("OPT" "COMPILE" "DESTINATION" "OTHER_RUSTC_FLAGS" ${ARGN})
|
|
|
|
set(root_file "${CMAKE_CURRENT_SOURCE_DIR}/${local_root_file}")
|
|
|
|
set(dep_dir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/.cmake_rust_dependencies")
|
|
file(MAKE_DIRECTORY "${dep_dir}")
|
|
|
|
if(OPT_COMPILE)
|
|
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}")
|
|
set(flags --out-dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}")
|
|
message(STATUS "Compiling Rust dependency info for crate root ${local_root_file}")
|
|
# XXX: It'd be nice if this wasn't a separate operation (need to handle the dep file location being different, or rewrite this macro thing)
|
|
execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} ${flags} "${root_file}")
|
|
endif()
|
|
|
|
set(flags "-Zno-analysis")
|
|
message(STATUS "Getting Rust dependency info for crate root ${local_root_file}")
|
|
|
|
execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} ${flags} --emit dep-info -o "${dep_dir}/deps.d" "${root_file}")
|
|
|
|
# Read and parse the dependency information
|
|
file(STRINGS "${dep_dir}/deps.d" crate_deps LIMIT_COUNT 1)
|
|
file(REMOVE "${dep_dir}/deps.d")
|
|
string(REGEX REPLACE ".*: (.*)" "\\1" crate_deps "${crate_deps}")
|
|
string(STRIP "${crate_deps}" crate_deps)
|
|
string(REPLACE " " ";" crate_deps "${crate_deps}")
|
|
|
|
# Make the dependencies be relative to the source directory
|
|
set(crate_deps_relative "")
|
|
foreach(var IN ITEMS ${crate_deps})
|
|
file(TO_CMAKE_PATH "${var}" var)
|
|
file(RELATIVE_PATH var "${CMAKE_CURRENT_SOURCE_DIR}" "${var}")
|
|
list(APPEND crate_deps_relative "${var}")
|
|
# Hack to re-run CMake if the file changes
|
|
configure_file("${var}" "${dep_dir}/${var}" COPYONLY)
|
|
endforeach()
|
|
|
|
set(${out_var} "${crate_deps_relative}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Adds a target to build a rust crate with the crate root located at local_root_file.
|
|
# The compilation output is placed inside DESTINATION within the build directory.
|
|
#
|
|
# Please pass the crate dependencies obtained through get_rust_deps to the dependencies argument in
|
|
# addition to other targets/files you want this target to depend on.
|
|
#
|
|
# Optional arguments:
|
|
#
|
|
# ALL - Pass this to make this crate be built by default.
|
|
# DESTINATION dest - Where to place the compilation artifacts.
|
|
# TARGET_NAME target - Target name for the command to build this crate.
|
|
# DEPENDS depends - List of dependencies of this crate.
|
|
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
|
|
#
|
|
# This function sets two variables:
|
|
#
|
|
# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies
|
|
# for other targets when you want them to depend on the
|
|
# output of this target.
|
|
#
|
|
# ${target_name}_ARTIFACTS - The actual files generated by this command.
|
|
# You'd use this as a set of files to install/copy elsewhere.
|
|
function(rust_crate local_root_file)
|
|
cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTC_FLAGS" ${ARGN})
|
|
|
|
if(NOT OPT_TARGET_NAME)
|
|
set(OPT_TARGET_NAME CRATE)
|
|
endif()
|
|
|
|
if(OPT_ALL)
|
|
set(ALL_ARG "ALL")
|
|
else()
|
|
set(ALL_ARG "")
|
|
endif()
|
|
|
|
set(root_file "${CMAKE_CURRENT_SOURCE_DIR}/${local_root_file}")
|
|
|
|
execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} --print file-names "${root_file}"
|
|
OUTPUT_VARIABLE rel_crate_filenames
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
|
|
# Split up the names into a list
|
|
string(REGEX MATCHALL "[^\n\r]+" rel_crate_filenames "${rel_crate_filenames}")
|
|
|
|
set(comment "Building ")
|
|
set(crate_filenames "")
|
|
set(first TRUE)
|
|
foreach(name IN ITEMS ${rel_crate_filenames})
|
|
if(${first})
|
|
set(first FALSE)
|
|
else()
|
|
set(comment "${comment}, ")
|
|
endif()
|
|
set(comment "${comment}${OPT_DESTINATION}/${name}")
|
|
list(APPEND crate_filenames "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}/${name}")
|
|
endforeach()
|
|
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}")
|
|
|
|
add_custom_command(OUTPUT ${crate_filenames}
|
|
COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} --out-dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}" "${root_file}"
|
|
DEPENDS ${crate_deps_list}
|
|
DEPENDS ${OPT_DEPENDS}
|
|
COMMENT "${comment}")
|
|
|
|
add_custom_target("${OPT_TARGET_NAME}"
|
|
${ALL_ARG}
|
|
DEPENDS ${crate_filenames})
|
|
|
|
set("${OPT_TARGET_NAME}_ARTIFACTS" "${crate_filenames}" PARENT_SCOPE)
|
|
# CMake Bug #10082
|
|
set("${OPT_TARGET_NAME}_FULL_TARGET" "${OPT_TARGET_NAME};${crate_filenames}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Like rust_crate, but fetches the crate dependencies for you. This is convenient
|
|
# but inefficient if you want to compile the crate several times with different
|
|
# configurations (e.g. with --test and without) or if you want to build documentation.
|
|
#
|
|
# Optional arguments:
|
|
#
|
|
# ALL - Pass this to make this crate be built by default.
|
|
# DESTINATION dest - Where to place the compilation artifacts.
|
|
# TARGET_NAME target - Target name for the command to build this crate.
|
|
# DEPENDS depends - List of dependencies of this crate.
|
|
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
|
|
#
|
|
# This function sets two variables:
|
|
#
|
|
# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies
|
|
# for other targets when you want them to depend on the
|
|
# output of this target.
|
|
#
|
|
# ${target_name}_ARTIFACTS - The actual files generated by this command.
|
|
# You'd use this as a set of files to install/copy elsewhere.
|
|
function(rust_crate_auto local_root_file)
|
|
cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTC_FLAGS" ${ARGN})
|
|
|
|
if(NOT OPT_TARGET_NAME)
|
|
set(OPT_TARGET_NAME CRATE)
|
|
endif()
|
|
|
|
if(OPT_ALL)
|
|
set(ALL_ARG "ALL")
|
|
else()
|
|
set(ALL_ARG "")
|
|
endif()
|
|
|
|
get_rust_deps(${local_root_file} crate_deps_list
|
|
OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS})
|
|
|
|
rust_crate("${local_root_file}"
|
|
${ALL_ARG}
|
|
TARGET_NAME "${OPT_TARGET_NAME}"
|
|
DESTINATION "${OPT_DESTINATION}"
|
|
DEPENDS "${crate_deps_list};${OPT_DEPENDS}"
|
|
OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS})
|
|
set("${OPT_TARGET_NAME}_ARTIFACTS" "${${OPT_TARGET_NAME}_ARTIFACTS}" PARENT_SCOPE)
|
|
set("${OPT_TARGET_NAME}_FULL_TARGET" "${${OPT_TARGET_NAME}_FULL_TARGET}" PARENT_SCOPE)
|
|
endfunction(rust_crate_auto)
|
|
|
|
# Like rust_crate, but this time it generates documentation using rust_doc.
|
|
#
|
|
# Optional arguments:
|
|
#
|
|
# ALL - Pass this to make this crate be built by default.
|
|
# DESTINATION dest - Where to place the compilation artifacts.
|
|
# TARGET_NAME target - Target name for the command to build this crate.
|
|
# DEPENDS depends - List of dependencies of this crate.
|
|
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
|
|
# OTHER_RUSTDOC_FLAGS flags - Other flags to pass to rustdoc.
|
|
#
|
|
# This function sets two variables:
|
|
#
|
|
# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies
|
|
# for other targets when you want them to depend on the
|
|
# output of this target.
|
|
#
|
|
# ${target_name}_ARTIFACTS - The actual files generated by this command.
|
|
# You'd use this as a set of files to install/copy elsewhere.
|
|
function(rust_doc local_root_file)
|
|
cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTDOC_FLAGS;OTHER_RUSTC_FLAGS" ${ARGN})
|
|
|
|
if(NOT OPT_TARGET_NAME)
|
|
set(OPT_TARGET_NAME DOC)
|
|
endif()
|
|
|
|
if(OPT_ALL)
|
|
set(ALL_ARG "ALL")
|
|
else()
|
|
set(ALL_ARG "")
|
|
endif()
|
|
|
|
set(root_file "${CMAKE_CURRENT_SOURCE_DIR}/${local_root_file}")
|
|
|
|
execute_process(COMMAND ${RUSTC_EXECUTABLE} ${RUSTC_FLAGS} ${OPT_OTHER_RUSTC_FLAGS} --print crate-name "${root_file}"
|
|
OUTPUT_VARIABLE crate_name
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
|
|
set(doc_dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}/${crate_name}")
|
|
set(src_dir "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}/src/${crate_name}")
|
|
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}")
|
|
|
|
add_custom_command(OUTPUT "${doc_dir}/index.html" "${doc_dir}" "${src_dir}"
|
|
COMMAND ${RUSTDOC_EXECUTABLE} ${RUSTDOC_FLAGS} ${OPT_OTHER_RUSTDOC_FLAGS} -o "${CMAKE_CURRENT_BINARY_DIR}/${OPT_DESTINATION}" "${root_file}"
|
|
DEPENDS ${crate_deps_list}
|
|
DEPENDS ${OPT_DEPENDS})
|
|
|
|
add_custom_target("${OPT_TARGET_NAME}"
|
|
${ALL_ARG}
|
|
DEPENDS "${doc_dir}/index.html")
|
|
|
|
set("${OPT_TARGET_NAME}_ARTIFACTS" "${doc_dir};${src_dir}" PARENT_SCOPE)
|
|
# CMake Bug #10082
|
|
set("${OPT_TARGET_NAME}_FULL_TARGET" "${OPT_TARGET_NAME};${doc_dir}/index.html" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Like rust_crate_auto, but this time it generates documentation using rust_doc.
|
|
#
|
|
# Optional arguments:
|
|
#
|
|
# ALL - Pass this to make this crate be built by default.
|
|
# DESTINATION dest - Where to place the compilation artifacts.
|
|
# TARGET_NAME target - Target name for the command to build this crate.
|
|
# DEPENDS depends - List of dependencies of this crate.
|
|
# OTHER_RUSTC_FLAGS flags - Other flags to pass to rustc.
|
|
# OTHER_RUSTDOC_FLAGS flags - Other flags to pass to rustdoc.
|
|
#
|
|
# This function sets two variables:
|
|
#
|
|
# ${target_name}_FULL_TARGET - This is what you would use as a set of dependencies
|
|
# for other targets when you want them to depend on the
|
|
# output of this target.
|
|
#
|
|
# ${target_name}_ARTIFACTS - The actual files generated by this command.
|
|
# You'd use this as a set of files to install/copy elsewhere.
|
|
function(rust_doc_auto local_root_file)
|
|
cmake_parse_arguments("OPT" "ALL" "DESTINATION;TARGET_NAME" "DEPENDS;OTHER_RUSTC_FLAGS;OTHER_RUSTDOC_FLAGS" ${ARGN})
|
|
|
|
if(NOT OPT_TARGET_NAME)
|
|
set(OPT_TARGET_NAME DOC)
|
|
endif()
|
|
|
|
if(OPT_ALL)
|
|
set(ALL_ARG "ALL")
|
|
else()
|
|
set(ALL_ARG "")
|
|
endif()
|
|
|
|
get_rust_deps(${local_root_file} crate_deps_list
|
|
OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS})
|
|
|
|
rust_doc("${local_root_file}"
|
|
${ALL_ARG}
|
|
TARGET_NAME "${OPT_TARGET_NAME}"
|
|
DESTINATION "${OPT_DESTINATION}"
|
|
DEPENDS "${crate_deps_list};${OPT_DEPENDS}"
|
|
OTHER_RUSTC_FLAGS ${OPT_OTHER_RUSTC_FLAGS}
|
|
OTHER_RUSTDOC_FLAGS ${OPT_OTHER_RUSTDOC_FLAGS})
|
|
set("${OPT_TARGET_NAME}_ARTIFACTS" "${${OPT_TARGET_NAME}_ARTIFACTS}" PARENT_SCOPE)
|
|
set("${OPT_TARGET_NAME}_FULL_TARGET" "${${OPT_TARGET_NAME}_FULL_TARGET}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Creates a dummy cargo project named ${name} to fetch crates.io dependencies.
|
|
# The package will be created in the ${CMAKE_CURRENT_BINARY_DIR}. Typically you
|
|
# would then pass "-L ${CMAKE_CURRENT_BINARY_DIR}/target/debug/deps" to rustc so
|
|
# it can pick up the dependencies.
|
|
#
|
|
# Optional arguments:
|
|
#
|
|
# OTHER_CARGO_FLAGS - Flags to pass to cargo.
|
|
# PACKAGE_NAMES - List of package names to fetch.
|
|
# PACKAGE_VERSIONS - List of package versions to fetch.
|
|
function(cargo_dependency name)
|
|
cmake_parse_arguments("OPT" "" "" "OTHER_CARGO_FLAGS;PACKAGE_NAMES;PACKAGE_VERSIONS" ${ARGN})
|
|
|
|
list(LENGTH OPT_PACKAGE_NAMES num_packages)
|
|
list(LENGTH OPT_PACKAGE_VERSIONS num_versions)
|
|
message(STATUS "" ${OPT_PACKAGE_NAMES} " : " ${OPT_PACKAGE_VERSIONS})
|
|
|
|
if(NOT ${num_packages} EQUAL ${num_versions})
|
|
message(FATAL_ERROR "Number of cargo packages doesn't match the number of cargo versions.")
|
|
endif()
|
|
|
|
set(cargo_dependency_dir "${CMAKE_CURRENT_BINARY_DIR}/${name}")
|
|
file(MAKE_DIRECTORY "${cargo_dependency_dir}")
|
|
file(MAKE_DIRECTORY "${cargo_dependency_dir}/src")
|
|
|
|
set(CARGO_TOML [package] \n name = \"cargo_deps_fetcher\" \n version = \"0.0.0\" \n authors = [\"none\"] \n)
|
|
|
|
math(EXPR num_packages "${num_packages} - 1")
|
|
foreach(pkg_idx RANGE 0 ${num_packages})
|
|
list(GET OPT_PACKAGE_NAMES ${pkg_idx} pkg_name)
|
|
list(GET OPT_PACKAGE_VERSIONS ${pkg_idx} pkg_version)
|
|
set(CARGO_TOML ${CARGO_TOML} \n [dependencies.${pkg_name}] \n version = \"${pkg_version}\" \n)
|
|
endforeach()
|
|
|
|
file(WRITE "${cargo_dependency_dir}/Cargo.toml" ${CARGO_TOML})
|
|
file(WRITE "${cargo_dependency_dir}/src/lib.rs" "")
|
|
|
|
execute_process(COMMAND ${CARGO_EXECUTABLE} build ${CARGO_FLAGS} ${OPT_OTHER_CARGO_FLAGS}
|
|
WORKING_DIRECTORY ${cargo_dependency_dir})
|
|
endfunction()
|