Searches for tools relative to the current libIREECompiler.so. (#14559)
There are cases in library use and from Python where this needs to take
precedence.
Need to test/adapt on Windows/MacOS before landing.
diff --git a/compiler/src/iree/compiler/Utils/ToolUtils.cpp b/compiler/src/iree/compiler/Utils/ToolUtils.cpp
index 134c145..0d8141e 100644
--- a/compiler/src/iree/compiler/Utils/ToolUtils.cpp
+++ b/compiler/src/iree/compiler/Utils/ToolUtils.cpp
@@ -11,6 +11,12 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
+#if __linux__ || __APPLE__
+#include <dlfcn.h>
+#elif defined(WIN32)
+#include <Windows.h>
+#endif
+
#define DEBUG_TYPE "iree-tools"
namespace mlir {
@@ -101,6 +107,116 @@
return "";
}
+static std::string getCurrentDylibPath() {
+#if __linux__ || __APPLE__
+ Dl_info dlInfo;
+ if (dladdr((void *)getCurrentDylibPath, &dlInfo) == 0)
+ return {};
+ return (dlInfo.dli_fname);
+#elif defined(WIN32)
+ HMODULE hm = NULL;
+ if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+ (LPCSTR)&getCurrentDylibPath, &hm) == 0) {
+ LLVM_DEBUG(llvm::dbgs() << "GetModuleHandleEx could not find the module\n");
+ return {};
+ }
+ llvm::SmallVector<char, MAX_PATH> dllPath;
+ dllPath.resize_for_overwrite(dllPath.capacity());
+ while (1) {
+ auto size = ::GetModuleFileNameA(hm, dllPath.data(), dllPath.size());
+ if (size == 0) {
+ LLVM_DEBUG(llvm::dbgs() << "GetModuleFileNameA failed\n");
+ return {};
+ }
+ if (size == dllPath.size()) {
+ dllPath.resize_for_overwrite(dllPath.size() + MAX_PATH);
+ continue;
+ }
+ dllPath.truncate(size);
+ break;
+ }
+ return std::string(dllPath.data(), dllPath.size());
+#endif
+ LLVM_DEBUG(
+ llvm::dbgs() << "Platform cannot resolve its current dylib address\n");
+ return {};
+}
+
+std::string findToolFromDylibDir(SmallVector<std::string> toolNames) {
+ const auto &normalizedToolNames = normalizeToolNames(toolNames);
+ std::string dylibPath = getCurrentDylibPath();
+ if (dylibPath.empty())
+ return {};
+
+ SmallString<256> dylibDir(dylibPath);
+ llvm::sys::path::remove_filename(dylibDir);
+ LLVM_DEBUG({
+ llvm::dbgs() << "Searching from the dylib directory " << dylibDir
+ << " for one of these tools: [";
+ llvm::interleaveComma(normalizedToolNames, llvm::dbgs());
+ llvm::dbgs() << "]\n";
+ });
+
+ // First search the current dylib's directory. This should find tools
+ // like:
+ // libIREECompiler.so
+ // iree-lld
+ // Python extensions are always packaged this way, and it happens
+ // to be how Windows installs are organized (i.e. .exe always next to
+ // the .dll).
+ std::string toolPath = findToolAtPath(normalizedToolNames, dylibDir);
+ if (!toolPath.empty()) {
+ LLVM_DEBUG(llvm::dbgs() << "Found tool in library's directory at path "
+ << toolPath << "\n");
+ return toolPath;
+ }
+
+ // Then search in an adjacent bin/ directory. Binary installs are
+ // packaged this way:
+ // lib/
+ // libIREECompiler.so
+ // bin/
+ // iree-lld
+ toolPath = findToolAtPath(normalizedToolNames, dylibDir + "/../bin/");
+ if (!toolPath.empty()) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Found tool in library's adjacent bin directory at path "
+ << toolPath << "\n");
+ return toolPath;
+ }
+
+ // Then search in an adjacent tools/ directory. Build trees are
+ // organized this way for reasons:
+ // lib/
+ // libIREECompiler.so
+ // tools/
+ // iree-lld
+ toolPath = findToolAtPath(normalizedToolNames, dylibDir + "/../tools/");
+ if (!toolPath.empty()) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Found tool in library's adjacent tools directory at path "
+ << toolPath << "\n");
+ return toolPath;
+ }
+
+ // Next search around in the CMake build tree:
+ // lib/
+ // libIREECompiler.so
+ // llvm-project/bin
+ // lld
+ toolPath =
+ findToolAtPath(normalizedToolNames, dylibDir + "/../llvm-project/bin/");
+ if (!toolPath.empty()) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Found tool relative to dylib in build tree at path "
+ << toolPath << "\n");
+ return toolPath;
+ }
+
+ return "";
+}
+
std::string findToolInEnvironment(SmallVector<std::string> toolNames) {
const auto &normalizedToolNames = normalizeToolNames(toolNames);
LLVM_DEBUG({
@@ -124,6 +240,10 @@
std::string findTool(SmallVector<std::string> toolNames) {
// TODO(benvanik): add a test for IREE_[toolName]_PATH.
+ std::string dylibDirPath = findToolFromDylibDir(toolNames);
+ if (!dylibDirPath.empty())
+ return dylibDirPath;
+
// Search the install or build dir.
std::string executableDirPath = findToolFromExecutableDir(toolNames);
if (!executableDirPath.empty())