2929#include < cstring>
3030#include < iostream>
3131#include < chrono>
32+ #include < optional>
33+ #include < unordered_set>
34+ #include < cstdlib>
35+ #include < algorithm>
36+ #include < nlohmann/json.hpp>
3237
3338#ifndef _WIN32
3439#include < unistd.h>
@@ -68,6 +73,39 @@ namespace vix::commands::RunCommand::detail
6873 return false ;
6974 };
7075
76+ auto home_dir = []() -> std::optional<std::string>
77+ {
78+ #ifdef _WIN32
79+ const char *home = std::getenv (" USERPROFILE" );
80+ #else
81+ const char *home = std::getenv (" HOME" );
82+ #endif
83+ if (!home || std::string (home).empty ())
84+ return std::nullopt ;
85+ return std::string (home);
86+ };
87+
88+ auto vix_root = [&]() -> fs::path
89+ {
90+ if (const auto home = home_dir (); home)
91+ return fs::path (*home) / " .vix" ;
92+ return fs::path (" .vix" );
93+ };
94+
95+ auto global_manifest_path = [&]() -> fs::path
96+ {
97+ return vix_root () / " global" / " installed.json" ;
98+ };
99+
100+ auto dep_id_to_dir = [](std::string depId) -> std::string
101+ {
102+ depId.erase (std::remove (depId.begin (), depId.end (), ' @' ), depId.end ());
103+ std::replace (depId.begin (), depId.end (), ' /' , ' .' );
104+ return depId;
105+ };
106+
107+ std::unordered_set<std::string> localPkgDirs;
108+
71109 auto scan_one = [&](const fs::path &baseDir)
72110 {
73111 const fs::path depsRoot = baseDir / " .vix" / " deps" ;
@@ -82,6 +120,10 @@ namespace vix::commands::RunCommand::detail
82120 if (!it->is_directory ())
83121 continue ;
84122
123+ const std::string pkgDir = it->path ().filename ().string ();
124+ if (!pkgDir.empty ())
125+ localPkgDirs.insert (pkgDir);
126+
85127 const fs::path inc = it->path () / " include" ;
86128 if (!fs::exists (inc, ec) || ec)
87129 continue ;
@@ -92,14 +134,66 @@ namespace vix::commands::RunCommand::detail
92134 }
93135 };
94136
95- // Local: scan startDir only
137+ auto scan_global = [&]()
138+ {
139+ const fs::path manifestPath = global_manifest_path ();
140+ if (!fs::exists (manifestPath))
141+ return ;
142+
143+ std::ifstream ifs (manifestPath);
144+ if (!ifs)
145+ return ;
146+
147+ nlohmann::json root;
148+ ifs >> root;
149+
150+ if (!root.is_object () || !root.contains (" packages" ) || !root[" packages" ].is_array ())
151+ return ;
152+
153+ for (const auto &item : root[" packages" ])
154+ {
155+ if (!item.is_object ())
156+ continue ;
157+
158+ if (!item.contains (" id" ) || !item[" id" ].is_string ())
159+ continue ;
160+
161+ if (!item.contains (" installed_path" ) || !item[" installed_path" ].is_string ())
162+ continue ;
163+
164+ const std::string id = item[" id" ].get <std::string>();
165+ const std::string pkgDir = dep_id_to_dir (id);
166+
167+ // priorité au local
168+ if (localPkgDirs.contains (pkgDir))
169+ continue ;
170+
171+ std::string includeDir = " include" ;
172+ if (item.contains (" include" ) && item[" include" ].is_string ())
173+ includeDir = item[" include" ].get <std::string>();
174+
175+ const fs::path installedPath = fs::path (item[" installed_path" ].get <std::string>());
176+ const fs::path inc = installedPath / includeDir;
177+
178+ std::error_code ec;
179+ if (!fs::exists (inc, ec) || ec)
180+ continue ;
181+
182+ const std::string incStr = inc.string ();
183+ if (!already_has_I (incStr))
184+ opt.scriptFlags .push_back (" -I" + incStr);
185+ }
186+ };
187+
188+ // Local: scan startDir only, then globals
96189 if (opt.autoDeps == AutoDepsMode::Local)
97190 {
98191 scan_one (startDir);
192+ scan_global ();
99193 return ;
100194 }
101195
102- // Up: scan startDir and all parents up to filesystem root
196+ // Up: scan startDir and all parents up to filesystem root, then globals
103197 if (opt.autoDeps == AutoDepsMode::Up)
104198 {
105199 fs::path cur = startDir;
@@ -112,12 +206,13 @@ namespace vix::commands::RunCommand::detail
112206 if (parent.empty () || parent == cur)
113207 break ;
114208
115- // Stop at root ("/" or drive root)
116209 if (fs::equivalent (parent, cur, ec) && !ec)
117210 break ;
118211
119212 cur = parent;
120213 }
214+
215+ scan_global ();
121216 return ;
122217 }
123218 }
@@ -648,13 +743,21 @@ namespace vix::commands::RunCommand::detail
648743 using namespace std ;
649744 namespace fs = std::filesystem;
650745
651- const fs::path script = opt.cppFile ;
746+ Options o = opt;
747+
748+ const fs::path script = o.cppFile ;
652749 if (!fs::exists (script))
653750 {
654751 error (" C++ file not found: " + script.string ());
655752 return 1 ;
656753 }
657754
755+ // auto deps (single .cpp)
756+ if (o.autoDeps != AutoDepsMode::None)
757+ {
758+ apply_auto_deps_includes_from_deps_folder (o, script.parent_path ());
759+ }
760+
658761 const string exeName = script.stem ().string ();
659762
660763 fs::path scriptsRoot = get_scripts_root ();
@@ -673,17 +776,17 @@ namespace vix::commands::RunCommand::detail
673776 exeName,
674777 script,
675778 useVixRuntime,
676- opt .scriptFlags );
779+ o .scriptFlags );
677780 }
678781
679782 fs::path buildDir = projectDir / " build-ninja" ;
680783 const fs::path sigFile = projectDir / " .vix-config.sig" ;
681784
682785 const std::string sig = make_script_config_signature (
683786 useVixRuntime,
684- opt .enableSanitizers ,
685- opt .enableUbsanOnly ,
686- opt .scriptFlags );
787+ o .enableSanitizers ,
788+ o .enableUbsanOnly ,
789+ o .scriptFlags );
687790
688791 bool needConfigure = true ;
689792 {
0 commit comments