# -*- mode: makefile -*- # # Copyright (c) 2012, Joyent, Inc. All rights reserved. # # Makefile.targ: common targets. # # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped # into other repos as-is without requiring any modifications. If you find # yourself changing this file, you should instead update the original copy in # eng.git and then update your repo to use the new version. # # This Makefile defines several useful targets and rules. You can use it by # including it from a Makefile that specifies some of the variables below. # # Targets defined in this Makefile: # # check Checks JavaScript files for lint and style # Checks bash scripts for syntax # Checks SMF manifests for validity against the SMF DTD # # clean Removes built files # # docs Builds restdown documentation in docs/ # # prepush Depends on "check" and "test" # # test Does nothing (you should override this) # # xref Generates cscope (source cross-reference index) # # For details on what these targets are supposed to do, see the Joyent # Engineering Guide. # # To make use of these targets, you'll need to set some of these variables. Any # variables left unset will simply not be used. # # BASH_FILES Bash scripts to check for syntax # (paths relative to top-level Makefile) # # CLEAN_FILES Files to remove as part of the "clean" target. Note # that files generated by targets in this Makefile are # automatically included in CLEAN_FILES. These include # restdown-generated HTML and JSON files. # # DOC_FILES Restdown (documentation source) files. These are # assumed to be contained in "docs/", and must NOT # contain the "docs/" prefix. # # JSL_CONF_NODE Specify JavaScriptLint configuration files # JSL_CONF_WEB (paths relative to top-level Makefile) # # Node.js and Web configuration files are separate # because you'll usually want different global variable # configurations. If no file is specified, none is given # to jsl, which causes it to use a default configuration, # which probably isn't what you want. # # JSL_FILES_NODE JavaScript files to check with Node config file. # JSL_FILES_WEB JavaScript files to check with Web config file. # # You can also override these variables: # # BASH Path to bash (default: bash) # # CSCOPE_DIRS Directories to search for source files for the cscope # index. (default: ".") # # JSL Path to JavaScriptLint (default: "jsl") # # JSL_FLAGS_NODE Additional flags to pass through to JSL # JSL_FLAGS_WEB # JSL_FLAGS # # JSSTYLE Path to jsstyle (default: jsstyle) # # JSSTYLE_FLAGS Additional flags to pass through to jsstyle # # # Defaults for the various tools we use. # BASH ?= bash BASHSTYLE ?= tools/bashstyle CP ?= cp CSCOPE ?= cscope CSCOPE_DIRS ?= . JSL ?= jsl JSSTYLE ?= jsstyle MKDIR ?= mkdir -p MV ?= mv RESTDOWN_FLAGS ?= RMTREE ?= rm -rf JSL_FLAGS ?= --nologo --nosummary ifeq ($(shell uname -s),SunOS) TAR ?= gtar else TAR ?= tar endif # # Defaults for other fixed values. # BUILD = build DISTCLEAN_FILES += $(BUILD) DOC_BUILD = $(BUILD)/docs/public # # Configure JSL_FLAGS_{NODE,WEB} based on JSL_CONF_{NODE,WEB}. # ifneq ($(origin JSL_CONF_NODE), undefined) JSL_FLAGS_NODE += --conf=$(JSL_CONF_NODE) endif ifneq ($(origin JSL_CONF_WEB), undefined) JSL_FLAGS_WEB += --conf=$(JSL_CONF_WEB) endif # # Targets. For descriptions on what these are supposed to do, see the # Joyent Engineering Guide. # # # Instruct make to keep around temporary files. We have rules below that # automatically update git submodules as needed, but they employ a deps/*/.git # temporary file. Without this directive, make tries to remove these .git # directories after the build has completed. # .SECONDARY: $($(wildcard deps/*):%=%/.git) # # This rule enables other rules that use files from a git submodule to have # those files depend on deps/module/.git and have "make" automatically check # out the submodule as needed. # deps/%/.git: git submodule update --init deps/$* # # These recipes make heavy use of dynamically-created phony targets. The parent # Makefile defines a list of input files like BASH_FILES. We then say that each # of these files depends on a fake target called filename.bashchk, and then we # define a pattern rule for those targets that runs bash in check-syntax-only # mode. This mechanism has the nice properties that if you specify zero files, # the rule becomes a noop (unlike a single rule to check all bash files, which # would invoke bash with zero files), and you can check individual files from # the command line with "make filename.bashchk". # .PHONY: check-bash check-bash: $(BASH_FILES:%=%.bashchk) $(BASH_FILES:%=%.bashstyle) %.bashchk: % $(BASH) -n $^ %.bashstyle: % $(BASHSTYLE) $^ .PHONY: check-jsl check-jsl-node check-jsl-web check-jsl: check-jsl-node check-jsl-web check-jsl-node: $(JSL_FILES_NODE:%=%.jslnodechk) check-jsl-web: $(JSL_FILES_WEB:%=%.jslwebchk) %.jslnodechk: % $(JSL_EXEC) $(JSL) $(JSL_FLAGS) $(JSL_FLAGS_NODE) $< %.jslwebchk: % $(JSL_EXEC) $(JSL) $(JSL_FLAGS) $(JSL_FLAGS_WEB) $< .PHONY: check-jsstyle check-jsstyle: $(JSSTYLE_FILES:%=%.jsstylechk) %.jsstylechk: % $(JSSTYLE_EXEC) $(JSSTYLE) $(JSSTYLE_FLAGS) $< .PHONY: check check: check-jsl check-jsstyle check-bash @echo check ok .PHONY: clean clean:: -$(RMTREE) $(CLEAN_FILES) .PHONY: distclean distclean:: clean -$(RMTREE) $(DISTCLEAN_FILES) CSCOPE_FILES = cscope.in.out cscope.out cscope.po.out CLEAN_FILES += $(CSCOPE_FILES) .PHONY: xref xref: cscope.files $(CSCOPE) -bqR .PHONY: cscope.files cscope.files: find $(CSCOPE_DIRS) -name '*.c' -o -name '*.h' -o -name '*.cc' \ -o -name '*.js' -o -name '*.s' -o -name '*.cpp' > $@ # # The "docs" target is complicated because we do several things here: # # (1) Use restdown to build HTML and JSON files from each of DOC_FILES. # # (2) Copy these files into $(DOC_BUILD) (build/docs/public), which # functions as a complete copy of the documentation that could be # mirrored or served over HTTP. # # (3) Then copy any directories and media from docs/media into # $(DOC_BUILD)/media. This allows projects to include their own media, # including files that will override same-named files provided by # restdown. # # Step (3) is the surprisingly complex part: in order to do this, we need to # identify the subdirectories in docs/media, recreate them in # $(DOC_BUILD)/media, then do the same with the files. # DOC_MEDIA_DIRS := $(shell find docs/media -type d 2>/dev/null | grep -v "^docs/media$$") DOC_MEDIA_DIRS := $(DOC_MEDIA_DIRS:docs/media/%=%) DOC_MEDIA_DIRS_BUILD := $(DOC_MEDIA_DIRS:%=$(DOC_BUILD)/media/%) DOC_MEDIA_FILES := $(shell find docs/media -type f 2>/dev/null) DOC_MEDIA_FILES := $(DOC_MEDIA_FILES:docs/media/%=%) DOC_MEDIA_FILES_BUILD := $(DOC_MEDIA_FILES:%=$(DOC_BUILD)/media/%) # # Like the other targets, "docs" just depends on the final files we want to # create in $(DOC_BUILD), leveraging other targets and recipes to define how # to get there. # .PHONY: docs docs: \ $(DOC_FILES:%.restdown=$(DOC_BUILD)/%.html) \ $(DOC_FILES:%.restdown=$(DOC_BUILD)/%.json) \ $(DOC_MEDIA_FILES_BUILD) # # We keep the intermediate files so that the next build can see whether the # files in DOC_BUILD are up to date. # .PRECIOUS: \ $(DOC_FILES:%.restdown=docs/%.html) \ $(DOC_FILES:%.restdown=docs/%json) # # We do clean those intermediate files, as well as all of DOC_BUILD. # CLEAN_FILES += \ $(DOC_BUILD) \ $(DOC_FILES:%.restdown=docs/%.html) \ $(DOC_FILES:%.restdown=docs/%.json) # # Before installing the files, we must make sure the directories exist. The | # syntax tells make that the dependency need only exist, not be up to date. # Otherwise, it might try to rebuild spuriously because the directory itself # appears out of date. # $(DOC_MEDIA_FILES_BUILD): | $(DOC_MEDIA_DIRS_BUILD) $(DOC_BUILD)/%: docs/% | $(DOC_BUILD) $(CP) $< $@ docs/%.json docs/%.html: docs/%.restdown | $(DOC_BUILD) $(RESTDOWN_EXEC) $(RESTDOWN) $(RESTDOWN_FLAGS) -m $(DOC_BUILD) $< $(DOC_BUILD): $(MKDIR) $@ $(DOC_MEDIA_DIRS_BUILD): $(MKDIR) $@ # # The default "test" target does nothing. This should usually be overridden by # the parent Makefile. It's included here so we can define "prepush" without # requiring the repo to define "test". # .PHONY: test test: .PHONY: prepush prepush: check test