Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion mlx/backend/common/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,19 @@ std::filesystem::path current_binary_dir() {
if (!dladdr(reinterpret_cast<void*>(&current_binary_dir), &info)) {
throw std::runtime_error("Unable to get current binary dir.");
}
return std::filesystem::path(info.dli_fname).parent_path();
// glibc reports dli_fname for a main executable as argv[0] verbatim, so it
// may be relative or contain "."; resolve it so that parent_path() of the
// result names the real parent directory.
std::filesystem::path path(info.dli_fname);
if (!path.has_parent_path()) {
// A bare argv[0] carries no location, and the two standard libraries
// disagree about it: libc++ would resolve it against the current working
// directory, inventing an unrelated answer.
return path.parent_path();
}
std::error_code ec;
auto resolved = std::filesystem::weakly_canonical(path, ec);
return ec ? path.parent_path() : resolved.parent_path();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this function just return std::filesystem::canonical(info.dli_fname).parent_path()? If any error happens we can just let it throw.

}();
return binary_dir;
}
Expand Down
7 changes: 5 additions & 2 deletions mlx/backend/common/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
#include <tuple>
#include <vector>

#include "mlx/api.h"
#include "mlx/array.h"

namespace mlx::core {

// Return the directory that contains current shared library.
std::filesystem::path current_binary_dir();
// Return the resolved directory that contains the current binary, with ".",
// ".." and symlinks removed. Empty when the loader reports no location for
// it, which glibc does for a PATH-launched executable.
MLX_API std::filesystem::path current_binary_dir();

inline int64_t
elem_to_loc(int elem, const Shape& shape, const Strides& strides) {
Expand Down
12 changes: 12 additions & 0 deletions tests/utils_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,22 @@

#include "doctest/doctest.h"

#include "mlx/backend/common/utils.h"
#include "mlx/mlx.h"

using namespace mlx::core;

TEST_CASE("test current binary dir is resolved") {
auto dir = current_binary_dir();
// Empty is a legal result: a PATH-launched executable gets a bare argv[0],
// which carries no location to resolve.
if (dir.empty()) {
return;
}
CHECK(dir.is_absolute());
CHECK_EQ(dir, dir.lexically_normal());
}

TEST_CASE("test type promotion") {
for (auto t : {bool_, uint32, int32, int64, float32}) {
auto a = array(0, t);
Expand Down