diff --git a/executable_semantics/main.cpp b/executable_semantics/main.cpp index bff3f2646b03..00a001b61af3 100644 --- a/executable_semantics/main.cpp +++ b/executable_semantics/main.cpp @@ -16,8 +16,13 @@ #include "executable_semantics/interpreter/exec_program.h" #include "executable_semantics/syntax/parse.h" #include "executable_semantics/syntax/prelude.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" // Prints an error message and returns error code value. auto PrintError(const Carbon::Error& error) -> int { @@ -41,9 +46,29 @@ auto main(int argc, char* argv[]) -> int { opt trace_option("trace", desc("Enable tracing")); opt input_file_name(llvm::cl::Positional, desc(""), llvm::cl::Required); - opt prelude_file_name( - "prelude", desc(""), - llvm::cl::init("executable_semantics/data/prelude.carbon")); + + // Find the path of the executable if possible and use that as a relative root + // for finding the prelude. FIXME: Currently, this assumes a Bazel-like + // runfiles tree rather than any kind of installation tree. + llvm::SmallString<256> exe_path(argv[0]); + if (!llvm::sys::fs::exists(exe_path)) { + // Try to lookup the program name in the `PATH`. + if (llvm::ErrorOr path = + llvm::sys::findProgramByName(exe_path)) { + exe_path = *path; + } + } + // If we have a valid path, find the parent directory. Otherwise, just use an + // empty string to get the current working directory. + if (llvm::sys::fs::exists(exe_path)) { + llvm::sys::path::remove_filename(exe_path); + } else { + exe_path = ""; + } + llvm::SmallString<256> prelude_path = exe_path; + llvm::sys::path::append(prelude_path, "data/prelude.carbon"); + opt prelude_file_name("prelude", desc(""), + llvm::cl::init(prelude_path.str().str())); llvm::cl::ParseCommandLineOptions(argc, argv);