cmake_minimum_required(VERSION 3.20) project(sov_rtx LANGUAGES C) option(SOV_BUILD_CUDA "Enable PTX validation targets" ON) if(WIN32 AND CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") set(SOV_ZERO_LIBC_DEFAULT ON) else() set(SOV_ZERO_LIBC_DEFAULT OFF) endif() option(SOV_ZERO_LIBC "Build the supported GNU/Clang zero-CRT Windows entry point" ${SOV_ZERO_LIBC_DEFAULT}) option(SOV_BUILD_FORTRAN_REFERENCE "Build the optional Fortran 2018 transformer reference" OFF) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) set(SOV_PTX_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/cuda") set(SOV_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") set(SOV_PTX_BLOB_SOURCE "${SOV_GENERATED_DIR}/sov_ptx_blobs.c") file(MAKE_DIRECTORY "${SOV_GENERATED_DIR}") # Convert PTX bytes to a C array at configure time. The final zero byte is # included in both the array and *_len so every loader can validate the # complete bounded text-image contract before calling cuModuleLoadData. function(sov_ptx_to_c_source input_path symbol output_variable) if(NOT EXISTS "${input_path}") message(FATAL_ERROR "Required PTX source is missing: ${input_path}") endif() set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${input_path}") file(READ "${input_path}" ptx_text) if(ARGC GREATER 3) string(REGEX REPLACE "\\.target[ \t]+sm_[0-9]+" ".target ${ARGV3}" ptx_text "${ptx_text}") endif() string(HEX "${ptx_text}" ptx_hex) string(LENGTH "${ptx_hex}" ptx_hex_length) if(ptx_hex_length EQUAL 0) message(FATAL_ERROR "PTX source is empty: ${input_path}") endif() math(EXPR ptx_byte_count "${ptx_hex_length} / 2") math(EXPR ptx_buffer_size "${ptx_byte_count} + 1") math(EXPR ptx_last_offset "${ptx_hex_length} - 2") set(generated_text "const unsigned char ${symbol}[] = {\n ") set(bytes_on_line 0) foreach(offset RANGE 0 ${ptx_last_offset} 2) string(SUBSTRING "${ptx_hex}" ${offset} 2 byte_hex) string(APPEND generated_text "0x${byte_hex},") math(EXPR bytes_on_line "${bytes_on_line} + 1") if(bytes_on_line EQUAL 16) string(APPEND generated_text "\n ") set(bytes_on_line 0) endif() endforeach() string(APPEND generated_text "0x00\n};\n" "const unsigned int ${symbol}_len = ${ptx_buffer_size}u;\n") set(${output_variable} "${generated_text}" PARENT_SCOPE) endfunction() sov_ptx_to_c_source("${SOV_PTX_DIR}/flash_attention.ptx" flash_attention_ptx flash_ptx_source) sov_ptx_to_c_source("${SOV_PTX_DIR}/gemm.ptx" gemm_ptx gemm_ptx_source) file(WRITE "${SOV_PTX_BLOB_SOURCE}" "/* Generated by CMake. Do not edit. */\n" "${flash_ptx_source}\n" "${gemm_ptx_source}\n") add_library(sov_rtx STATIC src/loader/gguf.c src/kv_allocator.c src/sampler.c src/cuda_validation_chain.c src/rowm_cuda_validation.c src/cuda_gemm_dispatch.c src/cuda_kernels.c windows_rtx/cuda_driver_loader.c windows_rtx/power_handler.c "${SOV_PTX_BLOB_SOURCE}" ) target_include_directories(sov_rtx PUBLIC include PRIVATE src) if(SOV_BUILD_FORTRAN_REFERENCE) enable_language(Fortran) add_library(sov_rtx_fortran_reference STATIC src/fortran/transformer_kernel.f90) set_property(TARGET sov_rtx_fortran_reference PROPERTY Fortran_STANDARD 2018) set_property(TARGET sov_rtx_fortran_reference PROPERTY Fortran_STANDARD_REQUIRED ON) endif() if(SOV_ZERO_LIBC) if(NOT WIN32) message(FATAL_ERROR "SOV_ZERO_LIBC is supported only on Windows") endif() if(MSVC OR NOT CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") message(FATAL_ERROR "SOV_ZERO_LIBC currently requires GNU or Clang because main.c " "uses that compiler family's x86-64 inline assembly") endif() target_compile_options(sov_rtx PRIVATE -ffreestanding -fno-builtin -fno-stack-protector) add_executable(sov_main windows_rtx/main.c) target_link_libraries(sov_main PRIVATE sov_rtx) target_compile_options(sov_main PRIVATE -ffreestanding -fno-builtin -fno-stack-protector) target_link_options(sov_main PRIVATE -nostdlib -Wl,--entry=sov_main) add_executable(sov_gguf_zero_crt_link_smoke tests/gguf_zero_crt_link_smoke.c) target_link_libraries(sov_gguf_zero_crt_link_smoke PRIVATE sov_rtx kernel32) target_compile_options(sov_gguf_zero_crt_link_smoke PRIVATE -ffreestanding -fno-builtin -fno-stack-protector) target_link_options(sov_gguf_zero_crt_link_smoke PRIVATE -nostdlib -Wl,--entry=sov_main) endif() if(SOV_BUILD_CUDA) find_program(PTXAS_EXECUTABLE NAMES ptxas) if(PTXAS_EXECUTABLE) set(flash_cubin "${SOV_GENERATED_DIR}/flash_attention.cubin") set(gemm_cubin "${SOV_GENERATED_DIR}/gemm.cubin") add_custom_command(OUTPUT "${flash_cubin}" COMMAND "${PTXAS_EXECUTABLE}" -arch=sm_89 "${SOV_PTX_DIR}/flash_attention.ptx" -o "${flash_cubin}" DEPENDS "${SOV_PTX_DIR}/flash_attention.ptx" VERBATIM COMMENT "Validating flash_attention.ptx for sm_89") add_custom_command(OUTPUT "${gemm_cubin}" COMMAND "${PTXAS_EXECUTABLE}" -arch=sm_89 "${SOV_PTX_DIR}/gemm.ptx" -o "${gemm_cubin}" DEPENDS "${SOV_PTX_DIR}/gemm.ptx" VERBATIM COMMENT "Validating gemm.ptx for sm_89") add_custom_target(validate_ptx DEPENDS "${flash_cubin}" "${gemm_cubin}") else() add_custom_target(validate_ptx COMMAND "${CMAKE_COMMAND}" -E echo "ptxas not found; cuModuleLoadData will validate PTX at runtime" VERBATIM) endif() endif() include(CTest) if(BUILD_TESTING) add_executable(sov_rtx_host_tests tests/test_kv_sampler_host.c src/kv_allocator.c src/sampler.c) target_include_directories(sov_rtx_host_tests BEFORE PRIVATE tests/host_include) target_include_directories(sov_rtx_host_tests PRIVATE include src) add_test(NAME sov_rtx_host_tests COMMAND sov_rtx_host_tests) add_executable(sov_gguf_host_tests tests/test_gguf_host.c src/loader/gguf.c) target_include_directories(sov_gguf_host_tests PRIVATE include) add_test(NAME sov_gguf_host_tests COMMAND sov_gguf_host_tests) add_executable(sov_cuda_validation_chain_host_tests tests/test_cuda_validation_chain_host.c src/cuda_validation_chain.c) target_include_directories(sov_cuda_validation_chain_host_tests PRIVATE include) add_test(NAME sov_cuda_validation_chain_host_tests COMMAND sov_cuda_validation_chain_host_tests) add_executable(sov_cuda_kernels_host_tests tests/test_cuda_kernels_host.c src/cuda_validation_chain.c src/cuda_kernels.c) target_include_directories(sov_cuda_kernels_host_tests BEFORE PRIVATE tests/host_include) target_include_directories(sov_cuda_kernels_host_tests PRIVATE include src) add_test(NAME sov_cuda_kernels_host_tests COMMAND sov_cuda_kernels_host_tests) if(WIN32) set(SOV_CUDA_SM86_SOURCE "${SOV_GENERATED_DIR}/sov_cuda_sm86.c") sov_ptx_to_c_source("${SOV_PTX_DIR}/flash_attention.ptx" flash_attention_ptx flash_sm86 sm_86) sov_ptx_to_c_source("${SOV_PTX_DIR}/gemm.ptx" gemm_ptx gemm_sm86 sm_86) file(WRITE "${SOV_CUDA_SM86_SOURCE}" "/* Generated test-only sm_86 PTX blobs. */\n" "${flash_sm86}\n" "${gemm_sm86}\n") add_executable(sov_cuda_reference_gpu_test tests/test_cuda_reference_gpu.c src/kv_allocator.c src/cuda_validation_chain.c src/rowm_cuda_validation.c src/cuda_gemm_dispatch.c src/cuda_kernels.c windows_rtx/cuda_driver_loader.c "${SOV_CUDA_SM86_SOURCE}") target_include_directories(sov_cuda_reference_gpu_test PRIVATE include src) target_compile_definitions(sov_cuda_reference_gpu_test PRIVATE SOV_CUDA_COMPILED_PTX_TARGET=86) if(NOT MSVC) target_link_libraries(sov_cuda_reference_gpu_test PRIVATE m) endif() add_test(NAME sov_cuda_reference_gpu_test COMMAND sov_cuda_reference_gpu_test) set_tests_properties(sov_cuda_reference_gpu_test PROPERTIES LABELS gpu SKIP_RETURN_CODE 77) endif() endif() add_custom_target(cmm_info COMMAND "${CMAKE_COMMAND}" -E echo "C-- scheduler: src/c--/scheduler.cmm (GHC C-- backend)" VERBATIM)