cmake_minimum_required(VERSION 3.20)
project(rslibc LANGUAGES NONE)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

find_program(RUSTC rustc REQUIRED)

set(RUST_MACRO_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/macros/src/lib.rs")
set(RUST_MACRO "${CMAKE_CURRENT_BINARY_DIR}/rslibc_macros${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(RUST_LIBRARY_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/src/lib.rs")
set(RUST_RUNTIME_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/runtime/main.rs")
set(RUST_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/librslibc.rlib")
set(RUST_BINARY "${CMAKE_CURRENT_BINARY_DIR}/rslibc_example${CMAKE_EXECUTABLE_SUFFIX}")

set(RUSTC_FLAGS --edition=2021 -C panic=abort)

# CMAKE_BUILD_TYPE does not automatically affect a custom rustc command.
# Pass the corresponding optimization/debug-info settings explicitly.
if (CMAKE_BUILD_TYPE STREQUAL "Release")
    list(APPEND RUSTC_FLAGS -C opt-level=3 -C debuginfo=0)
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
    list(APPEND RUSTC_FLAGS -C opt-level=3 -C debuginfo=2)
else()
    list(APPEND RUSTC_FLAGS -C opt-level=0 -C debuginfo=2)
endif()

# A no_std binary does not get Rust's normal startup or allocator setup.
# Use the OS heap and dynamically link only the small platform libraries
# needed by this runtime.
if (WIN32)
    set(RUSTC_LINK_ARGS
        -l kernel32
        -l vcruntime
        -C
        "link-args=/ENTRY:mainCRTStartup /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF"
    )
elseif (UNIX)
    set(RUSTC_LINK_ARGS -C "link-args=-lc")
endif()

add_custom_command(
    OUTPUT "${RUST_MACRO}"
    COMMAND "${RUSTC}"
            "${RUST_MACRO_SOURCE}"
            --crate-name rslibc_macros
            --crate-type proc-macro
            -o "${RUST_MACRO}"
            --edition=2021
            -C opt-level=3
    DEPENDS "${RUST_MACRO_SOURCE}"
    VERBATIM
)

add_custom_command(
    OUTPUT "${RUST_LIBRARY}"
    COMMAND "${RUSTC}"
            "${RUST_LIBRARY_SOURCE}"
            --crate-name rslibc
            --crate-type rlib
            -o "${RUST_LIBRARY}"
            ${RUSTC_FLAGS}
    DEPENDS
            "${RUST_LIBRARY_SOURCE}"
            "${CMAKE_CURRENT_SOURCE_DIR}/src/io.rs"
            "${CMAKE_CURRENT_SOURCE_DIR}/src/runtime.rs"
    VERBATIM
)

add_custom_command(
    OUTPUT "${RUST_BINARY}"
    COMMAND "${RUSTC}"
            "${RUST_RUNTIME_SOURCE}"
            --crate-name rslibc_example
            --crate-type bin
            --extern "rslibc=${RUST_LIBRARY}"
            --extern "rslibc_macros=${RUST_MACRO}"
            -o "${RUST_BINARY}"
            ${RUSTC_FLAGS}
            ${RUSTC_LINK_ARGS}
    DEPENDS "${RUST_RUNTIME_SOURCE}" "${RUST_LIBRARY}" "${RUST_MACRO}"
    VERBATIM
)

add_custom_target(rslibc_macros DEPENDS "${RUST_MACRO}")
add_custom_target(rslibc_library DEPENDS "${RUST_LIBRARY}")
add_custom_target(rslibc_example ALL DEPENDS "${RUST_BINARY}")
