--- /dev/null
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+ @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
--- /dev/null
+QUIET_CMD_ECHO = echo
+#####################
+# Build pseudo-pass #
+#####################
+
+all: build-pseudo-pass
+
+rule_targets = $($(1)_targets)
+rule_deps = $($(1)_deps)
+rule_msg = $($(1)_msg)
+rule_cmd = $($(1)_cmd)
+
+# Usage: $(call build_rule,<target>)
+define build_rule
+$(value rule_targets): $(value rule_deps) $(omk_inc_file)
+ @$(QUIET_CMD_ECHO) " "$(rule_msg) "$$@" #"$$(call strip_out,$$@)"
+ $(Q)$(value rule_cmd)
+endef
+
+# TODO: Include target.omk only in the subtree
+-include $(shell true; find $(USER_BUILD_DIR) -name '*omk.inc') # `true' is a hack for MinGW
+
+$(foreach rule,$(prepared_rules),$(eval $(call build_rule,$(rule))))
+
+.PHONY: build-pseudo-pass
+build-pseudo-pass: $(foreach target,$(omk_goals),$(target))
+
--- /dev/null
+SUBDIRS=dir
--- /dev/null
+../snippets/Makefile.rules.test
\ No newline at end of file
--- /dev/null
+# Generic directory or leaf node makefile for OCERA make framework
+
+ifndef MAKERULES_DIR
+MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) )
+endif
+
+ifeq ($(MAKERULES_DIR),)
+all : default
+.DEFAULT::
+ @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n"
+else
+include $(MAKERULES_DIR)/Makefile.rules
+endif
+
--- /dev/null
+bin_PROGRAMS = test
+
+test_SOURCES = test.c
+test_LIBS = m
--- /dev/null
+#include <stdio.h>
+
+int main()
+{
+ printf("Hello world\n");
+ return 0;
+}
--- /dev/null
+alias omk='_omk_rules=$(old_pwd=""; while [ ! -e Makefile.rules ]; do if [ "$old_pwd" = `pwd` ]; then echo "Makefile.rules has not been found in this or parent directory" >&2; exit 1; else old_pwd=`pwd`; cd -L .. 2>/dev/null; fi; done; echo `pwd`/Makefile.rules); [ "$_omk_rules" ] && make -f $_omk_rules'
--- /dev/null
+
+# -*- makefile-gmake -*-
+include base.omk #omkbuild
+
+USER_INCLUDE_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/include
+USER_LIB_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/lib
+USER_UTILS_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/bin-utils
+USER_TESTS_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/bin-tests
+USER_BIN_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/bin
+USER_BUILD_DIR := $(OUTPUT_DIR)/$(BUILD_DIR_NAME)/user
+#LINK_BUILD_DIR := $(OUTPUT_DIR)/$(BUILD_DIR_NAME)/link
+
+check-dir::
+ @$(call mkdir_def,$(USER_BUILD_DIR))
+ @$(call mkdir_def,$(USER_INCLUDE_DIR))
+ @$(call mkdir_def,$(USER_LIB_DIR))
+ @$(call mkdir_def,$(USER_BIN_DIR))
+ @$(call mkdir_def,$(USER_UTILS_DIR))
+ @$(call mkdir_def,$(USER_TESTS_DIR))
+
+# Avoid double slash at the end in the top-level directory
+USER_OBJS_DIR = $(USER_BUILD_DIR)$(RELATIVE_DIR:%=/%)
+KERN_OBJS_DIR = $(KERN_BUILD_DIR)$(RELATIVE_DIR:%=/%)
+
+############
+# Programs #
+############
+
+ifeq ($(BUILD_OS),)
+ # Check for target
+ ifeq ($(OS),Windows_NT)
+ BUILD_OS := win32
+ else
+ BUILD_OS := $(shell uname | tr '[A-Z]' '[a-z]' )
+ #$(warning BUILD_OS=$(BUILD_OS))
+ endif
+endif
+
+ifeq ($(TARGET_OS),)
+ TARGET_OS := $(BUILD_OS)
+endif
+
+export TARGET_OS
+export BUILD_OS
+
+# Assign default values to CFLAGS variable. If the variable is defined
+# earlier (i.g. in config.omk), it is not overriden here.
+CFLAGS ?= -O2 -Wall
+CXXFLAGS ?= -O2 -Wall
+
+
+CPPFLAGS += -I $(USER_INCLUDE_DIR)
+LOADLIBES += -L$(USER_LIB_DIR)
+LOADLIBES += $(lib_LOADLIBES:%=-l%)
+
+LIB_CPPFLAGS += $(CPPFLAGS)
+LIB_CFLAGS += $(CFLAGS)
+
+ifeq ($(TARGET_OS),win32)
+ SOLIB_EXT = dll
+else
+ SOLIB_EXT = so
+ SOLIB_PICFLAGS += -fpic
+endif
+
+# Check GCC version for user build
+ifndef CC_MAJOR_VERSION
+CC_MAJOR_VERSION := $(shell $(CC) -dumpversion | sed -e 's/\([^.]\)\..*/\1/')
+# TODO: export CC_MAJOR_VERSION to save the above shell invocation in
+# submakes. This will work only if CC is not changed in Makefile.omk.
+endif
+# Prepare suitable define for dependency building
+ifeq ($(CC_MAJOR_VERSION),2)
+CC_DEPFLAGS = -Wp,-MD,"$$@.d.tmp"
+else
+CC_DEPFLAGS = -MT $$@ -MD -MP -MF "$$@.d.tmp"
+endif
+
+c_o_COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -DOMK_FOR_USER
+
+cc_o_COMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -DOMK_FOR_USER
+
+S_o_COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(ASFLAGS) -DOMK_FOR_USER
+
+c_o_cmd = \
+ if $(c_o_COMPILE) $(CC_DEPFLAGS) -o $$@ -c $$< ; \
+ then mv -f "$$@.d.tmp" "$$@.d"; \
+ else rm -f "$$@.d.tmp"; exit 1; \
+ fi
+
+cc_o_cmd = \
+ if $(cc_o_COMPILE) $(CC_DEPFLAGS) -o $$@ -c $$< ; \
+ then mv -f "$$@.d.tmp" "$$@.d"; \
+ else rm -f "$$@.d.tmp"; exit 1; \
+ fi
+
+S_o_cmd = \
+ if $(S_o_COMPILE) -D__ASSEMBLY__ $(CC_DEPFLAGS) $($(1)_CFLAGS) -o $$@ -c $$< ; \
+ then mv -f "$$@.d.tmp" "$$@.d" ; \
+ else rm -f "$$@.d.tmp" ; exit 1; \
+ fi
+# TODO: Implement $($(1)_CFLAGS)
+
+# Default values for IDL_* variable are suitable for ORBit-like IDL compilers
+IDL_CLIENT_SOURCES ?= $(1:%.idl=%-stubs.c) $(1:%.idl=%-common.c)
+IDL_SERVER_SOURCES ?= $(1:%.idl=%-skels.c) $(1:%.idl=%-common.c)
+IDL_TARGETS ?= $(1:%.idl=%-stubs.c) $(1:%.idl=%-skels.c) $(1:%.idl=%-common.c) $(1:%.idl=%.h)
+IDL_FLAGS ?= --output-dir=$(USER_OBJS_DIR)
+
+idl_src_cmd = $(IDL_COMPILER) $(IDL_FLAGS) $($(1)_IDLFLAGS) $$<
+
+# TODO: Implement CMETRIC
+
+_linker = $(if $(call c++sources,$($(1)_SOURCES) $($(1)_GEN_SOURCES)),$(CXX),$(CC))
+_map_file = $(USER_OBJS_DIR)/$(1).exe.map
+_dep_file = $(USER_OBJS_DIR)/$(1).exe.d
+program_cmd = set -e; \
+ $(_linker) $($(1)_OBJS) $($(1)_LIBS:%=-l%) $(LOADLIBES) $(LDFLAGS) \
+ -Wl,-rpath-link,$(USER_LIB_DIR) -Wl,-Map,$(_map_file) -o $$@; \
+ echo "$$@: \\" >$(_dep_file); \
+ sed -n -e 's|^LOAD \(.*\)$$$$| \1 \&|p' $(_map_file)\
+ |tr '&' '\134' >>$(_dep_file); \
+ echo >>$(_dep_file)
+
+library_cmd = $(AR) rcs $$@ $$^
+
+solib_cmd = set -e; \
+ $(_linker) $($(1)_OBJS) $($(1)_LIBS:%=-l%) $(LOADLIBES) $(LDFLAGS) \
+ -Wl,-rpath-link,$(USER_LIB_DIR) -Wl,-Map,$(_map_file) -o $$@; \
+ echo "$$@: \\" >$(_dep_file); \
+ sed -n -e 's|^LOAD \(.*\)$$$$| \1 \&|p' $(_map_file)\
+ |tr '&' '\134' >>$(_dep_file); \
+ echo >>$(_dep_file)
+
+
+include cprog.omk #omkbuild
OUTPUT_DIR := $(MAKERULES_DIR)
endif
-.PHONY: all default check-make-ver omkize
-
ifdef W
ifeq ("$(origin W)", "command line")
OMK_WHOLE_TREE:=$(W)
endif
ifneq ($(OMK_WHOLE_TREE),1)
-all: check-make-ver default
- @echo "Compilation finished"
+ ifndef omk_prereq_checked
+ omk_checks=check-make-ver check-dir
+ export omk_prereq_checked=1
+ endif
+all: build-pseudo-pass
+
+prepare: $(omk_checks) prepare-pass
+build-pseudo-pass: prepare
+ +@$(QUIET_CMD_ECHO) "make[omk]: build"
+ $(Q3)$(MAKE) -C $(MAKERULES_DIR) -f Makefile.rules build
+ @$(QUIET_CMD_ECHO) "Compilation finished"
+
+prepare-pass:: $(omk_checks)
else
# Run make in the top-level directory
all:
- @$(MAKE) -C $(MAKERULES_DIR) OMK_SERIALIZE_INCLUDED=n SOURCES_DIR=$(MAKERULES_DIR) RELATIVE_DIR="" $(MAKECMDGOALS) W=0
+ $(Q3)$(MAKE) -C $(MAKERULES_DIR) OMK_SERIALIZE_INCLUDED=n SOURCES_DIR=$(MAKERULES_DIR) RELATIVE_DIR="" $(MAKECMDGOALS) W=0
endif
+.PHONY: all default check-make-ver omkize prepare build-pseudo-pass
+
ifdef OMK_TESTSROOT
# Usage: $(call canttest,<error message>)
define canttest
ifndef OMK_VERBOSE
OMK_VERBOSE = 0
endif
-ifneq ($(OMK_VERBOSE),0)
- Q =
-else
- Q = @
-endif
+
+Q = $(if $(filter 0 ,$(OMK_VERBOSE)),@)
+Q2 = $(if $(filter 0 1 ,$(OMK_VERBOSE)),@)
+Q3 = $(if $(filter 0 1 2,$(OMK_VERBOSE)),@)
+
ifneq ($(findstring s,$(MAKEFLAGS)),)
QUIET_CMD_ECHO = true
OMK_SILENT = 1
QUIET_CMD_ECHO = echo
endif
+# Convenient variables
+comma := ,
+squote := '
+#'
+empty :=
+space := $(empty) $(empty)
+
+###
+# Escape single quote for use in echo statements
+escsq = $(subst $(squote),'\$(squote)',$1)
+
+###
+# Strip/replace OUTPUT_DIR from/in the argument
+strip_out = $(patsubst $(OUTPUT_DIR)/%,%,$(1))
+repl_out = $(patsubst $(OUTPUT_DIR)/%,$$(OUTPUT_DIR)/%,$(1))
+
+.PHONY: FORCE
+
+
MAKEFILE_OMK=Makefile.omk
# All subdirectories (even linked ones) containing Makefile.omk
# Usage in Makefile.omk: SUBDIRS = $(ALL_OMK_SUBDIRS)
OMK_INCLUDED := 1
endif
+
check-make-ver:
@GOOD_MAKE_VERSION=`echo $(MAKE_VERSION) | sed -n -e 's/^[4-9]\..*\|^3\.9[0-9].*\|^3\.8[1-9].*/y/p'` ; \
if [ x$$GOOD_MAKE_VERSION != xy ] ; then \
distclean dist-clean:
@$(QUIET_CMD_ECHO) " RM $(COMPILED_DIR_NAME) $(BUILD_DIR_NAME)"
- @rm -fr $(OUTPUT_DIR)/$(COMPILED_DIR_NAME) $(OUTPUT_DIR)/$(BUILD_DIR_NAME)
+ $(Q3)rm -fr $(OUTPUT_DIR)/$(COMPILED_DIR_NAME) $(OUTPUT_DIR)/$(BUILD_DIR_NAME)
# Common OMK templates
# ====================
-# Syntax: $(call mkdir,<dir name>)
+# Syntax: $(call mkdir_def,<dir name>)
define mkdir_def
[ -d $(1) ] || mkdir -p $(1) || exit 1
endef
SOURCESDIR_MAKEFILE=$(SOURCES_DIR)/Makefile
endif
+BUILD_DIR_NAME = _build
+COMPILED_DIR_NAME = _compiled
+
+BUILD_OMK_DIR := $(OUTPUT_DIR)/$(BUILD_DIR_NAME)/omk
+OMK_WORK_DIR := $(BUILD_OMK_DIR)$(RELATIVE_DIR:%=/%)
+
+check-dir::
+ $(Q3)$(call mkdir_def,$(BUILD_OMK_DIR))
+
pass = $(strip $(1))
# Call a pass in a subdirectory
-# Usage: $(call omk_pass_subdir_template,<pass name>,<build dir>,<subdir>)
+# Usage: $(call omk_pass_subdir_template,<pass name>,<subdir>)
define omk_pass_subdir_template
-.PHONY: $(pass)-$(3)-subdir
-$(pass)-submakes: $(pass)-$(3)-subdir
-$(pass)-$(3)-subdir:
- @$(call mkdir_def,$(2)/$(3))
- +@$(MAKE) SOURCES_DIR=$(SOURCES_DIR)/$(3) $(NO_PRINT_DIRECTORY) \
- RELATIVE_DIR=$(RELATIVE_PREFIX)$(3) -C $(2)/$(3) \
- -f $(SUBDIR_MAKEFILE) $(pass)-submakes
-# In subdirectories we can call submakes directly since passes are
-# already searialized on the toplevel make.
+.PHONY: $(pass)-$(2)-subdir
+$(pass)-subdirs: $(pass)-$(2)-subdir
+$(pass)-$(2)-subdir:
+ +$(Q3)$(MAKE) SOURCES_DIR=$(SOURCES_DIR)/$(2) $(NO_PRINT_DIRECTORY) \
+ RELATIVE_DIR=$(RELATIVE_PREFIX)$(2) -C $(2) \
+ -f $(SUBDIR_MAKEFILE) $(pass)
endef
ifdef OMK_TESTSROOT
define extra_rules_subdir_template
extra-rules-subdirs: extra-rules-$(1)
extra-rules-$(1):
- +@$(MAKE) OMK_SERIALIZE_INCLUDED=n MAKERULES_DIR=$(SOURCES_DIR)/$(1) OUTPUT_DIR=$(OUTPUT_DIR) \
+ +$(Q3)$(MAKE) OMK_SERIALIZE_INCLUDED=n MAKERULES_DIR=$(SOURCES_DIR)/$(1) OUTPUT_DIR=$(OUTPUT_DIR) \
SOURCES_DIR=$(SOURCES_DIR)/$(1) RELATIVE_DIR=$(RELATIVE_PREFIX)$(1) -C $(SOURCES_DIR)/$(1)
endef
-.PHONY: extra-rules-subdirs
+.PHONY: extra-rules-subdirs mkdir-omk-work
extra-rules-subdirs:
$(foreach subdir,$(EXTRA_RULES_SUBDIRS),$(eval $(call extra_rules_subdir_template,$(subdir))))
-# Usage: $(call omk_pass_template,<pass name>,<build dir>,[<local make flags>],[<local enable condition>])
+# Usage: $(call omk_pass_template,<pass name>)
define omk_pass_template
-.PHONY: $(pass) $(pass)-local $(pass)-check $(pass)-submakes
-$(foreach subdir,$(SUBDIRS),$(eval $(call omk_pass_subdir_template,$(pass),$(2),$(subdir))))
-$(pass):
-# Submakes have to be called this way and not as dependecies for pass
-# serialization to work
- +@$(MAKE) SOURCES_DIR=$(SOURCES_DIR) $(NO_PRINT_DIRECTORY) \
- RELATIVE_DIR=$(RELATIVE_DIR) \
- -f $(SOURCESDIR_MAKEFILE) $(pass)-submakes
-$(pass)-submakes:
- @true # Do not emit "nothing to be done" messages
-
-ifneq ($(4)$($(pass)_HOOKS),)
-$(pass)-submakes: $(pass)-this-dir
-$(pass)-this-dir: $(foreach subdir,$(SUBDIRS),$(pass)-$(subdir)-subdir)
- +@echo "make[omk]: $(pass) in $(RELATIVE_DIR)"
- @$(call mkdir_def,$(2))
- +@$(MAKE) $(NO_PRINT_DIRECTORY) SOURCES_DIR=$(SOURCES_DIR) RELATIVE_DIR=$(RELATIVE_DIR) -C $(2) \
- -f $(SOURCESDIR_MAKEFILE) $(3) $(check-target) $(1:%=%-local)
-$(pass)-local: $($(pass)_HOOKS)
-endif
+.PHONY: $(pass) $(pass)-msg $(pass)-subdirs
+$(pass):: $(pass)-subdirs $(pass)-msg mkdir-omk-work
+$(foreach subdir,$(SUBDIRS),$$(eval $$(call omk_pass_subdir_template,$(pass),$(subdir))))
+
+$(pass)-msg: $(pass)-subdirs
+ +@$(QUIET_CMD_ECHO) "make[omk]: $(pass) in $(RELATIVE_DIR)"
endef
+mkdir-omk-work:
+ $(Q3)$(call mkdir_def,$(OMK_WORK_DIR))
+
+
+
# =======================
# DEFAULT CONFIG PASS
default-config:
- @echo "# Start of OMK config file" > "$(CONFIG_FILE)-default"
- @echo "# This file should not be altered manually" >> "$(CONFIG_FILE)-default"
- @echo "# Overrides should be stored in file $(notdir $(CONFIG_FILE))" >> "$(CONFIG_FILE)-default"
- @echo >> "$(CONFIG_FILE)-default"
- @$(MAKE) $(NO_PRINT_DIRECTORY) -C $(OUTPUT_DIR) \
+ $(Q3)echo "# Start of OMK config file" > "$(CONFIG_FILE)-default"
+ $(Q3)echo "# This file should not be altered manually" >> "$(CONFIG_FILE)-default"
+ $(Q3)echo "# Overrides should be stored in file $(notdir $(CONFIG_FILE))" >> "$(CONFIG_FILE)-default"
+ $(Q3)echo >> "$(CONFIG_FILE)-default"
+ $(Q3)$(MAKE) $(NO_PRINT_DIRECTORY) -C $(MAKERULES_DIR) \
RELATIVE_DIR="" SOURCES_DIR=$(OUTPUT_DIR) \
-f $(OUTPUT_DIR)/Makefile default-config-pass
$(eval $(call omk_pass_template,default-config-pass,$$(LOCAL_BUILD_DIR),,always))
-default-config-pass-local:
-# @echo Default config for $(RELATIVE_DIR)
- @echo "# Config for $(RELATIVE_DIR)" >> "$(CONFIG_FILE)-default"
- @$(foreach x, $(default_CONFIG), echo '$(x)' | \
+default-config-pass::
+# $(Q3)echo Default config for $(RELATIVE_DIR)
+ $(Q3)echo "# Config for $(RELATIVE_DIR)" >> "$(CONFIG_FILE)-default"
+ $(Q3)$(foreach x, $(default_CONFIG), echo '$(x)' | \
sed -e 's/^[^=]*=x$$/#\0/' >> "$(CONFIG_FILE)-default" ; )
cp -v Makefile "$${d}/Makefile"; \
fi \
done
+
+include prepare.omk #omkbuild
+include build.omk #omkbuild
--- /dev/null
+
+#####################
+# Build pseudo-pass #
+#####################
+
+ifneq (,$(filter build,$(MAKECMDGOALS)))
+rule_targets = $(value $(1)_targets)
+rule_deps = $(value $(1)_deps)
+rule_msg = $(value $(1)_msg)
+rule_cmd = $(value $(1)_cmd)
+
+# Usage: $(eval $(call build_rule,<target>))
+define build_rule
+$(rule_targets): $(rule_deps) #$(omk_inc_file)
+ @$(QUIET_CMD_ECHO) " "$(rule_msg)"$$@" #"$$(call strip_out,$$@)"
+ $(Q)$(rule_cmd)
+endef
+
+# Goals are included only for this directory and all subdirectories
+# TODO: What if a target depends on a library from different
+# subtree. Then the library would be remade even if it should not
+# because its __goals.omk.inc is not included.
+-include $(shell true; find $(OMK_WORK_DIR) -name '__goals.omk.inc') # `true' is a hack for MinGW
+
+# Definition of rules is included everywhere to allow multi-directory
+# targets.
+-include $(shell true; find $(BUILD_OMK_DIR) -name '*.omk.inc' -not -name '__goals.omk.inc') # `true' is a hack for MinGW
+
+# FIXME: Disable automatic remake of included files
+
+$(foreach rule,$(prepared_rules),$(eval $(call build_rule,$(rule))))
+
+.PHONY: build
+
+build: $(omk_goals)
+
+endif # (,$(filter build,$(MAKECMDGOALS)))
config_h_stamp_files = $(addprefix $(USER_OBJS_DIR)/,$(notdir $(addsuffix .stamp,$(config_include_HEADERS) $(LOCAL_CONFIG_H))))
# Add some hooks to standard passes
-include-pass-local: $(config_h_stamp_files)
+include-pass-local: $(config_h_stamp_files) # TODO remove -local
ifneq ($(KERN_CONFIG_HEADERS_REQUIRED),)
kern_config_h_stamp_files = $(addprefix $(KERN_OBJS_DIR)/,$(notdir $(addsuffix .stamp,$(config_include_HEADERS) $(LOCAL_CONFIG_H))))
# Add some hooks to standard passes
-include-pass-local: $(kern_config_h_stamp_files)
+include-pass-local: $(kern_config_h_stamp_files) # TODO remove -local
endif
-clean-local: clean-local-config-h
+clean-local: clean-local-config-h # TODO remove -local
clean-local-config-h:
@$(foreach confh,$(config_h_stamp_files) $(kern_config_h_stamp_files),\
--- /dev/null
+
+##################
+# C/C++ programs #
+##################
+
+c++ext = cc C cxx cpp
+c++sources = $(strip $(foreach ext,$(c++ext),$(filter %.$(ext),$(1))))
+
+###
+# template_variables - variables common to program, libraries, ...
+#
+define template_variables
+USER_IDLS += $$($(1)_SERVER_IDL) $$($(1)_CLIENT_IDL) $$($(1)_IDL)
+$(1)_GEN_SOURCES += $$(call IDL_SERVER_SOURCES,$$($(1)_SERVER_IDL))
+$(1)_GEN_SOURCES += $$(call IDL_CLIENT_SOURCES,$$($(1)_CLIENT_IDL))
+$(1)_GEN_SOURCES += $$(sort $$(call IDL_SERVER_SOURCES,$$($(1)_IDL)) \
+ $$(call IDL_CLIENT_SOURCES,$$($(1)_IDL)))
+USER_GEN_SOURCES += $$($(1)_GEN_SOURCES)
+$(1)_OBJS += $(foreach ext,c $(c++ext),$$(patsubst %.$(ext),%.o,$$(filter %.$(ext),$$($(1)_SOURCES) $$($(1)_GEN_SOURCES))))
+$(1)_OBJS := $$(sort $$($(1)_OBJS:%/=%)) # Why is here the backslash substitution???
+$(1)_OBJS := $$(addprefix $(USER_OBJS_DIR)/,$$(sort $$($(1)_OBJS:%/=%)))
+
+USER_OBJS += $$($(1)_OBJS)
+USER_SOURCES += $$($(1)_SOURCES)
+endef
+
+###
+# program_template
+#
+# Usage: $(call program_template,<executable-name>,<bin|utils|test>)
+define program_template
+$(template_variables)
+$$(eval $$(call prepare_rule_goal,\
+ $(USER_BIN_DIR)/$(1)$(EXE_SUFFIX),\
+ $$($(1)_OBJS),\
+ "LINK ",\
+ $$(call program_cmd,$(1))))
+endef
+
+###
+# library_template
+#
+# Usage: $(call library_template,<library-name>)
+define library_template
+$(template_variables)
+$$(eval $$(call prepare_rule_goal,\
+ $(USER_LIB_DIR)/lib$(1).a,\
+ $$($(1)_OBJS),\
+ "AR ",\
+ $$(call library_cmd,$(1))))
+endef
+
+###
+# solib_template
+#
+# Usage: $(call solib_template,<library-name>)
+define solib_template
+$(template_variables) # FIXME: OBJSLO, etc.
+# TODO: Add dependencies on other shared libraries ala:
+# $(1)_libs += $$($(1)_LIBS) $$(lib_LOADLIBES)
+# $(1)_shared_libs = $$(patsubst %,$(USER_LIB_DIR)/lib%.$(SOLIB_EXT),$$(filter $$(shared_libs),$$($(1)_libs)))
+
+$$(eval $$(call prepare_rule_goal,\
+ $(USER_LIB_DIR)/lib$(1).$(SOLIB_EXT),\
+ $$($(1)_OBJS),\
+ "LINK ",\
+ $$(call solib_cmd,$(1))))
+endef
+
+ifneq ($(bin_PROGRAMS)$(test_PROGRAMS)$(utils_PROGRAMS)$(lib_LIBRARIES)$(shared_LIBRARIES),)
+prepare-pass::
+ @$(call mkdir_def,$(USER_OBJS_DIR))
+endif
+
+# TODO: $(foreach cmetrh,...)
+
+$(foreach prog,$(bin_PROGRAMS),$(eval $(call program_template,$(prog),bin)))
+$(foreach prog,$(utils_PROGRAMS),$(eval $(call program_template,$(prog),utils)))
+$(foreach prog,$(test_PROGRAMS),$(eval $(call program_template,$(prog),test)))
+$(foreach lib,$(lib_LIBRARIES),$(eval $(call library_template,$(lib))))
+$(foreach lib,$(shared_LIBRARIES),$(eval $(call solib_template,$(lib))))
+
+$(foreach src,$(filter %.c,$(USER_SOURCES)),\
+ $(eval $(call prepare_rule,\
+ $(USER_OBJS_DIR)/$(src:%.c=%.o),\
+ $(SOURCES_DIR)/$(src),\
+ "CC ",\
+ $(c_o_cmd))))
+
+include include.omk #omkbuild
+$(eval $(call include-pass-template,$(USER_INCLUDE_DIR),include))
+
+$(foreach idl,$(USER_IDLS),\
+ $(eval $(call prepare_rule_goal,\
+ $(addprefix $(USER_OBJS_DIR)/,$(call IDL_TARGETS,$(idl))),\
+ $(SOURCES_DIR)/$(idl),\
+ "IDL ",\
+ $(call idl_src_cmd,$(idl)))))
# LN_HEADERS .. if "y", header files are symbolicaly linked instead of copied.
-ifeq ($(OMK_VERBOSE),1)
+ifneq ($(OMK_VERBOSE),0)
CPHEADER_FLAGS += -v
LNHEADER_FLAGS += -v
endif
endef
else
define cp_cmd
-( echo " LN $(1:$(OUTPUT_DIR)/%=%) -> $(2:$(OUTPUT_DIR)/%=%)"; [ -f $(1) ] && ln -sf $(LNHEADER_FLAGS) $(1) $(2) )
+( echo " LN $(1:$(OUTPUT_DIR)/%=%) -> $(2:$(OUTPUT_DIR)/%=%)"; [ -f $(1) ] || exit 1; ln -sf $(LNHEADER_FLAGS) $(SOURCES_DIR)/$(1) $(2) )
endef
endif
# Syntax: $(call include-pass-template,<include dir>,<keyword>)
define include-pass-template
-include-pass-local: include-pass-local-$(2)
-include-pass-local-$(2): $$($(2)_GEN_HEADERS) $$(foreach f,$$(renamed_$(2)_GEN_HEADERS),$$(shell echo '$$(f)' | sed -e 's/^\(.*\)->.*$$$$/\1/'))
- @$$(foreach f, $$($(2)_HEADERS), cmp --quiet $$(SOURCES_DIR)/$$(f) $(1)/$$(notdir $$(f)) \
- || $$(call cp_cmd,$$(SOURCES_DIR)/$$(f),$(1)/$$(notdir $$(f))) || exit 1 ; )
- @$$(foreach f, $$($(2)_GEN_HEADERS), cmp --quiet $$(f) $(1)/$$(notdir $$(f)) \
- || $$(call cp_cmd,$$(LOCAL_BUILD_DIR)/$$(f),$(1)/$$(notdir $$(f))) || exit 1 ; ) # FIXME: Use correct build dir, then document it
- @$$(foreach f, $$(nobase_$(2)_HEADERS), cmp --quiet $$(SOURCES_DIR)/$$(f) $(1)/$$(f) \
- || ( mkdir -p $(1)/$$(dir $$(f)) && $$(call cp_cmd,$$(SOURCES_DIR)/$$(f),$(1)/$$(f)) ) || exit 1 ; )
- @$$(foreach f, $$(renamed_$(2)_HEADERS), \
- srcfname=`echo '$$(f)' | sed -e 's/^\(.*\)->.*$$$$/\1/'` ; destfname=`echo '$$(f)' | sed -e 's/^.*->\(.*\)$$$$/\1/'` ; \
- cmp --quiet $$(SOURCES_DIR)/$$$${srcfname} $(1)/$$$${destfname} \
- || ( mkdir -p `dirname $(1)/$$$${destfname}` && $$(call cp_cmd,$$(SOURCES_DIR)/$$$${srcfname},$(1)/$$$${destfname}) ) || exit 1 ; )
- @$$(foreach f, $$(renamed_$(2)_GEN_HEADERS), \
+prepare-pass::
+ $(Q3)$$(foreach f, $$($(2)_HEADERS), cmp --quiet $$(f) $(1)/$$(notdir $$(f)) \
+ || $$(call cp_cmd,$$(f),$(1)/$$(notdir $$(f))) || exit 1 ; )
+ $(Q3)$$(foreach f, $$($(2)_GEN_HEADERS), cmp --quiet TODO_BUILD_DIR/$$(f) $(1)/$$(notdir $$(f)) \
+ || $$(call cp_cmd,TODO_BUILD_DIR/$$(f),$(1)/$$(notdir $$(f))) || exit 1 ; ) # FIXME: Use correct build dir, then document it
+ $(Q3)$$(foreach f, $$(nobase_$(2)_HEADERS), cmp --quiet $$(f) $(1)/$$(f) \
+ || ( mkdir -p $(1)/$$(dir $$(f)) && $$(call cp_cmd,$$(f),$(1)/$$(f)) ) || exit 1 ; )
+ $(Q3)$$(foreach f, $$(renamed_$(2)_HEADERS), \
srcfname=`echo '$$(f)' | sed -e 's/^\(.*\)->.*$$$$/\1/'` ; destfname=`echo '$$(f)' | sed -e 's/^.*->\(.*\)$$$$/\1/'` ; \
cmp --quiet $$$${srcfname} $(1)/$$$${destfname} \
- || ( mkdir -p `dirname $(1)/$$$${destfname}` && $$(call cp_cmd,$$(LOCAL_BUILD_DIR)/$$$${srcfname},$(1)/$$$${destfname}) ) || exit 1 ; )
+ || ( mkdir -p `dirname $(1)/$$$${destfname}` && $$(call cp_cmd,$$$${srcfname},$(1)/$$$${destfname}) ) || exit 1 ; )
+ $(Q3)$$(foreach f, $$(renamed_$(2)_GEN_HEADERS), \
+ srcfname=`echo '$$(f)' | sed -e 's/^\(.*\)->.*$$$$/\1/'` ; destfname=`echo '$$(f)' | sed -e 's/^.*->\(.*\)$$$$/\1/'` ; \
+ cmp --quiet TODO_BUILD_DIR/$$$${srcfname} $(1)/$$$${destfname} \
+ || ( mkdir -p `dirname $(1)/$$$${destfname}` && $$(call cp_cmd,TODO_BUILD_DIR/$$$${srcfname},$(1)/$$$${destfname}) ) || exit 1 ; )
endef
+
+# TODO: *_GEN_HEADERS should be copied by normal rules during build
+# phase because they are generated by another rule.
--- /dev/null
+
+################
+# Prepare pass #
+################
+
+$(eval $(call omk_pass_template,prepare-pass))
+
+###
+# Name of the prepared rule. This name is used as prefix of variable
+# names in .omk.inc and is based on the first target
+omk_inc_rule = $(firstword $(1:$(OUTPUT_DIR)/%=%))
+
+# The name of .omk.inc file is derived from $(omk_inc_rule) and
+# depends whether the target is under _build or elsewhere.
+omk_inc_file = $(if $(filter $(BUILD_DIR_NAME)%,$(omk_inc_rule)),\
+ $(OMK_WORK_DIR)/$(notdir $(omk_inc_rule)).omk.inc,\
+ $(OMK_WORK_DIR)/$(subst /,_,$(omk_inc_rule)).omk.inc)
+
+target_omk_file = $(OMK_WORK_DIR)/$(notdir $(1)).target.omk
+
+# >\< substitution to preserve \ in echo argument
+# >'< substitution is for echo to work,
+# >$< substitution to preserve $ when reloading .omk.inc file
+subst-cmd = $(subst $$,$$$$,$(call escsq,$(subst \,\\,$(1))))
+
+###
+# prepare_rule is used to generate .omk.inc files during prepare-pass.
+# All paths in this file should be relative to $(OUTPUT_DIR)
+# Usage: $(eval $(call prepare_rule,<targets>,<deps>,<msg>,<cmd>))
+define prepare_rule
+prepare-pass::
+#TODO remove echos from the next commands
+ @set -e;\
+ echo 'prepared_rules += $(omk_inc_rule)' > $(omk_inc_file).tmp; \
+ echo '$(omk_inc_rule)_targets = $$(call strip_out,$(1))' >> $(omk_inc_file).tmp; \
+ echo '$(omk_inc_rule)_deps += $$(call strip_out,$(2))' >> $(omk_inc_file).tmp; \
+ echo '$(omk_inc_rule)_msg = $(3)' >> $(omk_inc_file).tmp; \
+ echo '$(omk_inc_rule)_cmd = $(call subst-cmd,$(4))' >> $(omk_inc_file).tmp; \
+ if cmp -s $(omk_inc_file).tmp $(omk_inc_file); then rm $(omk_inc_file).tmp; echo " CHK "$$(call strip_out,$(omk_inc_file)); else mv $(omk_inc_file).tmp $(omk_inc_file); echo " UPD "$$(call strip_out,$(omk_inc_file)); fi
+endef
+
+###
+# prepare_rule_goal - same as prepare rules but the target is put
+# as dependency to the default goal, which causes it to be built
+# upon calling make
+define prepare_rule_goal
+$(call prepare_rule,$(1),$(2),$(3),$(4))
+prepared_goals += $(call strip_out,$(1))
+endef
+
+_goals := $(OMK_WORK_DIR)/__goals.omk.inc
+
+prepare-pass::
+ @echo 'omk_goals += $(prepared_goals)' > $(_goals).tmp; \
+ if cmp -s $(_goals).tmp $(_goals); \
+ then rm $(_goals).tmp; \
+ else mv $(_goals).tmp $(_goals); fi
+
+
-# QT_PROJECTS .. list of QT .pro file to use for compilation
-# QT_SUBDIRS .. subdirectories where to build QT applications using qmake (depricated)
+# QT_SUBDIRS .. subdirectories where to build QT applications using qmake
# QTDIR .. where QT resides
-ifneq ($(QT_SUBDIRS)$(QT_PROJECTS),)
+ifneq ($(QT_SUBDIRS),)
-# Usage: $(call qt_project_template,<.pro_file relative to SOURCES_DIR>)
-define qt_project_template
+.PHONY: qt-subpass clean-qt distclean-qt
-.PHONY: qt-subpass-$(1) clean-qt-$(dir $(1))
-
-# FIXME: Handle multiple .pro files correctly
-$(LOCAL_BUILD_DIR)/$(dir $(1))Makefile: $(SOURCES_DIR)/$(1)
- $(Q)mkdir -p $$(dir $$(@)) && cd $$(dir $$(@)) && \
- $(QTDIR:%=%/bin/)qmake \
- TOP_DIR=$(OUTPUT_DIR) \
- RELATIVE_DIR=$(RELATIVE_PREFIX)$(dir $(1)) \
- $(QTDIR:%=QTDIR=%) CC=$(CC) CXX=$(CXX) \
- LIBS+="-L$(USER_LIB_DIR)" DESTDIR=$(USER_BIN_DIR) \
- INCLUDEPATH+="$(USER_INCLUDE_DIR)" \
- QMAKE_LFLAGS="-Wl,-rpath-link,$(USER_LIB_DIR) $$(QMAKE_LFLAGS)" \
- $(SOURCES_DIR)/$(1)
+# Usage: $(call qt_makefile_template,<qt-subdir>)
+define qt_makefile_template
+$(SOURCES_DIR)/$(1)/Makefile: $(wildcard $(SOURCES_DIR)/$(1)/*.pro)
+ cd $(SOURCES_DIR)/$(1); $(QTDIR:%=%/bin/)qmake TOP_DIR=$(OUTPUT_DIR) \
+ RELATIVE_DIR=$(RELATIVE_PREFIX)$(1) $(QTDIR:%=QTDIR=%) CC=$(CC) \
+ CXX=$(CXX) LIBS+="-L$(USER_LIB_DIR)" INCLUDEPATH+="$(USER_INCLUDE_DIR)"
+endef
+$(foreach dir,$(QT_SUBDIRS), $(eval $(call qt_makefile_template,$(dir))))
-# This horrible substitution is here to properly escape
-# -Wl,-rpath,$ORIGIN flags. It includes escaping for make, shell,
-# qmake and again make and shell run on qmake generated makefile.
-QMAKE_LFLAGS = $$(subst $$$$,\\\\\\$$$$\$$$$,$$(LDFLAGS))
+qt-subpass: $(foreach dir,$(QT_SUBDIRS), $(SOURCES_DIR)/$(dir)/Makefile)
+ $(foreach dir,$(QT_SUBDIRS),\
+ $(MAKE) SOURCES_DIR=$(SOURCES_DIR)/$(dir) \
+ RELATIVE_DIR=$(RELATIVE_PREFIX)$(dir) -C $(SOURCES_DIR)/$(dir) \
+ -f $(SOURCES_DIR)/$(dir)/Makefile || exit 1 ;)
# Hook to binary pass
-binary-pass-submakes: qt-subpass-$(1)
-qt-subpass-$(1): $(LOCAL_BUILD_DIR)/$(dir $(1))Makefile
- $(Q)$(MAKE) SOURCES_DIR=$(SOURCES_DIR)/$(dir $(1)) \
- RELATIVE_DIR=$(RELATIVE_PREFIX)$(dir $(1)) -C $(LOCAL_BUILD_DIR)/$(dir $(1)) || exit 1 ;
+binary-pass-submakes: qt-subpass
# Hook to clean pass
-clean-local: clean-qt-$(dir $(1))
-clean-qt-$(dir $(1)): $(LOCAL_BUILD_DIR)/$(dir $(1))Makefile
- @$(QUIET_CMD_ECHO) " QT CLEAN $(dir $(1))"
- $(Q)$(MAKE) SOURCES_DIR=$(SOURCES_DIR)/$(dir $(1)) \
- RELATIVE_DIR=$(RELATIVE_PREFIX)$(dir $(1)) \
- -C $(LOCAL_BUILD_DIR)/$(dir $(1)) clean
- $(Q)rm $(LOCAL_BUILD_DIR)/$(dir $(1))Makefile
-endef
-
-$(foreach pro,$(QT_PROJECTS), $(eval $(call qt_project_template,$(pro))))
-$(foreach pro,$(foreach dir,$(QT_SUBDIRS), $(wildcard $(dir)/*.pro)), $(eval $(call qt_project_template,$(pro))))
-
+clean-local: clean-qt
+clean-qt:
+ +@$(foreach dir, $(QT_SUBDIRS), \
+ $(if $(wildcard $(SOURCES_DIR)/$(dir)/Makefile), \
+ @$(QUIET_CMD_ECHO) " CLEAN $(dir)"; \
+ $(MAKE) SOURCES_DIR=$(SOURCES_DIR)/$(dir) \
+ RELATIVE_DIR=$(RELATIVE_PREFIX)$(dir) -C $(SOURCES_DIR)/$(dir) \
+ -f $(SOURCES_DIR)/$(dir)/Makefile clean|| exit 1 ;))
+
+
+# Hook to distclean
+distclean: distclean-qt
+
+# TODO: Add distclean-qt-pass to handle QT_SUBDIRS in the whole
+# tree. This way we only distclean toplevel subdirs.
+distclean-qt:
+ +@$(foreach dir, $(QT_SUBDIRS), \
+ $(if $(wildcard $(SOURCES_DIR)/$(dir)/Makefile), \
+ @$(QUIET_CMD_ECHO) " DISTCLEAN $(dir)"; \
+ $(MAKE) SOURCES_DIR=$(SOURCES_DIR)/$(dir) \
+ RELATIVE_DIR=$(RELATIVE_PREFIX)$(dir) -C $(SOURCES_DIR)/$(dir) \
+ -f $(SOURCES_DIR)/$(dir)/Makefile distclean|| exit 1 ;))
endif