Skip to content

Support target names containing dots in all utilities #65812

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
9 changes: 1 addition & 8 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
/// Normalize the program name from argv[0] by stripping the file extension if
/// present and lower-casing the string on Windows.
static std::string normalizeProgramName(llvm::StringRef Argv0) {
std::string ProgName = std::string(llvm::sys::path::filename(Argv0));
std::string ProgName = std::string(sys::path::program_name(Argv0));
if (is_style_windows(llvm::sys::path::Style::native)) {
// Transform to lowercase for case insensitive file systems.
std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(),
Expand All @@ -345,13 +345,6 @@ static const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) {
// added via -target as implicit first argument.
const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos);

if (!DS && ProgName.endswith(".exe")) {
// Try again after stripping the executable suffix:
// clang++.exe -> clang++
ProgName = ProgName.drop_back(StringRef(".exe").size());
DS = FindDriverSuffix(ProgName, Pos);
}

if (!DS) {
// Try again after stripping any trailing version number:
// clang++3.5 -> clang++
Expand Down
5 changes: 5 additions & 0 deletions clang/unittests/Driver/ToolChainTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,11 @@ TEST(ToolChainTest, GetTargetAndMode) {
EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
EXPECT_TRUE(Res.TargetIsValid);

Res = ToolChain::getTargetAndModeFromProgramName(
"x86_64-unknown-freebsd13.2-clang-c++");
EXPECT_TRUE(Res.TargetPrefix == "x86_64-unknown-freebsd13.2");
EXPECT_TRUE(Res.TargetIsValid);

Res = ToolChain::getTargetAndModeFromProgramName(
"x86_64-linux-gnu-clang-c++-tot");
EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
Expand Down
2 changes: 1 addition & 1 deletion lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
auto *ctx = new COFFLinkerContext;

ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
ctx->e.logName = args::getFilenameWithoutExe(args[0]);
ctx->e.logName = sys::path::program_name(args[0]);
ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now"
" (use /errorlimit:0 to see all errors)";

Expand Down
6 changes: 0 additions & 6 deletions lld/Common/Args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,3 @@ std::vector<StringRef> lld::args::getLines(MemoryBufferRef mb) {
}
return ret;
}

StringRef lld::args::getFilenameWithoutExe(StringRef path) {
if (path.ends_with_insensitive(".exe"))
return sys::path::stem(path);
return sys::path::filename(path);
}
2 changes: 1 addition & 1 deletion lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,

SharedFile::vernauxNum = 0;
};
ctx->e.logName = args::getFilenameWithoutExe(args[0]);
ctx->e.logName = sys::path::program_name(args[0]);
ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use "
"--error-limit=0 to see all errors)";

Expand Down
2 changes: 1 addition & 1 deletion lld/MachO/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,7 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
InputFile::resetIdCount();
};

ctx->e.logName = args::getFilenameWithoutExe(argsArr[0]);
ctx->e.logName = sys::path::program_name(argsArr[0]);

MachOOptTable parser;
InputArgList args = parser.parse(argsArr.slice(1));
Expand Down
2 changes: 0 additions & 2 deletions lld/include/lld/Common/Args.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ uint64_t getZOptionValue(llvm::opt::InputArgList &args, int id, StringRef key,

std::vector<StringRef> getLines(MemoryBufferRef mb);

StringRef getFilenameWithoutExe(StringRef path);

} // namespace args
} // namespace lld

Expand Down
2 changes: 1 addition & 1 deletion lld/wasm/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
auto *ctx = new CommonLinkerContext;

ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
ctx->e.logName = args::getFilenameWithoutExe(args[0]);
ctx->e.logName = sys::path::program_name(args[0]);
ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";

Expand Down
2 changes: 1 addition & 1 deletion lldb/tools/driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ int main(int argc, char const *argv[]) {
ArrayRef<const char *> arg_arr = ArrayRef(argv + 1, argc - 1);
opt::InputArgList input_args =
T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
llvm::StringRef argv0 = llvm::sys::path::program_name(argv[0]);

if (input_args.hasArg(OPT_help)) {
printHelp(T, argv0);
Expand Down
15 changes: 15 additions & 0 deletions llvm/include/llvm/Support/Path.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,21 @@ StringRef stem(StringRef path, Style style = Style::native);
/// @result The extension of \a path.
StringRef extension(StringRef path, Style style = Style::native);

/// Get the program's name
///
/// If the path ends with the string ".exe", returns the stem of
/// \a path. Otherwise returns the filename of \a path.
///
/// @code
/// /foo/prog.exe => prog
/// /bar/prog => prog
/// /foo/prog1.2 => prog1.2
/// @endcode
///
/// @param path Input path.
/// @result The filename of \a path without any ".exe" component.
StringRef program_name(StringRef path, Style style = Style::native);

/// Check whether the given char is a path separator on the host OS.
///
/// @param value a character
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Support/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,13 @@ StringRef extension(StringRef path, Style style) {
return fname.substr(pos);
}

StringRef program_name(StringRef path, Style style) {
// In the future this may need to be extended to other program suffixes.
if (path.ends_with_insensitive(".exe"))
return stem(path, style);
return filename(path, style);
}

bool is_separator(char value, Style style) {
if (value == '/')
return true;
Expand Down
5 changes: 5 additions & 0 deletions llvm/test/tools/llvm-ar/tool-name.test
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm. I'm happy with this file, but I also discovered a bunch of other tool-name tests that can be updated. I'll add those too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, added tool-name tests for the utilities for ELF and such. Not sure if I should add similar tests for Windows targets; they never have dots in their names.

Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@
# RUN: mkdir %t
# RUN: ln -s llvm-ar %t/llvm-ar-9
# RUN: ln -s llvm-ar %t/ar.exe
# RUN: ln -s llvm-ar %t/x86_64-portbld-freebsd13.2-llvm-ar
# RUN: ln -s llvm-ar %t/x86_64-portbld-freebsd13.2-llvm-ar.exe
# RUN: ln -s llvm-ar %t/arm-pokymllib32-linux-gnueabi-llvm-ar-9

# RUN: llvm-ar h | FileCheck %s --check-prefix=DEFAULT
# RUN: %t/llvm-ar-9 h | FileCheck %s --check-prefix=VERSION
# RUN: %t/ar.exe h | FileCheck %s --check-prefix=SUFFIX
# RUN: %t/x86_64-portbld-freebsd13.2-llvm-ar h | FileCheck %s --check-prefix=TARGETDOT
# RUN: %t/x86_64-portbld-freebsd13.2-llvm-ar.exe h | FileCheck %s --check-prefix=TARGETDOT
## Ensure that the "lib" substring does not result in misidentification as the
## llvm-lib tool.
# RUN: %t/arm-pokymllib32-linux-gnueabi-llvm-ar-9 h | FileCheck %s --check-prefix=ARM

# DEFAULT: USAGE: llvm-ar{{ }}
# VERSION: USAGE: llvm-ar-9{{ }}
# SUFFIX: USAGE: ar{{ }}
# TARGETDOT: USAGE: x86_64-portbld-freebsd13.2-llvm-ar{{ }}
# ARM: USAGE: arm-pokymllib32-linux-gnueabi-llvm-ar-9{{ }}
4 changes: 2 additions & 2 deletions llvm/test/tools/llvm-objcopy/tool-name.test
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
# RUN: mkdir %t

# RUN: ln -s llvm-objcopy %t/llvm-objcopy-11.exe
# RUN: ln -s llvm-objcopy %t/powerpc64-unknown-freebsd13-objcopy
# RUN: ln -s llvm-objcopy %t/powerpc64-unknown-freebsd13.0-objcopy

# RUN: llvm-objcopy --help | FileCheck --check-prefix=OBJCOPY %s
# RUN: %t/llvm-objcopy-11.exe --help | FileCheck --check-prefix=OBJCOPY %s
# RUN: %t/powerpc64-unknown-freebsd13-objcopy --help | FileCheck --check-prefix=OBJCOPY %s
# RUN: %t/powerpc64-unknown-freebsd13.0-objcopy --help | FileCheck --check-prefix=OBJCOPY %s

# OBJCOPY: OVERVIEW: llvm-objcopy tool

Expand Down
4 changes: 2 additions & 2 deletions llvm/test/tools/llvm-objdump/tool-name.test
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
# RUN: mkdir %t

# RUN: ln -s llvm-objdump %t/llvm-otool-11.exe
# RUN: ln -s llvm-objdump %t/powerpc64-unknown-freebsd13-objdump
# RUN: ln -s llvm-objdump %t/powerpc64-unknown-freebsd13.0-objdump

# RUN: %t/llvm-otool-11.exe --help | FileCheck --check-prefix=OTOOL %s
# RUN: %t/powerpc64-unknown-freebsd13-objdump --help | \
# RUN: %t/powerpc64-unknown-freebsd13.0-objdump --help | \
# RUN: FileCheck --check-prefix=OBJDUMP %s

# OBJDUMP: OVERVIEW: llvm object file dumper
Expand Down
3 changes: 3 additions & 0 deletions llvm/test/tools/llvm-ranlib/tool-name.test
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
# RUN: mkdir %t
# RUN: ln -s llvm-ranlib %t/llvm-ranlib-9
# RUN: ln -s llvm-ranlib %t/ranlib.exe
# RUN: ln -s llvm-ranlib %t/x86_64-unknown-freebsd13.2-llvm-ranlib
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm struggling to understand the logic in the llvm-ar test case gaining two new test cases, but the ranlib one only gaining one.

(On further investigation, I'm struggling to understand why the llvm-ranlib tool-name test even needs to exist, given that the code is the same code as llvm-ar at the relevant point).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, your second point is why I didn't bother making the second case for llvm-ranlib. On my first pass I just updated the existing testcases I found, but for ranlib I realised the same thing you did. I may just drop the ranlib test entirely.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's put the new test files and deletion of this old test in a different PR. The old code was untested, so we're not making things worse, but it also helps keep the PRs focused. Aside: if we're deleting this old file, I think it would be a good idea to add one or two cases to the llvm-ar test showing the "llvm-ranlib" name.


# RUN: llvm-ranlib -h | FileCheck %s --check-prefix=DEFAULT
# RUN: %t/llvm-ranlib-9 -h | FileCheck %s --check-prefix=VERSION
# RUN: %t/ranlib.exe -h | FileCheck %s --check-prefix=SUFFIX
# RUN: %t/x86_64-unknown-freebsd13.2-llvm-ranlib -h | FileCheck %s --check-prefix=TRIPLE

# DEFAULT: USAGE: llvm-ranlib{{ }}
# VERSION: USAGE: llvm-ranlib-9{{ }}
# SUFFIX: USAGE: ranlib{{ }}
# TRIPLE: USAGE: x86_64-unknown-freebsd13.2-llvm-ranlib{{ }}
3 changes: 2 additions & 1 deletion llvm/tools/llvm-ar/llvm-ar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1508,7 +1508,8 @@ int llvm_ar_main(int argc, char **argv, const llvm::ToolContext &) {
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();

Stem = sys::path::stem(ToolName);
Stem = sys::path::program_name(ToolName);

auto Is = [](StringRef Tool) {
// We need to recognize the following filenames.
//
Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/llvm-cov/llvm-cov.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ int main(int argc, const char **argv) {
InitLLVM X(argc, argv);

// If argv[0] is or ends with 'gcov', always be gcov compatible
if (sys::path::stem(argv[0]).ends_with_insensitive("gcov"))
if (sys::path::program_name(argv[0]).ends_with_insensitive("gcov"))
return gcovMain(argc, argv);

// Check if we are invoking a specific tool command.
Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/llvm-driver/llvm-driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static int findTool(int Argc, char **Argv, const char *Argv0) {
return 0;
}

StringRef Stem = sys::path::stem(ToolName);
StringRef Stem = sys::path::program_name(ToolName);
auto Is = [=](StringRef Tool) {
auto IsImpl = [=](StringRef Stem) {
auto I = Stem.rfind_insensitive(Tool);
Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/llvm-objcopy/llvm-objcopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ static ErrorSuccess reportWarning(Error E) {
}

static Expected<DriverConfig> getDriverConfig(ArrayRef<const char *> Args) {
StringRef Stem = sys::path::stem(ToolName);
StringRef Stem = sys::path::program_name(ToolName);
auto Is = [=](StringRef Tool) {
// We need to recognize the following filenames:
//
Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/llvm-objdump/llvm-objdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3297,7 +3297,7 @@ int llvm_objdump_main(int argc, char **argv, const llvm::ToolContext &) {
std::unique_ptr<CommonOptTable> T;
OptSpecifier Unknown, HelpFlag, HelpHiddenFlag, VersionFlag;

StringRef Stem = sys::path::stem(ToolName);
StringRef Stem = sys::path::program_name(ToolName);
auto Is = [=](StringRef Tool) {
// We need to recognize the following filenames:
//
Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/llvm-rc/llvm-rc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ void preprocess(StringRef Src, StringRef Dst, const RcOptions &Opts,
}

static std::pair<bool, std::string> isWindres(llvm::StringRef Argv0) {
StringRef ProgName = llvm::sys::path::stem(Argv0);
StringRef ProgName = sys::path::program_name(Argv0);
// x86_64-w64-mingw32-windres -> x86_64-w64-mingw32, windres
// llvm-rc -> "", llvm-rc
// aarch64-w64-mingw32-llvm-windres-10.exe -> aarch64-w64-mingw32, llvm-windres
Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/llvm-readobj/llvm-readobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ int llvm_readobj_main(int argc, char **argv, const llvm::ToolContext &) {
return 0;
}

if (sys::path::stem(argv[0]).contains("readelf"))
if (sys::path::filename(argv[0]).contains("readelf"))
opts::Output = opts::GNU;
parseOptions(Args);

Expand Down
2 changes: 1 addition & 1 deletion llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ int llvm_symbolizer_main(int argc, char **argv, const llvm::ToolContext &) {
sys::InitializeCOMRAII COM(sys::COMThreadingMode::MultiThreaded);

ToolName = argv[0];
bool IsAddr2Line = sys::path::stem(ToolName).contains("addr2line");
bool IsAddr2Line = sys::path::filename(ToolName).contains("addr2line");
BumpPtrAllocator A;
StringSaver Saver(A);
SymbolizerOptTable Tbl;
Expand Down
34 changes: 34 additions & 0 deletions llvm/unittests/Support/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1696,6 +1696,40 @@ TEST(Support, ReplacePathPrefix) {
EXPECT_EQ(Path, "C:\\old/foo\\bar");
}

TEST(Support, FindProgramName) {
StringRef WindowsProgName =
path::program_name("C:\\Test\\foo.exe", path::Style::windows);
EXPECT_EQ(WindowsProgName, "foo");

StringRef WindowsProgNameManyDots = path::program_name(
"C:\\Test.7\\x86_64-freebsd14.0-clang.exe", path::Style::windows);
EXPECT_EQ(WindowsProgNameManyDots, "x86_64-freebsd14.0-clang");

StringRef PosixProgName =
path::program_name("/var/empty/clang.exe", path::Style::posix);
EXPECT_EQ(PosixProgName, "clang");

StringRef PosixProgNameManyDotsExe = path::program_name(
"/llvm-test16.4/x86_64-portbld-freebsd13.2-llvm-ar.exe",
path::Style::posix);
EXPECT_EQ(PosixProgNameManyDotsExe, "x86_64-portbld-freebsd13.2-llvm-ar");

StringRef PosixProgNameManyDots = path::program_name(
"/llvm-test16.4/x86_64-portbld-freebsd13.2-llvm-ar", path::Style::posix);
EXPECT_EQ(PosixProgNameManyDots, "x86_64-portbld-freebsd13.2-llvm-ar");

StringRef PosixProgNameSh =
path::program_name("/llvm-test16.4/x86_64-portbld-freebsd13.2-llvm-ar.sh",
path::Style::posix);
EXPECT_EQ(PosixProgNameSh, "x86_64-portbld-freebsd13.2-llvm-ar.sh");

// TODO: determine if this is correct. What happens on windows with an executable
// named ".exe"?
StringRef OnlyExe =
path::program_name("/var/empty/.exe", path::Style::posix);
EXPECT_EQ(OnlyExe, "");
}

TEST_F(FileSystemTest, OpenFileForRead) {
// Create a temp file.
int FileDescriptor;
Expand Down