Skip to content

Commit 7f80ff5

Browse files
committed
Use long executable path instead of argv[0] in all launchers
`argv[0]` can differ from the path of the launcher executable and can contain 8.3 style filenames, which need to be resolved to long paths before path manipulation (e.g. appending ".runfiles") can succeed. The Python launcher handled this correctly, but other launchers didn't use the long executable path consistently.
1 parent de7b26a commit 7f80ff5

9 files changed

+64
-44
lines changed

src/tools/launcher/bash_launcher.cc

+1-5
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,7 @@ ExitCode BashBinaryLauncher::Launch() {
5252

5353
vector<wstring> origin_args = this->GetCommandlineArguments();
5454
wostringstream bash_command;
55-
// In case the given binary path is a shortened Windows 8dot3 path, we need to
56-
// convert it back to its long path form before using it to find the bash main
57-
// file.
58-
wstring full_binary_path = GetWindowsLongPath(origin_args[0]);
59-
wstring bash_main_file = GetBinaryPathWithoutExtension(full_binary_path);
55+
wstring bash_main_file = GetBinaryPathWithoutExtension(GetExecutableFile());
6056
bash_command << BashEscapeArg(bash_main_file);
6157
for (int i = 1; i < origin_args.size(); i++) {
6258
bash_command << L' ';

src/tools/launcher/bash_launcher.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ namespace launcher {
2222

2323
class BashBinaryLauncher : public BinaryLauncherBase {
2424
public:
25-
BashBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info, int argc,
25+
BashBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info,
26+
const std::wstring& executable_file,
27+
int argc,
2628
wchar_t* argv[])
27-
: BinaryLauncherBase(launch_info, argc, argv) {}
29+
: BinaryLauncherBase(launch_info, executable_file, argc, argv) {}
2830
~BashBinaryLauncher() override = default;
2931
ExitCode Launch() override;
3032
};

src/tools/launcher/java_launcher.cc

+3-5
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,7 @@ static void WriteJarClasspath(const wstring& jar_path,
162162
}
163163

164164
wstring JavaBinaryLauncher::GetJunctionBaseDir() {
165-
wstring binary_base_path =
166-
GetBinaryPathWithExtension(this->GetCommandlineArguments()[0]);
165+
wstring binary_base_path = GetBinaryPathWithExtension(GetExecutableFile());
167166
wstring result;
168167
if (!NormalizePath(binary_base_path + L".j", &result)) {
169168
die(L"Failed to get normalized junction base directory.");
@@ -191,8 +190,7 @@ void JavaBinaryLauncher::DeleteJunctionBaseDir() {
191190
}
192191

193192
wstring JavaBinaryLauncher::CreateClasspathJar(const wstring& classpath) {
194-
wstring binary_base_path =
195-
GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]);
193+
wstring binary_base_path = GetBinaryPathWithoutExtension(GetExecutableFile());
196194
wstring abs_manifest_jar_dir_norm = GetManifestJarDir(binary_base_path);
197195

198196
wostringstream manifest_classpath;
@@ -312,7 +310,7 @@ ExitCode JavaBinaryLauncher::Launch() {
312310
// Run deploy jar if needed, otherwise generate the CLASSPATH by rlocation.
313311
if (this->singlejar) {
314312
wstring deploy_jar =
315-
GetBinaryPathWithoutExtension(this->GetCommandlineArguments()[0]) +
313+
GetBinaryPathWithoutExtension(GetExecutableFile()) +
316314
L"_deploy.jar";
317315
if (!DoesFilePathExist(deploy_jar.c_str())) {
318316
die(L"Option --singlejar was passed, but %s does not exist.\n (You may "

src/tools/launcher/java_launcher.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ static const int MAX_ARG_STRLEN = 7000;
2929

3030
class JavaBinaryLauncher : public BinaryLauncherBase {
3131
public:
32-
JavaBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info, int argc,
32+
JavaBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info,
33+
const std::wstring& executable_file,
34+
int argc,
3335
wchar_t* argv[])
34-
: BinaryLauncherBase(launch_info, argc, argv),
36+
: BinaryLauncherBase(launch_info, executable_file, argc, argv),
3537
singlejar(false),
3638
print_javabin(false),
3739
classpath_limit(MAX_ARG_STRLEN) {}

src/tools/launcher/launcher.cc

+20-11
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ using std::vector;
4242
using std::wostringstream;
4343
using std::wstring;
4444

45-
static wstring GetRunfilesDir(const wchar_t* argv0) {
45+
static wstring GetRunfilesDir(const wchar_t* executable_file) {
4646
wstring runfiles_dir;
4747
// If RUNFILES_DIR is already set (probably we are either in a test or in a
4848
// data dependency) then use it.
4949
if (!GetEnv(L"RUNFILES_DIR", &runfiles_dir)) {
5050
// Otherwise this is probably a top-level non-test binary (e.g. a genrule
5151
// tool) and should look for its runfiles beside the executable.
52-
runfiles_dir = GetBinaryPathWithExtension(argv0) + L".runfiles";
52+
runfiles_dir = GetBinaryPathWithExtension(executable_file) + L".runfiles";
5353
}
5454
// Make sure we return a normalized absolute path.
5555
if (!blaze_util::IsAbsolute(runfiles_dir)) {
@@ -63,10 +63,14 @@ static wstring GetRunfilesDir(const wchar_t* argv0) {
6363
}
6464

6565
BinaryLauncherBase::BinaryLauncherBase(
66-
const LaunchDataParser::LaunchInfo& _launch_info, int argc, wchar_t* argv[])
67-
: launch_info(_launch_info),
68-
manifest_file(FindManifestFile(argv[0])),
69-
runfiles_dir(GetRunfilesDir(argv[0])),
66+
const LaunchDataParser::LaunchInfo& _launch_info,
67+
const std::wstring& executable_file,
68+
int argc,
69+
wchar_t* argv[])
70+
: executable_file(executable_file),
71+
launch_info(_launch_info),
72+
manifest_file(FindManifestFile(executable_file.c_str())),
73+
runfiles_dir(GetRunfilesDir(executable_file.c_str())),
7074
workspace_name(GetLaunchInfoByKey(WORKSPACE_NAME)),
7175
symlink_runfiles_enabled(GetLaunchInfoByKey(SYMLINK_RUNFILES_ENABLED) ==
7276
L"1") {
@@ -81,7 +85,8 @@ BinaryLauncherBase::BinaryLauncherBase(
8185
}
8286
}
8387

84-
static bool FindManifestFileImpl(const wchar_t* argv0, wstring* result) {
88+
static bool FindManifestFileImpl(const wchar_t* executable_file,
89+
wstring* result) {
8590
// If this binary X runs as the data-dependency of some other binary Y, then
8691
// X has no runfiles manifest/directory and should use Y's.
8792
if (GetEnv(L"RUNFILES_MANIFEST_FILE", result) &&
@@ -100,7 +105,7 @@ static bool FindManifestFileImpl(const wchar_t* argv0, wstring* result) {
100105
// If this binary X runs by itself (not as a data-dependency of another
101106
// binary), then look for the manifest in a runfiles directory next to the
102107
// main binary, then look for it (the manifest) next to the main binary.
103-
directory = GetBinaryPathWithExtension(argv0) + L".runfiles";
108+
directory = GetBinaryPathWithExtension(executable_file) + L".runfiles";
104109
*result = directory + L"/MANIFEST";
105110
if (DoesFilePathExist(result->c_str())) {
106111
return true;
@@ -114,9 +119,9 @@ static bool FindManifestFileImpl(const wchar_t* argv0, wstring* result) {
114119
return false;
115120
}
116121

117-
wstring BinaryLauncherBase::FindManifestFile(const wchar_t* argv0) {
122+
wstring BinaryLauncherBase::FindManifestFile(const wchar_t* executable_file) {
118123
wstring manifest_file;
119-
if (!FindManifestFileImpl(argv0, &manifest_file)) {
124+
if (!FindManifestFileImpl(executable_file, &manifest_file)) {
120125
return L"";
121126
}
122127
// The path will be set as the RUNFILES_MANIFEST_FILE envvar and used by the
@@ -125,9 +130,13 @@ wstring BinaryLauncherBase::FindManifestFile(const wchar_t* argv0) {
125130
return manifest_file;
126131
}
127132

133+
wstring BinaryLauncherBase::GetExecutableFile() const {
134+
return executable_file;
135+
}
136+
128137
wstring BinaryLauncherBase::GetRunfilesPath() const {
129138
wstring runfiles_path =
130-
GetBinaryPathWithExtension(this->commandline_arguments[0]) + L".runfiles";
139+
GetBinaryPathWithExtension(executable_file) + L".runfiles";
131140
std::replace(runfiles_path.begin(), runfiles_path.end(), L'/', L'\\');
132141
return runfiles_path;
133142
}

src/tools/launcher/launcher.h

+15-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ class BinaryLauncherBase {
4141
typedef std::unordered_map<std::wstring, std::wstring> ManifestFileMap;
4242

4343
public:
44-
BinaryLauncherBase(const LaunchDataParser::LaunchInfo& launch_info, int argc,
44+
BinaryLauncherBase(const LaunchDataParser::LaunchInfo& launch_info,
45+
const std::wstring& executable_file,
46+
int argc,
4547
wchar_t* argv[]);
4648

4749
virtual ~BinaryLauncherBase() = default;
@@ -77,13 +79,22 @@ class BinaryLauncherBase {
7779
// A launch function to be implemented for a specific language.
7880
virtual ExitCode Launch() = 0;
7981

82+
// Returns the path of the launcher's executable file.
83+
//
84+
// The returned path is always a long path, that is, it never contains 8.3
85+
// style filenames.
86+
std::wstring GetExecutableFile() const;
87+
8088
// Return the runfiles directory of this binary.
8189
//
82-
// The method appends ".exe.runfiles" to the first command line argument,
83-
// converts forward slashes to back slashes, then returns that.
90+
// The method appends ".exe.runfiles" to the path of the launcher executable,
91+
// converts forward slashes to backslashes, then returns that.
8492
std::wstring GetRunfilesPath() const;
8593

8694
private:
95+
// The path of the launcher binary.
96+
const std::wstring executable_file;
97+
8798
// A map to store all the launch information.
8899
const LaunchDataParser::LaunchInfo& launch_info;
89100

@@ -127,7 +138,7 @@ class BinaryLauncherBase {
127138
// Expect the manifest file to be at
128139
// 1. <path>/<to>/<binary>/<target_name>.runfiles/MANIFEST
129140
// or 2. <path>/<to>/<binary>/<target_name>.runfiles_manifest
130-
static std::wstring FindManifestFile(const wchar_t* argv0);
141+
static std::wstring FindManifestFile(const wchar_t* executable_file);
131142

132143
// Parse manifest file into a map
133144
static void ParseManifestFile(ManifestFileMap* manifest_file_map,

src/tools/launcher/launcher_main.cc

+11-3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ static constexpr const char* BINARY_TYPE = "binary_type";
4545
using bazel::launcher::BashBinaryLauncher;
4646
using bazel::launcher::BinaryLauncherBase;
4747
using bazel::launcher::GetBinaryPathWithExtension;
48+
using bazel::launcher::GetWindowsLongPath;
4849
using bazel::launcher::JavaBinaryLauncher;
4950
using bazel::launcher::LaunchDataParser;
5051
using bazel::launcher::PythonBinaryLauncher;
@@ -64,7 +65,12 @@ static std::wstring GetExecutableFileName() {
6465
}
6566

6667
int wmain(int argc, wchar_t* argv[]) {
67-
const std::wstring executable_file = GetExecutableFileName();
68+
// In case the given binary path is a shortened Windows 8dot3 path, we convert
69+
// it back to its long path form so that path manipulations (e.g. appending
70+
// ".runfiles") work as expected. Note that GetExecutableFileName may return a
71+
// path different from argv[0].
72+
const std::wstring executable_file =
73+
GetWindowsLongPath(GetExecutableFileName());
6874
LaunchDataParser::LaunchInfo launch_info;
6975
if (!LaunchDataParser::GetLaunchInfo(executable_file, &launch_info)) {
7076
die(L"Failed to parse launch info.");
@@ -81,9 +87,11 @@ int wmain(int argc, wchar_t* argv[]) {
8187
binary_launcher = make_unique<PythonBinaryLauncher>(
8288
launch_info, executable_file, argc, argv);
8389
} else if (result->second == L"Bash") {
84-
binary_launcher = make_unique<BashBinaryLauncher>(launch_info, argc, argv);
90+
binary_launcher = make_unique<BashBinaryLauncher>(
91+
launch_info, executable_file, argc, argv);
8592
} else if (result->second == L"Java") {
86-
binary_launcher = make_unique<JavaBinaryLauncher>(launch_info, argc, argv);
93+
binary_launcher = make_unique<JavaBinaryLauncher>(
94+
launch_info, executable_file, argc, argv);
8795
} else {
8896
die(L"Unknown binary type, cannot launch anything.");
8997
}

src/tools/launcher/python_launcher.cc

+2-6
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,10 @@ ExitCode PythonBinaryLauncher::Launch() {
5656
vector<wstring> args = this->GetCommandlineArguments();
5757
wstring use_zip_file = this->GetLaunchInfoByKey(USE_ZIP_FILE);
5858
wstring python_file;
59-
// In case the given binary path is a shortened Windows 8dot3 path, we need to
60-
// convert it back to its long path form before using it to find the python
61-
// file.
62-
wstring full_binary_path = GetWindowsLongPath(executable_file_);
6359
if (use_zip_file == L"1") {
64-
python_file = GetBinaryPathWithoutExtension(full_binary_path) + L".zip";
60+
python_file = GetBinaryPathWithoutExtension(GetExecutableFile()) + L".zip";
6561
} else {
66-
python_file = GetBinaryPathWithoutExtension(full_binary_path);
62+
python_file = GetBinaryPathWithoutExtension(GetExecutableFile());
6763
}
6864

6965
// Replace the first argument with python file path

src/tools/launcher/python_launcher.h

+4-6
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,12 @@ namespace launcher {
2626
class PythonBinaryLauncher : public BinaryLauncherBase {
2727
public:
2828
PythonBinaryLauncher(const LaunchDataParser::LaunchInfo& launch_info,
29-
std::wstring executable_file, int argc, wchar_t* argv[])
30-
: BinaryLauncherBase(launch_info, argc, argv),
31-
executable_file_(std::move(executable_file)) {}
29+
const std::wstring& executable_file,
30+
int argc,
31+
wchar_t* argv[])
32+
: BinaryLauncherBase(launch_info, executable_file, argc, argv) {}
3233
~PythonBinaryLauncher() override = default;
3334
ExitCode Launch() override;
34-
35-
private:
36-
std::wstring executable_file_;
3735
};
3836

3937
} // namespace launcher

0 commit comments

Comments
 (0)