@@ -197,7 +197,11 @@ std::string emit_ninja_string(const BuildPlan& plan) {
197197 append (" \n " );
198198
199199 append (" rule cp_bmi\n " );
200+ #if defined(_WIN32)
201+ append (" command = cmd /c copy /y $in $out >nul\n " );
202+ #else
200203 append (" command = mkdir -p $$(dirname $out) && cp -f $in $out\n " );
204+ #endif
201205 append (" description = STAGE $out\n\n " );
202206
203207 // P1: per-file dyndep rule. Converts one .ddi → .dd independently.
@@ -222,9 +226,9 @@ std::string emit_ninja_string(const BuildPlan& plan) {
222226 append (" rule cxx_module\n " );
223227#if defined(_WIN32)
224228 // Windows: skip BMI restat optimization (requires POSIX shell).
225- // Just compile directly — incremental rebuild still works via dyndep .
229+ // No $toolenv (empty on Windows; its leading space breaks CreateProcess) .
226230 append (std::format (" command = "
227- " $toolenv $ cxx $cxxflags{} -c $in -o $out\n " , module_output_flag));
231+ " $cxx $cxxflags{} -c $in -o $out\n " , module_output_flag));
228232#else
229233 append (std::format (" command = "
230234 " if [ -n \" $bmi_out\" ] && [ -f \" $bmi_out\" ]; then "
@@ -244,21 +248,42 @@ std::string emit_ninja_string(const BuildPlan& plan) {
244248 append (" \n " );
245249
246250 append (" rule cxx_object\n " );
251+ #if defined(_WIN32)
252+ append (" command = $cxx $cxxflags -c $in -o $out\n " );
253+ #else
247254 append (" command = $toolenv $cxx $cxxflags -c $in -o $out\n " );
255+ #endif
248256 append (" description = OBJ $out\n " );
249257 if (dyndep)
250258 append (" restat = 1\n " );
251259 append (" \n " );
252260
253261 if (need_c_rule) {
254262 append (" rule c_object\n " );
263+ #if defined(_WIN32)
264+ append (" command = $cc $cflags -c $in -o $out\n " );
265+ #else
255266 append (" command = $toolenv $cc $cflags -c $in -o $out\n " );
267+ #endif
256268 append (" description = CC $out\n " );
257269 if (dyndep)
258270 append (" restat = 1\n " );
259271 append (" \n " );
260272 }
261273
274+ #if defined(_WIN32)
275+ append (" rule cxx_link\n " );
276+ append (" command = $cxx $in -o $out $ldflags\n " );
277+ append (" description = LINK $out\n\n " );
278+
279+ append (" rule cxx_archive\n " );
280+ append (" command = $ar rcs $out $in\n " );
281+ append (" description = AR $out\n\n " );
282+
283+ append (" rule cxx_shared\n " );
284+ append (" command = $cxx -shared $in -o $out $ldflags\n " );
285+ append (" description = SHARED $out\n\n " );
286+ #else
262287 append (" rule cxx_link\n " );
263288 append (" command = $toolenv $cxx $in -o $out $ldflags\n " );
264289 append (" description = LINK $out\n\n " );
@@ -270,6 +295,7 @@ std::string emit_ninja_string(const BuildPlan& plan) {
270295 append (" rule cxx_shared\n " );
271296 append (" command = $toolenv $cxx -shared $in -o $out $ldflags\n " );
272297 append (" description = SHARED $out\n\n " );
298+ #endif
273299
274300 if (dyndep) {
275301 // Scan rule: produce P1689 .ddi for one TU.
@@ -278,14 +304,23 @@ std::string emit_ninja_string(const BuildPlan& plan) {
278304 append (" rule cxx_scan\n " );
279305 if (plan.scanDepsPath .empty ()) {
280306 // GCC path: compiler-integrated P1689 scanning.
307+ #if defined(_WIN32)
308+ append (" command = $cxx $cxxflags -fmodules "
309+ #else
281310 append (" command = $toolenv $cxx $cxxflags -fmodules "
311+ #endif
282312 " -fdeps-format=p1689r5 "
283313 " -fdeps-file=$out -fdeps-target=$compile_target "
284314 " -M -MM -MF $out.dep -E $in -o $compile_target\n " );
285315 } else {
286316 // Clang path: clang-scan-deps produces P1689 JSON to stdout.
317+ #if defined(_WIN32)
318+ append (" command = $scan_deps -format=p1689 -- "
319+ " $cxx $cxxflags -c $in -o $compile_target > $out\n " );
320+ #else
287321 append (" command = $toolenv $scan_deps -format=p1689 -- "
288322 " $cxx $cxxflags -c $in -o $compile_target > $out\n " );
323+ #endif
289324 }
290325 append (" description = SCAN $out\n\n " );
291326
0 commit comments