libcruft-vk/icd/vendor_posix.cpp

54 lines
1.7 KiB
C++

#include "vendor.hpp"
#include <cruft/util/log.hpp>
#include <cruft/util/posix/except.hpp>
#include <cruft/json/tree.hpp>
#include <wordexp.h>
namespace fs = std::filesystem;
///////////////////////////////////////////////////////////////////////////////
std::vector<cruft::vk::icd::icd_t>
cruft::vk::icd::enumerate (void)
{
// The predefined, ordered, search locations for manifests
static char const *locations[] = {
"/usr/local/etc/vulkan/icd.d/",
"/usr/local/share/vulkan/icd.d/",
"/etc/vulkan/icd.d/",
"/usr/share/vulkan/icd.d/",
"$HOME/.local/share/vulkan/icd.d/",
};
std::vector<icd_t> found;
for (auto const &loc: locations) {
// We use wordexp rather than std::filesystem because we need to
// perform environment expansion to account of $HOME in at least one
// of the paths, so we may as well just use the same approach for
// everything else too.
wordexp_t words;
posix::error::try_call (wordexp, loc, &words, WRDE_NOCMD | WRDE_UNDEF);
std::unique_ptr<wordexp_t, decltype(&wordfree)> cleanup {&words, &wordfree};
// Just try to parse everything we can find in the directory (if it
// happens to exist) and fail out if it doesn't work. Marginally safer
// than doing various tests.
for (size_t i = 0; i < words.we_wordc; ++i) {
try {
for (auto const &path: fs::directory_iterator (words.we_wordv[i])) {
found.push_back (from_json<icd_t> (*json::tree::parse (path)));
}
} catch (std::exception const &e) {
LOG_INFO("failed to parse icd manifest; %!", e.what ());
}
}
}
return found;
}