﻿cmake_minimum_required(VERSION 3.20)
# The oldest macOS a build runs on. CMake reads it at project(), so it is set
# before; every other platform ignores it. 14.0 is what the community's Apple
# Silicon build was proved on; -DCMAKE_OSX_DEPLOYMENT_TARGET on the command
# line wins over this.
set(CMAKE_OSX_DEPLOYMENT_TARGET "14.0" CACHE STRING "The oldest macOS the build runs on")
project(Snap64Recomp VERSION 1.1.7 LANGUAGES C CXX)
if (APPLE)
    # Objective-C for RT64's Apple sources and SDL's Cocoa back end; the
    # port's own sources stay C++ (main.cpp takes the Metal layer through SDL).
    enable_language(OBJC OBJCXX)
endif()

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# =============================================================================
# Version -- the one place it lives
# =============================================================================
# project(VERSION) takes numbers only, so the prerelease tag is its own
# variable. SNAP_VERSION_FULL is what every surface shows: the title bar,
# the log banner, the credits line, the exe's version resource and the
# package name (all through the generated version.h / snap64.rc, below).
# An empty SNAP_VERSION_PRERELEASE is a final release; the release workflow
# passes one (-DSNAP_VERSION_PRERELEASE=rc1) for a build that must not pass
# for the release itself.
set(SNAP_PRODUCT_NAME "Snap64 Recomp")
set(SNAP_VERSION_PRERELEASE "" CACHE STRING "Prerelease label (rc1, ...); empty for a release")
# The label is drawn on the title screen in the credits face, which has every
# digit but, of the lower-case letters, only these (src/version.h.in); a label
# with any other character would make the port withhold its whole title dress.
if (SNAP_VERSION_PRERELEASE AND NOT SNAP_VERSION_PRERELEASE MATCHES "^[acdeikmnoprstuv0-9.]+$")
    message(FATAL_ERROR "SNAP_VERSION_PRERELEASE '${SNAP_VERSION_PRERELEASE}': a prerelease label uses only "
                        "the letters a c d e i k m n o p r s t u v, digits and dots (rc1, pre2), the characters "
                        "the title screen's credits face can draw.")
endif()
if (SNAP_VERSION_PRERELEASE)
    set(SNAP_VERSION_SUFFIX "-${SNAP_VERSION_PRERELEASE}")
    set(SNAP_RC_FILEFLAGS "VS_FF_PRERELEASE")
else()
    set(SNAP_VERSION_SUFFIX "")
    set(SNAP_RC_FILEFLAGS "0x0L")
endif()
set(SNAP_VERSION_FULL "${PROJECT_VERSION}${SNAP_VERSION_SUFFIX}")
# The title screen's credits face has no hyphen (src/version.h.in).
string(REPLACE "-" " " SNAP_VERSION_CREDITS "${SNAP_VERSION_FULL}")
if (MSVC)
    enable_language(RC)
    # The C++ runtime is linked into the executable (and into SDL2.dll, built
    # here), so a machine without the Visual C++ Redistributable runs it.
    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
    # __FILE__ -- asserts, the crash report, RT64's own messages -- would
    # otherwise carry the absolute path of the machine that built the
    # release. The prefix is trimmed at compile time; what remains is the
    # path inside the repository.
    file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/" SNAP_SOURCE_PREFIX_NATIVE)
    add_compile_options("/d1trimfile:${SNAP_SOURCE_PREFIX_NATIVE}")
else()
    # The same for Clang and GCC: the source and build folders are mapped
    # away, in __FILE__ and in debug information alike. Without this the
    # Linux binary carried the builder's home folder and the Mac one the
    # runner's (1.0.x to 1.1.0).
    add_compile_options("-ffile-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/="
                        "-ffile-prefix-map=${CMAKE_CURRENT_BINARY_DIR}/=")
endif()

# =============================================================================
# Options
# =============================================================================
option(BUILD_RT64 "Build RT64 rendering backend" ON)

message(STATUS "${SNAP_PRODUCT_NAME} ${SNAP_VERSION_FULL}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")

# =============================================================================
# Find dependencies
# =============================================================================
# SDL2: built from the vendored tree on Windows, macOS and Android, the
# system's on Linux. SNAP_SDL_TARGET is what the port links; rt64 links
# SDL2_LIBRARIES.
if (WIN32 OR APPLE OR ANDROID)
    set(SDL_TEST OFF CACHE BOOL "" FORCE)
    set(SDL2_DISABLE_INSTALL ON CACHE BOOL "" FORCE)
    if (APPLE)
        # Static, inside the executable: the application bundle then carries
        # no dylib of its own to re-path or sign, and the Cocoa, IOKit, audio
        # and GameController frameworks come with the target.
        set(SDL_SHARED OFF CACHE BOOL "" FORCE)
        set(SDL_STATIC ON CACHE BOOL "" FORCE)
    elseif (ANDROID)
        # Shared, libSDL2.so: SDL's own activity loads "SDL2" and then the
        # game's library, "main", by name (lib/SDL/android-project,
        # SDLActivity.getLibraries) and calls the SDL_main inside it. HIDAPI
        # stays SDL's Android default, through its Java side.
        set(SDL_SHARED ON CACHE BOOL "" FORCE)
        set(SDL_STATIC OFF CACHE BOOL "" FORCE)
    endif()
    add_subdirectory(lib/SDL EXCLUDE_FROM_ALL)
    set(SDL2_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/lib/SDL/include")
    if (APPLE)
        set(SDL2_LIBRARIES SDL2-static)
        set(SNAP_SDL_TARGET SDL2::SDL2-static)
    else()
        set(SDL2_LIBRARIES SDL2)
        set(SNAP_SDL_TARGET SDL2::SDL2)
    endif()
else()
    find_package(SDL2 REQUIRED)
    set(SNAP_SDL_TARGET SDL2::SDL2)
endif()

# =============================================================================
# RT64 -- static rendering backend
# =============================================================================
if (BUILD_RT64)
    set(RT64_STATIC ON CACHE BOOL "Build RT64 as a static library" FORCE)
    set(RT64_SDL_WINDOW_VULKAN ON CACHE BOOL "RT64 uses SDL Vulkan window" FORCE)
    add_subdirectory(lib/rt64 EXCLUDE_FROM_ALL)
    if (WIN32)
        # SDK 22621 lacks D3D12_HEAP_TYPE_GPU_UPLOAD / OPTIONS15 / OPTIONS16;
        # the standalone DirectX-Headers provide current definitions.
        set(DXHEADERS "${CMAKE_CURRENT_SOURCE_DIR}/lib/DirectX-Headers/include")
        foreach(_dxtarget plume rt64)
            if (TARGET ${_dxtarget})
                target_include_directories(${_dxtarget} BEFORE PRIVATE "${DXHEADERS}/directx" "${DXHEADERS}")
            endif()
        endforeach()
    endif()
endif()

# =============================================================================
# N64ModernRuntime (ultramodern + librecomp)
# =============================================================================
add_subdirectory(lib/N64ModernRuntime EXCLUDE_FROM_ALL)

# =============================================================================
# Recompiled functions -- static library from N64Recomp output
# =============================================================================
file(GLOB RECOMP_FUNC_SOURCES
    "${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs/funcs_*.c"
)

add_library(recomp_funcs STATIC
    ${RECOMP_FUNC_SOURCES}
    
)

target_include_directories(recomp_funcs PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs"
)

# recomp_funcs needs access to recomp.h (for recomp_context, gpr, etc.)
target_include_directories(recomp_funcs PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/lib/N64ModernRuntime/N64Recomp/include"
)

# Suppress warnings in generated recompiled code.
if (MSVC)
    # /O2, not /O1: this target is the whole recompiled game and is the
    # hottest code in the build, so favor speed over size.
    target_compile_options(recomp_funcs PRIVATE /w /bigobj /O2)
else()
target_compile_options(recomp_funcs PRIVATE
    # Emulated RAM is read through several widths at once; under strict
    # aliasing an optimizer may reorder those, and a contributor's Clang
    # build crashed in the audio start-up on exactly that.
    -fno-strict-aliasing
    -g
    -Wno-unused-variable
    -Wno-unused-parameter
    -Wno-sign-compare
    -Wno-unused-but-set-variable
    -Wno-implicit-function-declaration
)
endif()

# =============================================================================
# Audio microcode -- recompiled from the ROM at build time
# =============================================================================
# aspMain is Nintendo's RSP audio microcode. Its recompiled C++ is derived
# from the ROM and is therefore never committed: RSPRecomp (vendored under
# lib/N64ModernRuntime/N64Recomp and already a target of this build through
# librecomp's add_subdirectory, EXCLUDE_FROM_ALL) regenerates it into the
# build tree from the builder's own ROM -- the same ROM the executable runs
# against. The DEPENDS below is what makes the build compile RSPRecomp first.
set(SNAP_ROM "" CACHE FILEPATH
    "Pokemon Snap (USA) ROM, big-endian .z64, used to recompile the RSP audio microcode")
if (SNAP_ROM STREQUAL "")
    foreach(_snap_rom_candidate
            "${CMAKE_CURRENT_SOURCE_DIR}/pokemonsnap.z64"
            "${CMAKE_CURRENT_BINARY_DIR}/Release/pokemonsnap.z64"
            "${CMAKE_CURRENT_BINARY_DIR}/pokemonsnap.z64")
        if (EXISTS "${_snap_rom_candidate}")
            set(SNAP_ROM "${_snap_rom_candidate}" CACHE FILEPATH
                "Pokemon Snap (USA) ROM, big-endian .z64, used to recompile the RSP audio microcode" FORCE)
            break()
        endif()
    endforeach()
endif()
if (NOT EXISTS "${SNAP_ROM}")
    message(FATAL_ERROR
        "SNAP_ROM: no ROM found. The RSP audio microcode (aspMain) is recompiled from "
        "the game's ROM at build time and is not part of the repository. Pass "
        "-DSNAP_ROM=<path to pokemonsnap.z64> (a big-endian .z64 dump of Pokemon Snap (USA)), "
        "or place pokemonsnap.z64 in ${CMAKE_CURRENT_SOURCE_DIR}, "
        "${CMAKE_CURRENT_BINARY_DIR}/Release or ${CMAKE_CURRENT_BINARY_DIR}.")
endif()
# Two cheap checks on the file itself; the runtime's hash check (src/main.cpp)
# remains the authority on the game.
file(READ "${SNAP_ROM}" _snap_rom_magic LIMIT 4 HEX)
file(READ "${SNAP_ROM}" _snap_rom_name OFFSET 32 LIMIT 20 HEX)
string(TOLOWER "${_snap_rom_magic}" _snap_rom_magic)
string(TOLOWER "${_snap_rom_name}" _snap_rom_name)
if (NOT _snap_rom_magic STREQUAL "80371240")
    message(FATAL_ERROR
        "SNAP_ROM=${SNAP_ROM} does not start with the big-endian N64 header 80 37 12 40; "
        "a byte-swapped (.v64) or little-endian (.n64) dump cannot be recompiled. Convert it to .z64 first.")
endif()
# "POKEMON SNAP" padded with spaces to the header's twenty-byte name field.
if (NOT _snap_rom_name STREQUAL "504f4b454d4f4e20534e41502020202020202020")
    message(FATAL_ERROR
        "SNAP_ROM=${SNAP_ROM}: the ROM header's internal name is not 'POKEMON SNAP'; this is not the expected game.")
endif()
message(STATUS "RSP audio microcode from ROM: ${SNAP_ROM}")

set(SNAP_RSP_DIR "${CMAKE_CURRENT_BINARY_DIR}/rsp")
set(SNAP_ASPMAIN_CPP "${SNAP_RSP_DIR}/aspMain.cpp")
# Absolute, forward-slashed paths: RSPRecomp joins a relative path with the
# toml's own directory and uses an absolute one as is, and a TOML basic string
# takes forward slashes without escaping.
file(TO_CMAKE_PATH "${SNAP_ROM}" SNAP_ROM_CMAKE)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/rsp/aspMain.us.toml.in"
               "${SNAP_RSP_DIR}/aspMain.us.toml" @ONLY)
# A cross build (Android) cannot run the RSPRecomp it builds: it takes the
# aspMain.cpp a native build of this tree generated from the same ROM
# (build-linux's, say), named here, and compiles a copy of it in the same
# place.
set(SNAP_ASPMAIN_PREBUILT "" CACHE FILEPATH
    "A host-generated rsp/aspMain.cpp to compile instead of running RSPRecomp (required when cross-compiling)")
if (SNAP_ASPMAIN_PREBUILT)
    if (NOT EXISTS "${SNAP_ASPMAIN_PREBUILT}")
        message(FATAL_ERROR "SNAP_ASPMAIN_PREBUILT=${SNAP_ASPMAIN_PREBUILT} does not exist")
    endif()
    configure_file("${SNAP_ASPMAIN_PREBUILT}" "${SNAP_ASPMAIN_CPP}" COPYONLY)
    message(STATUS "RSP audio microcode: the prebuilt ${SNAP_ASPMAIN_PREBUILT}")
elseif (CMAKE_CROSSCOMPILING)
    message(FATAL_ERROR
        "This is a cross build, which cannot run RSPRecomp to recompile the audio microcode: pass "
        "-DSNAP_ASPMAIN_PREBUILT=<the rsp/aspMain.cpp of a native build of this tree>.")
else()
    add_custom_command(
        OUTPUT "${SNAP_ASPMAIN_CPP}"
        COMMAND RSPRecomp "${SNAP_RSP_DIR}/aspMain.us.toml"
        DEPENDS RSPRecomp "${SNAP_RSP_DIR}/aspMain.us.toml" "${SNAP_ROM}"
        COMMENT "Recompiling the aspMain audio microcode from ${SNAP_ROM}"
        VERBATIM)
endif()

# =============================================================================
# Game executable
# =============================================================================
# Game-side patches, recompiled from patches/ by N64Recomp (see patches.toml).
# Compiled straight into the executable rather than into a library, so these
# definitions are already resolved by the time the linker reaches
# recomp_funcs and the game's own versions are never pulled in.
set(SNAP_PATCH_SOURCES)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/RecompiledPatches/patches.c")
    # Compiled from a copy in the build tree in which the two libultra names
    # glibc reserves, __sinf and __cosf, are the game's own __sinf_recomp and
    # __cosf_recomp (tools/portable_patches.cmake says why). The copy is
    # remade whenever the recompiler's output changes.
    set(SNAP_PATCH_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated/patches")
    set(SNAP_PATCH_C "${SNAP_PATCH_DIR}/patches.c")
    add_custom_command(
        OUTPUT "${SNAP_PATCH_C}"
        COMMAND ${CMAKE_COMMAND} "-DINPUT_DIR=${CMAKE_CURRENT_SOURCE_DIR}/RecompiledPatches" "-DOUTPUT_DIR=${SNAP_PATCH_DIR}" -P "${CMAKE_CURRENT_SOURCE_DIR}/tools/portable_patches.cmake"
        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/RecompiledPatches/patches.c"
                "${CMAKE_CURRENT_SOURCE_DIR}/RecompiledPatches/funcs.h"
                "${CMAKE_CURRENT_SOURCE_DIR}/tools/portable_patches.cmake"
        COMMENT "Copying RecompiledPatches with glibc's reserved names renamed")
    set(SNAP_PATCH_SOURCES "${SNAP_PATCH_C}")
    message(STATUS "Game patches: RecompiledPatches/patches.c")
    # Same treatment the recompiled game gets: it is generated MIPS-derived C.
    set_source_files_properties("${SNAP_PATCH_C}"
        # /Oi-: the game has functions named sinf and cosf, which MSVC would
        # otherwise replace with its math intrinsics and then reject for
        # taking the recompiler's two arguments.
        PROPERTIES COMPILE_OPTIONS "$<IF:$<BOOL:${MSVC}>,/w;/O2;/Oi-,-w;-fno-strict-aliasing>")

    # The patch ELF's loadable bytes: code the recompiler already turned into
    # C, and the .data section holding every patch's constants (IDO keeps
    # float literals and tables there). Embedded here and handed to librecomp
    # at start-up (src/main.cpp, snap_register_patches), which copies them to
    # the address the patches are linked at. Without the copy a patch that
    # read one of its own constants read zero.
    set(SNAP_PATCH_BIN "${CMAKE_CURRENT_SOURCE_DIR}/patches/build/patches.bin")
    if (NOT EXISTS "${SNAP_PATCH_BIN}")
        message(FATAL_ERROR "RecompiledPatches/patches.c exists but patches/build/patches.bin does not: run make -C patches (BUILDING.md, step 8)")
    endif()
    set(SNAP_PATCH_BIN_C "${CMAKE_CURRENT_BINARY_DIR}/generated/snap_patches_bin.c")
    add_custom_command(
        OUTPUT "${SNAP_PATCH_BIN_C}"
        COMMAND ${CMAKE_COMMAND} "-DINPUT=${SNAP_PATCH_BIN}" "-DOUTPUT=${SNAP_PATCH_BIN_C}" -DSYMBOL=snap_patches_bin -P "${CMAKE_CURRENT_SOURCE_DIR}/tools/embed_bin.cmake"
        DEPENDS "${SNAP_PATCH_BIN}" "${CMAKE_CURRENT_SOURCE_DIR}/tools/embed_bin.cmake"
        COMMENT "Embedding patches/build/patches.bin")
    list(APPEND SNAP_PATCH_SOURCES "${SNAP_PATCH_BIN_C}")
    set(SNAP_HAS_PATCH_BIN 1)
endif()

set(SNAP_SOURCES
    ${SNAP_PATCH_SOURCES}
    src/main.cpp
    src/paths.cpp
    src/rom_picker.cpp
    src/fast_forward.cpp
    src/steam_deck.cpp
    src/steam_art.cpp
    src/relaunch_window.cpp
    src/mod_api.cpp
    src/mod_data_api.cpp
    src/mod_time_api.cpp
    src/mod_installer.cpp
    src/menu_mouse.cpp
    src/pointer.cpp
    src/gpu_check.cpp
    src/dds_image.cpp
    src/rt64_render_context.cpp
    src/rsp_microcode.cpp
    src/audio.cpp
    src/input.cpp
    src/touch_controls.cpp
    src/android_thermal.cpp
    src/os_stubs.cpp
    src/overlay_hook.cpp
    src/matrix_tags.cpp
    src/rect_tags.cpp
    src/lab_monitor.cpp
    src/save_file.cpp
    src/autosave.cpp
    src/rect_census.cpp
    src/fx_tags.cpp
    src/host_hooks.cpp
    src/menu_assets.cpp
    src/menu_harvest.cpp
    src/anim_steps.cpp
    src/focus_dot.cpp
    src/dl_budget.cpp
    src/frame_cost.cpp
    src/sfx_volume_probe.cpp
    src/score_probe.cpp
    src/intro_probe.cpp
    src/settings.cpp
    src/photo_export.cpp
    src/snap_station.cpp
    "${SNAP_ASPMAIN_CPP}"
)

# The machine the build is for: the one CMake runs on, unless a macOS build
# names others (-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" is one executable for
# both kinds of Mac, which the package calls universal). Also the package
# name's.
if (APPLE AND CMAKE_OSX_ARCHITECTURES)
    list(LENGTH CMAKE_OSX_ARCHITECTURES _snap_arch_count)
    if (_snap_arch_count GREATER 1)
        set(SNAP_TARGET_ARCH "universal")
    else()
        set(SNAP_TARGET_ARCH "${CMAKE_OSX_ARCHITECTURES}")
    endif()
else()
    set(SNAP_TARGET_ARCH "${CMAKE_SYSTEM_PROCESSOR}")
endif()
# librecomp's RSP vector-unit implementation uses SSSE3 intrinsics on x86; on
# ARM (an Apple Silicon Mac) the same header goes through sse2neon, which the
# runtime's include path provides, and the flag would be refused. A universal
# Mac build compiles the file once for each; the flag goes to the Intel pass
# only (a list of two options: the SHELL: prefix that keeps a pair together
# in target options is not honored by a source file's property, and clang
# took it for a file name).
if (APPLE AND CMAKE_OSX_ARCHITECTURES MATCHES "x86_64" AND CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
    set_source_files_properties("${SNAP_ASPMAIN_CPP}" PROPERTIES COMPILE_OPTIONS "-Xarch_x86_64;-msse4.1")
elseif (NOT MSVC AND SNAP_TARGET_ARCH MATCHES "x86_64|AMD64|amd64")
    set_source_files_properties("${SNAP_ASPMAIN_CPP}" PROPERTIES COMPILE_OPTIONS "-msse4.1")
endif()

# The identity header and the Windows version resource are written from
# src/version.h.in and src/snap64.rc.in with the numbers above; the sources
# include "version.h" and find the generated one because src/version.h no
# longer exists.
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in"
               "${CMAKE_CURRENT_BINARY_DIR}/generated/version.h" @ONLY)
# The commit a build is made from, named in the log's first lines. A target and
# not a configure step, so a new commit reaches the next build by itself.
add_custom_target(snap_build_id
    BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/generated/build_id.h"
    COMMAND "${CMAKE_COMMAND}" "-DTREE=${CMAKE_CURRENT_SOURCE_DIR}"
            "-DOUT=${CMAKE_CURRENT_BINARY_DIR}/generated/build_id.h"
            -P "${CMAKE_CURRENT_SOURCE_DIR}/tools/build_id.cmake"
    VERBATIM)
if (MSVC)
    configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/snap64.rc.in"
                   "${CMAKE_CURRENT_BINARY_DIR}/generated/snap64.rc" @ONLY)
    list(APPEND SNAP_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/generated/snap64.rc")
endif()

if (APPLE)
    # The Metal layer's size left to the renderer (src/macos_support.mm).
    list(APPEND SNAP_SOURCES src/macos_support.mm)
endif()
if (ANDROID)
    # What the port asks Android's own side for, through SDL's activity
    # (android/): the document picker and the system log (src/android.cpp).
    list(APPEND SNAP_SOURCES src/android.cpp)
endif()

if (ANDROID)
    # On Android the game is a shared library, libmain.so, that SDL's own
    # activity loads after libSDL2.so and enters through SDL_main, which
    # SDL_main.h renames main() to there and exports.
    add_library(Snap64Recomp SHARED ${SNAP_SOURCES})
    set_target_properties(Snap64Recomp PROPERTIES OUTPUT_NAME "main")
else()
    add_executable(Snap64Recomp ${SNAP_SOURCES})
endif()
add_dependencies(Snap64Recomp snap_build_id)

target_include_directories(Snap64Recomp PRIVATE
    "${CMAKE_CURRENT_SOURCE_DIR}/src"
    "${CMAKE_CURRENT_BINARY_DIR}/generated"
    "${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs"
    "${CMAKE_CURRENT_SOURCE_DIR}/lib/N64ModernRuntime/N64Recomp/include"
    "${CMAKE_CURRENT_SOURCE_DIR}/lib/N64ModernRuntime/librecomp/include"
    "${CMAKE_CURRENT_SOURCE_DIR}/lib/N64ModernRuntime/ultramodern/include"
    "${CMAKE_CURRENT_SOURCE_DIR}/lib/N64ModernRuntime/thirdparty"
    "${CMAKE_CURRENT_SOURCE_DIR}/lib/N64ModernRuntime/thirdparty/concurrentqueue"
)

# RT64 include paths (for rt64_application.h, etc.)
if (BUILD_RT64)
    target_include_directories(Snap64Recomp PRIVATE
        "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src"
        "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib"
        "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/hlslpp/include"
        "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/plume"
        "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/imgui"
        "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/mupen64plus-core/src/api"
    )
    target_compile_definitions(Snap64Recomp PRIVATE HAS_RT64=1 HLSL_CPU FFX_GCC)
if (WIN32)
    target_compile_definitions(Snap64Recomp PRIVATE NOMINMAX)
    # Game threads inherit the image default; recompiled call chains need Linux-like depth.
    target_link_options(Snap64Recomp PRIVATE /STACK:8388608 /MAP)
    # A windowed program: no console opens beside the game window. main()
    # stays the entry point (SDL2main is not linked), so the CRT's console
    # start-up routine is named explicitly. Where the log goes when there is
    # no console is decided by snap_bind_stdio() in src/main.cpp: an
    # inherited pipe or file is kept, a parent console is attached, and
    # otherwise snap64.log is written beside the executable.
    set_target_properties(Snap64Recomp PROPERTIES WIN32_EXECUTABLE TRUE)
    target_link_options(Snap64Recomp PRIVATE /ENTRY:mainCRTStartup)
endif()
endif()

# Link libraries. recomp_funcs and librecomp are mutually dependent
# (recomp_funcs references librecomp symbols; librecomp needs recomp_funcs'
# function tables), which GNU ld needs --start-group to resolve. MSVC's
# link.exe resolves cyclic static libraries on its own and reports the GNU
# flags as LNK4044 on every link, so they are only passed where they mean
# something.
if (SNAP_HAS_PATCH_BIN)
    target_compile_definitions(Snap64Recomp PRIVATE SNAP_HAS_PATCH_BIN=1)
endif()

target_link_libraries(Snap64Recomp PRIVATE
    recomp_funcs
    librecomp
    ultramodern
    ${SNAP_SDL_TARGET}
)

if (WIN32)
    # The start-up check on the Direct3D 12 adapter (src/gpu_check.cpp).
    target_link_libraries(Snap64Recomp PRIVATE d3d12 dxgi)
endif()

if (MSVC)
    # A patch defines a function the recompiled game also defines. Object
    # files are linked before libraries and the first definition wins, so the
    # patch in RecompiledPatches takes precedence over recomp_funcs; the
    # linker still has to be told the duplicate is intentional. This replaces
    # the --allow-multiple-definition that serves the same purpose under GNU
    # ld, which also covers symbols such as guMtxF2L appearing in several
    # overlay sections.
    target_link_options(Snap64Recomp PRIVATE /FORCE:MULTIPLE /IGNORE:4006 /IGNORE:4088)
elseif (NOT APPLE)
    target_link_options(Snap64Recomp PRIVATE
        -Wl,--start-group
        -Wl,--end-group
        -Wl,--allow-multiple-definition
    )
    # macOS's ld64 has neither switch and needs neither: under Clang the
    # recompiler declares every game function weak (N64Recomp's recomp.h,
    # RECOMP_FUNC), so a patch's own definition simply wins.
endif()
if (APPLE)
    # A mod patches game functions inside the executable's own code, which
    # macOS allows only when the code segment's maximum protection includes
    # writing; ld64 will not link that, so a wrapper around it rewrites the
    # one byte afterward (tools/macos/ld64, Zelda64Recomp's; it needs
    # Python 3 with macholib). The bundle's entitlements (tools/macos/
    # entitlements.plist) let the signed program use it.
    target_link_options(Snap64Recomp PRIVATE "-fuse-ld=${CMAKE_CURRENT_SOURCE_DIR}/tools/macos/ld64")
    # The recompiled game carries debug information (-g, above), and for it
    # the linker writes a debug map naming every object file by its full path
    # (build-macos/librecomp_funcs.a(funcs_0.c.o)); the build folder is taken
    # off those names as -ffile-prefix-map takes it off the compilers'.
    target_link_options(Snap64Recomp PRIVATE "LINKER:-oso_prefix,${CMAKE_CURRENT_BINARY_DIR}/")
    # That edit breaks the signature ld64 puts on every Apple Silicon image,
    # and macOS runs no arm64 code without one: the build tree's executable
    # is signed again, ad hoc, so it runs from the Terminal too. The bundle
    # gets its own signature (tools/macos_bundle.py).
    add_custom_command(TARGET Snap64Recomp POST_BUILD
        COMMAND codesign --force --sign - "$<TARGET_FILE:Snap64Recomp>"
        COMMENT "Signing Snap64Recomp ad hoc after tools/macos/ld64"
        VERBATIM)
endif()

if (BUILD_RT64)
    target_link_libraries(Snap64Recomp PRIVATE rt64)
    if (NOT ANDROID)
        # The first run's file chooser (src/rom_picker.cpp) is RT64's own copy
        # of nativefiledialog-extended, already built for RT64's use. Not on
        # Android, where the library has no backend: the chooser is refused
        # there (rom_picker.cpp, mod_installer.cpp).
        target_link_libraries(Snap64Recomp PRIVATE nfd)
        target_include_directories(Snap64Recomp PRIVATE
            "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/nativefiledialog-extended/src/include")
    endif()
    # The slot map the mod data API keeps its collections in (lib/SlotMap).
    target_include_directories(Snap64Recomp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/lib/SlotMap")
endif()

# Platform-specific link flags
if (UNIX AND NOT APPLE AND NOT ANDROID)
    target_link_libraries(Snap64Recomp PRIVATE
        pthread
        dl
    )
endif()
if (ANDROID)
    # bionic has the threads; dlopen (librecomp, a mod's native library) is
    # libdl's, and the system log (src/android.cpp) liblog's.
    target_link_libraries(Snap64Recomp PRIVATE dl log)
endif()

# Compiler warnings for game code
if (NOT MSVC)
    target_compile_options(Snap64Recomp PRIVATE -fno-strict-aliasing -Wall -Wextra -Wno-unused-parameter)
endif()
if (UNIX AND NOT APPLE AND NOT ANDROID)
    # The C++ runtime inside the binary, as the other N64 recompilations
    # ship it: the tarball then runs on a SteamOS whose libstdc++ is older
    # or newer than the build machine's. glibc stays the system's; the
    # build machine's version is the floor (BUILDING.md, step 14). An
    # Android build's C++ runtime is the NDK's choice (ANDROID_STL).
    target_link_options(Snap64Recomp PRIVATE -static-libstdc++ -static-libgcc)
endif()

# =============================================================================
# Runtime files next to the executable
# =============================================================================
# A fresh build directory must run without hand-copying (the copies in
# build-win/Release were placed by hand). SDL2.dll is the SDL target's own
# output; the DXC pair is what rt64 loads at run time, taken from the same
# place lib/rt64/CMakeLists.txt copies it into rt64's own binary dir (an
# ignored tree -- see VENDORING.md); the PNG is the title screen's "Recomp"
# badge (menu_assets.cpp). copy_if_different takes several sources when the
# last argument is a directory.
if (WIN32)
    set(SNAP_DXC_BIN "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/bin/x64")
    set(SNAP_RUNTIME_DLLS "$<TARGET_FILE:SDL2>")
    if (BUILD_RT64)
        list(APPEND SNAP_RUNTIME_DLLS "${SNAP_DXC_BIN}/dxcompiler.dll" "${SNAP_DXC_BIN}/dxil.dll")
    endif()
    add_custom_command(TARGET Snap64Recomp POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SNAP_RUNTIME_DLLS} "$<TARGET_FILE_DIR:Snap64Recomp>"
        COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:Snap64Recomp>/menu_text"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/menu_text/recomp_logo.png"
            "$<TARGET_FILE_DIR:Snap64Recomp>/menu_text/recomp_logo.png"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/menu_text/pointer.png"
            "$<TARGET_FILE_DIR:Snap64Recomp>/menu_text/pointer.png"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/menu_text/pointer_flash.png"
            "$<TARGET_FILE_DIR:Snap64Recomp>/menu_text/pointer_flash.png"
        COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:Snap64Recomp>/cache"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/shaders/rt64-seen-shaders.bin"
            "$<TARGET_FILE_DIR:Snap64Recomp>/cache/rt64-seen-shaders.bin"
        COMMENT "Placing the runtime DLLs, menu_text/ and the seen-shader list next to Snap64Recomp.exe"
        VERBATIM)
elseif (NOT ANDROID)
    # (On Android nothing sits beside a library: the app shell carries these
    # files as the package's assets.)
    # Linux and macOS: no runtime libraries of the port's own (SDL2 is the
    # system's on Linux and inside the executable on macOS, and off Windows
    # RT64 needs no shader compiler at run time); the badge and the
    # seen-shader list.
    add_custom_command(TARGET Snap64Recomp POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:Snap64Recomp>/menu_text"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/menu_text/recomp_logo.png"
            "$<TARGET_FILE_DIR:Snap64Recomp>/menu_text/recomp_logo.png"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/menu_text/pointer.png"
            "$<TARGET_FILE_DIR:Snap64Recomp>/menu_text/pointer.png"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/menu_text/pointer_flash.png"
            "$<TARGET_FILE_DIR:Snap64Recomp>/menu_text/pointer_flash.png"
        COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:Snap64Recomp>/cache"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/shaders/rt64-seen-shaders.bin"
            "$<TARGET_FILE_DIR:Snap64Recomp>/cache/rt64-seen-shaders.bin"
        COMMENT "Placing menu_text/ and the seen-shader list next to Snap64Recomp"
        VERBATIM)
    # The port's icon. A Windows executable carries it as a resource
    # (src/snap64.rc.in): the whole logo on a tile at the big sizes, the
    # film canister alone at the title bar's. A Linux binary has none, so
    # both sit beside it: Snap64Recomp.png, the tile, for a Steam shortcut
    # and the launcher the port writes; Snap64Recomp-window.png, the
    # canister, which the window takes at start-up (src/menu_assets.cpp,
    # set_window_icon). README, "Linux and Steam Deck".
    add_custom_command(TARGET Snap64Recomp POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/src/snap64.png"
            "$<TARGET_FILE_DIR:Snap64Recomp>/Snap64Recomp.png"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_CURRENT_SOURCE_DIR}/src/snap64-window.png"
            "$<TARGET_FILE_DIR:Snap64Recomp>/Snap64Recomp-window.png"
        COMMENT "Placing the icons next to Snap64Recomp"
        VERBATIM)
    install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/snap64.png" DESTINATION . RENAME Snap64Recomp.png)
    install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/snap64-window.png" DESTINATION . RENAME Snap64Recomp-window.png)
    if (APPLE)
        # The application bundle's icon, written by tools/icon_gen.py beside
        # the .ico; tools/macos_bundle.py moves it into Contents/Resources.
        install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/snap64.icns" DESTINATION . RENAME Snap64Recomp.icns)
    endif()
endif()

# =============================================================================
# Installation and packaging: one flat, portable folder (README "Where things live")
# =============================================================================
# Not on Android, whose package is the app's, made by the app shell.
if (NOT ANDROID)
# The package is the Windows one (cpack -C Release in the build directory
# writes Snap64Recomp-<version>-win64.zip); the license list below names the
# trees the Windows build compiles.
install(TARGETS Snap64Recomp RUNTIME DESTINATION .)
if (WIN32)
    install(FILES ${SNAP_RUNTIME_DLLS} DESTINATION .)
    # The /MAP output. The [SNAP-AV] crash report (main.cpp) prints image RVAs
    # that are symbolized against this file; a user's crash log is unreadable
    # without it. The copy that ships has the build machine's paths replaced
    # (tools/filter_map.cmake); the symbols and addresses are untouched.
    set(SNAP_MAP_FILTERED "${CMAKE_CURRENT_BINARY_DIR}/generated/Snap64Recomp.map")
    add_custom_command(TARGET Snap64Recomp POST_BUILD
        COMMAND ${CMAKE_COMMAND}
            "-DINPUT=$<TARGET_FILE_DIR:Snap64Recomp>/$<TARGET_FILE_BASE_NAME:Snap64Recomp>.map"
            "-DOUTPUT=${SNAP_MAP_FILTERED}"
            "-DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}"
            "-DBINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}"
            -P "${CMAKE_CURRENT_SOURCE_DIR}/tools/filter_map.cmake"
        COMMENT "Filtering the linker map of build paths")
    install(FILES "${SNAP_MAP_FILTERED}" DESTINATION . OPTIONAL)
endif()
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/menu_text/recomp_logo.png" DESTINATION menu_text)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/menu_text/pointer.png" DESTINATION menu_text)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/menu_text/pointer_flash.png" DESTINATION menu_text)
# The list of every shader the game is known to ask for -- 623 raw packed
# ShaderDescriptions from a full playthrough, no compiled code, valid on both
# backends. RT64 warms the whole list during the boot logos on idle threads
# (rt64_application.cpp, openSeenList), so a course's first frame never pays
# for pipeline creation; without a shipped list every machine started cold,
# which under Proton was a slowdown in the later courses. RT64 appends any
# shader it meets that is not on the list.
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/shaders/rt64-seen-shaders.bin" DESTINATION cache)
# The two folders players are told about (README "Mods and texture packs")
# exist in a fresh unpack, each with the note that says what it is for and
# that nothing ships in it.
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/mods/README.md" DESTINATION mods)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/texture_packs/README.txt" DESTINATION texture_packs)
# The Steam art (src/steam_art.h), which the port gives a Steam shortcut of itself.
# Whatever this folder holds is what it gives. The Mac and Android builds have no
# code that reads it.
if (NOT APPLE AND NOT ANDROID)
    install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/docs/logo.png" DESTINATION steam_art)
    if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/assets/steam_art")
        install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/assets/steam_art/" DESTINATION steam_art
                FILES_MATCHING PATTERN "*.png" PATTERN "*.jpg")
    endif()
endif()
# "START HERE.txt" sorts to the top of the unpacked folder on every platform,
# which is the point: README.md is the reference and nobody reads a reference
# first. It says where the ROM goes and that the port's additions live inside
# the game's own Options screen, which is the one thing a launcher would have
# made obvious and this design does not.
# The community's pad mappings, read by SDL at start-up (src/input.cpp,
# load_controller_mappings). SDL's own list has a few thousand pads and not
# every one that is sold; this one is the rest. NOTICE.md and VENDORING.md
# say where it comes from and how to refresh it.
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/assets/gamecontrollerdb.txt" DESTINATION .)

install(FILES
    "${CMAKE_CURRENT_SOURCE_DIR}/START HERE.txt"
    "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE"
    "${CMAKE_CURRENT_SOURCE_DIR}/NOTICE.md"
    "${CMAKE_CURRENT_SOURCE_DIR}/README.md"
    "${CMAKE_CURRENT_SOURCE_DIR}/CHANGELOG.md"
    DESTINATION .)

# Third-party license texts, copied from the vendored trees at install time so
# they can never drift from the code that was built. name|path pairs; the
# name becomes licenses/<name>.txt. NOTICE.md lists the same components.
set(SNAP_THIRD_PARTY_LICENSES
    "SDL2|lib/SDL/LICENSE.txt"
    "RT64|lib/rt64/LICENSE"
    "N64ModernRuntime|lib/N64ModernRuntime/COPYING"
    "N64Recomp|lib/N64ModernRuntime/N64Recomp/LICENSE"
    "DirectX-Headers|lib/DirectX-Headers/LICENSE"
    "plume|lib/rt64/src/contrib/plume/LICENSE"
    "re-spirv|lib/rt64/src/contrib/re-spirv/LICENSE"
    "zstd|lib/rt64/src/contrib/zstd/LICENSE"
    "nativefiledialog-extended|lib/rt64/src/contrib/nativefiledialog-extended/LICENSE"
    "imgui|lib/rt64/src/contrib/imgui/LICENSE.txt"
    "im3d|lib/rt64/src/contrib/im3d/LICENSE"
    "implot|lib/rt64/src/contrib/implot/LICENSE"
    "hlslpp|lib/rt64/src/contrib/hlslpp/LICENSE"
    "ddspp|lib/rt64/src/contrib/ddspp/LICENSE"
    "stb|lib/rt64/src/contrib/stb/LICENSE"
    "xxHash|lib/rt64/src/contrib/xxHash/LICENSE"
    "mupen64plus-core|lib/rt64/src/contrib/mupen64plus-core/LICENSES"
    "miniz|lib/N64ModernRuntime/thirdparty/miniz/LICENSE"
    "o1heap|lib/N64ModernRuntime/thirdparty/o1heap/LICENSE"
    "sljit|lib/N64ModernRuntime/N64Recomp/lib/sljit/LICENSE"
    "fmt|lib/N64ModernRuntime/N64Recomp/lib/fmt/LICENSE"
    "rabbitizer|lib/N64ModernRuntime/N64Recomp/lib/rabbitizer/LICENSE"
    "tomlplusplus|lib/N64ModernRuntime/N64Recomp/lib/tomlplusplus/LICENSE"
    "SlotMap|lib/SlotMap/LICENSE"
)
if (APPLE)
    # Apple's C++ Metal headers, inside plume's tree: compiled into plume's
    # Metal backend and so into the macOS executable only (NOTICE.md).
    list(APPEND SNAP_THIRD_PARTY_LICENSES "metal-cpp|lib/rt64/src/contrib/plume/contrib/metal-cpp/LICENSE.txt")
endif()
foreach(_entry IN LISTS SNAP_THIRD_PARTY_LICENSES)
    string(REPLACE "|" ";" _pair "${_entry}")
    list(GET _pair 0 _name)
    list(GET _pair 1 _file)
    install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" DESTINATION licenses RENAME "${_name}.txt")
endforeach()
# concurrentqueue ships its license only as the header's leading comment
# (everything before "#pragma once"); cut that out at configure time.
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/lib/N64ModernRuntime/thirdparty/concurrentqueue/concurrentqueue.h" _cq_head LIMIT 8192)
string(FIND "${_cq_head}" "#pragma once" _cq_end)
if (_cq_end LESS 1)
    message(FATAL_ERROR "concurrentqueue.h: no '#pragma once' in the first 8 KB; its license comment could not be cut out")
endif()
string(SUBSTRING "${_cq_head}" 0 ${_cq_end} _cq_license)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/generated/licenses/concurrentqueue.txt" "${_cq_license}")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/generated/licenses/concurrentqueue.txt" DESTINATION licenses)
# Tracked in the repository because the vendored copies carry no license file:
# nlohmann/json has only an SPDX header, and the DXC binaries ship without
# their license texts (BUILDING.md, step 13). DirectXShaderCompiler.txt is the
# LLVM Release License of the compiler and headers; DirectXShaderCompiler-dxil.txt
# is Microsoft's LICENSE-MS.txt of release v1.7.2308, the terms dxil.dll is
# shipped under (NOTICE.md, VENDORING.md "dxc"). A package without them is not
# produced.
foreach(_lic IN ITEMS DirectXShaderCompiler.txt DirectXShaderCompiler-dxil.txt roboto.txt SDL_GameControllerDB.txt)
    if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/licenses/${_lic}")
        message(WARNING "licenses/${_lic} is missing; cpack stops until it is added (BUILDING.md, step 13)")
    endif()
endforeach()
install(FILES
    "${CMAKE_CURRENT_SOURCE_DIR}/licenses/nlohmann-json.txt"
    "${CMAKE_CURRENT_SOURCE_DIR}/licenses/DirectXShaderCompiler.txt"
    "${CMAKE_CURRENT_SOURCE_DIR}/licenses/DirectXShaderCompiler-dxil.txt"
    "${CMAKE_CURRENT_SOURCE_DIR}/licenses/roboto.txt"
    "${CMAKE_CURRENT_SOURCE_DIR}/licenses/SDL_GameControllerDB.txt"
    DESTINATION licenses)

# cpack -C Release (from the build directory) -> Snap64Recomp-<version>-win64.zip
# with a top-level folder of the same name, and a .sha256 beside it.
set(CPACK_PACKAGE_NAME "Snap64Recomp")
set(CPACK_PACKAGE_VERSION "${SNAP_VERSION_FULL}")
if (WIN32)
    set(CPACK_GENERATOR "ZIP")
    set(CPACK_PACKAGE_FILE_NAME "Snap64Recomp-${SNAP_VERSION_FULL}-win64")
elseif (APPLE)
    # The macOS release is the application bundle tools/macos_bundle.py
    # builds from the install tree; cpack here is the same flat folder, for
    # a run from the Terminal, named for the machine it was built for.
    set(CPACK_GENERATOR "TGZ")
    set(CPACK_PACKAGE_FILE_NAME "Snap64Recomp-${SNAP_VERSION_FULL}-macos-${SNAP_TARGET_ARCH}")
else()
    # The same flat folder as a tarball (permissions kept, so the binary is
    # executable when unpacked); the Linux name says which machine it runs on,
    # x86_64 or arm64 (the name the other recompilations use for AArch64).
    if (SNAP_TARGET_ARCH MATCHES "aarch64|arm64|ARM64")
        set(SNAP_LINUX_ARCH "arm64")
    else()
        set(SNAP_LINUX_ARCH "x86_64")
    endif()
    set(CPACK_GENERATOR "TGZ")
    set(CPACK_PACKAGE_FILE_NAME "Snap64Recomp-${SNAP_VERSION_FULL}-linux-${SNAP_LINUX_ARCH}")
endif()
set(CPACK_PACKAGE_CHECKSUM SHA256)
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY ON)
set(CPACK_SOURCE_GENERATOR "")
include(CPack)
endif()

# =============================================================================
# Summary
# =============================================================================
message(STATUS "RT64 backend: ${BUILD_RT64}")
message(STATUS "Recompiled function sources: ${RECOMP_FUNC_SOURCES}")








