Skip to content

Commit d85abae

Browse files
committed
feat: add Zig version parsing and minimum version warning
1 parent f6742a0 commit d85abae

1 file changed

Lines changed: 63 additions & 39 deletions

File tree

zig-toolchain.cmake

Lines changed: 63 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# ==============================================================================
2-
# zig-toolchain.cmake v0.2.1
2+
# zig-toolchain.cmake v0.2.2
33
#
44
# Copyright (c) 2025 tayne3
55
# Licensed under the MIT License.
66
# ==============================================================================
77
include_guard(GLOBAL)
88

99
option(ZIG_USE_CCACHE "Enable ccache optimization for Zig toolchain" OFF)
10-
set(ZIG_MCPU "" CACHE STRING "Target CPU (e.g. 'baseline', 'native', 'cortex_a53'). See: zig targets")
11-
set(ZIG_MCPU_FEATURES "" CACHE STRING "CPU feature modifiers appended directly to -mcpu=<cpu>, e.g. '+avx2-sse4_1'")
10+
set(ZIG_MCPU "" CACHE STRING "Target CPU (e.g. 'baseline', 'native', 'cortex_a53'). See: zig targets")
11+
set(ZIG_MCPU_FEATURES "" CACHE STRING "CPU feature modifiers appended directly to -mcpu=<cpu>, e.g. '+avx2-sse4_1'")
1212
set(ZIG_COMPILER_FLAGS "" CACHE STRING "Additional compilation flags")
1313

1414
if(ZIG_MCPU_FEATURES AND NOT ZIG_MCPU)
@@ -32,7 +32,32 @@ execute_process(
3232
RESULT_VARIABLE _zig_version_result
3333
)
3434
if(NOT _zig_version_result EQUAL 0)
35-
message(FATAL_ERROR "Zig Toolchain: Zig compiler found but failed to get version.")
35+
message(FATAL_ERROR "Zig Toolchain: Zig compiler found at '${_zig_compiler_exe}' but failed to retrieve its version.")
36+
endif()
37+
38+
# Parse version string into components for version-gated logic
39+
# Handles both release ("0.16.0") and dev ("0.16.0-dev.1484+d0ba6642b") formats
40+
if(ZIG_COMPILER_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
41+
set(ZIG_VERSION_MAJOR "${CMAKE_MATCH_1}")
42+
set(ZIG_VERSION_MINOR "${CMAKE_MATCH_2}")
43+
set(ZIG_VERSION_PATCH "${CMAKE_MATCH_3}")
44+
else()
45+
message(WARNING "Zig Toolchain: Could not parse version '${ZIG_COMPILER_VERSION}'. Proceeding anyway.")
46+
set(ZIG_VERSION_MAJOR 0)
47+
set(ZIG_VERSION_MINOR 0)
48+
set(ZIG_VERSION_PATCH 0)
49+
endif()
50+
# Capture optional pre-release/dev suffix (e.g. "dev.1484+d0ba6642b")
51+
if(ZIG_COMPILER_VERSION MATCHES "-(.+)$")
52+
set(ZIG_VERSION_DEV "${CMAKE_MATCH_1}")
53+
else()
54+
set(ZIG_VERSION_DEV "")
55+
endif()
56+
57+
if(ZIG_COMPILER_VERSION VERSION_LESS "0.15.0")
58+
message(WARNING
59+
"Zig Toolchain: Zig ${ZIG_COMPILER_VERSION} predates the recommended minimum (0.15.0). "
60+
"Toolchain behaviour is untested on this version.")
3661
endif()
3762

3863
unset(_zig_ccache_exe CACHE)
@@ -52,37 +77,34 @@ if(NOT ZIG_TARGET)
5277
if(NOT CMAKE_SYSTEM_PROCESSOR)
5378
set(CMAKE_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}")
5479
endif()
55-
5680
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ZIG_ARCH)
5781
if(ZIG_ARCH MATCHES "arm64|aarch64")
5882
set(ZIG_ARCH "aarch64")
5983
elseif(ZIG_ARCH MATCHES "x64|x86_64|amd64")
6084
set(ZIG_ARCH "x86_64")
6185
endif()
62-
6386
string(TOLOWER "${CMAKE_SYSTEM_NAME}" ZIG_OS)
6487
set(ZIG_ABI "gnu")
6588
if(ZIG_OS MATCHES "darwin|macos")
66-
set(ZIG_OS "macos")
89+
set(ZIG_OS "macos")
6790
set(ZIG_ABI "none") # macOS uses its own ABI, not GNU
6891
elseif(ZIG_OS MATCHES "windows")
6992
set(ZIG_OS "windows")
7093
elseif(ZIG_OS MATCHES "linux")
7194
set(ZIG_OS "linux")
7295
endif()
73-
7496
set(ZIG_TARGET "${ZIG_ARCH}-${ZIG_OS}-${ZIG_ABI}")
7597
else()
7698
if(NOT ZIG_TARGET MATCHES "^([^-]+)-([^-]+)(-(.+))?$")
7799
message(FATAL_ERROR "Zig Toolchain: ZIG_TARGET '${ZIG_TARGET}' is invalid. Expected format: <arch>-<os>[-<abi>]")
78100
endif()
79-
set(ZIG_ARCH ${CMAKE_MATCH_1})
80-
set(ZIG_OS ${CMAKE_MATCH_2})
101+
set(ZIG_ARCH "${CMAKE_MATCH_1}")
102+
set(ZIG_OS "${CMAKE_MATCH_2}")
81103
endif()
82104

83-
# Dummy version satisfies CMake's cross-compilation requirements without affecting Zig's behavior
84-
set(CMAKE_SYSTEM_VERSION 1)
85-
set(CMAKE_SYSTEM_PROCESSOR ${ZIG_ARCH})
105+
# Dummy version satisfies CMake's cross-compilation requirements without affecting Zig's behaviour
106+
set(CMAKE_SYSTEM_VERSION 1)
107+
set(CMAKE_SYSTEM_PROCESSOR "${ZIG_ARCH}")
86108
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
87109

88110
if(ZIG_OS STREQUAL "linux")
@@ -92,8 +114,8 @@ elseif(ZIG_OS STREQUAL "windows")
92114
elseif(ZIG_OS STREQUAL "macos")
93115
set(CMAKE_SYSTEM_NAME "Darwin")
94116
else()
95-
set(CMAKE_SYSTEM_NAME ${ZIG_OS})
96-
message(WARNING "Unknown OS: ${ZIG_OS}")
117+
set(CMAKE_SYSTEM_NAME "${ZIG_OS}")
118+
message(WARNING "Zig Toolchain: Unknown target OS '${ZIG_OS}'; CMAKE_SYSTEM_NAME set verbatim.")
97119
endif()
98120

99121
message(STATUS "Zig Toolchain: v${ZIG_COMPILER_VERSION}${ZIG_TARGET}")
@@ -110,27 +132,25 @@ endif()
110132

111133
if(CMAKE_HOST_WIN32)
112134
set(_zig_wrapper_ext ".exe")
113-
set(_zig_host_win32 1)
135+
set(_zig_host_win32 1)
114136
else()
115137
set(_zig_wrapper_ext "")
116-
set(_zig_host_win32 0)
138+
set(_zig_host_win32 0)
117139
endif()
118140

119141
set(_zig_shims_dir "${CMAKE_BINARY_DIR}/.zig-shims")
120142
file(MAKE_DIRECTORY "${_zig_shims_dir}")
121143

122-
# Use Bracket Argument [=[ ... ]=] to avoid escaping hell
144+
# Use bracket argument [=[ ... ]=] to avoid escaping hell
123145
set(_zig_shim_template [=[
124146
// @_zig_tool_name@ wrapper for Zig toolchain
125147
#include <stdio.h>
126148
#include <stdlib.h>
127-
128149
#if @_zig_host_win32@
129150
#include <process.h>
130151
#else
131152
#include <unistd.h>
132153
#endif
133-
134154
int main(int argc, char** argv) {
135155
// User args (argc - 1) + NULL terminator (1) + Injected args count
136156
const char* exargv[argc + @_zig_extra_args_count@];
@@ -141,7 +161,6 @@ int main(int argc, char** argv) {
141161
@_zig_flags_stmts@
142162
for (int i = 1; i < argc; ++i) { *p++ = argv[i]; }
143163
*p = NULL;
144-
145164
#if @_zig_host_win32@
146165
return (int)_spawnvp(_P_WAIT, exargv[0], (const char* const*)exargv);
147166
#else
@@ -153,25 +172,25 @@ int main(int argc, char** argv) {
153172
]=])
154173

155174
function(_zig_generate_shim tool_name subcommand inject_flags use_ccache)
156-
set(_zig_tool_name "${tool_name}")
175+
set(_zig_tool_name "${tool_name}")
157176
set(_zig_subcommand "${subcommand}")
158177

159-
# 2 injected args baseline: zig executable + subcommand
160-
set(_zig_extra_args_count 2)
178+
# 2 baseline injected args: zig executable + subcommand
179+
set(_zig_extra_args_count 2)
161180
set(_zig_ccache_stmt "")
162181
set(_zig_flags_stmts "")
163182

164-
# Escape executable paths for C string literal
183+
# Escape executable path for C string literal
165184
string(REPLACE "\\" "\\\\" _zig_compiler_exe_escaped "${_zig_compiler_exe}")
166185

167-
# Process ccache injection
186+
# Inject ccache prefix if requested
168187
if(use_ccache AND _zig_ccache_exe)
169188
string(REPLACE "\\" "\\\\" _zig_ccache_exe_escaped "${_zig_ccache_exe}")
170189
set(_zig_ccache_stmt " *p++ = \"${_zig_ccache_exe_escaped}\";")
171190
math(EXPR _zig_extra_args_count "${_zig_extra_args_count} + 1")
172191
endif()
173192

174-
# Process target flags injection
193+
# Inject target/cpu/extra flags
175194
if(inject_flags)
176195
foreach(_flag IN LISTS _zig_target_flags)
177196
string(REPLACE "\\" "\\\\" _flag_escaped "${_flag}")
@@ -181,14 +200,14 @@ function(_zig_generate_shim tool_name subcommand inject_flags use_ccache)
181200
endforeach()
182201
endif()
183202

184-
# Render C template
203+
# Render C source from template
185204
string(CONFIGURE "${_zig_shim_template}" _shim_content @ONLY)
186205

187206
set(_shim_src "${_zig_shims_dir}/${tool_name}.c")
188207
set(_shim_exe "${_zig_shims_dir}/${tool_name}${_zig_wrapper_ext}")
189208
set(_shim_hash "${_zig_shims_dir}/${tool_name}.hash")
190209

191-
# Avoid recompilation using MD5 hash check
210+
# Skip recompilation when content is unchanged
192211
string(MD5 _new_hash "${_shim_content}")
193212
if(EXISTS "${_shim_hash}" AND EXISTS "${_shim_exe}")
194213
file(READ "${_shim_hash}" _old_hash)
@@ -212,15 +231,20 @@ function(_zig_generate_shim tool_name subcommand inject_flags use_ccache)
212231
ERROR_VARIABLE _compile_stderr
213232
OUTPUT_QUIET
214233
)
234+
215235
if(NOT _compile_result EQUAL 0)
216236
message(FATAL_ERROR
217-
"Zig Toolchain: Failed to compile wrapper executable for '${tool_name}'.\n"
237+
"Zig Toolchain: Failed to compile wrapper for '${tool_name}'.\n"
218238
"${_compile_stderr}"
219239
)
220240
endif()
221241

222242
if(NOT CMAKE_HOST_WIN32)
223-
execute_process(COMMAND chmod +x "${_shim_exe}" OUTPUT_QUIET)
243+
execute_process(
244+
COMMAND chmod +x "${_shim_exe}"
245+
OUTPUT_QUIET
246+
ERROR_QUIET
247+
)
224248
endif()
225249

226250
file(WRITE "${_shim_hash}" "${_new_hash}")
@@ -237,15 +261,15 @@ _zig_generate_shim("zig-strip" "strip" FALSE FALSE)
237261

238262
set(CMAKE_C_COMPILER "${_zig_shims_dir}/zig-cc${_zig_wrapper_ext}")
239263
set(CMAKE_CXX_COMPILER "${_zig_shims_dir}/zig-c++${_zig_wrapper_ext}")
240-
set(CMAKE_AR "${_zig_shims_dir}/zig-ar${_zig_wrapper_ext}" CACHE FILEPATH "Archiver" FORCE)
241-
set(CMAKE_RANLIB "${_zig_shims_dir}/zig-ranlib${_zig_wrapper_ext}" CACHE FILEPATH "Ranlib" FORCE)
242-
set(CMAKE_NM "${_zig_shims_dir}/zig-nm${_zig_wrapper_ext}" CACHE FILEPATH "NM" FORCE)
243-
set(CMAKE_OBJCOPY "${_zig_shims_dir}/zig-objcopy${_zig_wrapper_ext}" CACHE FILEPATH "Objcopy" FORCE)
244-
set(CMAKE_STRIP "${_zig_shims_dir}/zig-strip${_zig_wrapper_ext}" CACHE FILEPATH "Strip" FORCE)
264+
set(CMAKE_AR "${_zig_shims_dir}/zig-ar${_zig_wrapper_ext}" CACHE FILEPATH "Archiver" FORCE)
265+
set(CMAKE_RANLIB "${_zig_shims_dir}/zig-ranlib${_zig_wrapper_ext}" CACHE FILEPATH "Ranlib" FORCE)
266+
set(CMAKE_NM "${_zig_shims_dir}/zig-nm${_zig_wrapper_ext}" CACHE FILEPATH "NM" FORCE)
267+
set(CMAKE_OBJCOPY "${_zig_shims_dir}/zig-objcopy${_zig_wrapper_ext}" CACHE FILEPATH "Objcopy" FORCE)
268+
set(CMAKE_STRIP "${_zig_shims_dir}/zig-strip${_zig_wrapper_ext}" CACHE FILEPATH "Strip" FORCE)
245269

246270
if(CMAKE_HOST_WIN32)
247271
# Unsupported linker arg: --dependency-file. See https://github.com/ziglang/zig/issues/22213
248-
set(CMAKE_C_LINKER_DEPFILE_SUPPORTED FALSE)
272+
set(CMAKE_C_LINKER_DEPFILE_SUPPORTED FALSE)
249273
set(CMAKE_CXX_LINKER_DEPFILE_SUPPORTED FALSE)
250274
endif()
251275

@@ -255,6 +279,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "Windows")
255279
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> /fo <OBJECT> <SOURCE>")
256280
elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
257281
# Prevent CMake from searching for Xcode SDKs since Zig provides its own sysroot
258-
set(CMAKE_OSX_SYSROOT "" CACHE PATH "Force empty sysroot for Zig" FORCE)
259-
set(CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force empty deployment target" FORCE)
282+
set(CMAKE_OSX_SYSROOT "" CACHE PATH "Force empty sysroot for Zig" FORCE)
283+
set(CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force empty deployment target for Zig" FORCE)
260284
endif()

0 commit comments

Comments
 (0)