mk: rewrite the documentation handling.

This converts it to be very similar to crates.mk, with a single list of
the documentation items creating all the necessary bits and pieces.

Changes include:
- rustdoc is used to render HTML & test standalone docs
- documentation building now obeys NO_REBUILD=1
- testing standalone docs now obeys NO_REBUILD=1
- L10N is slightly less broken (in particular, it shares dependencies
  and code with the rest of the code)
- PDFs can be built for all documentation items, not just tutorial and
  manual
- removes the obsolete & unused extract-tests.py script
- adjust the CSS for standalone docs to use the rustdoc syntax
  highlighting
This commit is contained in:
Huon Wilson 2014-03-09 01:41:31 +11:00
parent 2d7d7e59f9
commit f7833215b0
6 changed files with 227 additions and 497 deletions

View File

@ -41,7 +41,6 @@ clean-misc:
@$(call E, cleaning)
$(Q)rm -f $(RUNTIME_OBJS) $(RUNTIME_DEF)
$(Q)rm -f $(RUSTLLVM_LIB_OBJS) $(RUSTLLVM_OBJS_OBJS) $(RUSTLLVM_DEF)
$(Q)rm -Rf $(DOCS)
$(Q)rm -Rf $(GENERATED)
$(Q)rm -Rf tmp/*
$(Q)rm -Rf rust-stage0-*.tar.bz2 $(PKG_NAME)-*.tar.gz $(PKG_NAME)-*.exe dist

View File

@ -92,6 +92,7 @@ TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
################################################################################
DOC_CRATES := $(filter-out rustc, $(filter-out syntax, $(CRATES)))
COMPILER_DOC_CRATES := rustc syntax
# This macro creates some simple definitions for each crate being built, just
# some munging of all of the parameters above.

View File

@ -9,24 +9,93 @@
# except according to those terms.
######################################################################
# Doc variables and rules
# The various pieces of standalone documentation: guides, tutorial,
# manual etc.
#
# The DOCS variable is their names (with no file extension).
#
# RUSTDOC_FLAGS_xyz variables are extra arguments to pass to the
# rustdoc invocation for xyz.
#
# RUSTDOC_DEPS_xyz are extra dependencies for the rustdoc invocation
# on xyz.
#
# L10N_LANGS are the languages for which the docs have been
# translated.
######################################################################
DOCS := index tutorial guide-ffi guide-macros guide-lifetimes \
guide-tasks guide-container guide-pointers \
complement-cheatsheet guide-runtime \
rust
DOCS :=
CDOCS :=
DOCS_L10N :=
HTML_DEPS := doc/
RUSTDOC_DEPS_rust := doc/full-toc.inc
RUSTDOC_FLAGS_rust := --markdown-in-header=doc/full-toc.inc
BASE_DOC_OPTS := --standalone --toc --number-sections
HTML_OPTS = $(BASE_DOC_OPTS) --to=html5 --section-divs --css=rust.css \
--include-before-body=doc/version_info.html \
--include-in-header=doc/favicon.inc --include-after-body=doc/footer.inc
TEX_OPTS = $(BASE_DOC_OPTS) --include-before-body=doc/version.md \
--from=markdown --include-before-body=doc/footer.tex --to=latex
EPUB_OPTS = $(BASE_DOC_OPTS) --to=epub
L10N_LANGS := ja
# Generally no need to edit below here.
# The options are passed to the documentation generators.
RUSTDOC_HTML_OPTS = --markdown-css rust.css \
--markdown-before-content=doc/version_info.html \
--markdown-in-header=doc/favicon.inc --markdown-after-content=doc/footer.inc
PANDOC_BASE_OPTS := --standalone --toc --number-sections
PANDOC_TEX_OPTS = $(PANDOC_BASE_OPTS) --include-before-body=doc/version.md \
--from=markdown --include-before-body=doc/footer.tex --to=latex
PANDOC_EPUB_OPTS = $(PANDOC_BASE_OPTS) --to=epub
# The rustdoc executable...
RUSTDOC_EXE = $(HBIN2_H_$(CFG_BUILD))/rustdoc$(X_$(CFG_BUILD))
# ...with rpath included in case --disable-rpath was provided to
# ./configure
RUSTDOC = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(RUSTDOC_EXE)
D := $(S)src/doc
DOC_TARGETS :=
COMPILER_DOC_TARGETS :=
DOC_L10N_TARGETS :=
# If NO_REBUILD is set then break the dependencies on rustdoc so we
# build the documentation without having to rebuild rustdoc.
ifeq ($(NO_REBUILD),)
HTML_DEPS := $(RUSTDOC_EXE)
else
HTML_DEPS :=
endif
# Check for the various external utilities for the EPUB/PDF docs:
ifeq ($(CFG_PDFLATEX),)
$(info cfg: no pdflatex found, omitting doc/rust.pdf)
NO_PDF_DOCS = 1
else
ifeq ($(CFG_XETEX),)
$(info cfg: no xetex found, disabling doc/rust.pdf)
NO_PDF_DOCS = 1
else
ifeq ($(CFG_LUATEX),)
$(info cfg: lacking luatex, disabling pdflatex)
NO_PDF_DOCS = 1
endif
endif
endif
ifeq ($(CFG_PANDOC),)
$(info cfg: no pandoc found, omitting PDF and EPUB docs)
ONLY_HTML_DOCS = 1
endif
ifeq ($(CFG_NODE),)
$(info cfg: no node found, omitting PDF and EPUB docs)
ONLY_HTML_DOCS = 1
endif
######################################################################
# Rust version
######################################################################
@ -46,7 +115,7 @@ doc/version_info.html: $(D)/version_info.html.template $(MKFILE_DEPS) \
GENERATED += doc/version.md doc/version_info.html
######################################################################
# Docs, from pandoc, rustdoc (which runs pandoc), and node
# Docs, from rustdoc and sometimes pandoc & node
######################################################################
doc/:
@ -75,184 +144,78 @@ doc/footer.tex: $(D)/footer.tex | doc/
@$(call E, cp: $@)
$(Q)cp -a $< $@ 2> /dev/null
ifeq ($(CFG_PANDOC),)
$(info cfg: no pandoc found, omitting docs)
NO_DOCS = 1
endif
# The (english) documentation for each doc item.
ifeq ($(CFG_NODE),)
$(info cfg: no node found, omitting docs)
NO_DOCS = 1
endif
define DEF_DOC
ifneq ($(NO_DOCS),1)
# HTML (rustdoc)
DOC_TARGETS += doc/$(1).html
doc/$(1).html: $$(D)/$(1).md $$(HTML_DEPS) $$(RUSTDOC_DEPS_$(1)) | doc/
@$$(call E, rustdoc: $$@)
$$(RUSTDOC) $$(RUSTDOC_HTML_OPTS) $$(RUSTDOC_FLAGS_$(1)) $$<
DOCS += doc/rust.html
doc/rust.html: $(D)/rust.md doc/full-toc.inc $(HTML_DEPS) | doc/
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --include-in-header=doc/full-toc.inc --output=$@
ifneq ($(ONLY_HTML_DOCS),1)
DOCS += doc/rust.tex
doc/rust.tex: $(D)/rust.md doc/footer.tex doc/version.md | doc/
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js $< | \
$(CFG_PANDOC) $(TEX_OPTS) --output=$@
# EPUB (pandoc directly)
DOC_TARGETS += doc/$(1).epub
doc/$(1).epub: $$(D)/$(1).md | doc/
@$$(call E, pandoc: $$@)
$$(Q)$$(CFG_NODE) $$(D)/prep.js --highlight $$< | \
$$(CFG_PANDOC) $$(PANDOC_EPUB_OPTS) --output=$$@
DOCS += doc/rust.epub
doc/rust.epub: $(D)/rust.md | doc/
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(EPUB_OPTS) --output=$@
# PDF (md =(pandoc)=> tex =(pdflatex)=> pdf)
DOC_TARGETS += doc/$(1).tex
doc/$(1).tex: $$(D)/$(1).md doc/footer.tex doc/version.md | doc/
@$$(call E, pandoc: $$@)
$$(Q)$$(CFG_NODE) $$(D)/prep.js $$< | \
$$(CFG_PANDOC) $$(PANDOC_TEX_OPTS) --output=$$@
DOCS += doc/rustdoc.html
doc/rustdoc.html: $(D)/rustdoc.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
ifneq ($(NO_PDF_DOCS),1)
DOC_TARGETS += doc/$(1).pdf
doc/$(1).pdf: doc/$(1).tex
@$$(call E, pdflatex: $$@)
$$(Q)$$(CFG_PDFLATEX) \
-interaction=batchmode \
-output-directory=doc \
$$<
endif # NO_PDF_DOCS
DOCS += doc/tutorial.html
doc/tutorial.html: $(D)/tutorial.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
endif # ONLY_HTML_DOCS
DOCS += doc/tutorial.tex
doc/tutorial.tex: $(D)/tutorial.md doc/footer.tex doc/version.md
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js $< | \
$(CFG_PANDOC) $(TEX_OPTS) --output=$@
endef
DOCS += doc/tutorial.epub
doc/tutorial.epub: $(D)/tutorial.md
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(EPUB_OPTS) --output=$@
$(foreach docname,$(DOCS),$(eval $(call DEF_DOC,$(docname))))
DOCS_L10N += doc/l10n/ja/tutorial.html
doc/l10n/ja/tutorial.html: doc/l10n/ja/tutorial.md doc/version_info.html doc/rust.css
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight doc/l10n/ja/tutorial.md | \
$(CFG_PANDOC) --standalone --toc \
--section-divs --number-sections \
--from=markdown --to=html5 --css=../../rust.css \
--include-before-body=doc/version_info.html \
--output=$@
# Localized documentation
# Complementary documentation
# FIXME: I (huonw) haven't actually been able to test properly, since
# e.g. (by default) I'm doing an out-of-tree build (#12763), but even
# adjusting for that, the files are too old(?) and are rejected by
# po4a.
#
DOCS += doc/index.html
doc/index.html: $(D)/index.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
# As such, I've attempted to get it working as much as possible (and
# switching from pandoc to rustdoc), but preserving the old behaviour
# (e.g. only running on the tutorial)
.PHONY: l10n-mds
l10n-mds: $(D)/po4a.conf \
$(foreach lang,$(L10N_LANG),$(D)/po/$(lang)/*.md.po)
$(warning WARNING: localized documentation is experimental)
po4a --copyright-holder="The Rust Project Developers" \
--package-name="Rust" \
--package-version="$(CFG_RELEASE)" \
-M UTF-8 -L UTF-8 \
$(D)/po4a.conf
DOCS += doc/complement-lang-faq.html
doc/complement-lang-faq.html: $(D)/complement-lang-faq.md doc/full-toc.inc $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --include-in-header=doc/full-toc.inc --output=$@
define DEF_L10N_DOC
DOC_L10N_TARGETS += doc/l10n/$(1)/$(2).html
doc/l10n/$(1)/$(2).html: l10n-mds $$(HTML_DEPS) $$(RUSTDOC_DEPS_$(2))
@$$(call E, rustdoc: $$@)
$$(RUSTDOC) $$(RUSTDOC_HTML_OPTS) $$(RUSTDOC_FLAGS_$(1)) doc/l10n/$(1)/$(2).md
endef
DOCS += doc/complement-project-faq.html
doc/complement-project-faq.html: $(D)/complement-project-faq.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
$(foreach lang,$(L10N_LANGS),$(eval $(call DEF_L10N_DOC,$(lang),tutorial)))
DOCS += doc/complement-cheatsheet.html
doc/complement-cheatsheet.html: $(D)/complement-cheatsheet.md doc/full-toc.inc $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --include-in-header=doc/full-toc.inc --output=$@
DOCS += doc/complement-bugreport.html
doc/complement-bugreport.html: $(D)/complement-bugreport.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
# Guides
DOCS += doc/guide-macros.html
doc/guide-macros.html: $(D)/guide-macros.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
DOCS += doc/guide-container.html
doc/guide-container.html: $(D)/guide-container.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
DOCS += doc/guide-ffi.html
doc/guide-ffi.html: $(D)/guide-ffi.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
DOCS += doc/guide-testing.html
doc/guide-testing.html: $(D)/guide-testing.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
DOCS += doc/guide-lifetimes.html
doc/guide-lifetimes.html: $(D)/guide-lifetimes.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
DOCS += doc/guide-tasks.html
doc/guide-tasks.html: $(D)/guide-tasks.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
DOCS += doc/guide-pointers.html
doc/guide-pointers.html: $(D)/guide-pointers.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
DOCS += doc/guide-runtime.html
doc/guide-runtime.html: $(D)/guide-runtime.md $(HTML_DEPS)
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(D)/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
ifeq ($(CFG_PDFLATEX),)
$(info cfg: no pdflatex found, omitting doc/rust.pdf)
else
ifeq ($(CFG_XETEX),)
$(info cfg: no xetex found, disabling doc/rust.pdf)
else
ifeq ($(CFG_LUATEX),)
$(info cfg: lacking luatex, disabling pdflatex)
else
DOCS += doc/rust.pdf
doc/rust.pdf: doc/rust.tex
@$(call E, pdflatex: $@)
$(Q)$(CFG_PDFLATEX) \
-interaction=batchmode \
-output-directory=doc \
$<
DOCS += doc/tutorial.pdf
doc/tutorial.pdf: doc/tutorial.tex
@$(call E, pdflatex: $@)
$(Q)$(CFG_PDFLATEX) \
-interaction=batchmode \
-output-directory=doc \
$<
endif
endif
endif
endif # No pandoc / node
######################################################################
# LLnextgen (grammar analysis from refman)
@ -278,50 +241,44 @@ endif
# Rustdoc (libstd/extra)
######################################################################
# The rustdoc executable, rpath included in case --disable-rpath was provided to
# ./configure
RUSTDOC = $(HBIN2_H_$(CFG_BUILD))/rustdoc$(X_$(CFG_BUILD))
# The library documenting macro
#
# $(1) - The crate name (std/extra)
#
# Passes --cfg stage2 to rustdoc because it uses the stage2 librustc.
define libdoc
doc/$(1)/index.html: \
$$(CRATEFILE_$(1)) \
$$(RSINPUTS_$(1)) \
$$(RUSTDOC) \
$$(foreach dep,$$(RUST_DEPS_$(1)), \
$$(TLIB2_T_$(CFG_BUILD)_H_$(CFG_BUILD))/stamp.$$(dep))
@$$(call E, rustdoc: $$@)
$$(Q)$$(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $$(RUSTDOC) \
--cfg stage2 $$<
define DEF_LIB_DOC
# If NO_REBUILD is set then break the dependencies on rustdoc so we
# build crate documentation without having to rebuild rustdoc.
ifeq ($(NO_REBUILD),)
LIB_DOC_DEP_$(1) = \
$$(CRATEFILE_$(1)) \
$$(RSINPUTS_$(1)) \
$$(RUSTDOC_EXE) \
$$(foreach dep,$$(RUST_DEPS_$(1)), \
$$(TLIB2_T_$(CFG_BUILD)_H_$(CFG_BUILD))/stamp.$$(dep))
else
LIB_DOC_DEP_$(1) = $$(CRATEFILE_$(1)) $$(RSINPUTS_$(1))
endif
$(2) += doc/$(1)/index.html
doc/$(1)/index.html: $$(LIB_DOC_DEP_$(1))
@$$(call E, rustdoc $$@)
$$(Q)$$(RUSTDOC) --cfg stage2 $$<
endef
$(foreach crate,$(CRATES),$(eval $(call libdoc,$(crate))))
DOCS += $(DOC_CRATES:%=doc/%/index.html)
CDOCS += doc/rustc/index.html
CDOCS += doc/syntax/index.html
$(foreach crate,$(DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),DOC_TARGETS)))
$(foreach crate,$(COMPILER_DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),COMPILER_DOC_TARGETS)))
ifdef CFG_DISABLE_DOCS
$(info cfg: disabling doc build (CFG_DISABLE_DOCS))
DOCS :=
DOC_TARGETS :=
endif
docs: $(DOCS)
compiler-docs: $(CDOCS)
docs: $(DOC_TARGETS)
compiler-docs: $(COMPILER_DOC_TARGETS)
docs-l10n: $(DOCS_L10N)
doc/l10n/%.md: doc/po/%.md.po doc/po4a.conf
po4a --copyright-holder="The Rust Project Developers" \
--package-name="Rust" \
--package-version="$(CFG_RELEASE)" \
-M UTF-8 -L UTF-8 \
doc/po4a.conf
docs-l10n: $(DOC_L10N_TARGETS)
.PHONY: docs-l10n

View File

@ -19,12 +19,6 @@ TEST_DOC_CRATES = $(DOC_CRATES)
TEST_HOST_CRATES = $(HOST_CRATES)
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
# Markdown files under doc/ that should have their code extracted and run
DOC_TEST_NAMES = tutorial guide-ffi guide-macros guide-lifetimes \
guide-tasks guide-container guide-pointers \
complement-cheatsheet guide-runtime \
rust
######################################################################
# Environment configuration
######################################################################
@ -318,7 +312,7 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec: \
check-stage$(1)-T-$(2)-H-$(3)-doc-$$(crate)-exec)
check-stage$(1)-T-$(2)-H-$(3)-doc-exec: \
$$(foreach docname,$$(DOC_TEST_NAMES), \
$$(foreach docname,$$(DOCS), \
check-stage$(1)-T-$(2)-H-$(3)-doc-$$(docname)-exec)
check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \
@ -662,32 +656,56 @@ $(foreach host,$(CFG_HOST), \
$(foreach pretty-name,$(PRETTY_NAMES), \
$(eval $(call DEF_RUN_PRETTY_TEST,$(stage),$(target),$(host),$(pretty-name)))))))
define DEF_RUN_DOC_TEST
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),doc-$(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) [$(2)]: $$<)
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
$$(DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-doc-$(4)) \
--logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),doc-$(4)) \
&& touch $$@
######################################################################
# Crate & freestanding documentation tests
######################################################################
define DEF_RUSTDOC
RUSTDOC_EXE_$(1)_T_$(2)_H_$(3) := $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3))
RUSTDOC_$(1)_T_$(2)_H_$(3) := $$(RPATH_VAR$(1)_T_$(2)_H_$(3)) $$(RUSTDOC_EXE_$(1)_T_$(2)_H_$(3))
endef
$(foreach host,$(CFG_HOST), \
$(foreach target,$(CFG_TARGET), \
$(foreach stage,$(STAGES), \
$(foreach docname,$(DOC_TEST_NAMES), \
$(eval $(call DEF_RUN_DOC_TEST,$(stage),$(target),$(host),$(docname)))))))
$(eval $(call DEF_RUSTDOC,$(stage),$(target),$(host))))))
# Freestanding
define DEF_DOC_TEST
check-stage$(1)-T-$(2)-H-$(3)-doc-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4))
# If NO_REBUILD is set then break the dependencies on everything but
# the source files so we can test documentation without rebuilding
# rustdoc etc.
ifeq ($(NO_REBUILD),)
DOCTESTDEP_$(1)_$(2)_$(3)_$(4) = \
$$(D)/$(4).md \
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
$$(RUSTDOC_EXE_$(1)_T_$(2)_H_$(3))
else
DOCTESTDEP_$(1)_$(2)_$(3)_$(4) = $$(D)/$(4).md
endif
ifeq ($(2),$$(CFG_BUILD))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): $$(DOCTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, run doc-$(4) [$(2)])
$$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test $$< --test-args "$$(TESTARGS)" && touch $$@
else
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)):
touch $$@
endif
endef
$(foreach host,$(CFG_HOST), \
$(foreach target,$(CFG_TARGET), \
$(foreach stage,$(STAGES), \
$(foreach docname,$(DOCS), \
$(eval $(call DEF_DOC_TEST,$(stage),$(target),$(host),$(docname)))))))
# Crates
define DEF_CRATE_DOC_TEST
@ -695,21 +713,20 @@ define DEF_CRATE_DOC_TEST
# the source files so we can test crate documentation without
# rebuilding any of the parent crates.
ifeq ($(NO_REBUILD),)
DOCTESTDEP_$(1)_$(2)_$(3)_$(4) = \
CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4) = \
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
$$(CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4)) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3))
$$(RUSTDOC_EXE_$(1)_T_$(2)_H_$(3))
else
DOCTESTDEP_$(1)_$(2)_$(3)_$(4) = $$(RSINPUTS_$(4))
CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4) = $$(RSINPUTS_$(4))
endif
check-stage$(1)-T-$(2)-H-$(3)-doc-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4))
ifeq ($(2),$$(CFG_BUILD))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): $$(DOCTESTDEP_$(1)_$(2)_$(3)_$(4))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): $$(CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, run doc-$(4) [$(2)])
$$(Q)$$(RPATH_VAR$(1)_T_$(2)_H_$(3)) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) --test \
$$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test \
$$(CRATEFILE_$(4)) --test-args "$$(TESTARGS)" && touch $$@
else
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)):
@ -724,26 +741,6 @@ $(foreach host,$(CFG_HOST), \
$(foreach crate,$(TEST_DOC_CRATES), \
$(eval $(call DEF_CRATE_DOC_TEST,$(stage),$(target),$(host),$(crate)))))))
######################################################################
# Extracting tests for docs
######################################################################
EXTRACT_TESTS := "$(CFG_PYTHON)" $(S)src/etc/extract-tests.py
define DEF_DOC_TEST_HOST
doc-$(2)-extract$(1):
@$$(call E, extract: $(2) tests)
$$(Q)rm -f $(1)/test/doc-$(2)/*.rs
$$(Q)$$(EXTRACT_TESTS) $$(D)/$(2).md $(1)/test/doc-$(2)
endef
$(foreach host,$(CFG_HOST), \
$(foreach docname,$(DOC_TEST_NAMES), \
$(eval $(call DEF_DOC_TEST_HOST,$(host),$(docname)))))
######################################################################
# Shortcut rules
######################################################################
@ -762,7 +759,7 @@ TEST_GROUPS = \
debuginfo \
codegen \
doc \
$(foreach docname,$(DOC_TEST_NAMES),doc-$(docname)) \
$(foreach docname,$(DOCS),doc-$(docname)) \
pretty \
pretty-rpass \
pretty-rpass-full \
@ -830,9 +827,9 @@ $(foreach stage,$(STAGES), \
$(eval $(call DEF_CHECK_FOR_STAGE_AND_HOSTS_AND_GROUP,$(stage),$(host),$(group))))))
define DEF_CHECK_DOC_FOR_STAGE
check-stage$(1)-docs: $$(foreach docname,$$(DOC_TEST_NAMES),\
check-stage$(1)-docs: $$(foreach docname,$$(DOCS),\
check-stage$(1)-T-$$(CFG_BUILD)-H-$$(CFG_BUILD)-doc-$$(docname)) \
$$(foreach crate,$$(DOC_CRATE_NAMES),\
$$(foreach crate,$$(TEST_DOC_CRATES),\
check-stage$(1)-T-$$(CFG_BUILD)-H-$$(CFG_BUILD)-doc-$$(crate))
endef

View File

@ -142,25 +142,18 @@ pre code {
}
/* Code highlighting */
.cm-s-default span.cm-keyword {color: #8959A8;}
.cm-s-default span.cm-atom {color: #219;}
.cm-s-default span.cm-number {color: #3E999F;}
.cm-s-default span.cm-def {color: #4271AE;}
/*.cm-s-default span.cm-variable {color: #C82829;}*/
.cm-s-default span.cm-variable-2 {color: #6F906C;}
.cm-s-default span.cm-variable-3 {color: #B76514;}
.cm-s-default span.cm-property {color: black;}
.cm-s-default span.cm-operator {color: black;}
.cm-s-default span.cm-comment {color: #8E908C;}
.cm-s-default span.cm-string {color: #718C00;}
.cm-s-default span.cm-string-2 {color: #866544;}
.cm-s-default span.cm-meta {color: #555;}
/*.cm-s-default span.cm-error {color: #F00;}*/
.cm-s-default span.cm-qualifier {color: #555;}
.cm-s-default span.cm-builtin {color: #30A;}
.cm-s-default span.cm-bracket {color: #CC7;}
.cm-s-default span.cm-tag {color: #C82829;}
.cm-s-default span.cm-attribute {color: #00C;}
pre.rust .kw { color: #8959A8; }
pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
pre.rust .number { color: #718C00; }
pre.rust .self { color: #C13928; }
pre.rust .boolval { color: #C13928; }
pre.rust .prelude-val { color: #C13928; }
pre.rust .comment { color: #8E908C; }
pre.rust .doccomment { color: #4D4D4C; }
pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999f; }
pre.rust .string { color: #718C00; }
pre.rust .lifetime { color: #C13928; }
pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
/* The rest
========================================================================== */

View File

@ -1,217 +0,0 @@
# Copyright 2012-2014 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.
"""
Script for extracting compilable fragments from markdown documentation. See
prep.js for a description of the format recognized by this tool. Expects
a directory fragments/ to exist under the current directory, and writes the
fragments in there as individual .rs files.
"""
from __future__ import print_function
from codecs import open
from collections import deque
from itertools import imap
import os
import re
import sys
# regexes
CHAPTER_NAME_REGEX = re.compile(r'# (.*)')
CODE_BLOCK_DELIM_REGEX = re.compile(r'~~~')
COMMENT_REGEX = re.compile(r'^# ')
COMPILER_DIRECTIVE_REGEX = re.compile(r'\#\[(.*)\];')
ELLIPSES_REGEX = re.compile(r'\.\.\.')
EXTERN_CRATE_REGEX = re.compile(r'\bextern crate extra\b')
MAIN_FUNCTION_REGEX = re.compile(r'\bfn main\b')
TAGS_REGEX = re.compile(r'\.([\w-]*)')
# tags to ignore
IGNORE_TAGS = \
frozenset(["abnf", "ebnf", "field", "keyword", "notrust", "precedence"])
# header for code snippet files
OUTPUT_BLOCK_HEADER = '\n'.join((
"#[ deny(warnings) ];",
"#[ allow(unused_variable) ];",
"#[ allow(dead_assignment) ];",
"#[ allow(unused_mut) ];",
"#[ allow(attribute_usage) ];",
"#[ allow(dead_code) ];",
"#[ feature(macro_rules, globs, struct_variant, managed_boxes) ];\n",))
def add_extern_mod(block):
if not has_extern_mod(block):
# add `extern crate extra;` after compiler directives
directives = []
while len(block) and is_compiler_directive(block[0]):
directives.append(block.popleft())
block.appendleft("\nextern crate extra;\n\n")
block.extendleft(reversed(directives))
return block
def add_main_function(block):
if not has_main_function(block):
prepend_spaces = lambda x: ' ' + x
block = deque(imap(prepend_spaces, block))
block.appendleft("\nfn main() {\n")
block.append("\n}\n")
return block
def extract_code_fragments(dest_dir, lines):
"""
Extracts all the code fragments from a file that do not have ignored tags
writing them to the following file:
[dest dir]/[chapter name]_[chapter_index].rs
"""
chapter_name = None
chapter_index = 0
for line in lines:
if is_chapter_title(line):
chapter_name = get_chapter_name(line)
chapter_index = 1
continue
if not is_code_block_delim(line):
continue
assert chapter_name, "Chapter name missing for code block."
tags = get_tags(line)
block = get_code_block(lines)
if tags & IGNORE_TAGS:
continue
block = add_extern_mod(add_main_function(block))
block.appendleft(OUTPUT_BLOCK_HEADER)
if "ignore" in tags:
block.appendleft("//ignore-test\n")
elif "should_fail" in tags:
block.appendleft("//should-fail\n")
output_filename = os.path.join(
dest_dir,
chapter_name + '_' + str(chapter_index) + '.rs')
write_file(output_filename, block)
chapter_index += 1
def has_extern_mod(block):
"""Checks if a code block has the line `extern crate extra`."""
find_extern_mod = lambda x: re.search(EXTERN_CRATE_REGEX, x)
return any(imap(find_extern_mod, block))
def has_main_function(block):
"""Checks if a code block has a main function."""
find_main_fn = lambda x: re.search(MAIN_FUNCTION_REGEX, x)
return any(imap(find_main_fn, block))
def is_chapter_title(line):
return re.match(CHAPTER_NAME_REGEX, line)
def is_code_block_delim(line):
return re.match(CODE_BLOCK_DELIM_REGEX, line)
def is_compiler_directive(line):
return re.match(COMPILER_DIRECTIVE_REGEX, line)
def get_chapter_name(line):
"""Get the chapter name from a `# Containers` line."""
return re.sub(
r'\W',
'_',
re.match(CHAPTER_NAME_REGEX, line).group(1)).lower()
def get_code_block(lines):
"""
Get a code block surrounded by ~~~, for example:
1: ~~~ { .tag }
2: let u: ~[u32] = ~[0, 1, 2];
3: let v: &[u32] = &[0, 1, 2, 3];
4: let w: [u32, .. 5] = [0, 1, 2, 3, 4];
5:
6: println!("u: {}, v: {}, w: {}", u.len(), v.len(), w.len());
7: ~~~
Returns lines 2-6. Assumes line 1 has been consumed by the caller.
"""
strip_comments = lambda x: re.sub(COMMENT_REGEX, '', x)
strip_ellipses = lambda x: re.sub(ELLIPSES_REGEX, '', x)
result = deque()
for line in lines:
if is_code_block_delim(line):
break
result.append(strip_comments(strip_ellipses(line)))
return result
def get_lines(filename):
with open(filename) as f:
for line in f:
yield line
def get_tags(line):
"""
Retrieves all tags from the line format:
~~~ { .tag1 .tag2 .tag3 }
"""
return set(re.findall(TAGS_REGEX, line))
def write_file(filename, lines):
with open(filename, 'w', encoding='utf-8') as f:
for line in lines:
f.write(unicode(line, encoding='utf-8', errors='replace'))
def main(argv=None):
if not argv:
argv = sys.argv
if len(sys.argv) < 2:
sys.stderr.write("Please provide an input filename.")
sys.exit(1)
elif len(sys.argv) < 3:
sys.stderr.write("Please provide a destination directory.")
sys.exit(1)
input_file = sys.argv[1]
dest_dir = sys.argv[2]
if not os.path.exists(input_file):
sys.stderr.write("Input file does not exist.")
sys.exit(1)
if not os.path.exists(dest_dir):
os.mkdir(dest_dir)
extract_code_fragments(dest_dir, get_lines(input_file))
if __name__ == "__main__":
sys.exit(main())