@@ -10,6 +10,8 @@ find_program(ZIG_COMPILER zig)
1010if (NOT ZIG_COMPILER)
1111 message (FATAL_ERROR "Zig Toolchain: Zig compiler not found. Please install Zig and ensure it is in your PATH." )
1212endif ()
13+ string (REPLACE "\\ " "\\\\ " _ZIG_COMPILER_EXE "${ZIG_COMPILER} " )
14+
1315execute_process (
1416 COMMAND "${ZIG_COMPILER} " version
1517 OUTPUT_VARIABLE ZIG_COMPILER_VERSION
@@ -48,104 +50,207 @@ if(NOT ZIG_TARGET)
4850
4951 set (ZIG_TARGET "${ZIG_ARCH} -${ZIG_OS} -${ZIG_ABI} " )
5052else ()
51- if (NOT ZIG_TARGET MATCHES "^([a-zA-Z0-9_ ]+)-([a-zA-Z0-9_ ]+)(-([a-zA-Z0-9_.] +))?$" )
52- message (FATAL_ERROR "Zig Toolchain: ZIG_TARGET is invalid. Please specify it manually using -DZIG_TARGET= <arch>-<os>[-<abi>]" )
53+ if (NOT ZIG_TARGET MATCHES "^([^- ]+)-([^- ]+)(-(. +))?$" )
54+ message (FATAL_ERROR "Zig Toolchain: ZIG_TARGET ' ${ZIG_TARGET} ' is invalid. Expected format: <arch>-<os>[-<abi>]" )
5355 endif ()
5456 set (ZIG_ARCH ${CMAKE_MATCH_1} )
5557 set (ZIG_OS ${CMAKE_MATCH_2} )
56- if (CMAKE_MATCH_4)
57- set (ZIG_ABI ${CMAKE_MATCH_4} )
58- else ()
59- set (ZIG_ABI "none" )
60- endif ()
6158endif ()
6259
6360# Dummy version satisfies CMake's cross-compilation requirements without affecting Zig's behavior
6461set (CMAKE_SYSTEM_VERSION 1)
6562set (CMAKE_SYSTEM_PROCESSOR ${ZIG_ARCH} )
63+ set (CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
64+
6665if (ZIG_OS STREQUAL "linux" )
6766 set (CMAKE_SYSTEM_NAME "Linux" )
6867elseif (ZIG_OS STREQUAL "windows" )
6968 set (CMAKE_SYSTEM_NAME "Windows" )
7069elseif (ZIG_OS STREQUAL "macos" )
7170 set (CMAKE_SYSTEM_NAME "Darwin" )
7271else ()
73- message (FATAL_ERROR "Unknown OS: ${ZIG_OS} " )
72+ set (CMAKE_SYSTEM_NAME ${ZIG_OS} )
73+ message (WARNING "Unknown OS: ${ZIG_OS} " )
7474endif ()
7575message (STATUS "Zig Toolchain: v${ZIG_COMPILER_VERSION} → ${ZIG_TARGET} " )
7676
77+ option (ZIG_USE_CCACHE "Enable ccache optimization for Zig toolchain" OFF )
78+ if (ZIG_USE_CCACHE)
79+ find_program (ZIG_CCACHE_EXECUTABLE ccache )
80+ if (ZIG_CCACHE_EXECUTABLE)
81+ message (STATUS "Zig Toolchain: ccache enabled at ${ZIG_CCACHE_EXECUTABLE} " )
82+ else ()
83+ message (WARNING "Zig Toolchain: ZIG_USE_CCACHE is ON but 'ccache' was not found in PATH." )
84+ endif ()
85+ endif ()
86+ if (ZIG_USE_CCACHE AND ZIG_CCACHE_EXECUTABLE)
87+ string (REPLACE "\\ " "\\\\ " _ZIG_CCACHE_EXE "${ZIG_CCACHE_EXECUTABLE} " )
88+ else ()
89+ set (_ZIG_CCACHE_EXE "" )
90+ endif ()
91+
7792set (ZIG_MCPU "" CACHE STRING "Target CPU (e.g. 'baseline', 'native', 'cortex_a53'). See: zig targets" )
7893set (ZIG_MCPU_FEATURES "" CACHE STRING "CPU feature modifiers appended directly to -mcpu=<cpu>, e.g. '+avx2-sse4_1'. Each feature must start with + or -." )
7994set (ZIG_COMPILER_FLAGS "" CACHE STRING "Additional compilation flags" )
8095
81- set (ZIG_WRAPPER_ARGS "" )
96+ if (ZIG_MCPU_FEATURES AND NOT ZIG_MCPU)
97+ message (WARNING "Zig Toolchain: ZIG_MCPU_FEATURES='${ZIG_MCPU_FEATURES} ' is set but ZIG_MCPU is empty." )
98+ endif ()
99+ set (_ZIG_EXTRA_FLAGS_LIST "" )
82100if (ZIG_MCPU)
83- string (APPEND ZIG_WRAPPER_ARGS " -mcpu=${ZIG_MCPU} " )
84- if (ZIG_MCPU_FEATURES)
85- string (APPEND ZIG_WRAPPER_ARGS "${ZIG_MCPU_FEATURES} " )
86- endif ()
101+ list (APPEND _ZIG_EXTRA_FLAGS_LIST "-mcpu=${ZIG_MCPU}${ZIG_MCPU_FEATURES} " )
87102endif ()
88103if (ZIG_COMPILER_FLAGS)
89- string (APPEND ZIG_WRAPPER_ARGS " ${ZIG_COMPILER_FLAGS} " )
104+ separate_arguments (_ZIG_COMPILER_FLAGS NATIVE_COMMAND "${ZIG_COMPILER_FLAGS} " )
105+ list (APPEND _ZIG_EXTRA_FLAGS_LIST ${_ZIG_COMPILER_FLAGS} )
90106endif ()
91- string (STRIP "${ZIG_WRAPPER_ARGS} " ZIG_WRAPPER_ARGS)
92- if (ZIG_WRAPPER_ARGS)
93- message (STATUS "Zig Toolchain: Compiler flags → ${ZIG_WRAPPER_ARGS} " )
107+
108+ set (_ZIG_COMPILER_INJECTED_FLAGS "-target" "${ZIG_TARGET} " ${_ZIG_EXTRA_FLAGS_LIST} )
109+ set (_ZIG_INJECTED_C_CODE "" )
110+ foreach (_arg IN LISTS _ZIG_COMPILER_INJECTED_FLAGS)
111+ string (REPLACE "\\ " "\\\\ " _arg_escaped "${_arg} " )
112+ string (REPLACE "\" " "\\\" " _arg_escaped "${_arg_escaped} " )
113+ string (APPEND _ZIG_INJECTED_C_CODE "\" ${_arg_escaped} \" , " )
114+ endforeach ()
115+
116+ if (CMAKE_HOST_WIN32 )
117+ set (_ZIG_WRAPPER_EXT ".exe" )
118+ set (_ZIG_IS_WIN32 1)
119+ else ()
120+ set (_ZIG_WRAPPER_EXT "" )
121+ set (_ZIG_IS_WIN32 0)
94122endif ()
95123
96- option (ZIG_USE_CCACHE "Enable ccache optimization for Zig toolchain" OFF )
97- set (ZIG_CC_PREFIX "" )
98- if (ZIG_USE_CCACHE)
99- find_program (CCACHE_TOOL ccache )
100- if (CCACHE_TOOL)
101- set (ZIG_CC_PREFIX "\" ${CCACHE_TOOL} \" " )
102- message (STATUS "Zig Toolchain: ccache enabled at ${CCACHE_TOOL} " )
103- else ()
104- message (WARNING "Zig Toolchain: ZIG_USE_CCACHE is ON but 'ccache' was not found in PATH." )
105- endif ()
124+ if (CMAKE_HOST_APPLE )
125+ set (_ZIG_SHIM_STRIP_FLAG "" )
126+ else ()
127+ set (_ZIG_SHIM_STRIP_FLAG "-s" )
106128endif ()
107129
108- # Generate wrapper scripts to inject -target flag and ccache prefix transparently
109130set (ZIG_SHIMS_DIR "${CMAKE_BINARY_DIR} /.zig-shims" )
110131file (MAKE_DIRECTORY "${ZIG_SHIMS_DIR} " )
111- if (CMAKE_HOST_WIN32 )
112- set (EXT ".cmd" )
113- set (HEADER "@echo off" )
114- set (ARGS "%*" )
115- else ()
116- set (EXT "" )
117- set (HEADER "#!/bin/sh" )
118- set (ARGS "\" $@\" " )
119- endif ()
120132
121- file (WRITE "${ZIG_SHIMS_DIR} /zig-cc${EXT} " "${HEADER} \n ${ZIG_CC_PREFIX} \" ${ZIG_COMPILER} \" cc -target ${ZIG_TARGET} ${ZIG_WRAPPER_ARGS} ${ARGS} \n " )
122- file (WRITE "${ZIG_SHIMS_DIR} /zig-c++${EXT} " "${HEADER} \n ${ZIG_CC_PREFIX} \" ${ZIG_COMPILER} \" c++ -target ${ZIG_TARGET} ${ZIG_WRAPPER_ARGS} ${ARGS} \n " )
123- file (WRITE "${ZIG_SHIMS_DIR} /zig-ar${EXT} " "${HEADER} \n\" ${ZIG_COMPILER} \" ar ${ARGS} \n " )
124- file (WRITE "${ZIG_SHIMS_DIR} /zig-rc${EXT} " "${HEADER} \n\" ${ZIG_COMPILER} \" rc ${ARGS} \n " )
125- file (WRITE "${ZIG_SHIMS_DIR} /zig-ranlib${EXT} " "${HEADER} \n\" ${ZIG_COMPILER} \" ranlib ${ARGS} \n " )
126- if (NOT CMAKE_HOST_WIN32 )
127- execute_process (COMMAND chmod +x
128- "${ZIG_SHIMS_DIR} /zig-cc${EXT} "
129- "${ZIG_SHIMS_DIR} /zig-c++${EXT} "
130- "${ZIG_SHIMS_DIR} /zig-ar${EXT} "
131- "${ZIG_SHIMS_DIR} /zig-rc${EXT} "
132- "${ZIG_SHIMS_DIR} /zig-ranlib${EXT} "
133+ function (generate_shim_binary TOOL_NAME ZIG_SUBCOMMAND INJECT_FLAGS USE_CCACHE )
134+ set (WRAPPER_SOURCE "${ZIG_SHIMS_DIR} /${TOOL_NAME} .c" )
135+ set (WRAPPER_EXE "${ZIG_SHIMS_DIR} /${TOOL_NAME}${_ZIG_WRAPPER_EXT} " )
136+ set (WRAPPER_HASH "${ZIG_SHIMS_DIR} /${TOOL_NAME} .hash" )
137+
138+ if (${INJECT_FLAGS} )
139+ set (WRAPPER_INJECT_CODE "${_ZIG_INJECTED_C_CODE} " )
140+ else ()
141+ set (WRAPPER_INJECT_CODE "" )
142+ endif ()
143+
144+ if (${USE_CCACHE} AND _ZIG_CCACHE_EXE)
145+ set (WRAPPER_USE_CCACHE 1)
146+ else ()
147+ set (WRAPPER_USE_CCACHE 0)
148+ endif ()
149+
150+ set (C_CODE_CONTENT "
151+ #include <stddef.h>
152+ #include <stdio.h>
153+ #include <stdlib.h>
154+ #include <string.h>
155+
156+ #if ${_ZIG_IS_WIN32}
157+ #include <process.h>
158+ #else
159+ #include <unistd.h>
160+ #endif
161+
162+ #define ZIG_EXE \" ${_ZIG_COMPILER_EXE} \"
163+ #define ZIG_CMD \" ${ZIG_SUBCOMMAND} \"
164+ #define CCACHE_EXE \" ${_ZIG_CCACHE_EXE} \"
165+ #define USE_CCACHE ${WRAPPER_USE_CCACHE}
166+
167+ int main(int argc, char** argv) {
168+ const char* ijlist[] = {${WRAPPER_INJECT_CODE} NULL};
169+ const int ijcount = (int)(sizeof(ijlist) / sizeof(char*)) - 1;
170+ const int exargc = USE_CCACHE + 2 + ijcount + (argc - 1);
171+ const char** exargv = (const char**)malloc(sizeof(char*) * (size_t)(exargc + 1));
172+
173+ if (!exargv) {
174+ fprintf(stderr, \" malloc failed\\ n\" );
175+ return 1;
176+ }
177+
178+ const char **p = exargv;
179+ if (USE_CCACHE) { *p++ = CCACHE_EXE; }
180+ *p++ = ZIG_EXE;
181+ *p++ = ZIG_CMD;
182+ for (int i = 0; i < ijcount; ++i) { *p++ = ijlist[i]; }
183+ for (int i = 1; i < argc; ++i) { *p++ = argv[i]; }
184+ *p = NULL;
185+
186+ #if ${_ZIG_IS_WIN32}
187+ intptr_t ret = _spawnvp(_P_WAIT, exargv[0], (const char* const*)exargv);
188+ free(exargv);
189+ return (int)ret;
190+ #else
191+ execvp(exargv[0], (char* const*)exargv);
192+ perror(\" execvp failed\" );
193+ free(exargv);
194+ return 1;
195+ #endif
196+ }" )
197+
198+ string (MD5 _new_hash "${C_CODE_CONTENT} " )
199+ if (EXISTS "${WRAPPER_HASH} " AND EXISTS "${WRAPPER_EXE} " )
200+ file (READ "${WRAPPER_HASH} " _old_hash )
201+ string (STRIP "${_old_hash} " _old_hash)
202+ if (_old_hash STREQUAL _new_hash)
203+ return ()
204+ endif ()
205+ endif ()
206+
207+ file (WRITE "${WRAPPER_SOURCE} " "${C_CODE_CONTENT} " )
208+ message (STATUS "Zig Toolchain: Compiling native wrapper for '${TOOL_NAME} '..." )
209+
210+ execute_process (
211+ COMMAND "${ZIG_COMPILER} " cc -O2 ${_ZIG_SHIM_STRIP_FLAG} "${WRAPPER_SOURCE} " -o "${WRAPPER_EXE} "
212+ RESULT_VARIABLE COMPILE_RESULT
213+ ERROR_VARIABLE COMPILE_STDERR
214+ OUTPUT_QUIET
133215 )
134- endif ()
216+ if (NOT COMPILE_RESULT EQUAL 0)
217+ message (FATAL_ERROR
218+ "Zig Toolchain: Failed to compile wrapper executable for '${TOOL_NAME} '.\n "
219+ "${COMPILE_STDERR} " )
220+ endif ()
221+
222+ if (NOT CMAKE_HOST_WIN32 )
223+ execute_process (COMMAND chmod +x "${WRAPPER_EXE} " OUTPUT_QUIET )
224+ endif ()
225+
226+ file (WRITE "${WRAPPER_HASH} " "${_new_hash} " )
227+ endfunction ()
228+
229+ generate_shim_binary ("zig-cc" "cc" TRUE TRUE )
230+ generate_shim_binary ("zig-c++" "c++" TRUE TRUE )
231+ generate_shim_binary ("zig-ar" "ar" FALSE FALSE )
232+ generate_shim_binary ("zig-rc" "rc" FALSE FALSE )
233+ generate_shim_binary ("zig-ranlib" "ranlib" FALSE FALSE )
234+ generate_shim_binary ("zig-nm" "nm" FALSE FALSE )
235+ generate_shim_binary ("zig-objcopy" "objcopy" FALSE FALSE )
236+ generate_shim_binary ("zig-strip" "strip" FALSE FALSE )
135237
136- set (CMAKE_C_COMPILER "${ZIG_SHIMS_DIR} /zig-cc${EXT} " )
137- set (CMAKE_CXX_COMPILER "${ZIG_SHIMS_DIR} /zig-c++${EXT} " )
138- set (CMAKE_AR "${ZIG_SHIMS_DIR} /zig-ar${EXT} " CACHE FILEPATH "Archiver" FORCE )
139- set (CMAKE_RANLIB "${ZIG_SHIMS_DIR} /zig-ranlib${EXT} " CACHE FILEPATH "Ranlib" FORCE )
238+ set (CMAKE_C_COMPILER "${ZIG_SHIMS_DIR} /zig-cc${_ZIG_WRAPPER_EXT} " )
239+ 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 )
140245
141246if (CMAKE_HOST_WIN32 )
142- # unsupported linker arg: --dependency-file
143- set (CMAKE_C_LINKER_DEPFILE_SUPPORTED FALSE )
144- set (CMAKE_CXX_LINKER_DEPFILE_SUPPORTED FALSE )
247+ # unsupported linker arg: --dependency-file. see https://github.com/ziglang/zig/issues/22213
248+ set (CMAKE_C_LINKER_DEPFILE_SUPPORTED FALSE )
249+ set (CMAKE_CXX_LINKER_DEPFILE_SUPPORTED FALSE )
145250endif ()
146251
147252if (CMAKE_SYSTEM_NAME MATCHES "Windows" )
148- set (CMAKE_RC_COMPILER "${ZIG_SHIMS_DIR} /zig-rc${EXT } " CACHE FILEPATH "Resource Compiler" FORCE )
253+ set (CMAKE_RC_COMPILER "${ZIG_SHIMS_DIR} /zig-rc${_ZIG_WRAPPER_EXT } " CACHE FILEPATH "Resource Compiler" FORCE )
149254 # Explicitly specify MSVC syntax because zig rc only supports this format
150255 set (CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> /fo <OBJECT> <SOURCE>" )
151256elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin" )
0 commit comments