summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-04-16 13:49:16 +0300
committerTimo Teras <timo.teras@iki.fi>2009-04-16 13:49:16 +0300
commitaf1b460033d874f1b1fd5ac248d49b0a6bb7363a (patch)
tree08cd843c3f9b035ca38190f8bd4829a095da40f8
parent9c5200f0e19496e9f0e5248038222077c0763262 (diff)
downloadapk-tools-af1b460033d874f1b1fd5ac248d49b0a6bb7363a.tar.gz
apk-tools-af1b460033d874f1b1fd5ac248d49b0a6bb7363a.tar.bz2
apk-tools-af1b460033d874f1b1fd5ac248d49b0a6bb7363a.tar.xz
apk-tools-af1b460033d874f1b1fd5ac248d49b0a6bb7363a.zip
build: rewrite make system to something slightly similar to kbuild
Tracks now probler header file dependencies and command line parameters used to build files. E.g. changing CFLAGS rebuild all C-files. And changing version rebuild now the files where it's used.
-rw-r--r--.gitignore2
-rw-r--r--Make.rules269
-rw-r--r--Makefile78
-rw-r--r--src/Makefile57
4 files changed, 303 insertions, 103 deletions
diff --git a/.gitignore b/.gitignore
index 4770815..c49a2cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
apk
*.o
+*.d
+*.cmd
diff --git a/Make.rules b/Make.rules
new file mode 100644
index 0000000..e633659
--- /dev/null
+++ b/Make.rules
@@ -0,0 +1,269 @@
+##
+# A set of makefile rules loosely based on kbuild.
+
+all: compile
+
+ifndef build
+
+toplevelrun:=yes
+
+##
+# Disable default rules and make output pretty.
+
+MAKEFLAGS += -rR --no-print-directory
+
+Makefile: ;
+
+ifdef V
+ ifeq ("$(origin V)", "command line")
+ VERBOSE = $(V)
+ endif
+endif
+ifndef VERBOSE
+ VERBOSE = 0
+endif
+
+ifeq ($(VERBOSE),1)
+ quiet =
+ Q =
+else
+ quiet=quiet_
+ Q = @
+endif
+
+ifneq ($(findstring s,$(MAKEFLAGS)),)
+ quiet=silent_
+endif
+
+export quiet Q VERBOSE
+
+##
+# Recursion helpers.
+srctree := $(CURDIR)
+objtree := $(CURDIR)
+
+export srctree objtree
+
+##
+# Consult SCM for better version string.
+
+GIT_REV := $(shell git describe || echo exported)
+ifneq ($(GIT_REV), exported)
+FULL_VERSION := $(patsubst $(PACKAGE)-%,%,$(GIT_REV))
+FULL_VERSION := $(patsubst v%,%,$(FULL_VERSION))
+else
+FULL_VERSION := $(VERSION)
+endif
+
+RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o
+
+export FULL_VERSION RCS_FIND_IGNORE
+
+##
+# Utilities and default flags for them.
+
+CROSS_COMPILE ?=
+CC := $(CROSS_COMPILE)gcc
+LD := $(CROSS_COMPILE)ld
+INSTALL := install
+INSTALLDIR := $(INSTALL) -d
+
+CFLAGS ?= -g
+CFLAGS_ALL := -Werror -Wall -Wstrict-prototypes -D_GNU_SOURCE -std=gnu99
+CFLAGS_ALL += $(CFLAGS)
+
+LDFLAGS ?= -g
+LDFLAGS_ALL += $(LDFLAGS)
+
+export CC LD INSTALL INSTALLDIR CFLAGS_ALL LDFLAGS_ALL
+
+build :=
+
+endif
+
+##
+# Reset all variables.
+ifneq ($(origin targets),file)
+targets :=
+endif
+
+src :=
+obj :=
+
+src += $(build)
+obj := $(build)
+
+##
+# Include directory specific stuff
+
+ifneq ($(build),)
+$(build)/Makefile: ;
+include $(build)/Makefile
+endif
+
+##
+# Rules and helpers
+
+PHONY += all compile install clean FORCE
+
+# Convinient variables
+comma := ,
+squote := '
+empty :=
+space := $(empty) $(empty)
+
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
+
+build-dir = $(patsubst %/,%,$(dir $@))
+target-dir = $(dir $@)
+
+##
+# Build rules
+
+ifneq ($(NOCMDDEP),1)
+# Check if both arguments has same arguments. Result in empty string if equal
+# User may override this check using make NOCMDDEP=1
+# Check if both arguments has same arguments. Result is empty string if equal.
+# User may override this check using make KBUILD_NOCMDDEP=1
+arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+ $(filter-out $(cmd_$@), $(cmd_$(1))) )
+endif
+
+# echo command.
+# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
+echo-cmd = $(if $($(quiet)cmd_$(1)),\
+ echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
+
+make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
+
+# printing commands
+cmd = @$(echo-cmd) $(cmd_$(1))
+
+# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
+dot-target = $(dir $@).$(notdir $@)
+
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(dot-target).d)
+
+# Escape single quote for use in echo statements
+escsq = $(subst $(squote),'\$(squote)',$1)
+
+# Find any prerequisites that is newer than target or that does not exist.
+# PHONY targets skipped in both cases.
+any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
+
+# Execute command if command has changed or prerequisite(s) are updated.
+#
+if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
+ @set -e; \
+ $(echo-cmd) $(cmd_$(1)); \
+ echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
+
+# Usage: $(call if_changed_rule,foo)
+# Will check if $(cmd_foo) or any of the prerequisites changed,
+# and if so will execute $(rule_foo).
+if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \
+ @set -e; \
+ $(rule_$(1)))
+
+#####
+# Handle options to gcc.
+
+c_flags = -Wp,-MD,$(depfile) $(CFLAGS_ALL) $(CFLAGS_$(notdir $@))
+ld_flags = $(LDFLAGS_ALL) $(LDFLAGS_$(notdir $@))
+
+#####
+# Compile c-files.
+quiet_cmd_cc_o_c = CC $@
+
+cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+
+define rule_cc_o_c
+ $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
+ (echo 'cmd_$@ := $(call make-cmd,cc_o_c)'; \
+ echo -n "\n$(obj)/" ; cat $(depfile)) \
+ > $(dot-target).cmd ; \
+ rm $(depfile)
+endef
+
+$(obj)/%.o: $(src)/%.c FORCE
+ $(call if_changed_rule,cc_o_c)
+
+#####
+# Link programs
+
+# Link an executable based on list of .o files, all plain c
+# host-cmulti -> executable
+__progs := $(addprefix $(obj)/,$(sort $(progs-y)))
+cobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(progs-y),$($(m)-objs))))
+
+quiet_cmd_ld = LD $@
+ cmd_ld = $(CC) $(ld_flags) -o $@ \
+ $(addprefix $(obj)/,$($(@F)-objs)) \
+ $(LIBS) $(LIBS_$(@F))
+
+$(__progs): $(obj)/%: $(cobjs) FORCE
+ $(call if_changed,ld)
+
+targets += $(__progs) $(cobjs)
+
+###
+# why - tell why a a target got build
+ifeq ($(VERBOSE),2)
+why = \
+ $(if $(filter $@, $(PHONY)),- due to target is PHONY, \
+ $(if $(wildcard $@), \
+ $(if $(strip $(any-prereq)),- due to: $(any-prereq), \
+ $(if $(arg-check), \
+ $(if $(cmd_$@),- due to command line change: $(arg-check), \
+ $(if $(filter $@, $(targets)), \
+ - due to missing .cmd file, \
+ - due to $(notdir $@) not in $$(targets) \
+ ) \
+ ) \
+ ) \
+ ), \
+ - due to target missing \
+ ) \
+ )
+
+echo-why = $(call escsq, $(strip $(why)))
+endif
+
+##
+# Top level rules.
+
+%/: FORCE
+ $(Q)$(MAKE) -f Make.rules build=$(build-dir) $(MAKECMDGOALS)
+
+compile install:: $(targets)
+
+clean: $(filter %/,$(targets))
+ifeq ($(toplevelrun),yes)
+ $(Q)find . $(RCS_FIND_IGNORE) \
+ \( -name '*.[oas]' -o -name '.*.cmd' -o -name '.*.d' \) \
+ -type f -print | xargs rm -f
+endif
+ $(Q)rm -rf $(addprefix $(obj)/,$(sort $(progs-y) $(progs-n) $(progs-)))
+
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+ include $(cmd_files)
+endif
+
+# Declare the contents of the .PHONY variable as phony. We keep that
+# information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
diff --git a/Makefile b/Makefile
index d656c34..c60c198 100644
--- a/Makefile
+++ b/Makefile
@@ -1,74 +1,36 @@
-# Makefile - one file to rule them all, one file to bind them
-#
-# Copyright (C) 2007 Timo Teräs <timo.teras@iki.fi>
-# All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 3 as published
-# by the Free Software Foundation. See http://www.gnu.org/ for details.
+##
+# Building apk-tools
PACKAGE := apk-tools
VERSION := 2.0_pre10
-GIT_REV := $(shell git describe || echo exported)
-ifneq ($(GIT_REV), exported)
-ifneq ($(filter apk-tools-$(VERSION)%, $(GIT_REV)),)
-FULL_VERSION := $(patsubst apk-tools-%,%,$(GIT_REV))
-else
-FULL_VERSION := $(GIT_REV)
-endif
-else
-FULL_VERSION := $(VERSION)
-endif
+##
+# Default directories
-CC=gcc
-INSTALL=install
-INSTALLDIR=$(INSTALL) -d
+DESTDIR :=
+SBINDIR := /sbin
+CONFDIR := /etc/apk
+MANDIR := /usr/share/man
+DOCDIR := /usr/share/doc/apk
-CFLAGS?=-g -Werror -Wall -Wstrict-prototypes
-CFLAGS+=-D_GNU_SOURCE -std=gnu99 -DAPK_VERSION=\"$(FULL_VERSION)\"
+export DESTDIR SBINDIR CONFDIR MANDIR DOCDIR
-LDFLAGS?=-g
-LDFLAGS+=-nopie
-LIBS=/usr/lib/libz.a
+##
+# Top-level rules and targets
-ifeq ($(STATIC),yes)
-CFLAGS+=-fno-stack-protector
-LDFLAGS+=-static
-endif
+targets := src/
-DESTDIR=
-SBINDIR=/sbin
-CONFDIR=/etc/apk
-MANDIR=/usr/share/man
-DOCDIR=/usr/share/doc/apk
+##
+# Include all rules and stuff
-SUBDIRS=src
+include Make.rules
-.PHONY: compile install clean all static
-
-all: compile
-
-static:
- $(MAKE) $(MFLAGS) -C src apk.static
-
-compile install clean::
- @for i in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$i $(MAKECMDGOALS); done
+##
+# Top-level targets
install::
$(INSTALLDIR) $(DESTDIR)$(DOCDIR)
$(INSTALL) README $(DESTDIR)$(DOCDIR)
-clean::
- rm -rf $(TARBALL)
-
-TARBALL := $(PACKAGE)-$(VERSION).tar.bz2
-dist: $(TARBALL)
-$(TARBALL):
- rm -rf $(PACKAGE)
- git clone . $(PACKAGE)
- cd $(PACKAGE) && (cd .. && git diff) | patch -p1
- tar -cjf $@ $(PACKAGE)
- rm -rf $(PACKAGE)
-
-.EXPORT_ALL_VARIABLES:
+static:
+ $(Q)$(MAKE) STATIC=y
diff --git a/src/Makefile b/src/Makefile
index d4a7244..993ca91 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,50 +1,17 @@
-# Makefile - one file to rule them all, one file to bind them
-#
-# Copyright (C) 2007 Timo Teräs <timo.teras@iki.fi>
-# All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 3 as published
-# by the Free Software Foundation. See http://www.gnu.org/ for details.
+progs-y += apk
+apk-objs := state.o database.o package.o archive.o \
+ version.o io.o url.o gunzip.o blob.o \
+ hash.o md5.o apk.o \
+ add.o del.o ver.o index.o info.o search.o \
+ fetch.o audit.o
+CFLAGS_apk.o := -DAPK_VERSION=\"$(FULL_VERSION)\"
-TARGETS = apk
+progs-$(STATIC) += apk.static
+apk.static-objs := $(apk-objs)
+LDFLAGS_apk.static := -static
-apk_OBJS = \
- state.o \
- database.o \
- package.o \
- archive.o \
- version.o \
- io.o \
- url.o \
- gunzip.o \
- blob.o \
- hash.o \
- md5.o \
- add.o \
- del.o \
- ver.o \
- index.o \
- info.o \
- search.o \
- fetch.o \
- audit.o \
- apk.o
-
-ALL_OBJS = $(apk_OBJS)
-
-all: $(TARGETS)
-
-apk: $(apk_OBJS)
- $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
-
-apk.static: $(apk_OBJS)
- $(CC) $(LDFLAGS) -static -o $@ $^ $(LIBS)
-
-clean::
- @rm -f $(TARGETS) $(ALL_OBJS)
+LIBS := /usr/lib/libz.a
install::
$(INSTALLDIR) $(DESTDIR)$(SBINDIR)
- $(INSTALL) $(TARGETS) $(DESTDIR)$(SBINDIR)
-
+ $(INSTALL) $(obj)/apk $(DESTDIR)$(SBINDIR)