Commit d7016f14 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

build: nmk -- Initial import

This is initial import of NMK engine which we gonna use for
CRIU and related tools building.

It's very tiny and while here we merge it as is in future
it gonna be rather a submodule from

	https://github.com/cyrillos/nmk

An idea is to have unified build engine for most tools
we're gonna use.
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent 9445c316
*.swp
*.swo
.git-ignore
ASCIIDOC := asciidoc
A2X := a2x
XMLTO := xmlto
PS2PDF := ps2pdf
SRC += nmk.txt
XMLS := $(patsubst %.txt,%.xml,$(SRC))
MANS := $(patsubst %.txt,%.8,$(SRC))
GROFF := groff
PAPER := $(shell paperconf 2>/dev/null || echo letter)
GROFF_OPTS := -Tps -t -dpaper=$(PAPER) -P-p$(PAPER) -man -msafer -rC1 -rD1 -rS11
PSS := $(MANS:%.8=%.ps)
PDFS := $(MANS:%.8=%.pdf)
ps: $(PSS)
pdf: $(PDFS)
all: check $(MANS)
.PHONY: all ps pdf check clean
check:
$(Q) for B in $(ASCIIDOC) $(A2X) $(XMLTO); do \
$$B --version > /dev/null || exit 1; \
done
%.8: %.txt
$(call msg-gen, $@)
$(Q) $(ASCIIDOC) -b docbook -d manpage -o $(patsubst %.8,%.xml,$@) $<
$(Q) $(XMLTO) man --skip-validation $(patsubst %.8,%.xml,$@) 2>/dev/null
%.ps: %.8
$(call msg-gen, $@)
$(Q) $(GROFF) $(GROFF_OPTS) $^ > $@
%.pdf: %.ps
$(call msg-gen, $@)
$(Q) $(PS2PDF) $< $@
clean:
$(call msg-clean, "docs")
$(Q) $(RM) $(XMLS) $(MANS) $(PSS) $(PDFS)
nmk(8)
======
NAME
----
nmk - a framework to minimize Makefile code needed for simple projects
SYNOPSIS
--------
*make* -f main.mk makefile=Makefile obj=<dir>
OVERVIEW
--------
Most of projects have similar source code structure:
* Toplevel 'Makefile'
* Source code itself in directory '<src>'
* Headers are gathered into directory '<include>'
so that building procedure is invoking *make* to read toplevel 'Makefile',
compile sources and link a final executable program. Taking this into account
*nmk* is trying to minimize efforts needed to write 'Makefile'.
USAGE
-----
First of all the *nmk* scripts are to be placed into some known place so the
*make* would be able to read them from a command line. Internally *nmk* uses
*__nmk_dir* variable to find own sources. Thus one can export
----------
export __nmk_dir=<directory>/
----------
in a makefile or do it via environment variables. Note the ending slash is mandatory.
As been mentioned earlier source code tree should include toplevel 'Makefile'
and source code in '<src>' directory. Source code '<src>' should provide own
'Makefile' (secondlevel) where files to be compiled are enumerated.
A typical source code tree will look like
----------
Makefile # toplevel Makefile
<scripts> # directory with nmk scripts
<src> # source code directory
Makefile # secondlevel Makefile
src1.c # source code
src2.c
...
----------
In toplevel 'Makefile' we should plug in *nmk* itself
----------
export __nmk_dir=scripts/
include $(__nmk_dir)include.mk
----------
In secondlevel 'Makefile' we should enumerate files to be compiled.
----------
obj-y += src1.o
obj-y += src2.o
...
----------
That is basically all one need to build a program.
__nmk_dir=scripts/
export __nmk_dir
include $(__nmk_dir)include.mk
MAKEFLAGS := -r -R --no-print-directory
.PHONY: all help test docs clean install
help:
@echo ' Targets:'
@echo ' install dir=<dir> - Install scripts into directory <dir>'
@echo ' docs - Build documentation'
@echo ' clean - Clean everything'
test:
$(Q) $(MAKE) -C tests all
docs:
$(Q) $(MAKE) -C Documentation all
install:
@echo 'Copying scripts into $(dir)'
@cp scripts/build.mk $(dir)
@cp scripts/include.mk $(dir)
@cp scripts/macro.mk $(dir)
@cp scripts/main.mk $(dir)
@cp scripts/rules.mk $(dir)
@cp scripts/tools.mk $(dir)
@cp scripts/utils.mk $(dir)
all:
@true
clean:
$(call msg-clean, "nmk")
$(Q) $(MAKE) -C Documentation clean
$(Q) $(MAKE) -C tests clean
.DEFAULT_GOAL ?= all
NMK
===
NMK stands for NetMaKe -- is a very simple framework for make build system.
Most ideas are taken from the Linux kernel kbuild system.
ifndef ____nmk_defined__build
#
# General helpers for simplified Makefiles.
#
src := $(obj)
obj-y :=
lib-y :=
target :=
deps-y :=
all-y :=
builtin-name :=
lib-name :=
ld_flags :=
cleanup-y :=
MAKECMDGOALS := $(call uniq,$(MAKECMDGOALS))
ifndef obj
$(error obj is undefined)
endif
include $(call objectify,$(makefile))
ifneq ($(strip $(target)),)
target := $(sort $(call uniq,$(target)))
endif
#
# Prepare the unique entries.
obj-y := $(sort $(call uniq,$(obj-y)))
lib-y := $(filter-out $(obj-y),$(sort $(call uniq,$(lib-y))))
#
# Add subdir path
obj-y := $(call objectify,$(obj-y))
lib-y := $(call objectify,$(lib-y))
#
# Strip custom names.
lib-name := $(strip $(lib-name))
builtin-name := $(strip $(builtin-name))
#
# Link flags.
ld_flags := $(strip $(LDFLAGS) $(ldflags-y))
#
# Prepare targets.
ifneq ($(lib-y),)
lib-target :=
ifneq ($(lib-name),)
lib-target := $(obj)/$(lib-name)
else
lib-target := $(obj)/lib.a
endif
cleanup-y += $(lib-target)
all-y += $(lib-target)
endif
ifneq ($(obj-y),)
builtin-target :=
ifneq ($(builtin-name),)
builtin-target := $(obj)/$(builtin-name)
else
builtin-target := $(obj)/built-in.o
endif
cleanup-y += $(builtin-target)
all-y += $(builtin-target)
endif
#
# Helpers for targets.
define gen-ld-target-rule
$(1): $(3)
$$(call msg-link, $$@)
$$(Q) $$(LD) $(2) -r -o $$@ $(4)
endef
define gen-ar-target-rule
$(1): $(3)
$$(call msg-link, $$@)
$$(Q) $$(AR) -rcs$(2) $$@ $(4)
endef
#
# Predefined (builtins) targets rules.
ifdef builtin-target
$(eval $(call gen-ld-target-rule, \
$(builtin-target), \
$(ld_flags), \
$(obj-y),$(obj-y) $(call objectify,$(obj-e))))
endif
ifdef lib-target
$(eval $(call gen-ar-target-rule, \
$(lib-target), \
$(ARFLAGS) $(arflags-y), \
$(lib-y),$(lib-y) $(call objectify,$(lib-e))))
endif
#
# Custom targets rules.
define gen-custom-target-rule
ifneq ($($(1)-obj-y),)
$(eval $(call gen-ld-target-rule, \
$(obj)/$(1).built-in.o, \
$(ld_flags) $($(1)-ldflags-y), \
$(call objectify,$($(1)-obj-y)), \
$(call objectify,$($(1)-obj-y)) \
$(call objectify,$($(1)-obj-e))))
all-y += $(obj)/$(1).built-in.o
cleanup-y += $(obj)/$(1).built-in.o
endif
ifneq ($($(1)-lib-y),)
$(eval $(call gen-ar-target-rule, \
$(obj)/$(1).lib.a, \
$(ARFLAGS) $($(1)-arflags-y), \
$(call objectify,$($(1)-lib-y)) \
$(call objectify,$($(1)-lib-e)), \
$(call objectify,$($(1)-lib-y))))
all-y += $(obj)/$(1).lib.a
cleanup-y += $(obj)/$(1).lib.a
endif
endef
$(foreach t,$(target),$(eval $(call gen-custom-target-rule,$(t))))
#
# Figure out if the target we're building needs deps to include.
define collect-deps
ifneq ($(filter-out %.d,$(1)),)
ifneq ($(filter %.o %.i %.s,$(1)),)
deps-y += $(addsuffix .d,$(basename $(1)))
endif
endif
ifeq ($(builtin-target),$(1))
deps-y += $(obj-y:.o=.d)
endif
ifeq ($(lib-target),$(1))
deps-y += $(lib-y:.o=.d)
endif
ifneq ($(filter all $(all-y) $(target),$(1)),)
deps-y += $(obj-y:.o=.d)
deps-y += $(lib-y:.o=.d)
deps-y += $(foreach t,$(target),$($(t)-lib-y:.o=.d) $($(t)-obj-y:.o=.d))
endif
endef
ifneq ($(MAKECMDGOALS),)
ifneq ($(MAKECMDGOALS),clean)
$(foreach goal,$(MAKECMDGOALS),$(eval $(call collect-deps,$(goal))))
deps-y := $(call uniq,$(deps-y))
ifneq ($(deps-y),)
$(eval -include $(deps-y))
endif
endif
endif
#
# Main phony rule.
all: $(all-y)
@true
.PHONY: all
#
# List of object files.
objlist:
$(E) $(obj-y) $(lib-y)
.PHONY: objlist
#
# Clean everything up.
clean:
$(call msg-clean, $(obj))
$(Q) $(RM) $(obj)/*.o $(obj)/*.d $(obj)/*.i $(obj)/*.s $(cleanup-y)
.PHONY: clean
#
# Footer.
$(__nmk_dir)scripts/build.mk:
@true
____nmk_defined__build = y
endif
ifndef ____nmk_defined__include
#
# Silent make rules.
ifeq ($(strip $(V)),)
E := @echo
Q := @
else
E := @\#
Q :=
endif
export E Q
#
# Message helpers.
define msg-gen
$(E) " GEN " $(1)
endef
define msg-clean
$(E) " CLEAN " $(1)
endef
define msg-cc
$(E) " CC " $(1)
endef
define msg-dep
$(E) " DEP " $(1)
endef
define msg-link
$(E) " LINK " $(1)
endef
define msg-ar
$(E) " AR " $(1)
endef
define msg-build
$(E) " BUILD " $(1)
endef
#
# Common vars.
SUBARCH := $(shell uname -m | sed \
-e s/i.86/x86/ \
-e s/x86_64/x86/ \
-e s/sun4u/sparc64/ \
-e s/arm.*/arm/ \
-e s/sa110/arm/ \
-e s/s390x/s390/ \
-e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ \
-e s/mips.*/mips/ \
-e s/sh[234].*/sh/ \
-e s/aarch64.*/arm64/)
ARCH ?= $(SUBARCH)
SRCARCH := $(ARCH)
export SUBARCH ARCH SRCARCH
ifndef ____nmk_defined__tools
include $(__nmk_dir)tools.mk
endif
# Do not use make's built-in rules and variables
# (this increases performance and avoids hard-to-debug behaviour).
MAKEFLAGS += -rR --no-print-directory
export MAKEFLAGS
# Avoid funny character set dependencies.
unexport LC_ALL
LC_COLLATE=C
LC_NUMERIC=C
export LC_COLLATE LC_NUMERIC
# Avoid interference with shell env settings.
unexport GREP_OPTIONS
# Shorthand for build.
build := -r -R -f $(__nmk_dir)main.mk makefile=Makefile obj
export build
# With specified Makefile
build-as := -r -R -f $(__nmk_dir)main.mk makefile=$$(1) obj=$$(2)
export build-as
#
# Dummy target for force building.
FORCE: ;
#
# Footer.
$(__nmk_dir)scripts/include.mk:
@true
____nmk_defined__include = y
endif
ifndef ____nmk_defined__macro
#
# Helper to include makefile only once.
#
define include-once
ifndef $(join ____nmk_defined__,$(1:.mk=))
include $(__nmk_dir)$(1)
endif
endef
# Helper to build built-in target in directory.
# $(eval $(call gen-built-in,<dir>))
define gen-built-in
$(1)/%:
$$(Q) $$(MAKE) $$(build)=$(1) $$@
$(1):
$$(Q) $$(MAKE) $$(build)=$(1) all
$(1)/built-in.o: $(1)
endef
#
# Footer.
$(__nmk_dir)scripts/macro.mk:
@true
____nmk_defined__macro = y
endif
ifndef ____nmk_defined__main
#
# Genaral inclusion statement
ifndef ____nmk_defined__include
include $(__nmk_dir)include.mk
endif
ifndef ____nmk_defined__macro
include $(__nmk_dir)macro.mk
endif
#
# Anything else might be included with
#
# $(eval $(call include-once,<name.mk>))
#
# Note the order does matter!
$(eval $(call include-once,tools.mk))
$(eval $(call include-once,utils.mk))
$(eval $(call include-once,rules.mk))
$(eval $(call include-once,build.mk))
#
# Footer
$(__nmk_dir)scripts/main.mk:
@true
____nmk_defined__main = y
endif
ifndef ____nmk_defined__rules
#
# Accumulate common flags.
define nmk-ccflags
$(CFLAGS) $(ccflags-y) $(CFLAGS_$@)
endef
define nmk-asflags
$(CFLAGS) $(ASFLAGS) $(asflags-y) $(ASFLAGS_$@)
endef
#
# General rules.
define gen-rule-o-from-c-by-name
$(1).o: $(2).c
$$(call msg-cc, $$@)
$$(Q) $$(CC) -c $$(strip $$(nmk-ccflags)) $$< -o $$@
endef
define gen-rule-i-from-c-by-name
$(1).i: $(2).c
$$(call msg-cc, $$@)
$$(Q) $$(CC) -E $$(strip $$(nmk-ccflags)) $$< -o $$@
endef
define gen-rule-s-from-c-by-name
$(1).s: $(2).c
$$(call msg-cc, $$@)
$$(Q) $$(CC) -S -fverbose-asm $$(strip $$(nmk-ccflags)) $$< -o $$@
endef
define gen-rule-o-from-S-by-name
$(1).o: $(2).S
$$(call msg-cc, $$@)
$$(Q) $$(CC) -c $$(strip $$(nmk-asflags)) $$< -o $$@
endef
define gen-rule-d-from-c-by-name
$(1).d: $(2).c
$$(call msg-dep, $$@)
$$(Q) $$(CC) -M -MT $$@ -MT $$(patsubst %.d,%.o,$$@) $$(strip $$(nmk-ccflags)) $$< -o $$@
endef
define gen-rule-d-from-S-by-name
$(1).d: $(2).S
$$(call msg-dep, $$@)
$$(Q) $$(CC) -M -MT $$@ -MT $$(patsubst %.d,%.o,$$@) $$(strip $$(nmk-asflags)) $$< -o $$@
endef
define gen-rule-i-from-S-by-name
$(1).i: $(2).S
$$(call msg-cc, $$@)
$$(Q) $$(CC) -E $$(strip $$(nmk-asflags)) $$< -o $$@
endef
#
# Expand early which matched all implicits.
$(eval $(call gen-rule-o-from-c-by-name,%,%))
$(eval $(call gen-rule-i-from-c-by-name,%,%))
$(eval $(call gen-rule-s-from-c-by-name,%,%))
$(eval $(call gen-rule-o-from-S-by-name,%,%))
$(eval $(call gen-rule-d-from-c-by-name,%,%))
$(eval $(call gen-rule-d-from-S-by-name,%,%))
$(eval $(call gen-rule-i-from-S-by-name,%,%))
#
# Footer.
$(__nmk_dir)scripts/rules.mk:
@true
____nmk_defined__rules = y
endif
ifndef ____nmk_defined__tools
#
# System tools shorthands
RM := rm -f
LD := $(CROSS_COMPILE)ld
CC := $(CROSS_COMPILE)gcc
CPP := $(CC) -E
AS := $(CROSS_COMPILE)as
AR := $(CROSS_COMPILE)ar
STRIP := $(CROSS_COMPILE)strip
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
NM := $(CROSS_COMPILE)nm
MAKE := make
MKDIR := mkdir -p
AWK := awk
PERL := perl
PYTHON := python
SH := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
export RM LD CC CPP AS AR STRIP OBJCOPY OBJDUMP
export NM SH MAKE MKDIR AWK PERL PYTHON SH
#
# Footer.
$(__nmk_dir)scripts/tools.mk:
@true
____nmk_defined__tools = y
endif
ifndef ____nmk_defined__utils
#
# Usage: option = $(call try-cc,source-to-build,cc-options,cc-defines)
try-cc = $(shell sh -c \
'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
echo "$(1)" | \
$(CC) $(3) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
rm -f "$$TMP"')
# pkg-config-check
# Usage: ifeq ($(call pkg-config-check, library),y)
pkg-config-check = $(shell sh -c 'pkg-config $(1) && echo y')
#
# Remove duplicates.
uniq = $(strip $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))))
#
# Add $(obj)/ for paths that are not relative
objectify = $(foreach o,$(sort $(call uniq,$(1))),$(if $(filter /% ./% ../%,$(o)),$(o),$(obj)/$(o)))
#
# Footer.
$(__nmk_dir)scripts/utils.mk:
@true
____nmk_defined__utils = y
endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment