set(SPRIV_TOOLS_DIR ""
    CACHE
    PATH
    "Absolute path to the directory containing the SPIR-V tools to use")

find_package(Python3 COMPONENTS Interpreter QUIET)

find_program(SPIRV_ASSEMBLER
    NAMES spirv-as
    HINTS ${SPIRV_TOOLS_DIR})

find_program(SPIRV_VALIDATOR
    NAMES spirv-val
    HINTS ${SPIRV_TOOLS_DIR})

if (Python3_FOUND AND
    NOT ${SPIRV_ASSEMBLER} STREQUAL "SPIRV_ASSEMBLER-NOTFOUND" AND
    NOT ${SPIRV_VALIDATOR} STREQUAL "SPIRV_VALIDATOR-NOTFOUND")
    message(STATUS "Using python3: ${Python3_EXECUTABLE}")
    message(STATUS "Using spirv-as: ${SPIRV_ASSEMBLER}")
    message(STATUS "Using spirv-val: ${SPIRV_VALIDATOR}")
else()
    message(STATUS "Skipping automatic build of SPIR-V files for spirv_new")
    # Empty custom target
    add_custom_target(spirv_new_binaries)
    return()
endif()

set(spirv_sources
    assume.spvasm32
    assume.spvasm64
    atomic_dec_global.spvasm32
    atomic_dec_global.spvasm64
    atomic_inc_global.spvasm32
    atomic_inc_global.spvasm64
    basic.spvasm32
    basic.spvasm64
    branch_conditional.spvasm32
    branch_conditional.spvasm64
    branch_conditional_weighted.spvasm32
    branch_conditional_weighted.spvasm64
    branch_simple.spvasm32
    branch_simple.spvasm64
    composite_construct_int4.spvasm32
    composite_construct_int4.spvasm64
    composite_construct_struct.spvasm32
    composite_construct_struct.spvasm64
    constant_char_simple.spvasm32
    constant_char_simple.spvasm64
    constant_double_simple.spvasm32
    constant_double_simple.spvasm64
    constant_false_simple.spvasm32
    constant_false_simple.spvasm64
    constant_float_simple.spvasm32
    constant_float_simple.spvasm64
    constant_half_simple.spvasm32
    constant_half_simple.spvasm64
    constant_int3_simple.spvasm32
    constant_int3_simple.spvasm64
    constant_int4_simple.spvasm32
    constant_int4_simple.spvasm64
    constant_int_simple.spvasm32
    constant_int_simple.spvasm64
    constant_long_simple.spvasm32
    constant_long_simple.spvasm64
    constant_short_simple.spvasm32
    constant_short_simple.spvasm64
    constant_struct_int_char_simple.spvasm32
    constant_struct_int_char_simple.spvasm64
    constant_struct_int_float_simple.spvasm32
    constant_struct_int_float_simple.spvasm64
    constant_struct_struct_simple.spvasm32
    constant_struct_struct_simple.spvasm64
    constant_true_simple.spvasm32
    constant_true_simple.spvasm64
    constant_uchar_simple.spvasm32
    constant_uchar_simple.spvasm64
    constant_uint_simple.spvasm32
    constant_uint_simple.spvasm64
    constant_ulong_simple.spvasm32
    constant_ulong_simple.spvasm64
    constant_ushort_simple.spvasm32
    constant_ushort_simple.spvasm64
    copy_char_simple.spvasm32
    copy_char_simple.spvasm64
    copy_double_simple.spvasm32
    copy_double_simple.spvasm64
    copy_float_simple.spvasm32
    copy_float_simple.spvasm64
    copy_half_simple.spvasm32
    copy_half_simple.spvasm64
    copy_int3_simple.spvasm32
    copy_int3_simple.spvasm64
    copy_int4_simple.spvasm32
    copy_int4_simple.spvasm64
    copy_int_simple.spvasm32
    copy_int_simple.spvasm64
    copy_long_simple.spvasm32
    copy_long_simple.spvasm64
    copy_short_simple.spvasm32
    copy_short_simple.spvasm64
    copy_struct_int_char_simple.spvasm32
    copy_struct_int_char_simple.spvasm64
    copy_struct_int_float_simple.spvasm32
    copy_struct_int_float_simple.spvasm64
    copy_struct_struct_simple.spvasm32
    copy_struct_struct_simple.spvasm64
    copy_uchar_simple.spvasm32
    copy_uchar_simple.spvasm64
    copy_uint_simple.spvasm32
    copy_uint_simple.spvasm64
    copy_ulong_simple.spvasm32
    copy_ulong_simple.spvasm64
    copy_ushort_simple.spvasm32
    copy_ushort_simple.spvasm64
    decorate_aliased.spvasm32
    decorate_aliased.spvasm64
    decorate_alignment.spvasm32
    decorate_alignment.spvasm64
    decorate_constant.spvasm32
    decorate_constant.spvasm64
    decorate_constant_fail.spvasm32
    decorate_constant_fail.spvasm64
    decorate_cpacked.spvasm32
    decorate_cpacked.spvasm64
    decorate_restrict.spvasm32
    decorate_restrict.spvasm64
    decorate_rounding_rte_double_long.spvasm32
    decorate_rounding_rte_double_long.spvasm64
    decorate_rounding_rte_float_int.spvasm32
    decorate_rounding_rte_float_int.spvasm64
    decorate_rounding_rte_half_short.spvasm32
    decorate_rounding_rte_half_short.spvasm64
    decorate_rounding_rtn_double_long.spvasm32
    decorate_rounding_rtn_double_long.spvasm64
    decorate_rounding_rtn_float_int.spvasm32
    decorate_rounding_rtn_float_int.spvasm64
    decorate_rounding_rtn_half_short.spvasm32
    decorate_rounding_rtn_half_short.spvasm64
    decorate_rounding_rtp_double_long.spvasm32
    decorate_rounding_rtp_double_long.spvasm64
    decorate_rounding_rtp_float_int.spvasm32
    decorate_rounding_rtp_float_int.spvasm64
    decorate_rounding_rtp_half_short.spvasm32
    decorate_rounding_rtp_half_short.spvasm64
    decorate_rounding_rtz_double_long.spvasm32
    decorate_rounding_rtz_double_long.spvasm64
    decorate_rounding_rtz_float_int.spvasm32
    decorate_rounding_rtz_float_int.spvasm64
    decorate_rounding_rtz_half_short.spvasm32
    decorate_rounding_rtz_half_short.spvasm64
    decorate_saturated_conversion_double_to_int.spvasm32
    decorate_saturated_conversion_double_to_int.spvasm64
    decorate_saturated_conversion_double_to_uint.spvasm32
    decorate_saturated_conversion_double_to_uint.spvasm64
    decorate_saturated_conversion_float_to_char.spvasm32
    decorate_saturated_conversion_float_to_char.spvasm64
    decorate_saturated_conversion_float_to_short.spvasm32
    decorate_saturated_conversion_float_to_short.spvasm64
    decorate_saturated_conversion_float_to_uchar.spvasm32
    decorate_saturated_conversion_float_to_uchar.spvasm64
    decorate_saturated_conversion_float_to_ushort.spvasm32
    decorate_saturated_conversion_float_to_ushort.spvasm64
    decorate_saturated_conversion_half_to_char.spvasm32
    decorate_saturated_conversion_half_to_char.spvasm64
    decorate_saturated_conversion_half_to_uchar.spvasm32
    decorate_saturated_conversion_half_to_uchar.spvasm64
    expect_bool.spvasm32
    expect_bool.spvasm64
    expect_char.spvasm32
    expect_char.spvasm64
    expect_int.spvasm32
    expect_int.spvasm64
    expect_long.spvasm32
    expect_long.spvasm64
    expect_short.spvasm32
    expect_short.spvasm64
    ext_cl_khr_spirv_no_integer_wrap_decoration_fadd_int.spvasm32
    ext_cl_khr_spirv_no_integer_wrap_decoration_fadd_int.spvasm64
    ext_cl_khr_spirv_no_integer_wrap_decoration_fadd_uint.spvasm32
    ext_cl_khr_spirv_no_integer_wrap_decoration_fadd_uint.spvasm64
    ext_cl_khr_spirv_no_integer_wrap_decoration_fmul_int.spvasm32
    ext_cl_khr_spirv_no_integer_wrap_decoration_fmul_int.spvasm64
    ext_cl_khr_spirv_no_integer_wrap_decoration_fmul_uint.spvasm32
    ext_cl_khr_spirv_no_integer_wrap_decoration_fmul_uint.spvasm64
    ext_cl_khr_spirv_no_integer_wrap_decoration_fnegate_int.spvasm32
    ext_cl_khr_spirv_no_integer_wrap_decoration_fnegate_int.spvasm64
    ext_cl_khr_spirv_no_integer_wrap_decoration_fshiftleft_int.spvasm32
    ext_cl_khr_spirv_no_integer_wrap_decoration_fshiftleft_int.spvasm64
    ext_cl_khr_spirv_no_integer_wrap_decoration_fshiftleft_uint.spvasm32
    ext_cl_khr_spirv_no_integer_wrap_decoration_fshiftleft_uint.spvasm64
    ext_cl_khr_spirv_no_integer_wrap_decoration_fsub_int.spvasm32
    ext_cl_khr_spirv_no_integer_wrap_decoration_fsub_int.spvasm64
    ext_cl_khr_spirv_no_integer_wrap_decoration_fsub_uint.spvasm32
    ext_cl_khr_spirv_no_integer_wrap_decoration_fsub_uint.spvasm64
    fadd_double.spvasm32
    fadd_double.spvasm64
    fadd_double2.spvasm32
    fadd_double2.spvasm64
    fadd_float.spvasm32
    fadd_float.spvasm64
    fadd_float4.spvasm32
    fadd_float4.spvasm64
    fadd_half.spvasm32
    fadd_half.spvasm64
    fdiv_double.spvasm32
    fdiv_double.spvasm64
    fdiv_double2.spvasm32
    fdiv_double2.spvasm64
    fdiv_float.spvasm32
    fdiv_float.spvasm64
    fdiv_float4.spvasm32
    fdiv_float4.spvasm64
    fdiv_half.spvasm32
    fdiv_half.spvasm64
    fmod_double.spvasm32
    fmod_double.spvasm64
    fmod_double2.spvasm32
    fmod_double2.spvasm64
    fmod_float.spvasm32
    fmod_float.spvasm64
    fmod_float4.spvasm32
    fmod_float4.spvasm64
    fmod_half.spvasm32
    fmod_half.spvasm64
    fmul_double.spvasm32
    fmul_double.spvasm64
    fmul_double2.spvasm32
    fmul_double2.spvasm64
    fmul_float.spvasm32
    fmul_float.spvasm64
    fmul_float4.spvasm32
    fmul_float4.spvasm64
    fmul_half.spvasm32
    fmul_half.spvasm64
    frem_double.spvasm32
    frem_double.spvasm64
    frem_double2.spvasm32
    frem_double2.spvasm64
    frem_float.spvasm32
    frem_float.spvasm64
    frem_float4.spvasm32
    frem_float4.spvasm64
    frem_half.spvasm32
    frem_half.spvasm64
    fsub_double.spvasm32
    fsub_double.spvasm64
    fsub_double2.spvasm32
    fsub_double2.spvasm64
    fsub_float.spvasm32
    fsub_float.spvasm64
    fsub_float4.spvasm32
    fsub_float4.spvasm64
    fsub_half.spvasm32
    fsub_half.spvasm64
    label_simple.spvasm32
    label_simple.spvasm64
    lifetime_simple.spvasm32
    lifetime_simple.spvasm64
    linkage_export.spvasm32
    linkage_export.spvasm64
    linkage_import.spvasm32
    linkage_import.spvasm64
    linkage_linkonce_odr_main.spvasm32
    linkage_linkonce_odr_main.spvasm64
    linkage_linkonce_odr_noa_main.spvasm32
    linkage_linkonce_odr_noa_main.spvasm64
    linkage_linkonce_odr_obj.spvasm32
    linkage_linkonce_odr_obj.spvasm64
    loop_merge_branch_conditional_dont_unroll.spvasm32
    loop_merge_branch_conditional_dont_unroll.spvasm64
    loop_merge_branch_conditional_none.spvasm32
    loop_merge_branch_conditional_none.spvasm64
    loop_merge_branch_conditional_unroll.spvasm32
    loop_merge_branch_conditional_unroll.spvasm64
    loop_merge_branch_dont_unroll.spvasm32
    loop_merge_branch_dont_unroll.spvasm64
    loop_merge_branch_none.spvasm32
    loop_merge_branch_none.spvasm64
    loop_merge_branch_unroll.spvasm32
    loop_merge_branch_unroll.spvasm64
    op_function_const.spvasm32
    op_function_const.spvasm64
    op_function_inline.spvasm32
    op_function_inline.spvasm64
    op_function_noinline.spvasm32
    op_function_noinline.spvasm64
    op_function_none.spvasm32
    op_function_none.spvasm64
    op_function_pure.spvasm32
    op_function_pure.spvasm64
    op_function_pure_ptr.spvasm32
    op_function_pure_ptr.spvasm64
    op_neg_double.spvasm32
    op_neg_double.spvasm64
    op_neg_float.spvasm32
    op_neg_float.spvasm64
    op_neg_float4.spvasm32
    op_neg_float4.spvasm64
    op_neg_half.spvasm32
    op_neg_half.spvasm64
    op_neg_int.spvasm32
    op_neg_int.spvasm64
    op_neg_int4.spvasm32
    op_neg_int4.spvasm64
    op_neg_long.spvasm32
    op_neg_long.spvasm64
    op_neg_short.spvasm32
    op_neg_short.spvasm64
    op_not_int.spvasm32
    op_not_int.spvasm64
    op_not_int4.spvasm32
    op_not_int4.spvasm64
    op_not_long.spvasm32
    op_not_long.spvasm64
    op_not_short.spvasm32
    op_not_short.spvasm64
    op_spec_constant_double_simple.spvasm32
    op_spec_constant_double_simple.spvasm64
    op_spec_constant_false_simple.spvasm32
    op_spec_constant_false_simple.spvasm64
    op_spec_constant_float_simple.spvasm32
    op_spec_constant_float_simple.spvasm64
    op_spec_constant_half_simple.spvasm32
    op_spec_constant_half_simple.spvasm64
    op_spec_constant_true_simple.spvasm32
    op_spec_constant_true_simple.spvasm64
    op_spec_constant_uchar_simple.spvasm32
    op_spec_constant_uchar_simple.spvasm64
    op_spec_constant_uint_simple.spvasm32
    op_spec_constant_uint_simple.spvasm64
    op_spec_constant_ulong_simple.spvasm32
    op_spec_constant_ulong_simple.spvasm64
    op_spec_constant_ushort_simple.spvasm32
    op_spec_constant_ushort_simple.spvasm64
    opaque.spvasm32
    opaque.spvasm64
    phi_2.spvasm32
    phi_2.spvasm64
    phi_3.spvasm32
    phi_3.spvasm64
    phi_4.spvasm32
    phi_4.spvasm64
    select_if_dont_flatten.spvasm32
    select_if_dont_flatten.spvasm64
    select_if_flatten.spvasm32
    select_if_flatten.spvasm64
    select_if_none.spvasm32
    select_if_none.spvasm64
    select_switch_dont_flatten.spvasm32
    select_switch_dont_flatten.spvasm64
    select_switch_flatten.spvasm32
    select_switch_flatten.spvasm64
    select_switch_none.spvasm32
    select_switch_none.spvasm64
    spv1.1/basic.spvasm32
    spv1.1/basic.spvasm64
    spv1.2/basic.spvasm32
    spv1.2/basic.spvasm64
    spv1.3/basic.spvasm32
    spv1.3/basic.spvasm64
    spv1.4/basic.spvasm32
    spv1.4/basic.spvasm64
    spv1.4/copylogical_struct.spvasm32
    spv1.4/copylogical_struct.spvasm64
    spv1.4/copymemory_memory_operands.spvasm32
    spv1.4/copymemory_memory_operands.spvasm64
    spv1.4/image_operand_signextend.spvasm32
    spv1.4/image_operand_signextend.spvasm64
    spv1.4/image_operand_zeroextend.spvasm32
    spv1.4/image_operand_zeroextend.spvasm64
    spv1.4/loop_control_iterationmultiple.spvasm32
    spv1.4/loop_control_iterationmultiple.spvasm64
    spv1.4/loop_control_maxiterations.spvasm32
    spv1.4/loop_control_maxiterations.spvasm64
    spv1.4/loop_control_miniterations.spvasm32
    spv1.4/loop_control_miniterations.spvasm64
    spv1.4/loop_control_partialcount.spvasm32
    spv1.4/loop_control_partialcount.spvasm64
    spv1.4/loop_control_peelcount.spvasm32
    spv1.4/loop_control_peelcount.spvasm64
    spv1.4/no_integer_wrap_decoration_fadd_int.spvasm32
    spv1.4/no_integer_wrap_decoration_fadd_int.spvasm64
    spv1.4/no_integer_wrap_decoration_fadd_uint.spvasm32
    spv1.4/no_integer_wrap_decoration_fadd_uint.spvasm64
    spv1.4/no_integer_wrap_decoration_fmul_int.spvasm32
    spv1.4/no_integer_wrap_decoration_fmul_int.spvasm64
    spv1.4/no_integer_wrap_decoration_fmul_uint.spvasm32
    spv1.4/no_integer_wrap_decoration_fmul_uint.spvasm64
    spv1.4/no_integer_wrap_decoration_fnegate_int.spvasm32
    spv1.4/no_integer_wrap_decoration_fnegate_int.spvasm64
    spv1.4/no_integer_wrap_decoration_fshiftleft_int.spvasm32
    spv1.4/no_integer_wrap_decoration_fshiftleft_int.spvasm64
    spv1.4/no_integer_wrap_decoration_fshiftleft_uint.spvasm32
    spv1.4/no_integer_wrap_decoration_fshiftleft_uint.spvasm64
    spv1.4/no_integer_wrap_decoration_fsub_int.spvasm32
    spv1.4/no_integer_wrap_decoration_fsub_int.spvasm64
    spv1.4/no_integer_wrap_decoration_fsub_uint.spvasm32
    spv1.4/no_integer_wrap_decoration_fsub_uint.spvasm64
    spv1.4/nonwriteable_decoration_function_storage_class.spvasm32
    spv1.4/nonwriteable_decoration_function_storage_class.spvasm64
    spv1.4/ptrops.spvasm32
    spv1.4/ptrops.spvasm64
    spv1.4/select_struct.spvasm32
    spv1.4/select_struct.spvasm64
    spv1.4/usersemantic_decoratestring.spvasm32
    spv1.4/usersemantic_decoratestring.spvasm64
    spv1.4/usersemantic_memberdecoratestring.spvasm32
    spv1.4/usersemantic_memberdecoratestring.spvasm64
    spv1.5/basic.spvasm32
    spv1.5/basic.spvasm64
    spv1.6/basic.spvasm32
    spv1.6/basic.spvasm64
    spv1.6/image_operand_nontemporal.spvasm32
    spv1.6/image_operand_nontemporal.spvasm64
    spv1.6/uniformdecoration_uniformid.spvasm32
    spv1.6/uniformdecoration_uniformid.spvasm64
    spv1.6/uniformdecoration_uniform.spvasm32
    spv1.6/uniformdecoration_uniform.spvasm64
    undef_char_simple.spvasm32
    undef_char_simple.spvasm64
    undef_double_simple.spvasm32
    undef_double_simple.spvasm64
    undef_false_simple.spvasm32
    undef_false_simple.spvasm64
    undef_float_simple.spvasm32
    undef_float_simple.spvasm64
    undef_half_simple.spvasm32
    undef_half_simple.spvasm64
    undef_int3_simple.spvasm32
    undef_int3_simple.spvasm64
    undef_int4_simple.spvasm32
    undef_int4_simple.spvasm64
    undef_int_simple.spvasm32
    undef_int_simple.spvasm64
    undef_long_simple.spvasm32
    undef_long_simple.spvasm64
    undef_short_simple.spvasm32
    undef_short_simple.spvasm64
    undef_struct_int_char_simple.spvasm32
    undef_struct_int_char_simple.spvasm64
    undef_struct_int_float_simple.spvasm32
    undef_struct_int_float_simple.spvasm64
    undef_struct_struct_simple.spvasm32
    undef_struct_struct_simple.spvasm64
    undef_true_simple.spvasm32
    undef_true_simple.spvasm64
    undef_uchar_simple.spvasm32
    undef_uchar_simple.spvasm64
    undef_uint_simple.spvasm32
    undef_uint_simple.spvasm64
    undef_ulong_simple.spvasm32
    undef_ulong_simple.spvasm64
    undef_ushort_simple.spvasm32
    undef_ushort_simple.spvasm64
    unreachable_simple.spvasm32
    unreachable_simple.spvasm64
    vector_char16_extract.spvasm32
    vector_char16_extract.spvasm64
    vector_char16_insert.spvasm32
    vector_char16_insert.spvasm64
    vector_double2_extract.spvasm32
    vector_double2_extract.spvasm64
    vector_double2_insert.spvasm32
    vector_double2_insert.spvasm64
    vector_float4_extract.spvasm32
    vector_float4_extract.spvasm64
    vector_float4_insert.spvasm32
    vector_float4_insert.spvasm64
    vector_half8_extract.spvasm32
    vector_half8_extract.spvasm64
    vector_half8_insert.spvasm32
    vector_half8_insert.spvasm64
    vector_int4_extract.spvasm32
    vector_int4_extract.spvasm64
    vector_int4_insert.spvasm32
    vector_int4_insert.spvasm64
    vector_long2_extract.spvasm32
    vector_long2_extract.spvasm64
    vector_long2_insert.spvasm32
    vector_long2_insert.spvasm64
    vector_times_scalar_double.spvasm32
    vector_times_scalar_double.spvasm64
    vector_times_scalar_float.spvasm32
    vector_times_scalar_float.spvasm64
    vector_times_scalar_half.spvasm32
    vector_times_scalar_half.spvasm64)

set(assembled_spirv_binaries "")
foreach(spirv_source ${spirv_sources})
    string(REPLACE ".spvasm" ".spv" assembled_spirv_binary ${spirv_source})
    set(assembled_spirv_binary "${CMAKE_CURRENT_BINARY_DIR}/../spirv_bin/${assembled_spirv_binary}")
    list(APPEND assembled_spirv_binaries ${assembled_spirv_binary})
endforeach()

add_custom_command(
    OUTPUT ${assembled_spirv_binaries}
    COMMENT "Generating SPIR-V binaries..."
    COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/assemble_spirv.py
            --source-dir "${CMAKE_CURRENT_SOURCE_DIR}"
            --output-dir "${CMAKE_CURRENT_BINARY_DIR}/../spirv_bin"
            --assembler "${SPIRV_ASSEMBLER}"
            --validator "${SPIRV_VALIDATOR}"
    DEPENDS assemble_spirv.py ${spirv_sources}
    USES_TERMINAL
    VERBATIM)

add_custom_target(spirv_new_binaries DEPENDS ${assembled_spirv_binaries})

include(GNUInstallDirs)

install(DIRECTORY
            ${CMAKE_CURRENT_BINARY_DIR}/../spirv_bin
        DESTINATION
            ${CMAKE_INSTALL_BINDIR}/$<CONFIG>)
