singe/cmake/zig/zig.cmake
2026-09-10 20:17:28 -05:00

77 lines
4.3 KiB
CMake

#
# Singe 3
# Copyright (C) 2006-2026 Scott Duensing <scott@kangaroopunch.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public Licens
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# The one place the zig version lives. Toolchain files include this and name a target; the
# compiler, archiver and resource compiler are small wrapper scripts so every tool that wants a
# single program name (FFmpeg's configure, OpenSSL's, CMake itself) gets one.
# Pinned release, fetched into .builddir/toolchains on first use and checked against its hash.
set(ZIG_VERSION 0.15.2)
set(ZIG_SHA256 02aa270f183da276e5b5920b1dac44a63f1a49e55050ebde3aecc9eb82f93239)
set(ZIG_NAME zig-x86_64-linux-${ZIG_VERSION})
set(ZIG_URL https://ziglang.org/download/${ZIG_VERSION}/${ZIG_NAME}.tar.xz)
get_filename_component(ZIG_TOOLCHAINS ${CMAKE_CURRENT_LIST_DIR}/../../.builddir/toolchains ABSOLUTE)
set(ZIG_ROOT ${ZIG_TOOLCHAINS}/${ZIG_NAME})
set(ZIG_EXECUTABLE ${ZIG_ROOT}/zig)
if(NOT EXISTS ${ZIG_EXECUTABLE})
message(STATUS "Downloading zig ${ZIG_VERSION} from ${ZIG_URL}")
file(MAKE_DIRECTORY ${ZIG_TOOLCHAINS})
file(DOWNLOAD ${ZIG_URL} ${ZIG_TOOLCHAINS}/${ZIG_NAME}.tar.xz EXPECTED_HASH SHA256=${ZIG_SHA256} STATUS status)
list(GET status 0 code)
if(NOT code EQUAL 0)
message(FATAL_ERROR "zig download failed: ${status}")
endif()
file(ARCHIVE_EXTRACT INPUT ${ZIG_TOOLCHAINS}/${ZIG_NAME}.tar.xz DESTINATION ${ZIG_TOOLCHAINS})
file(REMOVE ${ZIG_TOOLCHAINS}/${ZIG_NAME}.tar.xz)
if(NOT EXISTS ${ZIG_EXECUTABLE})
message(FATAL_ERROR "zig ${ZIG_VERSION} did not unpack to ${ZIG_ROOT}.")
endif()
endif()
# Writes the wrapper scripts for a target into the build tree and points CMake at them. extra is
# appended to every compiler invocation (a target's include and library directories).
function(singeZigToolchain target extra)
set(dir ${CMAKE_BINARY_DIR}/zig-${target})
file(MAKE_DIRECTORY ${dir})
# The compiler wrappers drop two flags FFmpeg's configure adds to every test link and zig's linker
# driver refuses: binutils' --pic-executable ASLR workaround on Windows and Apple's
# -dynamic,-search_paths_first on macOS. They also add
set(filter "for a in \"$@\"; do [[ $a == -Wl,--pic-executable* || $a == -Wl,-dynamic* ]] || args+=(\"$a\"); done")
# -fno-sanitize=undefined: zig cc instruments for UBSan by default and expects its runtime at
# link time; a release build wants neither.
# extra goes after the caller's arguments so the caller's -L directories are searched first.
# ld.lld and objcopy are here for vendored projects that shell out to a linker or a strip of
# their own rather than going through the compiler driver: Rockchip's MPP merges its archives
# with "ld -r" and then strips the result, and without these it would reach for the host's.
foreach(tool "cc;-target ${target} -fno-sanitize=undefined;${extra}" "c++;-target ${target} -fno-sanitize=undefined;${extra}" "ar;;" "ranlib;;" "rc;;" "ld.lld;;")
list(GET tool 0 name)
list(GET tool 1 args)
list(GET tool 2 after)
file(WRITE ${dir}/zig-${name} "#!/bin/bash\nargs=()\n${filter}\nexec \"${ZIG_EXECUTABLE}\" ${name} ${args} \"$\{args[@]}\" ${after}\n")
file(CHMOD ${dir}/zig-${name} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
endforeach()
set(CMAKE_C_COMPILER ${dir}/zig-cc CACHE FILEPATH "C compiler" FORCE)
set(CMAKE_CXX_COMPILER ${dir}/zig-c++ CACHE FILEPATH "C++ compiler" FORCE)
set(CMAKE_AR ${dir}/zig-ar CACHE FILEPATH "archiver" FORCE)
set(CMAKE_RANLIB ${dir}/zig-ranlib CACHE FILEPATH "ranlib" FORCE)
set(CMAKE_RC_COMPILER ${dir}/zig-rc CACHE FILEPATH "resource compiler" FORCE)
set(CMAKE_LINKER ${dir}/zig-ld.lld CACHE FILEPATH "linker" FORCE)
set(SINGE_ZIG_TARGET ${target} CACHE STRING "zig target triple" FORCE)
endfunction()