[M6] brute-force probe + INTERFACE IMPORTED target codegen
This commit is contained in:
@@ -65,6 +65,8 @@ auto Database::resolve(const std::string& package, const std::string& version,
|
||||
.targets = row.targets,
|
||||
.source = row.source,
|
||||
.pkg_config_module = row.pkg_config_module,
|
||||
.brute_force_libs = row.brute_force_libs,
|
||||
.brute_force_includes = row.brute_force_includes,
|
||||
};
|
||||
}
|
||||
return std::unexpected(util::Error{
|
||||
|
||||
@@ -25,6 +25,14 @@ struct Recipe {
|
||||
// overlay rows don't need a sentinel.
|
||||
std::optional<std::string> pkg_config_module;
|
||||
|
||||
// Set by the brute-force probe (the last-resort discover stage).
|
||||
// When non-empty, codegen skips `find_package(...)` and instead
|
||||
// synthesizes an INTERFACE IMPORTED target named in `targets[0]`
|
||||
// (which is `<pkg>::<pkg>`) with these absolute lib paths +
|
||||
// include dirs.
|
||||
std::vector<std::string> brute_force_libs;
|
||||
std::vector<std::string> brute_force_includes;
|
||||
|
||||
bool operator==(const Recipe&) const = default;
|
||||
};
|
||||
|
||||
@@ -40,6 +48,8 @@ struct OverlayRow {
|
||||
std::string source;
|
||||
std::int64_t verified_at = 0;
|
||||
std::optional<std::string> pkg_config_module;
|
||||
std::vector<std::string> brute_force_libs;
|
||||
std::vector<std::string> brute_force_includes;
|
||||
};
|
||||
|
||||
// RAII wrapper for an open sqlite3 connection used by the overlay database.
|
||||
|
||||
@@ -90,24 +90,40 @@ auto overlay_open(const std::filesystem::path& path)
|
||||
});
|
||||
}
|
||||
|
||||
// Schema migration: legacy overlays predate pkg_config_module.
|
||||
// SQLite ADD COLUMN errors when the column already exists; treat
|
||||
// "duplicate column" as success.
|
||||
constexpr const char* MIGRATE_PC =
|
||||
"ALTER TABLE recipes ADD COLUMN pkg_config_module TEXT";
|
||||
char* mig_err = nullptr;
|
||||
if (sqlite3_exec(state->handle(), MIGRATE_PC, nullptr, nullptr, &mig_err) !=
|
||||
SQLITE_OK) {
|
||||
if (mig_err && std::string_view{mig_err}.find("duplicate column") ==
|
||||
std::string_view::npos) {
|
||||
std::string msg = std::format("cannot migrate overlay schema: {}",
|
||||
mig_err ? mig_err : "?");
|
||||
// Schema migrations. SQLite ADD COLUMN errors when the column
|
||||
// already exists; treat "duplicate column" as success.
|
||||
auto add_column = [&](const char* sql) -> util::Result<void> {
|
||||
char* mig_err = nullptr;
|
||||
if (sqlite3_exec(state->handle(), sql, nullptr, nullptr, &mig_err) !=
|
||||
SQLITE_OK) {
|
||||
if (mig_err && std::string_view{mig_err}.find("duplicate column") ==
|
||||
std::string_view::npos) {
|
||||
std::string msg = std::format("cannot migrate overlay schema: {}",
|
||||
mig_err ? mig_err : "?");
|
||||
sqlite3_free(mig_err);
|
||||
return std::unexpected(util::Error{
|
||||
util::ErrorCode::LinkdbCorrupt, std::move(msg), "", path,
|
||||
std::nullopt,
|
||||
});
|
||||
}
|
||||
sqlite3_free(mig_err);
|
||||
return std::unexpected(util::Error{
|
||||
util::ErrorCode::LinkdbCorrupt, std::move(msg), "", path, std::nullopt,
|
||||
});
|
||||
}
|
||||
sqlite3_free(mig_err);
|
||||
return {};
|
||||
};
|
||||
if (auto r = add_column(
|
||||
"ALTER TABLE recipes ADD COLUMN pkg_config_module TEXT");
|
||||
!r) {
|
||||
return std::unexpected(r.error());
|
||||
}
|
||||
if (auto r = add_column(
|
||||
"ALTER TABLE recipes ADD COLUMN brute_force_libs TEXT");
|
||||
!r) {
|
||||
return std::unexpected(r.error());
|
||||
}
|
||||
if (auto r = add_column(
|
||||
"ALTER TABLE recipes ADD COLUMN brute_force_includes TEXT");
|
||||
!r) {
|
||||
return std::unexpected(r.error());
|
||||
}
|
||||
|
||||
return state;
|
||||
@@ -119,8 +135,8 @@ auto overlay_insert_manual(OverlayState& state, const std::string& package,
|
||||
constexpr const char* SQL =
|
||||
"INSERT OR REPLACE INTO recipes "
|
||||
"(package, version_range, nixpkgs_attr, find_package, targets, components, source, "
|
||||
" verified_at, pkg_config_module) "
|
||||
"VALUES (?, ?, ?, ?, ?, NULL, 'manual', ?, ?)";
|
||||
" verified_at, pkg_config_module, brute_force_libs, brute_force_includes) "
|
||||
"VALUES (?, ?, ?, ?, ?, NULL, 'manual', ?, ?, ?, ?)";
|
||||
|
||||
sqlite3* db = state.handle();
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
@@ -129,6 +145,8 @@ auto overlay_insert_manual(OverlayState& state, const std::string& package,
|
||||
}
|
||||
|
||||
auto targets_str = nlohmann::json(r.targets).dump();
|
||||
auto libs_str = nlohmann::json(r.brute_force_libs).dump();
|
||||
auto incs_str = nlohmann::json(r.brute_force_includes).dump();
|
||||
auto now = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
@@ -144,6 +162,8 @@ auto overlay_insert_manual(OverlayState& state, const std::string& package,
|
||||
} else {
|
||||
sqlite3_bind_null(stmt, 7);
|
||||
}
|
||||
sqlite3_bind_text(stmt, 8, libs_str.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 9, incs_str.c_str(), -1, SQLITE_TRANSIENT);
|
||||
|
||||
auto rc = sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -162,8 +182,8 @@ auto overlay_insert(OverlayState& state, const std::string& package,
|
||||
constexpr const char* SQL =
|
||||
"INSERT OR REPLACE INTO recipes "
|
||||
"(package, version_range, nixpkgs_attr, find_package, targets, components, source, "
|
||||
" verified_at, pkg_config_module) "
|
||||
"VALUES (?, ?, ?, ?, ?, NULL, ?, ?, ?)";
|
||||
" verified_at, pkg_config_module, brute_force_libs, brute_force_includes) "
|
||||
"VALUES (?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?)";
|
||||
|
||||
sqlite3* db = state.handle();
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
@@ -172,6 +192,8 @@ auto overlay_insert(OverlayState& state, const std::string& package,
|
||||
}
|
||||
|
||||
auto targets_str = nlohmann::json(r.targets).dump();
|
||||
auto libs_str = nlohmann::json(r.brute_force_libs).dump();
|
||||
auto incs_str = nlohmann::json(r.brute_force_includes).dump();
|
||||
|
||||
sqlite3_bind_text(stmt, 1, package.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 2, version_range.c_str(), -1, SQLITE_TRANSIENT);
|
||||
@@ -185,6 +207,8 @@ auto overlay_insert(OverlayState& state, const std::string& package,
|
||||
} else {
|
||||
sqlite3_bind_null(stmt, 8);
|
||||
}
|
||||
sqlite3_bind_text(stmt, 9, libs_str.c_str(), -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 10, incs_str.c_str(), -1, SQLITE_TRANSIENT);
|
||||
|
||||
auto rc = sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -276,7 +300,7 @@ auto overlay_query(OverlayState& state, const std::string& package)
|
||||
-> util::Result<std::vector<OverlayRow>> {
|
||||
constexpr const char* SQL =
|
||||
"SELECT version_range, nixpkgs_attr, find_package, targets, source, verified_at, "
|
||||
" pkg_config_module "
|
||||
" pkg_config_module, brute_force_libs, brute_force_includes "
|
||||
"FROM recipes WHERE package = ?";
|
||||
|
||||
sqlite3* db = state.handle();
|
||||
@@ -310,6 +334,23 @@ auto overlay_query(OverlayState& state, const std::string& package)
|
||||
if (sqlite3_column_type(stmt, 6) != SQLITE_NULL) {
|
||||
row.pkg_config_module = column_text(stmt, 6);
|
||||
}
|
||||
auto parse_str_array = [&](int col, std::vector<std::string>& out_arr) {
|
||||
if (sqlite3_column_type(stmt, col) == SQLITE_NULL) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
auto txt = column_text(stmt, col);
|
||||
if (txt.empty()) {
|
||||
return;
|
||||
}
|
||||
out_arr =
|
||||
nlohmann::json::parse(txt).get<std::vector<std::string>>();
|
||||
} catch (const nlohmann::json::exception&) {
|
||||
// legacy/manual rows may have stored garbage; ignore
|
||||
}
|
||||
};
|
||||
parse_str_array(7, row.brute_force_libs);
|
||||
parse_str_array(8, row.brute_force_includes);
|
||||
out.push_back(std::move(row));
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
Reference in New Issue
Block a user