[make] add feature to allow multiple parallel build dirs

Using environment variables LKROOT and LKINC you can specify multiple
parallel top level directories (outside of the lk root) that are overlayed
on top of the build system. This allows for a structure like

lk/
testproject/
someotherfirmware/

Where each of these subdirs has an entire overlayed tree of libraries, platforms,
targets, and projects.

To accomplish this, copy makefile into the root dir and build a lk_inc.mk that
sets LKROOT and LKINC.
This commit is contained in:
Travis Geiselbrecht
2013-03-12 03:12:24 -07:00
parent 4b63f75ff3
commit eaa673169e
4 changed files with 239 additions and 199 deletions

226
engine.mk Normal file
View File

@@ -0,0 +1,226 @@
LOCAL_MAKEFILE:=$(MAKEFILE_LIST)
ifeq ($(MAKECMDGOALS),spotless)
spotless:
rm -rf build-*
else
ifndef LKROOT
$(error please define LKROOT to the root of the lk build system)
endif
-include local.mk
include make/macros.mk
# If one of our goals (from the commandline) happens to have a
# matching project/goal.mk, then we should re-invoke make with
# that project name specified...
project-name := $(firstword $(MAKECMDGOALS))
ifneq ($(project-name),)
ifneq ($(strip $(foreach d,$(LKINC),$(wildcard $(d)/project/$(project-name).mk))),)
do-nothing := 1
$(MAKECMDGOALS) _all: make-make
make-make:
@PROJECT=$(project-name) $(MAKE) -rR -f $(LOCAL_MAKEFILE) $(filter-out $(project-name), $(MAKECMDGOALS))
.PHONY: make-make
endif
endif
ifeq ($(do-nothing),)
ifeq ($(PROJECT),)
$(error No project specified. Use "make projectname" or put "PROJECT := projectname" in local.mk)
endif
DEBUG ?= 2
BUILDROOT ?= .
BUILDDIR := $(BUILDROOT)/build-$(PROJECT)
OUTBIN := $(BUILDDIR)/lk.bin
OUTELF := $(BUILDDIR)/lk.elf
CONFIGHEADER := $(BUILDDIR)/config.h
INCLUDES := -I$(BUILDDIR) -I$(LKROOT)/include $(addsuffix /include,$(addprefix -I,$(LKINC)))
GLOBAL_OPTFLAGS ?= -Os
GLOBAL_COMPILEFLAGS := -g -fno-builtin -finline -W -Wall -Wno-multichar -Wno-unused-parameter -Wno-unused-function -include $(CONFIGHEADER)
GLOBAL_CFLAGS := --std=gnu99 -Werror-implicit-function-declaration
#GLOBAL_CFLAGS += -Werror
GLOBAL_CPPFLAGS := -fno-exceptions -fno-rtti -fno-threadsafe-statics
#GLOBAL_CPPFLAGS += -Weffc++
GLOBAL_ASMFLAGS := -DASSEMBLY
GLOBAL_LDFLAGS :=
GLOBAL_COMPILEFLAGS += -ffunction-sections -fdata-sections
GLOBAL_LDFLAGS += --gc-sections
# top level rule
all:: $(OUTBIN) $(OUTELF).lst $(OUTELF).debug.lst $(OUTELF).sym $(OUTELF).size $(OUTELF).hex
# master module object list
ALLOBJS_MODULE :=
# master object list (for dep generation)
ALLOBJS :=
# a linker script needs to be declared in one of the project/target/platform files
LINKER_SCRIPT :=
# anything you add here will be deleted in make clean
GENERATED := $(CONFIGHEADER)
# anything added to DEFINES will be put into $(BUILDDIR)/config.h
DEFINES := LK=1
# Anything added to SRCDEPS will become a dependency of every source file in the system.
# Useful for header files that may be included by one or more source files.
SRCDEPS := $(CONFIGHEADER)
# these need to be filled out by the project/target/platform rules.mk files
TARGET :=
PLATFORM :=
ARCH :=
ALLMODULES :=
# add any external module dependencies
MODULES := $(EXTERNAL_MODULES)
# any rules you put here will also be built by the system before considered being complete
EXTRA_BUILDDEPS :=
# any rules you put here will be depended on in clean builds
EXTRA_CLEANDEPS :=
# any objects you put here get linked with the final image
EXTRA_OBJS :=
# if someone defines this, the build id will be pulled into lib/version
BUILDID ?=
# try to include the project file
-include project/$(PROJECT).mk
ifndef TARGET
$(error couldn't find project or project doesn't define target)
endif
include target/$(TARGET)/rules.mk
ifndef PLATFORM
$(error couldn't find target or target doesn't define platform)
endif
include platform/$(PLATFORM)/rules.mk
$(info PROJECT = $(PROJECT))
$(info PLATFORM = $(PLATFORM))
$(info TARGET = $(TARGET))
include arch/$(ARCH)/rules.mk
include platform/rules.mk
include target/rules.mk
include kernel/rules.mk
include dev/rules.mk
include app/rules.mk
# recursively include any modules in the MODULE variable, leaving a trail of included
# modules in the ALLMODULES list
include make/recurse.mk
# any extra top level build dependencies that someone declared
all:: $(EXTRA_BUILDDEPS)
# add some automatic configuration defines
DEFINES += \
PROJECT_$(PROJECT)=1 \
PROJECT=\"$(PROJECT)\" \
TARGET_$(TARGET)=1 \
TARGET=\"$(TARGET)\" \
PLATFORM_$(PLATFORM)=1 \
PLATFORM=\"$(PLATFORM)\" \
ARCH_$(ARCH)=1 \
ARCH=\"$(ARCH)\" \
$(addsuffix =1,$(addprefix WITH_,$(ALLMODULES)))
# debug build?
ifneq ($(DEBUG),)
DEFINES += \
DEBUG=$(DEBUG)
endif
# allow additional defines from outside the build system
ifneq ($(EXTERNAL_DEFINES),)
DEFINES += $(EXTERNAL_DEFINES)
$(info EXTERNAL_DEFINES = $(EXTERNAL_DEFINES))
endif
DEPS := $(ALLOBJS:%o=%d)
#$(warning DEPS=$(DEPS))
# default to no ccache
CCACHE ?=
CC := $(CCACHE) $(TOOLCHAIN_PREFIX)gcc
LD := $(TOOLCHAIN_PREFIX)ld
OBJDUMP := $(TOOLCHAIN_PREFIX)objdump
OBJCOPY := $(TOOLCHAIN_PREFIX)objcopy
CPPFILT := $(TOOLCHAIN_PREFIX)c++filt
SIZE := $(TOOLCHAIN_PREFIX)size
NM := $(TOOLCHAIN_PREFIX)nm
# put all of the global build flags in config.h to force a rebuild if any change
DEFINES += INCLUDES=\"$(subst $(SPACE),_,$(INCLUDES))\"
DEFINES += GLOBAL_COMPILEFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_COMPILEFLAGS))\"
DEFINES += GLOBAL_OPTFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_OPTFLAGS))\"
DEFINES += GLOBAL_CFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_CFLAGS))\"
DEFINES += GLOBAL_CPPFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_CPPFLAGS))\"
DEFINES += GLOBAL_ASMFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_ASMFLAGS))\"
DEFINES += GLOBAL_LDFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_LDFLAGS))\"
# comment out or override if you want to see the full output of each command
NOECHO ?= @
#$(warning ALLMODULE_OBJS=$(ALLMODULE_OBJS))
ifneq ($(OBJS),)
$(warning OBJS=$(OBJS))
$(error OBJS is not empty, please convert to new module format)
endif
ifneq ($(OPTFLAGS),)
$(warning OPTFLAGS=$(OPTFLAGS))
$(error OPTFLAGS is not empty, please use GLOBAL_OPTFLAGS or MODULE_OPTFLAGS)
endif
ifneq ($(CFLAGS),)
$(warning CFLAGS=$(CFLAGS))
$(error CFLAGS is not empty, please use GLOBAL_CFLAGS or MODULE_CFLAGS)
endif
ifneq ($(CPPFLAGS),)
$(warning CPPFLAGS=$(CPPFLAGS))
$(error CPPFLAGS is not empty, please use GLOBAL_CPPFLAGS or MODULE_CPPFLAGS)
endif
# the logic to compile and link stuff is in here
include make/build.mk
clean: $(EXTRA_CLEANDEPS)
rm -f $(ALLOBJS) $(DEPS) $(GENERATED) $(OUTBIN) $(OUTELF) $(OUTELF).lst $(OUTELF).debug.lst $(OUTELF).sym $(OUTELF).size $(OUTELF).hex
install: all
scp $(OUTBIN) 192.168.0.4:/tftproot
# generate a config.h file with all of the DEFINES laid out in #define format
configheader:
$(CONFIGHEADER): configheader
$(call MAKECONFIGHEADER,$@,DEFINES)
# Empty rule for the .d files. The above rules will build .d files as a side
# effect. Only works on gcc 3.x and above, however.
%.d:
ifeq ($(filter $(MAKECMDGOALS), clean), )
-include $(DEPS)
endif
.PHONY: configheader
endif
endif # make spotless

View File

@@ -12,7 +12,7 @@ $(OUTELF).hex: $(OUTELF)
$(OUTELF): $(ALLMODULE_OBJS) $(EXTRA_OBJS) $(LINKER_SCRIPT)
@echo linking $@
$(NOECHO)$(SIZE) -t $(ALLMODULE_OBJS)
$(NOECHO)$(SIZE) -t --common $(sort $(ALLMODULE_OBJS))
$(NOECHO)$(LD) $(GLOBAL_LDFLAGS) -T $(LINKER_SCRIPT) $(ALLMODULE_OBJS) $(EXTRA_OBJS) $(LIBGCC) -o $@
$(OUTELF).sym: $(OUTELF)

View File

@@ -20,7 +20,7 @@ define MAKECONFIGHEADER
echo \#ifndef __$${LDEF}_H > $1.tmp; \
echo \#define __$${LDEF}_H >> $1.tmp; \
for d in `echo $($2) | tr '[:lower:]' '[:upper:]'`; do \
echo "#define $$d" | sed "s/=/\ /g;s/-/_/g;s/\//_/g" >> $1.tmp; \
echo "#define $$d" | sed "s/=/\ /g;s/-/_/g;s/\//_/g;s/\./_/g;s/\//_/g" >> $1.tmp; \
done; \
echo \#endif >> $1.tmp; \
if [ -f "$1" ]; then \

208
makefile
View File

@@ -1,201 +1,15 @@
ifeq ($(MAKECMDGOALS),spotless)
spotless:
rm -rf build-*
else
# the above include may override LKROOT and LKINC to allow external
# directories to be included in the build
-include lk_inc.mk
-include local.mk
include make/macros.mk
LKROOT ?= .
LKINC ?=
# If one of our goals (from the commandline) happens to have a
# matching project/goal.mk, then we should re-invoke make with
# that project name specified...
LKINC := $(LKROOT) $(LKINC)
project-name := $(firstword $(MAKECMDGOALS))
# vaneer makefile that calls into the engine with lk as the build root
# if we're the top level invocation, call ourselves with additional args
$(MAKECMDGOALS) _top:
LKROOT=$(LKROOT) LKINC="$(LKINC)" $(MAKE) -rR -f $(LKROOT)/engine.mk $(addprefix -I,$(LKINC)) $(MAKECMDGOALS)
ifneq ($(project-name),)
ifneq ($(wildcard project/$(project-name).mk),)
do-nothing := 1
$(MAKECMDGOALS) _all: make-make
make-make:
@PROJECT=$(project-name) $(MAKE) $(filter-out $(project-name), $(MAKECMDGOALS))
endif
endif
ifeq ($(do-nothing),)
ifeq ($(PROJECT),)
$(error No project specified. Use "make projectname" or put "PROJECT := projectname" in local.mk)
endif
DEBUG ?= 2
BUILDDIR := build-$(PROJECT)
OUTBIN := $(BUILDDIR)/lk.bin
OUTELF := $(BUILDDIR)/lk
CONFIGHEADER := $(BUILDDIR)/config.h
INCLUDES := -I$(BUILDDIR) -Iinclude
GLOBAL_OPTFLAGS ?= -Os
GLOBAL_COMPILEFLAGS := -g -fno-builtin -finline -W -Wall -Wno-multichar -Wno-unused-parameter -Wno-unused-function -include $(CONFIGHEADER)
GLOBAL_CFLAGS := --std=c99 -Werror-implicit-function-declaration
#GLOBAL_CFLAGS += -Werror
GLOBAL_CPPFLAGS := -fno-exceptions -fno-rtti -fno-threadsafe-statics
#GLOBAL_CPPFLAGS += -Weffc++
GLOBAL_ASMFLAGS := -DASSEMBLY
GLOBAL_LDFLAGS :=
GLOBAL_COMPILEFLAGS += -ffunction-sections -fdata-sections
GLOBAL_LDFLAGS += -gc-sections
# top level rule
all:: $(OUTBIN) $(OUTELF).lst $(OUTELF).debug.lst $(OUTELF).sym $(OUTELF).size $(OUTELF).hex
# master module object list
ALLOBJS_MODULE :=
# master object list (for dep generation)
ALLOBJS :=
# a linker script needs to be declared in one of the project/target/platform files
LINKER_SCRIPT :=
# anything you add here will be deleted in make clean
GENERATED := $(CONFIGHEADER)
# anything added to DEFINES will be put into $(BUILDDIR)/config.h
DEFINES := LK=1
# Anything added to SRCDEPS will become a dependency of every source file in the system.
# Useful for header files that may be included by one or more source files.
SRCDEPS := $(CONFIGHEADER)
# these need to be filled out by the project/target/platform rules.mk files
TARGET :=
PLATFORM :=
ARCH :=
ALLMODULES :=
MODULES :=
# any rules you put here will also be built by the system before considered being complete
EXTRA_BUILDDEPS :=
# any rules you put here will be depended on in clean builds
EXTRA_CLEANDEPS :=
# any objects you put here get linked with the final image
EXTRA_OBJS :=
include project/$(PROJECT).mk
include target/$(TARGET)/rules.mk
include platform/$(PLATFORM)/rules.mk
$(info PROJECT = $(PROJECT))
$(info PLATFORM = $(PLATFORM))
$(info TARGET = $(TARGET))
include arch/$(ARCH)/rules.mk
include platform/rules.mk
include target/rules.mk
include kernel/rules.mk
include dev/rules.mk
include app/rules.mk
# recursively include any modules in the MODULE variable, leaving a trail of included
# modules in the ALLMODULES list
include make/recurse.mk
# any extra top level build dependencies that someone declared
all:: $(EXTRA_BUILDDEPS)
# add some automatic configuration defines
DEFINES += \
PROJECT_$(PROJECT)=1 \
TARGET_$(TARGET)=1 \
PLATFORM_$(PLATFORM)=1 \
ARCH_$(ARCH)=1 \
$(addsuffix =1,$(addprefix WITH_,$(ALLMODULES)))
# debug build?
ifneq ($(DEBUG),)
DEFINES += \
DEBUG=$(DEBUG)
endif
# allow additional defines from outside the build system
ifneq ($(EXTERNAL_DEFINES),)
DEFINES += $(EXTERNAL_DEFINES)
$(info EXTERNAL_DEFINES = $(EXTERNAL_DEFINES))
endif
DEPS := $(ALLOBJS:%o=%d)
#$(warning DEPS=$(DEPS))
# default to no ccache
CCACHE ?=
CC := $(CCACHE) $(TOOLCHAIN_PREFIX)gcc
LD := $(TOOLCHAIN_PREFIX)ld
OBJDUMP := $(TOOLCHAIN_PREFIX)objdump
OBJCOPY := $(TOOLCHAIN_PREFIX)objcopy
CPPFILT := $(TOOLCHAIN_PREFIX)c++filt
SIZE := $(TOOLCHAIN_PREFIX)size
NM := $(TOOLCHAIN_PREFIX)nm
# put all of the global build flags in config.h to force a rebuild if any change
DEFINES += INCLUDES=\"$(subst $(SPACE),_,$(INCLUDES))\"
DEFINES += GLOBAL_COMPILEFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_COMPILEFLAGS))\"
DEFINES += GLOBAL_OPTFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_OPTFLAGS))\"
DEFINES += GLOBAL_CFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_CFLAGS))\"
DEFINES += GLOBAL_CPPFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_CPPFLAGS))\"
DEFINES += GLOBAL_ASMFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_ASMFLAGS))\"
DEFINES += GLOBAL_LDFLAGS=\"$(subst $(SPACE),_,$(GLOBAL_LDFLAGS))\"
# comment out or override if you want to see the full output of each command
NOECHO ?= @
#$(warning ALLMODULE_OBJS=$(ALLMODULE_OBJS))
ifneq ($(OBJS),)
$(warning OBJS=$(OBJS))
$(error OBJS is not empty, please convert to new module format)
endif
ifneq ($(OPTFLAGS),)
$(warning OPTFLAGS=$(OPTFLAGS))
$(error OPTFLAGS is not empty, please use GLOBAL_OPTFLAGS or MODULE_OPTFLAGS)
endif
ifneq ($(CFLAGS),)
$(warning CFLAGS=$(CFLAGS))
$(error CFLAGS is not empty, please use GLOBAL_CFLAGS or MODULE_CFLAGS)
endif
ifneq ($(CPPFLAGS),)
$(warning CPPFLAGS=$(CPPFLAGS))
$(error CPPFLAGS is not empty, please use GLOBAL_CPPFLAGS or MODULE_CPPFLAGS)
endif
# the logic to compile and link stuff is in here
include make/build.mk
clean: $(EXTRA_CLEANDEPS)
rm -f $(ALLOBJS) $(DEPS) $(GENERATED) $(OUTBIN) $(OUTELF) $(OUTELF).lst $(OUTELF).hex
install: all
scp $(OUTBIN) 192.168.0.4:/tftproot
# generate a config.h file with all of the DEFINES laid out in #define format
configheader:
$(CONFIGHEADER): configheader
$(call MAKECONFIGHEADER,$@,DEFINES)
# Empty rule for the .d files. The above rules will build .d files as a side
# effect. Only works on gcc 3.x and above, however.
%.d:
ifeq ($(filter $(MAKECMDGOALS), clean), )
-include $(DEPS)
endif
.PHONY: configheader
endif
endif # make spotless
.PHONY: _top