#   Copyright (C) 2017, 2018, 2020, 2021, 2022, 2023  Kai Mertens <kmx@posteo.net>
#
#   This source describes Hardware of a Free Design for the Zerocat Chipflasher
#   Project and is licensed under the CERN-OHL-S v2.
#
#   You may redistribute and modify this source and make products using it under
#   the terms of the CERN-OHL-S v2 (https://ohwr.org/cern_ohl_s_v2.txt) or any
#   later version.
#
#   This source is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING
#   OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR
#   PURPOSE. Please see the CERN-OHL-S v2 for applicable conditions.
#
#   Source location:   git://zerocat.org/zerocat/projects/chipflasher
#
#   As per CERN-OHL-S v2 section 4, should You produce hardware based on this
#   source, You must where practicable maintain the Source Location visible on
#   the external case of the Chipflasher Device or other products you make using
#   this source.


#   Documentation
#   =============
#
#
#   Usage
#   -----
#
#
#       $ make
#       $ make gerbv
#       $ make clean


#   Workaround for buggy GNU Make < 4.3
#   ===================================
#
#   Finalize commands within a $(shell) function with semicolon,
#   e.g.: $(shell echo;)


# Shell
SHELL                         := /bin/sh


# White Space
EMPTY                         :=
SPACE                         := $(EMPTY) $(EMPTY)
COMMA                         := ,
SQUOTE                        := '
HASH                          := $(shell echo '#';)
M5                            := ooooo
TAB1                          := \r\t\t
TAB2                          := \r\t\t\t


# Suffixes
.SUFFIXES :
.SUFFIXES : .sch .drc .bom .md .pcb .png .svg .gbr .cnc .pcb.bak .new.pcb .net .cmd


# Standard Utilities
WHEREIS                       := $(shell command -v whereis;)
WHEREIS_FLAGS                 := -b
$(if $(strip $(WHEREIS)),,    $(error Cannot find whereis utility))

CD                            := $(shell command -v cd;)
CD_FLAGS                      :=
$(if $(strip $(CD)),,         $(error Cannot find cd utility))

MV                            := $(shell command -v mv;)
MV_FLAGS                      :=
$(if $(strip $(MV)),,         $(error Cannot find mv utility))

RM                            := $(shell command -v rm;)
RM_FLAGS                      :=
$(if $(strip $(RM)),,         $(error Cannot find rm utility))

CAT                           := $(shell command -v cat;)
CAT_FLAGS                     :=
$(if $(strip $(CAT)),,        $(error Cannot find cat utility))

CUT                           := $(shell command -v cut;)
CUT_FLAGS                     := -d' '
$(if $(strip $(CUT)),,        $(error Cannot find cut utility))

GIT                           := $(shell command -v git;)
GIT_FLAGS                     :=
$(if $(strip $(GIT)),,        $(error Cannot find git utility))

SED                           := $(shell command -v sed;)
SED_FLAGS                     := -r
$(if $(strip $(SED)),,        $(error Cannot find sed utility))

SET                           := $(shell command -v set;)
SET_FLAGS                     := -f
$(if $(strip $(SET)),,        $(error Cannot find set utility))

ZIP                           := $(shell command -v zip;)
ZIP_FLAGS                     := -D
$(if $(strip $(ZIP)),,        $(error Cannot find zip utility))

ECHO                          := $(shell $(WHEREIS) $(WHEREIS_FLAGS) echo | $(CUT) $(CUT_FLAGS) -f2;)
ECHO_FLAGS                    := -e
$(if $(strip $(ECHO)),,       $(error Cannot find echo utility))

GREP                          := $(shell command -v grep;)
GREP_FLAGS                    :=
$(if $(strip $(GREP)),,       $(error Cannot find grep utility))

SORT                          := $(shell command -v sort;)
SORT_FLAGS                    :=
$(if $(strip $(SORT)),,       $(error Cannot find sort utility))

UNIQ                          := $(shell command -v uniq;)
UNIQ_FLAGS                    :=
$(if $(strip $(UNIQ)),,       $(error Cannot find uniq utility))

#   Note ‘mkdir -p’ might not be supported.
MKDIR                         := $(shell command -v mkdir;)
MKDIR_FLAGS                   :=
$(if $(strip $(MKDIR)),,      $(error Cannot find mkdir utility))

MKTEMP                        := $(shell command -v mktemp;)
MKTEMP_FLAGS                  :=
$(if $(strip $(MKTEMP)),,     $(error Cannot find mktemp utility))

MARKDOWN                      := $(shell command -v markdown;)
MARKDOWN_FLAGS                :=
$(if $(strip $(MARKDOWN)),,   $(error Cannot find markdown utility))


# Extra Utilities
GAF                           := $(shell command -v gaf;)
GAF_FLAGS                     :=
$(if $(strip $(GAF)),,        $(error Cannot find gaf utility))

PCB                           := $(shell command -v pcb;)
PCB_FLAGS                     :=
$(if $(strip $(PCB)),,        $(error Cannot find pcb utility))

GERBV                         := $(shell command -v gerbv;)
GERBV_FLAGS                   :=
$(if $(strip $(GERBV)),,      $(error Cannot find gerbv utility))

GSCHEM                        := $(shell command -v gschem;)
GSCHEM_FLAGS                  :=
$(if $(strip $(GSCHEM)),,     $(error Cannot find gschem utility))

CONVERT                       := $(shell command -v convert;)
CONVERT_FLAGS                 := -resize 2000x
$(if $(strip $(CONVERT)),,    $(error Cannot find convert utility))

GNETLIST                      := $(shell command -v gnetlist;)
GNETLIST_FLAGS                :=
$(if $(strip $(GNETLIST)),,   $(error Cannot find gnetlist utility))

GSCH2PCB                      := $(shell command -v gsch2pcb;)
GSCH2PCB_FLAGS                :=
$(if $(strip $(GSCH2PCB)),,   $(error Cannot find gsch2pcb utility))

INKSCAPE                      := $(shell command -v inkscape;)
INKSCAPE_FLAGS                :=
$(if $(strip $(INKSCAPE)),,   $(error Cannot find inkscape utility))
INKSCAPE_TESTED               := Inkscape 1.2.1
INKSCAPE_VERSION              := $(strip\
	$(shell\
		$(INKSCAPE) $(INKSCAPE_FLAGS)\
			--version;\
	)\
)
$(if $(findstring $(INKSCAPE_TESTED),$(INKSCAPE_VERSION)),,$(error Wrong inkscape version))


# Root Paths
ROOT_GSCHEM                   := gschem/
ROOT_SYMBOLS                  := gschem/symbols/
ROOT_PCB                      := pcb/
ROOT_FOOTPRINTS               := pcb/footprints/
ROOT_ARTWORK                  := artwork/


# Sources
GSCHEM_ATTRIBS                := $(ROOT_GSCHEM)attribs
GNETLIST_RULE                 := $(ROOT_GSCHEM)rules-drc.scm
GSCHEM_SYMBOLS                := $(wildcard $(ROOT_SYMBOLS)*.sym)

#   Sources Cables, common for Board and Testboard
CABLES_SCH                    := $(strip\
	$(shell\
		$(ECHO) $(ECHO_FLAGS)\
			$(ROOT_GSCHEM)chipflasher-page{09,10,11,12,13}.sch;\
	)\
)

#   Sources Board
BOARD_SCH                     := $(strip\
	$(shell\
		$(ECHO) $(ECHO_FLAGS)\
			$(ROOT_GSCHEM)chipflasher-page{01,02,03,04,05,06,07,08}.sch;\
	)\
)
BOARD_PCB                     := $(ROOT_PCB)board.pcb
BOARD_SVG                     := $(ROOT_ARTWORK)board-label.svg

#   Sources Testboard
TESTBOARD_SCH                 := $(wildcard $(ROOT_GSCHEM)testboard-page*.sch)
TESTBOARD_PCB                 :=
TESTBOARD_SVG                 := $(ROOT_ARTWORK)testboard-label.svg


# Settings
PROJECT_TITLE                 := Zerocat Chipflasher
PROJECT_BRIEF                 := Flash free firmware, kick the Management Engine.
PROJECT_REPO                  := git://zerocat.org/zerocat/projects/chipflasher
PROJECT_NUMBER                := $(strip\
	$(shell\
		$(SET) $(SET_FLAGS)\
		&& $(GIT) $(GIT_FLAGS)\
			describe\
				--always\
				--long\
				--match v*\
		| $(SED) $(SED_FLAGS)\
			-e 's/(.*)(-g)([0-9a-f]*)/\1-\3/;'\
				-;\
	)\
)
PROJECT_BRANCH                := $(strip\
	$(shell\
		$(GIT) $(GIT_FLAGS)\
			branch\
		| $(SED) $(SED_FLAGS)\
			-e '/^\*/!d; s/^\* //;'\
				-;\
	)\
)
PROJECT_COMMIT                := $(strip\
	$(shell\
		$(SET) $(SET_FLAGS)\
		&& $(GIT) $(GIT_FLAGS)\
			describe\
				--always\
				--long\
		| $(SED) $(SED_FLAGS)\
			-e 's/^.*-g//;'\
				-;\
	)\
)
BOARD_NUMBER                 := $(strip\
	$(shell\
		$(SET) $(SET_FLAGS)\
		&& $(GIT) $(GIT_FLAGS)\
			describe\
				--always\
				--long\
				--match board-v*\
		| $(SED) $(SED_FLAGS)\
			-e 's/(.*)(-g)([0-9a-f]*)/\1-\3/;'\
				-;\
	)\
)
TOKEN_BOARD_NUMBER            := <Board-Version>
MAKEFILE_TITLE                := Generate Hardware Files and Auxiliaries


# Files
TARGETS_GSCHEM_AUTO1          := $(addprefix $(ROOT_GSCHEM)$(SQUOTE)$(HASH), $(addsuffix $(HASH)$(SQUOTE),$(notdir $(CABLES_SCH) $(BOARD_SCH) $(TESTBOARD_SCH))))
TARGETS_GSCHEM_AUTO2          := $(addsuffix ~,$(CABLES_SCH) $(BOARD_SCH) $(TESTBOARD_SCH))
TARGETS_GSCHEM_AUTO3          := $(addsuffix ~,$(GSCHEM_SYMBOLS))
CABLES_DRC                    := $(ROOT_GSCHEM)cables.drc
BOARD_DRC                     := $(ROOT_GSCHEM)chipflasher.drc
TESTBOARD_DRC                 := $(ROOT_GSCHEM)testboard.drc
CABLES_BOM                    := $(patsubst %.sch,%.bom,$(CABLES_SCH))
BOARD_BOM                     := $(patsubst %.sch,%.bom,$(BOARD_SCH))
TESTBOARD_BOM                 := $(patsubst %.sch,%.bom,$(TESTBOARD_SCH))
CABLES_BOM_MD                 := $(addsuffix .md,$(CABLES_BOM))
BOARD_BOM_MD                  := $(addsuffix .md,$(BOARD_BOM))
TESTBOARD_BOM_MD              := $(addsuffix .md,$(TESTBOARD_BOM))
CABLES_BOM_HTML               := $(patsubst %.bom.md,%.bom.html,$(CABLES_BOM_MD))
BOARD_BOM_HTML                := $(patsubst %.bom.md,%.bom.html,$(BOARD_BOM_MD))
TESTBOARD_BOM_HTML            := $(patsubst %.bom.md,%.bom.html,$(TESTBOARD_BOM_MD))
CABLES_PDF                    := $(addsuffix .pdf,$(CABLES_SCH))
BOARD_PDF                     := $(addsuffix .pdf,$(BOARD_SCH))
TESTBOARD_PDF                 := $(addsuffix .pdf,$(TESTBOARD_SCH))
CABLES_PNG                    := $(addsuffix .png,$(CABLES_SCH)) $(addsuffix .top.png,$(CABLES_PCB)) $(addsuffix .bottom.png,$(CABLES_PCB))
BOARD_PNG                     := $(addsuffix .png,$(BOARD_SCH)) $(addsuffix .top.png,$(BOARD_PCB)) $(addsuffix .bottom.png,$(BOARD_PCB))
TESTBOARD_PNG                 := $(addsuffix .png,$(TESTBOARD_SCH)) $(addsuffix .top.png,$(TESTBOARD_PCB)) $(addsuffix .bottom.png,$(TESTBOARD_PCB))
CABLES_IMG                    := $(CABLES_PNG)
BOARD_IMG                     := $(BOARD_PNG)
TESTBOARD_IMG                 := $(TESTBOARD_PNG)
CABLES_AUX                    := $(CABLES_BOM)
BOARD_AUX                     := $(BOARD_BOM)
TESTBOARD_AUX                 := $(TESTBOARD_BOM)
CABLES_MARKDOWN               := $(CABLES_BOM_MD)
BOARD_MARKDOWN                := $(BOARD_BOM_MD)
TESTBOARD_MARKDOWN            := $(TESTBOARD_BOM_MD)
GERBER_FILE                   := board-$(PROJECT_COMMIT)
GERBER_ARCHIVE                := chipflasher-$(PROJECT_COMMIT)


# Tinned Cans
define HEADER
$(strip\
	$(ECHO) $(ECHO_FLAGS)\
		"\n$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)"\
		"\n$(M5) $(PROJECT_TITLE)"\
		"\n$(M5) – $(PROJECT_BRIEF)"\
		"\n$(M5) $(MAKEFILE_TITLE)"\
		"\n$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)$(M5)"\
)
endef
define HEADLINE
$(strip\
	$(ECHO) $(ECHO_FLAGS)\
		"$(M5) Process target “$@” $(M5)$(M5)"\
)
endef
define DONE
$(strip\
	$(ECHO) $(ECHO_FLAGS)\
		"... successfully processed: “$@”."\
		"\n"\
)
endef


# Built-in Special Targets
#~ .SECONDARY :                  # Uncomment for debugging
.PHONY :\
	all\
	\
	hello\
	help\
	\
	cables\
	board\
	testboard\
	settings\
	gerbv\
	gerber\
	gerber-archive\
	check\
	synchronize\
	\
	clean-gerber\
	clean-archive\
	clean-synchronize\
	clean-backups\
	clean-testboard\
	clean-board\
	clean


# Targets
#   Generate all selected files.
all : hello cables board testboard
	@$(HEADLINE)\
	&& $(DONE);

#   Say hello, provided with targets all, clean and help
hello :
	@$(HEADER)\
	&& $(DONE);

#   Provide help information
help : hello
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS)\
		"\nList of Targets"\
		"\n==============="\
		"\n"\
		"\nDefault Goal"\
		"\n------------"\
		"\n"\
		"\nall$(TAB2)generate all selected files"\
		"\n"\
		"\nHelp"\
		"\n----"\
		"\n"\
		"\nhello$(TAB2)greeter, provided with all, clean and help"\
		"\nhelp$(TAB2)provide this help message"\
		"\n"\
		"\nActions"\
		"\n-------"\
		"\n"\
		"\ncables$(TAB2)generate all cable files"\
		"\nboard$(TAB2)generate all board files"\
		"\ntestboard$(TAB2)generate all testboard files"\
		"\nsettings$(TAB2)display retrieved settings"\
		"\ngerber$(TAB2)export PCB layers as gerber files"\
		"\ngerber-archive$(TAB2)create archive with exported gerber files"\
		"\ngerbv$(TAB2)start $(GERBV) utility with all layers loaded"\
		"\ncheck$(TAB2)perform design rule check for schematics, cables, board and testboard"\
		"\nsynchronize$(TAB2)update board PCB file from schematic (manual action required)"\
		"\n"\
		"\nClean"\
		"\n-----"\
		"\n"\
		"\nclean-synchronize$(TAB2)remove files, generated by synchronize action"\
		"\nclean-backups$(TAB2)remove backup files, generated by PCB- and schematic editors"\
		"\nclean-gerber$(TAB2)remove exported gerber files"\
		"\nclean-archive$(TAB2)remove archive with gerber files"\
		"\nclean-testboard$(TAB2)remove generated testboard files"\
		"\nclean-board$(TAB2)remove generated board files"\
		"\nclean-cables$(TAB2)remove generated cable files"\
		"\nclean$(TAB2)make files and folders clean"\
		"\n"\
	&& $(DONE);

#  Generate files, related to cables
cables : $(CABLES_DRC) $(CABLES_AUX) $(CABLES_IMG) $(CABLES_PDF) $(CABLES_MARKDOWN) $(CABLES_BOM_HTML)
	@$(HEADLINE)\
	&& $(DONE);

#   Generate board related files
board : $(BOARD_DRC) $(BOARD_AUX) $(BOARD_IMG) $(BOARD_PDF) $(BOARD_MARKDOWN) $(BOARD_BOM_HTML) board-label gerber-archive
	@$(HEADLINE)\
	&& $(DONE);

#   Generate testboard related files
testboard : $(TESTBOARD_DRC) $(TESTBOARD_AUX) $(TESTBOARD_IMG) $(TESTBOARD_PDF) $(TESTBOARD_MARKDOWN) $(TESTBOARD_BOM_HTML) testboard-label
	@$(HEADLINE)\
	&& $(DONE);

#   Report retrieved settings.
settings :
	@$(HEADLINE)\
	&& $(ECHO) $(ECHO_FLAGS)\
		"\nBOARD_NUMBER:\r\t\t$(BOARD_NUMBER)"\
		"\nGERBER_FILE:\r\t\t$(GERBER_FILE)"\
		"\nGERBER_ARCHIVE:\r\t\t$(GERBER_ARCHIVE)"\
	&& $(DONE);

#   Check design rules in schematics (and create *.drc file by the way)
$(CABLES_DRC) : $(GNETLIST_RULE) $(CABLES_SCH)
	@$(HEADLINE)\
	&& $(GNETLIST) $(GNETLIST_FLAGS)\
		-g drc2\
		-l $<\
		-o $@\
			$(CABLES_SCH)\
	&& $(DONE);

#   Check design rules in schematics (and create *.drc file by the way)
$(BOARD_DRC) : $(GNETLIST_RULE) $(BOARD_SCH)
	@$(HEADLINE)\
	&& $(GNETLIST) $(GNETLIST_FLAGS)\
		-g drc2\
		-l $<\
		-o $@\
			$(BOARD_SCH)\
	&& $(DONE);

#   Check design rules in schematics (and create *.drc file by the way)
$(TESTBOARD_DRC) : $(GNETLIST_RULE) $(TESTBOARD_SCH)
	@$(HEADLINE)\
	&& $(GNETLIST) $(GNETLIST_FLAGS)\
		-g drc2\
		-l $<\
		-o $@\
			$(TESTBOARD_SCH)\
	&& $(DONE);

#   Generate bill of material files from gschem schematics.
%.bom : %.sch $(GSCHEM_ATTRIBS)
	@$(HEADLINE)\
	&& $(GNETLIST) $(GNETLIST_FLAGS)\
		-g bom2\
		-Oattrib_file=$(GSCHEM_ATTRIBS)\
		-o $@\
			$<\
	&& $(DONE);

#   Create markdown file from bom file.
%.bom.md : %.bom
	@$(HEADLINE)\
	&& $(SED) $(SED_FLAGS)\
		--in-place\
		-e '{;:nline /.*:.*/!{;/^:/!N; s/\n/ /g; t nline};};'\
			$<\
	&& $(SED) $(SED_FLAGS)\
		--in-place\
		-e '/:$$/{;N; s/\n//g;};'\
			$<\
	&& $(SED) $(SED_FLAGS)\
		--in-place\
		-e 's/^(refdes|[A-Z].*)/\r\n\* \1/;'\
		-e 's/:/\r\n    - /g;'\
			$<\
	&& $(ECHO) $(ECHO_FLAGS)\
		"# Bill of Material ($(notdir $*).sch)"\
		"\n"\
		"\n"\
		"\nFootprints are named according to gEDA/gaf and PCB footprint naming convention."\
			> $@\
	&& $(ECHO) $(ECHO_FLAGS)\
		"\n"\
		"\n## Pattern per Record"\
		"\n"\
		"\n"\
			>> $@\
	&& $(SED) $(SED_FLAGS)\
		-e '2,8!d;'\
			$<\
				>> $@\
	&& $(ECHO) $(ECHO_FLAGS)\
		"\n"\
		"\n## Bill"\
		"\n"\
		"\n"\
			>> $@\
	&& $(SED) $(SED_FLAGS)\
		-e '1,9d;'\
			$<\
				>> $@\
	&& $(DONE);

#   Create bom html files
%.bom.html : %.bom.md
	@$(HEADLINE)\
	&& $(MARKDOWN) $(MARKDOWN_FLAGS)\
		$<\
			> $@\
	&& $(DONE);

#   Update schematic titleblock
%.titleblock.sch : %.sch
	@$(HEADLINE)\
	&& authors="$(strip\
		$(shell\
			$(GIT) log --format="%al, " --follow -- $<\
			| $(SORT) $(SORT_FLAGS)\
			| $(UNIQ) $(UNIQ_FLAGS);\
		)\
	)"\
	&& $(SED) $(SED_FLAGS)\
		-e 's#\$$TITLE#$(PROJECT_TITLE)#;'\
		-e 's#\$$SUBTITLE#$(PROJECT_BRIEF)#;'\
		-e 's,\$$GITREPO,$(PROJECT_REPO),;'\
		-e 's,\$$FILENAME,$(notdir $<),;'\
		-e 's/\$$PAGES//;'\
		-e 's/\$$PAGE//;'\
		-e 's/\$$GITREF/$(PROJECT_NUMBER) ($(PROJECT_BRANCH))/;'\
		-e 's/\$$AUTHORS/'"$${authors%\,*}"'/;'\
			$<\
				> $@\
	&& $(DONE);

#   Generate temporary gschem images, high resolution
#     This makes overbars look quite OK.
%.sch.hires.png : %.titleblock.sch
	@$(HEADLINE)\
	&& $(GAF) $(GAF_FLAGS)\
		export\
			--color\
			--scale=29pt\
			--output=$@\
					$<\
	&& $(DONE);

#   Generate PDFs from schematics.
%.sch.pdf : %.sch.png
	@$(HEADLINE)\
	&& $(CONVERT) $(CONVERT_FLAGS)\
		$<\
			$@\
	&& $(DONE);

#   Generate images from hires schematics.
%.sch.png : %.sch.hires.png
	@$(HEADLINE)\
	&& $(CONVERT) $(CONVERT_FLAGS)\
		$<\
			$@\
	&& $(DONE);

#   Stamp version string onto pcb.
%.pcb.version : %.pcb
	@$(HEADLINE)\
	&& $(SED) $(SED_FLAGS)\
		-e "s/(PCB\[\")(.*)($(TOKEN_BOARD_NUMBER))(\".*)/\1\2$(BOARD_NUMBER)\4/;"\
		-e "s/(Text\[.*\")(.*)($(TOKEN_BOARD_NUMBER))(\".*)/\1\2$(BOARD_NUMBER)\4/;"\
			$< > $@\
	&& $(DONE);

#   Create top view images from pcb files.
%.pcb.top.png : %.pcb.version
	@$(HEADLINE)\
	&& $(PCB) $(PCB_FLAGS)\
		-x png --dpi 300 --use-alpha --only-visible --photo-mode\
		--outfile $@\
			$<\
	&& $(DONE);

#   Create bottom view images from pcb files.
%.pcb.bottom.png : %.pcb.version
	@$(HEADLINE)\
	&& $(PCB) $(PCB_FLAGS)\
		-x png --dpi 300 --use-alpha --only-visible --photo-mode --photo-flip-x\
		--outfile $@\
			$<\
	&& $(DONE);

#   Export board label files, png and pdf.
board-label : $(BOARD_SVG)
	@$(HEADLINE)\
	&& tmpfile=$(shell $(MKTEMP) $(MKTEMP_FLAGS) --suffix=.svg;)\
	&& $(SED) $(SED_FLAGS)\
		-e 's/(>Version: )(\$$.*\$$)/\1'$(PROJECT_NUMBER)'/;'\
			$< > $$tmpfile\
	&& $(INKSCAPE) $(INKSCAPE_FLAGS)\
		--export-filename=$(addsuffix .png,$<)\
		--export-id="layer7"\
		--export-id-only\
		--export-dpi=300\
			$$tmpfile\
	&& $(INKSCAPE) $(INKSCAPE_FLAGS)\
		--export-filename=$(addsuffix .pdf,$<)\
		--export-area-page\
			$$tmpfile\
	&& $(RM) $(RM_FLAGS)\
		$$tmpfile\
	&& $(DONE);

#   Export testboard label files, png and pdf.
testboard-label : $(TESTBOARD_SVG)
	@$(HEADLINE)\
	&& tmpfile=$(shell $(MKTEMP) $(MKTEMP_FLAGS) --suffix=.svg;)\
	&& $(SED) $(SED_FLAGS)\
		-e 's/(>Version: )(\$$.*\$$)/\1'$(PROJECT_NUMBER)'/;'\
			$< > $$tmpfile\
	&& $(INKSCAPE) $(INKSCAPE_FLAGS)\
		--export-filename=$(addsuffix .png,$<)\
		--export-id="layer6"\
		--export-id-only\
		--export-dpi=300\
			$$tmpfile\
	&& $(INKSCAPE) $(INKSCAPE_FLAGS)\
		--export-filename=$(addsuffix .pdf,$<)\
		--export-area-page\
			$$tmpfile\
	&& $(RM) $(RM_FLAGS)\
		$$tmpfile\
	&& $(DONE);

#   Start $(GERBV) utility with all layers loaded.
gerbv : gerber
	@$(HEADLINE)\
	&& $(CD) $(CD_FLAGS)\
		$(ROOT_PCB)\
	&& $(GERBV) $(GERBV_FLAGS)\
		./*.cnc\
		./*.*.gbr\
	&& $(CD) $(CD_FLAGS)\
		-\
	&& $(DONE);

#   Export layers as gerber files.
gerber : $(addsuffix .version,$(BOARD_PCB))
	@$(HEADLINE)\
	&& $(CD) $(CD_FLAGS)\
		$(ROOT_PCB)\
	&& $(PCB) $(PCB_FLAGS)\
		-x gerber\
		--gerberfile $(GERBER_FILE)\
			$(notdir $<)\
	&& $(CD) $(CD_FLAGS)\
		-\
	&& $(DONE);

#   target for gerber archive
gerber-archive : $(addsuffix .zip,$(ROOT_PCB)$(GERBER_ARCHIVE))
	@$(HEADLINE)\
	&& $(DONE);

#   Rule for gerber archive
$(ROOT_PCB)$(GERBER_ARCHIVE).zip : gerber
	@$(HEADLINE)\
	&& $(CD) $(CD_FLAGS)\
		$(ROOT_PCB)\
	&& $(ZIP) $(ZIP_FLAGS)\
		$(notdir $@)\
		$(GERBER_FILE).*.{gbr,cnc}\
	&& $(CD) $(CD_FLAGS)\
		-\
	&& $(DONE);

#   Perform checks
check : $(CABLES_DRC) $(BOARD_DRC) $(TESTBOARD_DRC)
	@$(HEADLINE)\
	&& $(DONE);

#   Synchronize board pcb file with board schematic
synchronize : $(BOARD_SCH) $(wildcard $(ROOT_FOOTPRINTS)*)
	@$(HEADLINE)\
	&& $(GSCH2PCB) $(GSCH2PCB_FLAGS)\
		-o $(ROOT_PCB)board\
		-d $(ROOT_FOOTPRINTS)\
			$(BOARD_SCH)\
	&& $(ECHO) $(ECHO_FLAGS)\
		"TODO:"\
		"\n* Start PCB Editor and load PCB file."\
	&& if [ -f "$(ROOT_PCB)board.new.pcb" ];\
		then\
			$(ECHO) $(ECHO_FLAGS)\
				"* Within PCB Editor, load new layout file into buffer.";\
		fi\
	&& if [ -f "$(ROOT_PCB)board.net" ];\
		then\
			$(ECHO) $(ECHO_FLAGS)\
				"* Within PCB Editor, load netlist file.";\
		fi\
	&& if [ -f "$(ROOT_PCB)board.cmd" ];\
		then\
			$(ECHO) $(ECHO_FLAGS)\
				"* Within PCB Editor, execute command file.";\
		fi\
	&& $(ECHO) $(ECHO_FLAGS)\
		"* Within PCB Editor, finalize the layout manually."\
	&& $(DONE);

#   Clean files generated by gsch2pcb.
clean-synchronize :
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS) -f\
		$(ROOT_PCB)board.{cmd,net,new.pcb,pcb.bak}\
	&& $(DONE);

#   Clean backup files, generated by PCB- and schematic editors.
clean-backups :
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS) -f\
		$(TARGETS_GSCHEM_AUTO1)\
		$(TARGETS_GSCHEM_AUTO2)\
		$(TARGETS_GSCHEM_AUTO3)\
	&& $(RM) $(RM_FLAGS) -f\
		$(wildcard $(ROOT_PCB)PCB.*.backup)\
		$(ROOT_PCB)board.pcb~\
		$(wildcard $(ROOT_FOOTPRINTS)*.fp~)\
	&& $(DONE);

#   Clean gerber files
clean-gerber :
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS) -f\
		$(wildcard $(ROOT_PCB)*.gbr)\
		$(wildcard $(ROOT_PCB)*.cnc)\
		$(addsuffix .version,$(BOARD_PCB))\
	&& $(DONE);

#   Clean gerber archive
clean-archive :
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS) -f\
		$(wildcard $(ROOT_PCB)*.zip)\
	&& $(DONE);

#   Clean cable files
clean-cables :
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS) -f\
		$(CABLES_DRC)\
		$(CABLES_PDF)\
		$(CABLES_PNG)\
		$(CABLES_BOM)\
		$(CABLES_BOM_MD)\
		$(CABLES_BOM_HTML)\
		$(addsuffix .png,$(CABLES_SVG))\
		$(addsuffix .pdf,$(CABLES_SVG))\
	&& $(DONE);

#   Clean board files
clean-board : clean-gerber clean-archive
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS) -f\
		$(BOARD_DRC)\
		$(BOARD_PDF)\
		$(BOARD_PNG)\
		$(BOARD_BOM)\
		$(BOARD_BOM_MD)\
		$(BOARD_BOM_HTML)\
		$(addsuffix .png,$(BOARD_SVG))\
		$(addsuffix .pdf,$(BOARD_SVG))\
	&& $(DONE);

#   Clean testboard files
clean-testboard :
	@$(HEADLINE)\
	&& $(RM) $(RM_FLAGS) -f\
		$(TESTBOARD_DRC)\
		$(TESTBOARD_PDF)\
		$(TESTBOARD_PNG)\
		$(TESTBOARD_BOM)\
		$(TESTBOARD_BOM_MD)\
		$(TESTBOARD_BOM_HTML)\
		$(addsuffix .png,$(TESTBOARD_SVG))\
		$(addsuffix .pdf,$(TESTBOARD_SVG))\
	&& $(DONE);

#   Clean all
clean : hello\
	clean-synchronize\
		clean-backups\
			clean-cables\
				clean-board\
					clean-testboard
	@$(HEADLINE)\
	&& $(DONE);
