tint: Make Command::LookPath also look in the executable directory
Added a utility to retrieve the executable path and directory, and make
Command::LookPath also look in there if not found in the CWD, and before
looking in the path environment variable. This should make it a lot
easier to run external executables and dlls as won't have to make sure
to set the path each time.
Change-Id: I09d6ff0a07f1a7904787d4be2a4abdf119a19ad6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/212914
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/utils/command/BUILD.bazel b/src/tint/utils/command/BUILD.bazel
index ffcef85..f321564 100644
--- a/src/tint/utils/command/BUILD.bazel
+++ b/src/tint/utils/command/BUILD.bazel
@@ -60,6 +60,7 @@
],
deps = [
"//src/tint/utils/macros",
+ "//src/tint/utils/system",
"//src/tint/utils/text",
],
copts = COPTS,
diff --git a/src/tint/utils/command/BUILD.cmake b/src/tint/utils/command/BUILD.cmake
index 4e40cc0..c05d974 100644
--- a/src/tint/utils/command/BUILD.cmake
+++ b/src/tint/utils/command/BUILD.cmake
@@ -44,6 +44,7 @@
tint_target_add_dependencies(tint_utils_command lib
tint_utils_macros
+ tint_utils_system
tint_utils_text
)
diff --git a/src/tint/utils/command/BUILD.gn b/src/tint/utils/command/BUILD.gn
index 67d6e4c..6650a54 100644
--- a/src/tint/utils/command/BUILD.gn
+++ b/src/tint/utils/command/BUILD.gn
@@ -47,6 +47,7 @@
sources = [ "command.h" ]
deps = [
"${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/system",
"${tint_src_dir}/utils/text",
]
diff --git a/src/tint/utils/command/command.h b/src/tint/utils/command/command.h
index 8fc7e00..f38c93c 100644
--- a/src/tint/utils/command/command.h
+++ b/src/tint/utils/command/command.h
@@ -52,9 +52,9 @@
/// @param path path to the executable
explicit Command(const std::string& path);
- /// Looks for an executable with the given name in the current working
- /// directory, and if not found there, in each of the directories in the
- /// `PATH` environment variable.
+ /// Looks for an executable with the given name in the current working directory,
+ /// then in the executable directory if not found there, then in each of the
+ /// directories in the `PATH` environment variable.
/// @param executable the executable name
/// @returns a Command which will return true for Found() if the executable
/// was found.
diff --git a/src/tint/utils/command/command_posix.cc b/src/tint/utils/command/command_posix.cc
index fae21be..e52632b 100644
--- a/src/tint/utils/command/command_posix.cc
+++ b/src/tint/utils/command/command_posix.cc
@@ -37,6 +37,8 @@
#include <sstream>
#include <vector>
+#include "src/tint/utils/system/executable_path.h"
+
namespace tint {
namespace {
@@ -132,6 +134,10 @@
if (ExecutableExists(in_cwd)) {
return in_cwd;
}
+ auto in_exe_path = tint::ExecutableDirectory() + "/" + name;
+ if (ExecutableExists(in_exe_path)) {
+ return in_exe_path;
+ }
}
if (ExecutableExists(name)) {
return name;
diff --git a/src/tint/utils/command/command_windows.cc b/src/tint/utils/command/command_windows.cc
index e591416..bf875d8 100644
--- a/src/tint/utils/command/command_windows.cc
+++ b/src/tint/utils/command/command_windows.cc
@@ -35,6 +35,7 @@
#include <string>
#include "src/tint/utils/macros/defer.h"
+#include "src/tint/utils/system/executable_path.h"
#include "src/tint/utils/text/string_stream.h"
namespace tint {
@@ -159,12 +160,22 @@
if (ExecutableExists(in_cwd + ".exe")) {
return in_cwd + ".exe";
}
+
+ auto in_exe_path = tint::ExecutableDirectory() + "/" + name;
+ if (ExecutableExists(in_exe_path)) {
+ return in_exe_path;
+ }
+ if (ExecutableExists(in_exe_path + ".exe")) {
+ return in_exe_path + ".exe";
+ }
+
if (ExecutableExists(name)) {
return name;
}
if (ExecutableExists(name + ".exe")) {
return name + ".exe";
}
+
if (name.find("/") == std::string::npos && name.find("\\") == std::string::npos) {
char* path_env = nullptr;
size_t path_env_len = 0;
diff --git a/src/tint/utils/system/BUILD.bazel b/src/tint/utils/system/BUILD.bazel
index 75861b6..f2f23b7 100644
--- a/src/tint/utils/system/BUILD.bazel
+++ b/src/tint/utils/system/BUILD.bazel
@@ -50,19 +50,31 @@
],
"//conditions:default": [],
}) + select({
+ ":tint_build_is_linux": [
+ "executable_path_linux.cc",
+ ],
+ "//conditions:default": [],
+ }) + select({
":tint_build_is_linux_or_tint_build_is_mac": [
"terminal_posix.cc",
],
"//conditions:default": [],
}) + select({
+ ":tint_build_is_mac": [
+ "executable_file_mac.cc",
+ ],
+ "//conditions:default": [],
+ }) + select({
":tint_build_is_win": [
"env_windows.cc",
+ "executable_path_windows.cc",
"terminal_windows.cc",
],
"//conditions:default": [],
}),
hdrs = [
"env.h",
+ "executable_path.h",
"terminal.h",
],
deps = [
diff --git a/src/tint/utils/system/BUILD.cmake b/src/tint/utils/system/BUILD.cmake
index 62570e0..770cbf4 100644
--- a/src/tint/utils/system/BUILD.cmake
+++ b/src/tint/utils/system/BUILD.cmake
@@ -40,6 +40,7 @@
################################################################################
tint_add_target(tint_utils_system lib
utils/system/env.h
+ utils/system/executable_path.h
utils/system/terminal.h
)
@@ -69,15 +70,28 @@
)
endif((NOT TINT_BUILD_IS_WIN))
+if(TINT_BUILD_IS_LINUX)
+ tint_target_add_sources(tint_utils_system lib
+ "utils/system/executable_path_linux.cc"
+ )
+endif(TINT_BUILD_IS_LINUX)
+
if(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
tint_target_add_sources(tint_utils_system lib
"utils/system/terminal_posix.cc"
)
endif(TINT_BUILD_IS_LINUX OR TINT_BUILD_IS_MAC)
+if(TINT_BUILD_IS_MAC)
+ tint_target_add_sources(tint_utils_system lib
+ "utils/system/executable_file_mac.cc"
+ )
+endif(TINT_BUILD_IS_MAC)
+
if(TINT_BUILD_IS_WIN)
tint_target_add_sources(tint_utils_system lib
"utils/system/env_windows.cc"
+ "utils/system/executable_path_windows.cc"
"utils/system/terminal_windows.cc"
)
endif(TINT_BUILD_IS_WIN)
diff --git a/src/tint/utils/system/BUILD.gn b/src/tint/utils/system/BUILD.gn
index 19a3f5f..1148997 100644
--- a/src/tint/utils/system/BUILD.gn
+++ b/src/tint/utils/system/BUILD.gn
@@ -42,6 +42,7 @@
libtint_source_set("system") {
sources = [
"env.h",
+ "executable_path.h",
"terminal.h",
]
deps = [
@@ -63,13 +64,22 @@
sources += [ "env_other.cc" ]
}
+ if (tint_build_is_linux) {
+ sources += [ "executable_path_linux.cc" ]
+ }
+
if (tint_build_is_linux || tint_build_is_mac) {
sources += [ "terminal_posix.cc" ]
}
+ if (tint_build_is_mac) {
+ sources += [ "executable_file_mac.cc" ]
+ }
+
if (tint_build_is_win) {
sources += [
"env_windows.cc",
+ "executable_path_windows.cc",
"terminal_windows.cc",
]
}
diff --git a/src/tint/utils/system/executable_file_mac.cc b/src/tint/utils/system/executable_file_mac.cc
new file mode 100644
index 0000000..928d285
--- /dev/null
+++ b/src/tint/utils/system/executable_file_mac.cc
@@ -0,0 +1,50 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// GEN_BUILD:CONDITION(tint_build_is_mac)
+
+#include "src/tint/utils/system/executable_path.h"
+
+#include <mach-o/dyld.h>
+#include <sys/syslimits.h>
+#include <filesystem>
+
+#include "src/tint/utils/containers/vector.h"
+
+std::string tint::ExecutablePath() {
+ uint32_t bufsize = 0;
+ auto result = _NSGetExecutablePath(nullptr, &bufsize);
+ TINT_ASSERT(result == -1 && bufsize > 0);
+ tint::Vector<char, PATH_MAX> buff;
+ buff.Resize(bufsize + 1, 0);
+ _NSGetExecutablePath(&buff[0], &bufsize);
+ return &buff[0];
+}
+
+std::string tint::ExecutableDirectory() {
+ return std::filesystem::path{ExecutablePath()}.remove_filename().string();
+}
diff --git a/src/tint/utils/system/executable_path.h b/src/tint/utils/system/executable_path.h
new file mode 100644
index 0000000..bb04d30
--- /dev/null
+++ b/src/tint/utils/system/executable_path.h
@@ -0,0 +1,43 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_UTILS_SYSTEM_EXECUTABLE_PATH_H_
+#define SRC_TINT_UTILS_SYSTEM_EXECUTABLE_PATH_H_
+
+#include <string>
+
+namespace tint {
+
+// Returns the path of the currently running executable
+std::string ExecutablePath();
+
+// Returns the directory of the currently running executable
+std::string ExecutableDirectory();
+
+} // namespace tint
+
+#endif // SRC_TINT_UTILS_SYSTEM_EXECUTABLE_PATH_H_
diff --git a/src/tint/utils/system/executable_path_linux.cc b/src/tint/utils/system/executable_path_linux.cc
new file mode 100644
index 0000000..fad508f
--- /dev/null
+++ b/src/tint/utils/system/executable_path_linux.cc
@@ -0,0 +1,53 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// GEN_BUILD:CONDITION(tint_build_is_linux)
+
+#include "src/tint/utils/system/executable_path.h"
+
+#include <unistd.h>
+#include <filesystem>
+
+#include "src/tint/utils/containers/vector.h"
+
+std::string tint::ExecutablePath() {
+ tint::Vector<char, 1024> buff;
+ buff.Resize(1024, 0);
+ while (true) {
+ ssize_t result = readlink("/proc/self/exe", &buff[0], buff.Length());
+ if (result == static_cast<ssize_t>(buff.Length())) {
+ buff.Resize(buff.Length() * 2, 0);
+ } else {
+ break;
+ }
+ }
+ return &buff[0];
+}
+
+std::string tint::ExecutableDirectory() {
+ return std::filesystem::path{ExecutablePath()}.remove_filename().string();
+}
diff --git a/src/tint/utils/system/executable_path_windows.cc b/src/tint/utils/system/executable_path_windows.cc
new file mode 100644
index 0000000..a9cea85
--- /dev/null
+++ b/src/tint/utils/system/executable_path_windows.cc
@@ -0,0 +1,53 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// GEN_BUILD:CONDITION(tint_build_is_win)
+
+#include "src/tint/utils/system/executable_path.h"
+
+#include <Windows.h>
+#include <filesystem>
+
+#include "src/tint/utils/containers/vector.h"
+
+std::string tint::ExecutablePath() {
+ tint::Vector<char, MAX_PATH> buff;
+ buff.Resize(MAX_PATH);
+ while (true) {
+ auto result = ::GetModuleFileNameA(NULL, &buff[0], buff.Length());
+ if (result == buff.Length() && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
+ buff.Resize(buff.Length() * 2);
+ } else {
+ break;
+ }
+ }
+ return &buff[0];
+}
+
+std::string tint::ExecutableDirectory() {
+ return std::filesystem::path{ExecutablePath()}.remove_filename().string();
+}