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# ==============================================================================
77include_guard (GLOBAL )
88
99option (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'" )
1212set (ZIG_COMPILER_FLAGS "" CACHE STRING "Additional compilation flags" )
1313
1414if (ZIG_MCPU_FEATURES AND NOT ZIG_MCPU)
@@ -32,7 +32,32 @@ execute_process(
3232 RESULT_VARIABLE _zig_version_result
3333)
3434if (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." )
3661endif ()
3762
3863unset (_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} " )
7597else ()
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} " )
81103endif ()
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} " )
86108set (CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
87109
88110if (ZIG_OS STREQUAL "linux" )
@@ -92,8 +114,8 @@ elseif(ZIG_OS STREQUAL "windows")
92114elseif (ZIG_OS STREQUAL "macos" )
93115 set (CMAKE_SYSTEM_NAME "Darwin" )
94116else ()
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. " )
97119endif ()
98120
99121message (STATUS "Zig Toolchain: v${ZIG_COMPILER_VERSION} → ${ZIG_TARGET} " )
@@ -110,27 +132,25 @@ endif()
110132
111133if (CMAKE_HOST_WIN32 )
112134 set (_zig_wrapper_ext ".exe" )
113- set (_zig_host_win32 1)
135+ set (_zig_host_win32 1)
114136else ()
115137 set (_zig_wrapper_ext "" )
116- set (_zig_host_win32 0)
138+ set (_zig_host_win32 0)
117139endif ()
118140
119141set (_zig_shims_dir "${CMAKE_BINARY_DIR} /.zig-shims" )
120142file (MAKE_DIRECTORY "${_zig_shims_dir} " )
121143
122- # Use Bracket Argument [=[ ... ]=] to avoid escaping hell
144+ # Use bracket argument [=[ ... ]=] to avoid escaping hell
123145set (_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-
134154int 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
155174function (_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
238262set (CMAKE_C_COMPILER "${_zig_shims_dir} /zig-cc${_zig_wrapper_ext} " )
239263set (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
246270if (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 )
250274endif ()
251275
@@ -255,6 +279,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "Windows")
255279 set (CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> /fo <OBJECT> <SOURCE>" )
256280elseif (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 )
260284endif ()
0 commit comments