Skip to content

Commit 88b6ff3

Browse files
committed
fix(run): auto-link installed registry dependencies
1 parent 64fe8f1 commit 88b6ff3

3 files changed

Lines changed: 256 additions & 4 deletions

File tree

src/commands/InstallCommand.cpp

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ namespace vix::commands
7575
std::string type;
7676
std::string include{"include"};
7777
std::vector<std::string> dependencies;
78+
std::vector<std::string> cmakeTargets;
7879

7980
fs::path checkout;
8081
fs::path linkDir;
@@ -465,6 +466,7 @@ namespace vix::commands
465466
dep.type = "unknown";
466467
dep.include = "include";
467468
dep.dependencies.clear();
469+
dep.cmakeTargets.clear();
468470
return;
469471
}
470472

@@ -508,6 +510,38 @@ namespace vix::commands
508510
}
509511
};
510512

513+
dep.cmakeTargets.clear();
514+
515+
auto append_target = [&](const std::string &target)
516+
{
517+
const std::string t = trim_copy(target);
518+
if (t.empty())
519+
return;
520+
521+
if (std::find(dep.cmakeTargets.begin(), dep.cmakeTargets.end(), t) == dep.cmakeTargets.end())
522+
dep.cmakeTargets.push_back(t);
523+
};
524+
525+
if (j.contains("cmake") && j["cmake"].is_object())
526+
{
527+
const auto &cmake = j["cmake"];
528+
529+
if (cmake.contains("target") && cmake["target"].is_string())
530+
append_target(cmake["target"].get<std::string>());
531+
532+
if (cmake.contains("targets") && cmake["targets"].is_array())
533+
{
534+
for (const auto &item : cmake["targets"])
535+
{
536+
if (item.is_string())
537+
append_target(item.get<std::string>());
538+
}
539+
}
540+
}
541+
542+
if (j.contains("cmake_target") && j["cmake_target"].is_string())
543+
append_target(j["cmake_target"].get<std::string>());
544+
511545
if (j.contains("dependencies"))
512546
read_dep_block(j["dependencies"]);
513547

@@ -744,6 +778,21 @@ namespace vix::commands
744778

745779
out << "set(_VIX_DEPS_DIR " << cmake_quote(project_deps_dir().string()) << ")\n\n";
746780

781+
out << "# Vix installed package roots\n";
782+
out << "if(DEFINED ENV{VIX_ROOT} AND NOT \"$ENV{VIX_ROOT}\" STREQUAL \"\")\n";
783+
out << " list(PREPEND CMAKE_PREFIX_PATH \"$ENV{VIX_ROOT}\")\n";
784+
out << "endif()\n\n";
785+
786+
out << "if(DEFINED ENV{HOME} AND NOT \"$ENV{HOME}\" STREQUAL \"\")\n";
787+
out << " list(APPEND CMAKE_PREFIX_PATH \"$ENV{HOME}/.vix\")\n";
788+
out << " list(APPEND CMAKE_PREFIX_PATH \"$ENV{HOME}/.local\")\n";
789+
out << "endif()\n\n";
790+
791+
out << "if(DEFINED ENV{USERPROFILE} AND NOT \"$ENV{USERPROFILE}\" STREQUAL \"\")\n";
792+
out << " list(APPEND CMAKE_PREFIX_PATH \"$ENV{USERPROFILE}/.vix\")\n";
793+
out << " list(APPEND CMAKE_PREFIX_PATH \"$ENV{USERPROFILE}/.local\")\n";
794+
out << "endif()\n\n";
795+
747796
out << "# ------------------------------------------------------\n";
748797
out << "# Internal helpers generated by Vix\n";
749798
out << "# ------------------------------------------------------\n\n";
@@ -825,12 +874,40 @@ namespace vix::commands
825874
out << " return()\n";
826875
out << " endif()\n";
827876
out << "\n";
877+
out << " string(REPLACE \"-\" \"_\" _VIX_NS_UNDERSCORE \"${dep_ns}\")\n";
878+
out << " string(REPLACE \".\" \"_\" _VIX_NS_UNDERSCORE \"${_VIX_NS_UNDERSCORE}\")\n";
879+
out << "\n";
880+
out << " string(REPLACE \"-\" \"_\" _VIX_NAME_UNDERSCORE \"${dep_name}\")\n";
881+
out << " string(REPLACE \".\" \"_\" _VIX_NAME_UNDERSCORE \"${_VIX_NAME_UNDERSCORE}\")\n";
882+
out << "\n";
883+
out << " string(REPLACE \"-\" \"\" _VIX_NAME_FLAT \"${dep_name}\")\n";
884+
out << " string(REPLACE \"_\" \"\" _VIX_NAME_FLAT \"${_VIX_NAME_FLAT}\")\n";
885+
out << " string(REPLACE \".\" \"\" _VIX_NAME_FLAT \"${_VIX_NAME_FLAT}\")\n";
886+
out << "\n";
828887
out << " set(_VIX_CANDIDATES\n";
888+
out << " ${ARGN}\n";
829889
out << " \"${dep_name}\"\n";
890+
out << " \"${_VIX_NAME_UNDERSCORE}\"\n";
891+
out << " \"${_VIX_NAME_FLAT}\"\n";
892+
out << "\n";
830893
out << " \"${dep_name}::${dep_name}\"\n";
894+
out << " \"${dep_name}::${_VIX_NAME_UNDERSCORE}\"\n";
895+
out << " \"${_VIX_NAME_UNDERSCORE}::${_VIX_NAME_UNDERSCORE}\"\n";
896+
out << " \"${_VIX_NAME_UNDERSCORE}::${dep_name}\"\n";
897+
out << " \"${_VIX_NAME_FLAT}::${_VIX_NAME_FLAT}\"\n";
898+
out << "\n";
831899
out << " \"${dep_ns}_${dep_name}\"\n";
900+
out << " \"${dep_ns}_${_VIX_NAME_UNDERSCORE}\"\n";
901+
out << " \"${_VIX_NS_UNDERSCORE}_${dep_name}\"\n";
902+
out << " \"${_VIX_NS_UNDERSCORE}_${_VIX_NAME_UNDERSCORE}\"\n";
903+
out << "\n";
832904
out << " \"${dep_ns}-${dep_name}\"\n";
833905
out << " \"${dep_ns}.${dep_name}\"\n";
906+
out << "\n";
907+
out << " \"${dep_ns}::${dep_name}\"\n";
908+
out << " \"${dep_ns}::${_VIX_NAME_UNDERSCORE}\"\n";
909+
out << " \"${_VIX_NS_UNDERSCORE}::${dep_name}\"\n";
910+
out << " \"${_VIX_NS_UNDERSCORE}::${_VIX_NAME_UNDERSCORE}\"\n";
834911
out << " )\n";
835912
out << "\n";
836913
out << " foreach(_VIX_CAND IN LISTS _VIX_CANDIDATES)\n";
@@ -877,7 +954,12 @@ namespace vix::commands
877954
<< cmake_quote((project_vix_dir() / buildDirName).string())
878955
<< " EXCLUDE_FROM_ALL)\n";
879956
out << "endif()\n";
880-
out << "_vix_try_bridge_for_dep(" << depNs << " " << depName << ")\n";
957+
out << "_vix_try_bridge_for_dep(" << depNs << " " << depName;
958+
959+
for (const auto &target : dep.cmakeTargets)
960+
out << " " << target;
961+
962+
out << ")\n";
881963
}
882964
else if (isHeaderOnly)
883965
{
@@ -908,7 +990,12 @@ namespace vix::commands
908990
<< cmake_quote((project_vix_dir() / buildDirName).string())
909991
<< " EXCLUDE_FROM_ALL)\n";
910992
out << "endif()\n";
911-
out << "_vix_try_bridge_for_dep(" << depNs << " " << depName << ")\n";
993+
out << "_vix_try_bridge_for_dep(" << depNs << " " << depName;
994+
995+
for (const auto &target : dep.cmakeTargets)
996+
out << " " << target;
997+
998+
out << ")\n";
912999
}
9131000
else if (fs::exists(depIncludeDir))
9141001
{

src/commands/run/RunScript.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,18 +101,80 @@ namespace vix::commands::RunCommand::detail
101101
return state;
102102
}
103103

104+
bool project_has_registry_lock_dependencies(const fs::path &projectDir)
105+
{
106+
const fs::path lockPath = projectDir / "vix.lock";
107+
108+
if (!fs::exists(lockPath))
109+
return false;
110+
111+
std::ifstream ifs(lockPath);
112+
if (!ifs)
113+
return false;
114+
115+
nlohmann::json lock;
116+
117+
try
118+
{
119+
ifs >> lock;
120+
}
121+
catch (...)
122+
{
123+
return false;
124+
}
125+
126+
if (!lock.is_object())
127+
return false;
128+
129+
if (!lock.contains("dependencies") || !lock["dependencies"].is_array())
130+
return false;
131+
132+
return !lock["dependencies"].empty();
133+
}
134+
135+
bool project_registry_deps_installed(const fs::path &projectDir)
136+
{
137+
const fs::path vixDir = projectDir / ".vix";
138+
const fs::path depsDir = vixDir / "deps";
139+
const fs::path depsCmake = vixDir / "vix_deps.cmake";
140+
141+
return fs::exists(depsDir) && fs::exists(depsCmake);
142+
}
143+
144+
bool ensure_registry_deps_installed_if_needed(const fs::path &projectDir)
145+
{
146+
if (!project_has_registry_lock_dependencies(projectDir))
147+
return true;
148+
149+
if (project_registry_deps_installed(projectDir))
150+
return true;
151+
152+
error("Dependencies not installed");
153+
hint("run: vix install");
154+
return false;
155+
}
156+
104157
int prepare_script_options_common(Options &opt)
105158
{
106159
print_double_dash_warning_if_needed(opt);
107160

108161
if (!ensure_script_exists(opt.cppFile))
109162
return 1;
110163

164+
const fs::path projectDir =
165+
opt.cppFile.has_parent_path()
166+
? fs::absolute(opt.cppFile.parent_path()).lexically_normal()
167+
: fs::current_path();
168+
169+
if (!ensure_registry_deps_installed_if_needed(projectDir))
170+
return 1;
171+
111172
if (opt.autoDeps != AutoDepsMode::None)
112173
apply_auto_deps_includes_from_deps_folder(opt, opt.cppFile.parent_path());
113174

114175
return 0;
115176
}
177+
116178
inline bool is_sigint_exit_code(int code) noexcept
117179
{
118180
return code == 130;

src/commands/run/detail/ScriptCMake.cpp

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,20 +348,59 @@ namespace vix::commands::RunCommand::detail
348348
if (pkg.contains("id") && pkg["id"].is_string())
349349
ordered.push_back(pkg["id"].get<std::string>());
350350
}
351+
352+
return ordered;
353+
}
354+
355+
if (j.contains("dependencies") && j["dependencies"].is_array())
356+
{
357+
for (const auto &dep : j["dependencies"])
358+
{
359+
if (dep.is_string())
360+
{
361+
ordered.push_back(dep.get<std::string>());
362+
}
363+
else if (dep.is_object())
364+
{
365+
if (dep.contains("id") && dep["id"].is_string())
366+
ordered.push_back(dep["id"].get<std::string>());
367+
}
368+
}
369+
351370
return ordered;
352371
}
353372

354373
if (j.contains("dependencies") && j["dependencies"].is_object())
355374
{
356375
for (auto it = j["dependencies"].begin(); it != j["dependencies"].end(); ++it)
357376
ordered.push_back(it.key());
377+
358378
return ordered;
359379
}
360380
}
361381

362382
return ordered;
363383
}
364384

385+
std::vector<std::string> lock_package_ids_to_aliases(
386+
const std::vector<std::string> &packageIds)
387+
{
388+
std::vector<std::string> aliases;
389+
390+
for (const auto &id : packageIds)
391+
{
392+
if (id.empty())
393+
continue;
394+
395+
append_unique_string(aliases, dep_id_to_cmake_alias(id));
396+
}
397+
398+
std::sort(aliases.begin(), aliases.end());
399+
aliases.erase(std::unique(aliases.begin(), aliases.end()), aliases.end());
400+
401+
return aliases;
402+
}
403+
365404
std::vector<std::pair<std::string, std::string>> extract_dep_packages_from_include_dirs(
366405
const std::vector<std::string> &includeDirs)
367406
{
@@ -686,6 +725,32 @@ namespace vix::commands::RunCommand::detail
686725
return out;
687726
}
688727

728+
fs::path local_vix_deps_cmake_path(const fs::path &cppPath)
729+
{
730+
return cppPath.parent_path() / ".vix" / "vix_deps.cmake";
731+
}
732+
733+
bool has_local_vix_deps_cmake(const fs::path &cppPath)
734+
{
735+
return fs::exists(local_vix_deps_cmake_path(cppPath));
736+
}
737+
738+
void append_local_vix_deps_include(
739+
std::string &s,
740+
const fs::path &cppPath)
741+
{
742+
const fs::path depsCmake = local_vix_deps_cmake_path(cppPath);
743+
744+
if (!fs::exists(depsCmake))
745+
return;
746+
747+
append_line(s, "# Local Vix registry dependencies");
748+
append_line(s, "if (EXISTS " + cmake_quote(depsCmake.string()) + ")");
749+
append_line(s, " include(" + cmake_quote(depsCmake.string()) + ")");
750+
append_line(s, "endif()");
751+
append_line(s);
752+
}
753+
689754
std::string cmake_quote_raw(const std::string &p)
690755
{
691756
return "\"" + p + "\"";
@@ -813,6 +878,24 @@ namespace vix::commands::RunCommand::detail
813878
append_line(s, "set(CMAKE_CXX_EXTENSIONS OFF)");
814879
append_line(s);
815880

881+
append_line(s, "# Vix installed package roots");
882+
append_line(s, "if(DEFINED ENV{VIX_ROOT} AND NOT \"$ENV{VIX_ROOT}\" STREQUAL \"\")");
883+
append_line(s, " list(PREPEND CMAKE_PREFIX_PATH \"$ENV{VIX_ROOT}\")");
884+
append_line(s, "endif()");
885+
append_line(s);
886+
887+
append_line(s, "if(DEFINED ENV{HOME} AND NOT \"$ENV{HOME}\" STREQUAL \"\")");
888+
append_line(s, " list(APPEND CMAKE_PREFIX_PATH \"$ENV{HOME}/.vix\")");
889+
append_line(s, " list(APPEND CMAKE_PREFIX_PATH \"$ENV{HOME}/.local\")");
890+
append_line(s, "endif()");
891+
append_line(s);
892+
893+
append_line(s, "if(DEFINED ENV{USERPROFILE} AND NOT \"$ENV{USERPROFILE}\" STREQUAL \"\")");
894+
append_line(s, " list(APPEND CMAKE_PREFIX_PATH \"$ENV{USERPROFILE}/.vix\")");
895+
append_line(s, " list(APPEND CMAKE_PREFIX_PATH \"$ENV{USERPROFILE}/.local\")");
896+
append_line(s, "endif()");
897+
append_line(s);
898+
816899
append_line(s, "if (NOT CMAKE_BUILD_TYPE)");
817900
append_line(s, " set(CMAKE_BUILD_TYPE Debug CACHE STRING \"Build type\" FORCE)");
818901
append_line(s, "endif()");
@@ -1156,15 +1239,35 @@ namespace vix::commands::RunCommand::detail
11561239
append_sanitizer_options_block(s, feat);
11571240

11581241
const ResolvedScriptDeps deps = resolve_script_deps(cppPath, cf);
1159-
append_dependency_subdirectories(s, deps.uniqueCmakeDeps);
1242+
1243+
const bool useLocalVixDepsCmake = has_local_vix_deps_cmake(cppPath);
1244+
1245+
if (useLocalVixDepsCmake)
1246+
{
1247+
append_local_vix_deps_include(s, cppPath);
1248+
}
1249+
else
1250+
{
1251+
append_dependency_subdirectories(s, deps.uniqueCmakeDeps);
1252+
}
11601253

11611254
append_line(s, "add_executable(" + targetName + " " + cmake_quote(cppPath.string()) + ")");
11621255
append_line(s, "set_target_properties(" + targetName + " PROPERTIES OUTPUT_NAME " + cmake_quote(outputName) + ")");
11631256
append_line(s);
11641257

11651258
append_target_include_directories(s, targetName, cf.includeDirs, false);
11661259
append_target_include_directories(s, targetName, cf.systemIncludeDirs, true);
1167-
append_bridged_dep_links(s, targetName, deps.cmakeDepAliases);
1260+
1261+
std::vector<std::string> scriptDepAliases = deps.cmakeDepAliases;
1262+
1263+
if (useLocalVixDepsCmake)
1264+
{
1265+
const fs::path lockPath = cppPath.parent_path() / "vix.lock";
1266+
scriptDepAliases = lock_package_ids_to_aliases(
1267+
load_ordered_packages_from_lock(lockPath));
1268+
}
1269+
1270+
append_bridged_dep_links(s, targetName, scriptDepAliases);
11681271
append_target_compile_definitions(s, targetName, cf.defines);
11691272
append_target_compile_options(s, targetName, cf.compileOpts);
11701273
append_target_link_directories(s, targetName, lf.libDirs);

0 commit comments

Comments
 (0)