@@ -72,6 +72,27 @@ std::string escape_ninja_path(const std::filesystem::path& p) {
7272 return out;
7373}
7474
75+ std::string escape_flag_path (const std::filesystem::path& p) {
76+ auto s = p.string ();
77+ std::string out;
78+ out.reserve (s.size ());
79+ for (char c : s) {
80+ if (c == ' ' || c == ' $' || c == ' :' )
81+ out.push_back (' $' );
82+ out.push_back (c);
83+ }
84+ return out;
85+ }
86+
87+ std::string local_include_flags (const CompileUnit& cu) {
88+ std::string flags;
89+ for (auto const & inc : cu.localIncludeDirs ) {
90+ flags += " -I" ;
91+ flags += escape_flag_path (inc);
92+ }
93+ return flags;
94+ }
95+
7596void write_file (const std::filesystem::path& p, std::string_view content) {
7697 std::filesystem::create_directories (p.parent_path ());
7798 std::ofstream os (p);
@@ -294,13 +315,13 @@ std::string emit_ninja_string(const BuildPlan& plan) {
294315 if constexpr (mcpp::platform::is_windows) {
295316 // Windows: skip BMI restat optimization (requires POSIX shell).
296317 append (std::format (" command = "
297- " $cxx $cxxflags{} -c $in -o $out\n " , module_output_flag));
318+ " $cxx $local_includes $ cxxflags{} -c $in -o $out\n " , module_output_flag));
298319 } else {
299320 append (std::format (" command = "
300321 " if [ -n \" $bmi_out\" ] && [ -f \" $bmi_out\" ]; then "
301322 " cp -p \" $bmi_out\" \" $bmi_out.bak\" ; "
302323 " fi && "
303- " $cxx $cxxflags{} -c $in -o $out && "
324+ " $cxx $local_includes $ cxxflags{} -c $in -o $out && "
304325 " if [ -n \" $bmi_out\" ] && [ -f \" $bmi_out.bak\" ] && "
305326 " cmp -s \" $bmi_out\" \" $bmi_out.bak\" ; then "
306327 " mv \" $bmi_out.bak\" \" $bmi_out\" ; "
@@ -314,15 +335,15 @@ std::string emit_ninja_string(const BuildPlan& plan) {
314335 append (" \n " );
315336
316337 append (" rule cxx_object\n " );
317- append (" command = $cxx $cxxflags -c $in -o $out\n " );
338+ append (" command = $cxx $local_includes $ cxxflags -c $in -o $out\n " );
318339 append (" description = OBJ $out\n " );
319340 if (dyndep)
320341 append (" restat = 1\n " );
321342 append (" \n " );
322343
323344 if (need_c_rule) {
324345 append (" rule c_object\n " );
325- append (" command = $cc $cflags -c $in -o $out\n " );
346+ append (" command = $cc $local_includes $ cflags -c $in -o $out\n " );
326347 append (" description = CC $out\n " );
327348 if (dyndep)
328349 append (" restat = 1\n " );
@@ -348,7 +369,7 @@ std::string emit_ninja_string(const BuildPlan& plan) {
348369 append (" rule cxx_scan\n " );
349370 if (plan.scanDepsPath .empty ()) {
350371 // GCC path: compiler-integrated P1689 scanning.
351- append (" command = $cxx $cxxflags -fmodules "
372+ append (" command = $cxx $local_includes $ cxxflags -fmodules "
352373 " -fdeps-format=p1689r5 "
353374 " -fdeps-file=$out -fdeps-target=$compile_target "
354375 " -M -MM -MF $out.dep -E $in -o $compile_target\n " );
@@ -358,10 +379,10 @@ std::string emit_ninja_string(const BuildPlan& plan) {
358379 // Wrap in cmd /c for shell redirection (ninja on Windows uses
359380 // CreateProcess which doesn't interpret > as redirect).
360381 append (" command = cmd /c \" $scan_deps -format=p1689 -- "
361- " $cxx $cxxflags -c $in -o $compile_target > $out\"\n " );
382+ " $cxx $local_includes $ cxxflags -c $in -o $compile_target > $out\"\n " );
362383 } else {
363384 append (" command = $scan_deps -format=p1689 -- "
364- " $cxx $cxxflags -c $in -o $compile_target > $out\n " );
385+ " $cxx $local_includes $ cxxflags -c $in -o $compile_target > $out\n " );
365386 }
366387 }
367388 append (" description = SCAN $out\n\n " );
@@ -438,6 +459,8 @@ std::string emit_ninja_string(const BuildPlan& plan) {
438459 append (std::format (" build {} : cxx_scan {}\n " , escape_ninja_path (ddi),
439460 escape_ninja_path (cu.source )));
440461 append (std::format (" compile_target = {}\n " , escape_ninja_path (cu.object )));
462+ if (auto includes = local_include_flags (cu); !includes.empty ())
463+ append (std::format (" local_includes ={}\n " , includes));
441464 }
442465 append (" \n " );
443466
@@ -481,6 +504,8 @@ std::string emit_ninja_string(const BuildPlan& plan) {
481504 } else {
482505 out_line += " \n " ;
483506 }
507+ if (auto includes = local_include_flags (cu); !includes.empty ())
508+ out_line += " local_includes =" + includes + " \n " ;
484509 append (std::move (out_line));
485510 }
486511 append (" \n " );
@@ -519,6 +544,8 @@ std::string emit_ninja_string(const BuildPlan& plan) {
519544 if (!implicit.empty ())
520545 out_line += " |" + implicit;
521546 out_line += " \n " ;
547+ if (auto includes = local_include_flags (cu); !includes.empty ())
548+ out_line += " local_includes =" + includes + " \n " ;
522549 // Clang needs $bmi_out to emit -fmodule-output=$bmi_out
523550 if (cu.providesModule ) {
524551 out_line += " bmi_out = " + bmi_path (*cu.providesModule ) + " \n " ;
0 commit comments