auto merge of #5014 : Kimundi/rust/incoming, r=graydon

This implements a rust tool similar to go's go tool. It acts as a central hub for the tools rustc, rustdoc, rustpkg, rusti, and also provides shortcuts for directly compiling and running a source file either as a normal or a test executable. Default usage message:

```
The rust tool is a convenience for managing rust source code.
It acts as a shortcut for programs of the rust tool chain.

Usage:	rust <command> [arguments]

The commands are:

    build   compile rust source files
    run     build a executable, and run it
    test    build a test executable, and run it
    doc     generate documentation from doc comments
    pkg     download, build, install rust packages
    sketch  run a rust interpreter
    help    show detailed usage of a command

Use "rust help <command>" for more information about a command.
```
This commit is contained in:
bors 2013-02-19 06:18:42 -08:00
commit a8efa21333
9 changed files with 306 additions and 7 deletions

View File

@ -134,6 +134,7 @@ CFG_LIBFUZZER :=$(call CFG_LIB_NAME,fuzzer)
CFG_LIBRUSTPKG :=$(call CFG_LIB_NAME,rustpkg)
CFG_LIBRUSTDOC :=$(call CFG_LIB_NAME,rustdoc)
CFG_LIBRUSTI :=$(call CFG_LIB_NAME,rusti)
CFG_LIBRUST :=$(call CFG_LIB_NAME,rust)
STDLIB_GLOB :=$(call CFG_LIB_GLOB,std)
CORELIB_GLOB :=$(call CFG_LIB_GLOB,core)
@ -143,6 +144,7 @@ LIBFUZZER_GLOB :=$(call CFG_LIB_GLOB,fuzzer)
LIBRUSTPKG_GLOB :=$(call CFG_LIB_GLOB,rustpkg)
LIBRUSTDOC_GLOB :=$(call CFG_LIB_GLOB,rustdoc)
LIBRUSTI_GLOB :=$(call CFG_LIB_GLOB,rusti)
LIBRUST_GLOB :=$(call CFG_LIB_GLOB,rust)
STDLIB_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,std)
CORELIB_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,core)
LIBRUSTC_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,rustc)
@ -151,6 +153,7 @@ LIBFUZZER_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,fuzzer)
LIBRUSTPKG_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,rustpkg)
LIBRUSTDOC_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,rustdoc)
LIBRUSTI_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,rusti)
LIBRUST_DSYM_GLOB :=$(call CFG_LIB_DSYM_GLOB,rust)
# version-string calculation
CFG_GIT_DIR := $(CFG_SRC_DIR).git
@ -374,10 +377,12 @@ CSREQ$(1)_T_$(2)_H_$(3) = \
$$(HBIN$(1)_H_$(3))/rustpkg$$(X) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X) \
$$(HBIN$(1)_H_$(3))/rusti$$(X) \
$$(HBIN$(1)_H_$(3))/rust$$(X) \
$$(HLIB$(1)_H_$(3))/$$(CFG_LIBFUZZER) \
$$(HLIB$(1)_H_$(3))/$$(CFG_LIBRUSTPKG) \
$$(HLIB$(1)_H_$(3))/$$(CFG_LIBRUSTDOC) \
$$(HLIB$(1)_H_$(3))/$$(CFG_LIBRUSTI) \
$$(HLIB$(1)_H_$(3))/$$(CFG_LIBRUST) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_CORELIB) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_STDLIB) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX) \
@ -385,7 +390,8 @@ CSREQ$(1)_T_$(2)_H_$(3) = \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBFUZZER) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTPKG) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTDOC) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTI)
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTI) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUST)
ifeq ($(1),0)
# Don't run the the stage0 compiler under valgrind - that ship has sailed

View File

@ -68,6 +68,7 @@ clean$(1)_H_$(2):
$(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X)
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X)
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rusti$(X)
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rust$(X)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBFUZZER)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOC)
@ -77,6 +78,7 @@ clean$(1)_H_$(2):
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTC)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBSYNTAX)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTI)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUST)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CORELIB_GLOB)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(STDLIB_GLOB)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTC_GLOB)
@ -85,6 +87,7 @@ clean$(1)_H_$(2):
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTPKG_GLOB)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_GLOB)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTI_GLOB)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUST_GLOB)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUSTLLVM)
$(Q)rm -f $$(HLIB$(1)_H_$(2))/libstd.rlib

View File

@ -27,6 +27,7 @@ PKG_FILES := \
driver \
librustpkg \
librusti \
librust \
librustc \
compiletest \
etc \

View File

@ -60,6 +60,8 @@ install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(2))
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBRUSTDOC_GLOB))
$$(Q)$$(call INSTALL_LIB, \
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBRUSTI_GLOB))
$$(Q)$$(call INSTALL_LIB, \
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBRUST_GLOB))
$$(Q)$$(call INSTALL,$$(TL$(1)$(2)),$$(PTL$(1)$(2)),libmorestack.a)
endef
@ -90,15 +92,18 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_HOST_TRIPLE)_H_$(CFG_HOST_TRIPLE))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X))
$(Q)$(call INSTALL,$(HB2),$(PHB),rusti$(X))
$(Q)$(call INSTALL,$(HB2),$(PHB),rust$(X))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBRUSTC))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBRUSTPKG))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBRUSTDOC))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBRUSTI))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_LIBRUST))
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(CORELIB_GLOB))
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(STDLIB_GLOB))
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTC_GLOB))
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBSYNTAX_GLOB))
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTI_GLOB))
$(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUST_GLOB))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUNTIME))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUSTLLVM))
$(Q)$(call INSTALL,$(S)/man, \
@ -114,12 +119,14 @@ uninstall:
$(Q)rm -f $(PHB)/rustc$(X)
$(Q)rm -f $(PHB)/rustpkg$(X)
$(Q)rm -f $(PHB)/rusti$(X)
$(Q)rm -f $(PHB)/rust$(X)
$(Q)rm -f $(PHB)/rustdoc$(X)
$(Q)rm -f $(PHL)/$(CFG_RUSTLLVM)
$(Q)rm -f $(PHL)/$(CFG_LIBRUSTPKG)
$(Q)rm -f $(PHL)/$(CFG_LIBRUSTC)
$(Q)rm -f $(PHL)/$(CFG_LIBRUSTDOC)
$(Q)rm -f $(PHL)/$(CFG_LIBRUSTI)
$(Q)rm -f $(PHL)/$(CFG_LIBRUST)
$(Q)rm -f $(PHL)/$(CFG_RUNTIME)
$(Q)for i in \
$(call HOST_LIB_FROM_HL_GLOB,$(CORELIB_GLOB)) \
@ -129,6 +136,7 @@ uninstall:
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB)) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOC_GLOB)) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTI_GLOB)) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUST_GLOB)) \
; \
do rm -f $$i ; \
done

View File

@ -19,7 +19,8 @@ else
$(S)src/test/*/*/*.rs) \
$(wildcard $(S)src/fuzzer/*.rs) \
$(wildcard $(S)src/rustpkg/*.rs) \
$(wildcard $(S)src/rusti/*.rs)
$(wildcard $(S)src/rusti/*.rs) \
$(wildcard $(S)src/rust/*.rs)
PP_INPUTS_FILTERED = $(shell echo $(PP_INPUTS) | xargs grep -L \
"no-reformat\|xfail-pretty\|xfail-test")

View File

@ -14,7 +14,7 @@
######################################################################
# The names of crates that must be tested
TEST_CRATES = core std syntax rustc rustdoc rusti rustpkg
TEST_CRATES = core std syntax rustc rustdoc rusti rust rustpkg
# Markdown files under doc/ that should have their code extracted and run
DOC_TEST_NAMES = tutorial tutorial-ffi tutorial-macros tutorial-borrowed-ptr tutorial-tasks rust
@ -241,6 +241,12 @@ $(3)/test/rustitest.stage$(1)-$(2)$$(X): \
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
$(3)/test/rusttest.stage$(1)-$(2)$$(X): \
$$(RUST_LIB) $$(RUST_INPUTS) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC)
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
$(3)/test/rustdoctest.stage$(1)-$(2)$$(X): \
$$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC)
@ -464,20 +470,20 @@ $(foreach host,$(CFG_TARGET_TRIPLES), \
define DEF_RUN_DOC_TEST
DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-$(4) := \
DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-doc-$(4) := \
$$(CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3)) \
--src-base $(3)/test/doc-$(4)/ \
--build-base $(3)/test/doc-$(4)/ \
--mode run-pass
check-stage$(1)-T-$(2)-H-$(3)-doc-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4))
check-stage$(1)-T-$(2)-H-$(3)-doc-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4))
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): \
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
doc-$(4)-extract$(3)
@$$(call E, run doc-$(4): $$<)
$$(Q)$$(call CFG_RUN_CTEST,$(1),$$<,$(3)) \
$$(DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \
$$(DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-doc-$(4)) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),doc-$(4)) \
&& touch $$@

View File

@ -30,6 +30,10 @@ RUSTDOC_INPUTS := $(wildcard $(S)src/librustdoc/*.rs)
RUSTI_LIB := $(S)src/librusti/rusti.rc
RUSTI_INPUTS := $(wildcard $(S)src/librusti/*.rs)
# Rust, the convenience tool
RUST_LIB := $(S)src/librust/rust.rc
RUST_INPUTS := $(wildcard $(S)src/librust/*.rs)
# FIXME: These are only built for the host arch. Eventually we'll
# have tools that need to built for other targets.
define TOOLS_STAGE_N_TARGET
@ -102,6 +106,21 @@ $$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X): \
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rusti -o $$@ $$<
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBRUST): \
$$(RUST_LIB) $$(RUST_INPUTS) \
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_CORELIB) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_STDLIB) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBRUSTC)
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) -o $$@ $$< && touch $$@
$$(TBIN$(1)_T_$(4)_H_$(3))/rust$$(X): \
$$(DRIVER_CRATE) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBRUST)
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rust -o $$@ $$<
endef
define TOOLS_STAGE_N_HOST
@ -185,6 +204,23 @@ $$(HBIN$(2)_H_$(4))/rusti$$(X): \
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(HLIB$(2)_H_$(4))/$$(CFG_LIBRUST): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$$(CFG_LIBRUST) \
$$(HLIB$(2)_H_$(4))/$$(CFG_LIBRUSTC) \
$$(HSREQ$(2)_H_$(4))
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUST_GLOB) \
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUST_DSYM_GLOB)) \
$$(HLIB$(2)_H_$(4))
$$(HBIN$(2)_H_$(4))/rust$$(X): \
$$(TBIN$(1)_T_$(4)_H_$(3))/rust$$(X) \
$$(HLIB$(2)_H_$(4))/$$(CFG_LIBRUST) \
$$(HSREQ$(2)_H_$(4))
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
endef
$(foreach host,$(CFG_TARGET_TRIPLES), \

View File

@ -23,6 +23,9 @@ extern mod this(name = "rustdoc", vers = "0.6");
#[cfg(rusti)]
extern mod this(name = "rusti", vers = "0.6");
#[cfg(rust)]
extern mod this(name = "rust", vers = "0.6");
#[cfg(rustc)]
extern mod this(name = "rustc", vers = "0.6");

235
src/librust/rust.rc Normal file
View File

@ -0,0 +1,235 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// rust - central access to other rust tools
// XXX: Make commands run and test emit proper file endings on winds
// XXX: Make run only accept source that emits an executable
#[link(name = "rust",
vers = "0.6",
uuid = "4a24da33-5cc8-4037-9352-2cbe9bd9d27c",
url = "https://github.com/mozilla/rust/tree/master/src/rust")];
#[crate_type = "lib"];
extern mod core(vers = "0.6");
use core::run;
enum ValidUsage {
Valid, Invalid
}
impl ValidUsage {
fn is_valid(&self) -> bool { match *self {
Valid => true,
Invalid => false
}}
}
enum Action {
Exec(&str),
Call(&fn(args: &[~str]) -> ValidUsage)
}
enum UsageSource {
UsgExec(&str),
UsgStr(&str)
}
struct Command {
cmd: &str,
action: Action,
usage_line: &str,
usage_full: UsageSource
}
const commands: &[Command] = &[
Command{
cmd: "build",
action: Exec("rustc"),
usage_line: "compile rust source files",
usage_full: UsgExec("rustc --help")
},
Command{
cmd: "run",
action: Call(cmd_run),
usage_line: "build a executable, and run it",
usage_full: UsgStr(
"The run command is an shortcut for the command line \n\
\"rustc <filename> -o <filestem>~ && ./<filestem>~\".\
\n\nUsage:\trust run <filename>"
)
},
Command{
cmd: "test",
action: Call(cmd_test),
usage_line: "build a test executable, and run it",
usage_full: UsgStr(
"The test command is an shortcut for the command line \n\
\"rustc --test <filename> -o <filestem>test~ && \
./<filestem>test~\"\n\nUsage:\trust test <filename>"
)
},
Command{
cmd: "doc",
action: Exec("rustdoc"),
usage_line: "generate documentation from doc comments",
usage_full: UsgExec("rustdoc --help")
},
Command{
cmd: "pkg",
action: Exec("rustpkg"),
usage_line: "download, build, install rust packages",
usage_full: UsgExec("rustpkg --help")
},
Command{
cmd: "sketch",
action: Exec("rusti"),
usage_line: "run a rust interpreter",
usage_full: UsgStr("\nUsage:\trusti")
},
Command{
cmd: "help",
action: Call(cmd_help),
usage_line: "show detailed usage of a command",
usage_full: UsgStr(
"The help command displays the usage text of another command.\n\
The text is either build in, or provided by the corresponding \
program.\n\nUsage:\trust help <command>"
)
}
];
fn find_cmd(command_string: &str) -> Option<Command> {
do commands.find |command| {
command.cmd == command_string
}
}
fn cmd_help(args: &[~str]) -> ValidUsage {
fn print_usage(command_string: ~str) -> ValidUsage {
match find_cmd(command_string) {
Some(command) => {
match command.action {
Exec(s) => io::println(fmt!(
"The %s command is an alias for the %s program.",
command.cmd, s)),
_ => ()
}
match command.usage_full {
UsgStr(msg) => io::println(fmt!("%s\n", msg)),
UsgExec(commandline) => {
let words = str::words(commandline);
let (prog, args) = (words.head(), words.tail());
run::run_program(prog, args);
}
}
Valid
},
None => Invalid
}
}
match args {
[command_string] => print_usage(command_string),
_ => Invalid
}
}
fn cmd_test(args: &[~str]) -> ValidUsage {
match args {
[filename] => {
let test_exec = Path(filename).filestem().unwrap() + "test~";
if run::run_program("rustc", [
~"--test",
filename.to_owned(),
~"-o",
test_exec.to_owned()
]) == 0 {
run::run_program(~"./" + test_exec, []);
}
Valid
}
_ => Invalid
}
}
fn cmd_run(args: &[~str]) -> ValidUsage {
match args {
[filename] => {
let exec = Path(filename).filestem().unwrap() + "~";
if run::run_program("rustc", [
filename.to_owned(),
~"-o",
exec.to_owned()
]) == 0 {
run::run_program(~"./"+exec, []);
}
Valid
}
_ => Invalid
}
}
fn do_command(command: &Command, args: &[~str]) -> ValidUsage {
match command.action {
Call(f) => f(args),
Exec(commandline) => {
let words = str::words(commandline);
let (prog, prog_args) = (words.head(), words.tail());
let exitstatus = run::run_program(prog, prog_args + args);
os::set_exit_status(exitstatus);
Valid
}
}
}
fn usage() {
const indent: uint = 8;
io::print(
"The rust tool is a convenience for managing rust source code.\n\
It acts as a shortcut for programs of the rust tool chain.\n\
\n\
Usage:\trust <command> [arguments]\n\
\n\
The commands are:\n\
\n"
);
for commands.each |command| {
let padding = str::repeat(" ", indent - command.cmd.len());
io::println(fmt!(" %s%s%s",
command.cmd, padding, command.usage_line));
}
io::print(
"\n\
Use \"rust help <command>\" for more information about a command.\n\
\n"
);
}
fn main() {
let args = os::args().tail();
if !args.is_empty() {
for commands.each |command| {
if command.cmd == args.head() {
let result = do_command(command, args.tail());
if result.is_valid() { return; }
}
}
}
usage();
}