From 09485820236ccb89f36ceb4e89437a005f626bc7 Mon Sep 17 00:00:00 2001 From: Jon Meow Date: Thu, 14 Apr 2022 10:53:46 -0700 Subject: [PATCH] Add install scripts (#1186) I think this will work on linux/mac, not windows obviously. But the essence is that running `bazel run -c opt //installers/local:install` will create: Symlink: /usr/bin/carbon-explorer -> /usr/lib/carbon/carbon BusyBox-style binary: /usr/lib/carbon/carbon File: /usr/lib/carbon/data/prelude.carbon And then just running `carbon-explorer foo.carbon` with no flags (in particular, not --prelude) will work. Since this removes the need for prelude_file in most cases, I'm removing the relative path logic added in #1179 -- it would otherwise conflict with what I'm doing here. I *think* overall this will result in something even simpler and more reliable for compiler explorer to use, and hopefully with enough flexibility that it's easy for us to change how it's implemented later without breaking much. --- executable_semantics/BUILD | 14 +++++- executable_semantics/main.cpp | 81 ++++++++++++------------------- executable_semantics/main.h | 18 +++++++ executable_semantics/main_bin.cpp | 11 +++++ installers/local/BUILD | 67 +++++++++++++++++++++++++ installers/local/carbon.cpp | 27 +++++++++++ installers/local/install.bzl | 18 +++++++ installers/local/install.sh | 68 ++++++++++++++++++++++++++ installers/local/uninstall.sh | 55 +++++++++++++++++++++ 9 files changed, 307 insertions(+), 52 deletions(-) create mode 100644 executable_semantics/main.h create mode 100644 executable_semantics/main_bin.cpp create mode 100644 installers/local/BUILD create mode 100644 installers/local/carbon.cpp create mode 100644 installers/local/install.bzl create mode 100755 installers/local/install.sh create mode 100755 installers/local/uninstall.sh diff --git a/executable_semantics/BUILD b/executable_semantics/BUILD index 1405b195d14e..b2f594e1d3f3 100644 --- a/executable_semantics/BUILD +++ b/executable_semantics/BUILD @@ -7,6 +7,7 @@ load("@mypy_integration//:mypy.bzl", "mypy_test") package(default_visibility = [ "//bazel/check_deps:__pkg__", "//executable_semantics:__subpackages__", + "//installers:__subpackages__", ]) filegroup( @@ -14,9 +15,10 @@ filegroup( srcs = ["data/prelude.carbon"], ) -cc_binary( - name = "executable_semantics", +cc_library( + name = "main", srcs = ["main.cpp"], + hdrs = ["main.h"], deps = [ "//common:error", "//executable_semantics/common:arena", @@ -28,6 +30,14 @@ cc_binary( ], ) +cc_binary( + name = "executable_semantics", + srcs = ["main_bin.cpp"], + deps = [ + ":main", + ], +) + py_binary( name = "gen_rtti", srcs = ["gen_rtti.py"], diff --git a/executable_semantics/main.cpp b/executable_semantics/main.cpp index 00a001b61af3..7a8cecc8e7ad 100644 --- a/executable_semantics/main.cpp +++ b/executable_semantics/main.cpp @@ -2,6 +2,8 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include "executable_semantics/main.h" + #include #include @@ -16,21 +18,15 @@ #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 { - llvm::errs() << error.message() << "\n"; - return EXIT_FAILURE; -} +namespace Carbon { -auto main(int argc, char* argv[]) -> int { +namespace cl = llvm::cl; + +static auto Main(llvm::StringRef default_prelude_file, int argc, char* argv[]) + -> ErrorOr { llvm::setBugReportMsg( "Please report issues to " "https://github.com/carbon-language/carbon-lang/issues and include the " @@ -41,48 +37,33 @@ auto main(int argc, char* argv[]) -> int { // is piped to stdout. llvm::errs().tie(&llvm::outs()); - using llvm::cl::desc; - using llvm::cl::opt; - opt trace_option("trace", desc("Enable tracing")); - opt input_file_name(llvm::cl::Positional, desc(""), - llvm::cl::Required); + cl::opt trace_option("trace", cl::desc("Enable tracing")); + cl::opt input_file_name(cl::Positional, cl::desc(""), + cl::Required); // 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())); + cl::opt prelude_file_name("prelude", cl::desc(""), + cl::init(default_prelude_file.str())); + cl::ParseCommandLineOptions(argc, argv); - llvm::cl::ParseCommandLineOptions(argc, argv); - - Carbon::Arena arena; - Carbon::ErrorOr ast = - Carbon::Parse(&arena, input_file_name, trace_option); - if (!ast.ok()) { - return PrintError(ast.error()); - } - AddPrelude(prelude_file_name, &arena, &ast->declarations); + Arena arena; + ASSIGN_OR_RETURN(AST ast, Parse(&arena, input_file_name, trace_option)); + AddPrelude(prelude_file_name, &arena, &ast.declarations); // Typecheck and run the parsed program. - Carbon::ErrorOr result = Carbon::ExecProgram(&arena, *ast, trace_option); - if (!result.ok()) { - return PrintError(result.error()); - } + ASSIGN_OR_RETURN(int unused_return_code, + ExecProgram(&arena, ast, trace_option)); + (void)unused_return_code; + return Success(); } + +auto ExecutableSemanticsMain(llvm::StringRef default_prelude_file, int argc, + char** argv) -> int { + if (auto result = Main(default_prelude_file, argc, argv); !result.ok()) { + llvm::errs() << result.error().message() << "\n"; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +} // namespace Carbon diff --git a/executable_semantics/main.h b/executable_semantics/main.h new file mode 100644 index 000000000000..594f1e289319 --- /dev/null +++ b/executable_semantics/main.h @@ -0,0 +1,18 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef EXECUTABLE_SEMANTICS_MAIN_H_ +#define EXECUTABLE_SEMANTICS_MAIN_H_ + +#include "llvm/ADT/StringRef.h" + +namespace Carbon { + +// Runs executable semantics. +auto ExecutableSemanticsMain(llvm::StringRef default_prelude_file, int argc, + char** argv) -> int; + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_MAIN_H_ diff --git a/executable_semantics/main_bin.cpp b/executable_semantics/main_bin.cpp new file mode 100644 index 000000000000..11a3a4d9f427 --- /dev/null +++ b/executable_semantics/main_bin.cpp @@ -0,0 +1,11 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "executable_semantics/main.h" + +auto main(int argc, char** argv) -> int { + // This assumes execution from bazel, in runfiles. + return Carbon::ExecutableSemanticsMain( + "executable_semantics/data/prelude.carbon", argc, argv); +} diff --git a/installers/local/BUILD b/installers/local/BUILD new file mode 100644 index 000000000000..1c0d226950d0 --- /dev/null +++ b/installers/local/BUILD @@ -0,0 +1,67 @@ +# Part of the Carbon Language project, under the Apache License v2.0 with LLVM +# Exceptions. See /LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Installs Carbon to /usr/bin and /usr/lib/carbon. +# +# To install to /usr, run: +# bazel run -c opt //installers/local:install +# +# To use a custom install path, run: +# bazel run -c opt //installers/local:install +# --//installers/local:install_path=/my/path +# +# To uninstall, run: +# bazel //installers/local:uninstall +# +# The build mode is important for installs, as debug versions may be installed. +# It is not relevant for uninstalls. +# +# If a custom install path is passed to :install, the same should be passed to +# :uninstall. + +load("install.bzl", "install_path_rule") + +# Turns `--//installers/local:install_path=arg` into `$(INSTALL_PATH)`. +install_path_rule( + name = "install_path", + build_setting_default = "/usr", +) + +sh_binary( + name = "install", + srcs = ["install.sh"], + args = [ + "--install_path", + "$(INSTALL_PATH)", + "--carbon", + "$(location :carbon)", + "$(locations //executable_semantics:standard_libraries)", + ], + data = [ + ":carbon", + "//executable_semantics:standard_libraries", + ], + toolchains = [":install_path"], +) + +sh_binary( + name = "uninstall", + srcs = ["uninstall.sh"], + args = [ + "--install_path", + "$(INSTALL_PATH)", + ], + toolchains = [":install_path"], +) + +# A busybox-like binary for Carbon tools; multiple tools are part of this binary +# so that shared code is deduplicated. +cc_binary( + name = "carbon", + srcs = ["carbon.cpp"], + deps = [ + "//executable_semantics:main", + "@llvm-project//llvm:Support", + ], +) diff --git a/installers/local/carbon.cpp b/installers/local/carbon.cpp new file mode 100644 index 000000000000..797da4287b36 --- /dev/null +++ b/installers/local/carbon.cpp @@ -0,0 +1,27 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "executable_semantics/main.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +namespace fs = llvm::sys::fs; +namespace path = llvm::sys::path; + +auto main(int argc, char** argv) -> int { + llvm::StringRef bin = path::filename(argv[0]); + if (bin == "carbon-explorer") { + static int static_for_main_addr; + std::string exe = fs::getMainExecutable( + argv[0], static_cast(&static_for_main_addr)); + llvm::StringRef install_path = path::parent_path(exe); + llvm::SmallString<256> prelude_file(install_path); + path::append(prelude_file, "data", "prelude.carbon"); + return Carbon::ExecutableSemanticsMain(prelude_file, argc, argv); + } else { + fprintf(stderr, "Unrecognized Carbon binary requested: %s", argv[0]); + return 1; + } +} diff --git a/installers/local/install.bzl b/installers/local/install.bzl new file mode 100644 index 000000000000..96e02cb22035 --- /dev/null +++ b/installers/local/install.bzl @@ -0,0 +1,18 @@ +# Part of the Carbon Language project, under the Apache License v2.0 with LLVM +# Exceptions. See /LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +"""Install-related rules.""" + +def _install_path_rule_impl(ctx): + """Turns the install path into a variable for rules to use.""" + return [ + platform_common.TemplateVariableInfo({ + "INSTALL_PATH": ctx.build_setting_value, + }), + ] + +install_path_rule = rule( + implementation = _install_path_rule_impl, + build_setting = config.string(flag = True), +) diff --git a/installers/local/install.sh b/installers/local/install.sh new file mode 100755 index 000000000000..0d993516335f --- /dev/null +++ b/installers/local/install.sh @@ -0,0 +1,68 @@ +#!/bin/bash -eu +# +# Part of the Carbon Language project, under the Apache License v2.0 with LLVM +# Exceptions. See /LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Performs a local install. This will replace any previous carbon installs +# without prompting. + +STANDARD_LIBRARIES=() + +while [[ $# -gt 0 ]]; do + case "$1" in + --carbon) + CARBON="$2" + shift + shift + ;; + --install_path) + INSTALL_PATH="$2" + shift + shift + ;; + *) + STANDARD_LIBRARIES+=("$1") + echo $1 + shift + ;; + esac +done + +# If the install path is relative, change it to be based on the working dir. +if [[ ! "${INSTALL_PATH}" = /* ]]; then + INSTALL_PATH="${BUILD_WORKING_DIRECTORY}/${INSTALL_PATH}" +fi + +# Prepare the install script to run. +SCRIPT=$(cat <