Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
MK(1)			    General Commands Manual			 MK(1)

NAME
       mk -- build stuff

SYNOPSIS
       mk [-hkpsSv] [-C	dir] [-f makefile] [-o objdir] [-V var]	[target	...]

DESCRIPTION
       mk  is  designed	 to help you build stuff.  It is specifically designed
       for larger projects, for	which make(1) is not suitable enough.

       The following options are available:

       -h      Print a help page for the current directory.

       -hv     Similar to -h, but do so	recursively for	all subdirectories.

       -p      Dump the	current	directory's makefile.

       -pv     Same as -p, but do so recursively for all subdirectories.

       -s      Do not echo commands, as	 they  are  executed.	Equivalent  to
	       specifying '@' before each command in the makefile.

       -S      stop  processing	when an	erorr is encountered.  This is the de-
	       fault behavior and is the opposite of -k.

       -k      Continue	processing after errors	are encountered, but  only  on
	       those  targets  that do not depend on the target	whose creating
	       caused the error.  This options is the opposite of the  -S  op-
	       tion.

       -v      Cause  mk  to  print  more  verbose output.  This option	can be
	       specified multiple times, to increase the verbosity.  This  op-
	       tion is negated by the -s option.

       -C dir  Change the current working directory to dir.

       -f mk   Read  file  mk  instead	of  the	default	makefile.  Contrary to
	       other implementations, only the last occurence of  this	option
	       is honored.

       -o obj  Put  generated  artifacts into the obj directory.  mk will also
	       search for artifacts in this directory.	This  is  very	useful
	       for out-of-tree builds.

       -V var  Print  the  expanded  value  of	var to the standard output and
	       exit.

DEPENDENCY LINES
       Dependency lines	consist	of one or more targets,	and zero or more  pre-
       requisites:

	    target ...:[prerequisite ...]

       This  creates a relationship, where the targets "depend"	on the prereq-
       uisites,	and are	built from them.

       Targets must consist of only characters in "[a-zA-Z._-]".  Dependencies
       can additionally	contain	"/" characters,	but the	resulting  paths  must
       be relative, and	cannot cross directories, that are outside the build.

SHELL COMMANDS
       Each  target  may  have	associated with	it a series of shell commands,
       normally	used to	build the target.  While several dependency lines  may
       name  the  same	target,	only one of these dependency lines may be fol-
       lowed by	shell commands,	and thus define	a complete target rule.

       If a command line begins	with one of the	characters, `@'	 or  `-',  the
       command is treated specially:

       `@'  causes the command not to be echoed	before it is executed.

       `-'  causes any non-zero	exit status of the command line	to be ignored.

       Commands	 are  executed	using  /bin/sh in "set -e" mode, unless	`-' is
       specified, or the shell is broken (in case of Minix-vmd).

INFERENCE RULES
       TODO

VARIABLE ASSIGNMENTS
       Variables in mk are much	like variables in the shell:

	    name = value

       They are	also sometimes refered to as  `macros'.	  Variable  names  can
       only  consist of	"[a-zA-Z0-9._-]" and may not start with	a digit	or hy-
       phen.  By tradition names consist of all	upper-case letters.

       The following operators can be used to define variables:

       =       Assign the value	to the variable.  Any previous value is	 over-
	       riden.

       :=      Like "=", but expand the	value, before assigning	it.

       ::=     Currently equivalent to ":=".

       +=      Append the value	to the current value of	the variable.

       ?=      Assign the value, if it is not already defined.

       ??=     Similar to "?=",	but take environment variables into account.

       !=      Perform variable	expansion and pass the result to the shell for
	       execution.  The output of the shell command will	be assigned to
	       the variable.

       Any  whitespace	before or after	the assigned value will	be removed; if
       the value is being appended, a single space  is	inserted  between  the
       previous	contents of the	variable and the appended value.

       Variables  are  expanded	 by  surrounding  the variable name with curly
       braces (`{}') and preceding it with a doller sign (`$').	 If the	 vari-
       able  name consists of only a single letter, the	surrounding braces can
       be omitted.

       Variables can be	made visible into subdirectories using the  ".EXPORT:"
       directive.

   SPECIAL VARIABLES
       The following special variables can be used:

       $$      The literal $ character.

       $.      Relative	 path  to the top-level	directory.  This is the	short-
	       form of ${.TOPDIR}.

       $@      The name	of the target currently	 being	built.	 This  is  the
	       shortform of ${.TARGET}.

       $<      The  name  of  the prerequisite from which this target is to be
	       built, if a valid inference rule	(suffix	 rule)	is  in	scope.
	       This is the shortform of	${.IMPSRC}.

       $^      All source dependencies.	 This is the shortform of ${.ALLSRC}.

       $*      This is the shortform of	${.IMPSRC:T}.

       ${.SUBDIRS}
	       A list of subdirectories	specified by the .SUBDIRS: directive.

       ${.EXPORTS}
	       A list of variables specified by	the .EXPORTS: directive.  This
	       is useful for invoking other build systems in foreign subdirec-
	       tories.

       ${.OBJDIR}
	       The  object directory specified by the -o objdir	option,	or the
	       current directory.

       ${.MAKEFILES}
	       A list of Mkfiles from this directory upwards.

       ${SHELL}
	       The shell used to interpret the command lines.

       ${MAKE}
	       The name	of the mk command.  Alias for ${.MAKE}.

       ${MAKEFLAGS}
	       A list of options given to mk.  Alias for ${.MAKEFLAGS}.

   MODIFIERS
       Modifiers can be	applied	to a macro expansion using the following  syn-
       tax:

	    ${NAME:modfiers...}

       The following modifiers can be applied to variable expansions:

       :U      Make all	characters in string uppercase.

       :L      Make all	characters in string lowercase.

       :F      Search  for  files  in  either  the  source  directory,	or  in
	       ${.OBJDIR}.

       :E      Replace each word by it's suffix.  "suffix" refers to the  file
	       extension.

       :R      Replace each word by everything but it's	suffix.

       :H      Replace each word by it's dirname(1) equivalent.

       :T      Replace each word by it's basename(1) equivalent.

       :Mpattern
	       Only retain words that match pattern.

       :Npattern
	       The opposite of the :M modifier.

       :Jseparator
	       Concatenate  each  word	and  separate  the resulting string by
	       separator.

       :name=value
	       Replace every occurence of name with value.  This has to	be the
	       last modifier.

       These are a few examples	for using macro	modifiers:

	     SOURCE = main.c lex.l parse.y gen.S

	     # Only retain words that match the	glob *.c
	     CFILES = ${SOURCE:M*.c}

	     # Replace all the file extension .c with .o
	     COBJS = ${CFILES:.c=.o}

	     clean:
		     # Use :F to search	for the	object files in	${.OBJDIR}
		     rm	-f ${COBJS:F}

	     print:
		     # Multiple	modifiers can be specified:
		     @echo ${SOURCE:T:U}

INCLUDE	STATEMENTS
       Using the include statement it is possible to instruct mk to  read  an-
       other file.

       Examples:

	     # Include a file called "templates.mk"
	     include templates.mk

	     # Try including a file called "config.mk",	if it exists
	     -include config.mk

SUBDIRECTORIES
       Subdirectories can be declared using the	.SUFFIXES: directive.

       The  handling of	subdirectories is done lazily, such that the Mkfile of
       the subdirectory	is only	parsed,	once a	target	in  that  subdirectory
       tree is needed.

       Examples:

	     # Declare subdirectories foo and bar
	     .SUBDIRS: foo bar

	     # Depend on targets from other directories
	     foobar: foo/libfoo.a bar/libbar.so	../config.h
		     # $^ refers to the	list of	prerequisites
		     build -o foobar $^

	     # Print a ", " separated list of subdirectories
	     list:
		     @echo "${.SUBDIRS:J, }"

	     # Depend on the clean target of every subdirectories:
	     clean: ${.SUBDIRS:=/clean}
		     # Prefix with ${.OBJDIR}/ for compatibility with the -o option.
		     rm	-f ${.OBJDIR}/foobar

   FOREIGN SUBDIRECTORIES
       TODO

       Foreign subdirectories allow integration	with other build systems.

       This is an example of integrating an example Autotools dependency:

	     # Declare hello as	a "foreign directory"
	     .FOREIGN: hello

	     HELLODIR =	hello

	     ##	External make used for building	libhello
	     EMAKE ?= make

	     ##	C Compiler
	     CC	?= cc

	     ##	C Compiler Flags
	     CFLAGS ?=

	     ##	Installation Prefix
	     PREFIX ?= /usr/local

	     ##	Installation destination directory
	     DESTDIR ?=

	     .EXPORTS: CC CFLAGS DESTDIR

	     ##	Build hello/hello and xhello
	     all: hello/hello xhello

	     ##	Delete build artifacts
	     clean: hello/clean
		     rm	-f xhello

	     ##	Delete all non-source files
	     distclean:	clean
		     rm	-rf ${HELLODIR:F}
		     rm	-f ${.OBJDIR}/{hello.tgz,.hello-configure,.hello-extract}

	     ##	Install	hello and xhello into ${DESTDIR}${PREFIX}
	     install: hello/install xhello
		     mkdir -p ${DESTDIR}${PREFIX}/bin
		     cp	-f ${.OBJDIR}/xhello ${DESTDIR}${PREFIX}/bin/

	     ##	Download hello source
	     hello.tgz:
		     ftp -o $@ https://got.stuerz.xyz/download/hello-2.0.tgz

	     .hello-extract: hello.tgz
		     tar -xzf $< -C ${.OBJDIR}
		     touch $@

	     .hello-configure: .hello-extract
		     (cd ${HELLODIR:F} && ./configure --prefix=${PREFIX})
		     touch $@

	     # Check if	$< is fresh in hello
	     hello?:
		     test -e ${HELLODIR:F}/Makefile
		     ${EMAKE} -q -C ${HELLODIR:F} ${.EXPORTS} "$$(echo "$<" | sed 's#./##')"

	     # Build $<	in hello
	     hello!: .hello-configure
		     ${EMAKE} -C ${HELLODIR:F} ${.EXPORTS} "$$(echo "$<" | sed 's#./##')"

	     ##	Build the xhello binary
	     xhello: xhello.c hello/libhello.a
		     ${CC} -o $@ xhello.c -I${HELLODIR:F} -L${HELLODIR:F} -lhello ${CFLAGS}

CONDITIONALS
       TODO

OTHER DIRECTIVES
       TODO

COMMENTS
       Comments	 begin	with  a	single hash (`#') character, anywhere but in a
       shell command line, and continue	to the end of the line.	 A (#) charac-
       ter within a shell command line will be interpreted as a	comment	by the
       shell.

   DOCUMENTATION COMMENTS
       Documentation comments are a special variant  of	 comments,  which  can
       only  appear  before  rule and macro definitions.  To define a doc-com-
       ment, two hash (`#') characters must be used.

       Example:

	     # This is a doc-comment for macro NAME
	     ##	Define the name	of the project
	     NAME = hello

	     # Macros in doc-comments will be expanded:
	     ##	Build ${NAME}
	     ${NAME}: ${NAME}.c
		     ${CC} -o $@ $<

SPECIAL	TARGETS
       TODO

ENVIRONMENT
       TODO

FILES
       Mkfile  default makefile

EXAMPLES
       The following is	a list of real-world projects built with mk:
          desktop: https://got.stuerz.xyz/?action=summary&path=desktop.git
          286bsd: https://got.stuerz.xyz/?action=summary&path=286bsd.git

EXIT STATUS
       The mk utility exits 0 on success, and >0 if an error occurs.

SEE ALSO
       make(1),	sh(1)

STANDARDS
       This implementation of make(1) does not strictly	follow any POSIX stan-
       dard, but still most simple Makefiles will work fine.

HISTORY
       Over the	the long history of make, there	have been many (competing) im-
       plementations of	make(1):
          Original make from PWB/UNIX 1.0
          GNU Make
          Various versions of BSD Make
          Plan	9's mk(1)

AUTHORS
       Benjamin	Strz <benni@stuerz.xyz>

CAVEATS
          All paths used as targets/dependencies must be relative.
          The handling	of the `?=` and	`??=` is different from	POSIX.
          The way environment and commandline variables are treated  is  dif-
	   ferent from POSIX.

BUGS
          There exists	another	project	called mk(1).
          Defining recursive dependencies can lead to mk crashing.
          Specifying multiple targets at once is broken.
          This	manual is unfinished.

TODO
          Run	commands of the	same rule in the same shell, instead of	creat-
	   ing a new shell for every command line.
          Create a detailed list of all features.
          Create a second implementation in Rust, which will support parallel
	   execution of	targets.
          Create a comparison to other	makes.
          See TODO.md file.
          Optional prerequisites (continue even if the	prerequisite failed).
          Numbered prerequisite macros.
          Strip "./" prefix for $< and	other variables.

FreeBSD	ports 15.0		January	4, 2025				 MK(1)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=mk&sektion=1&manpath=FreeBSD+Ports+15.0>

home | help