@@ -68,13 +68,18 @@ struct ScanResult {
6868ScanResult scan_package (const std::filesystem::path& root,
6969 const mcpp::manifest::Manifest& manifest);
7070
71- // Absolutize relative `-I<path>` compile flags against the package root
72- // (G8b). A manifest's relative -I means root-relative, but ninja runs
73- // commands with cwd = the output dir, so a verbatim relative flag resolves
74- // against the wrong base. Called at every point where per-unit flag vectors
75- // are attached (the scanner here; plan.cppm for a target's entry unit).
76- void absolutize_include_flags (const std::filesystem::path& root,
77- std::vector<std::string>& flags);
71+ // Absolutize relative include/lib-search-path flags against the package root
72+ // (G8b, generalized by #226). A manifest's relative include flag means
73+ // root-relative, but ninja runs commands with cwd = the output dir, so a
74+ // verbatim relative flag resolves against the wrong base. Recognizes the
75+ // whole include-family prefix set — -I, -iquote, -isystem, -idirafter,
76+ // -iprefix, -L — in BOTH the joined spelling (`-iquotehdr`) and the
77+ // separated spelling (`-isystem` followed by a standalone `hdr` element).
78+ // Called at every point where per-unit flag vectors are attached (the
79+ // scanner here; plan.cppm for a target's entry unit; flags.cppm for the
80+ // manifest-global [build] include_dirs).
81+ void normalize_include_flags (const std::filesystem::path& root,
82+ std::vector<std::string>& flags);
7883
7984enum class DependencyVisibility {
8085 Private,
@@ -543,16 +548,45 @@ std::vector<std::filesystem::path> expand_dir_glob(const std::filesystem::path&
543548 return out;
544549}
545550
546- void absolutize_include_flags (const std::filesystem::path& root,
547- std::vector<std::string>& flags)
551+ namespace {
552+
553+ // has_root_path: leave absolute AND root-relative ("/x" on Windows)
554+ // spellings alone — only genuinely root-less paths are project-relative.
555+ std::string rewrite_rel_copy (const std::string& p, const std::filesystem::path& root) {
556+ std::filesystem::path fp (p);
557+ if (fp.has_root_path ()) return p;
558+ return (root / fp).string ();
559+ }
560+
561+ void rewrite_rel (std::string& p, const std::filesystem::path& root) {
562+ p = rewrite_rel_copy (p, root);
563+ }
564+
565+ } // namespace
566+
567+ void normalize_include_flags (const std::filesystem::path& root,
568+ std::vector<std::string>& flags)
548569{
549- for (auto & f : flags) {
550- if (f.size () > 2 && f.starts_with (" -I" )) {
551- std::filesystem::path p (f.substr (2 ));
552- // has_root_path: leave absolute AND root-relative ("/x" on
553- // Windows) spellings alone — only genuinely root-less paths are
554- // project-relative.
555- if (!p.has_root_path ()) f = " -I" + (root / p).string ();
570+ // #226: the whole include/lib-search-path family, not just -I. Each
571+ // prefix is checked in both spellings:
572+ // joined: "-iquotehdr" (element starts_with prefix, has a tail)
573+ // separated: "-isystem", "hdr" (element == bare prefix, rewrite next)
574+ static constexpr std::string_view kIncPrefixes [] =
575+ {" -I" , " -iquote" , " -isystem" , " -idirafter" , " -iprefix" , " -L" };
576+
577+ for (std::size_t i = 0 ; i < flags.size (); ++i) {
578+ for (auto pre : kIncPrefixes ) {
579+ if (flags[i] == pre && i + 1 < flags.size ()) { // separated
580+ rewrite_rel (flags[i + 1 ], root);
581+ ++i;
582+ break ;
583+ }
584+ if (flags[i].size () > pre .size () && flags[i].starts_with (pre )) { // joined
585+ std::string tail = flags[i].substr (pre .size ());
586+ std::string abs = rewrite_rel_copy (tail, root);
587+ if (abs != tail) flags[i] = std::string (pre ) + abs;
588+ break ;
589+ }
556590 }
557591 }
558592}
@@ -836,9 +870,9 @@ void scan_one_into(ScanResult& result,
836870 u.packageCflags = packageCflags;
837871 u.packageCxxflags = packageCxxflags;
838872 apply_glob_flags (u);
839- absolutize_include_flags (root, u.packageCflags );
840- absolutize_include_flags (root, u.packageCxxflags );
841- absolutize_include_flags (root, u.packageAsmflags );
873+ normalize_include_flags (root, u.packageCflags );
874+ normalize_include_flags (root, u.packageCxxflags );
875+ normalize_include_flags (root, u.packageAsmflags );
842876 result.graph .units .push_back (std::move (u));
843877 continue ;
844878 }
@@ -851,9 +885,9 @@ void scan_one_into(ScanResult& result,
851885 r->packageCflags = packageCflags;
852886 r->packageCxxflags = packageCxxflags;
853887 apply_glob_flags (*r);
854- absolutize_include_flags (root, r->packageCflags );
855- absolutize_include_flags (root, r->packageCxxflags );
856- absolutize_include_flags (root, r->packageAsmflags );
888+ normalize_include_flags (root, r->packageCflags );
889+ normalize_include_flags (root, r->packageCxxflags );
890+ normalize_include_flags (root, r->packageAsmflags );
857891 result.graph .units .push_back (std::move (*r));
858892 }
859893
0 commit comments