# where py object files go (they have a name prefix to prevent filename clashes)
PY_BUILD = $(BUILD)/py

# where autogenerated header files go
HEADER_BUILD = $(BUILD)/genhdr

# file containing qstr defs for the core Python bit
PY_QSTR_DEFS = $(PY_SRC)/qstrdefs.h

# If qstr autogeneration is not disabled we specify the output header
# for all collected qstrings.
ifneq ($(QSTR_AUTOGEN_DISABLE),1)
QSTR_DEFS_COLLECTED = $(HEADER_BUILD)/qstrdefs.collected.h
endif

# Any files listed by these variables will cause a full regeneration of qstrs
# DEPENDENCIES: included in qstr processing; REQUIREMENTS: not included
QSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h
QSTR_GLOBAL_REQUIREMENTS += $(HEADER_BUILD)/mpversion.h

# some code is performance bottleneck and compiled with other optimization options
CSUPEROPT = -O3

# External modules written in C.

# Process manifest for C module extraction (appends to USER_C_MODULES).
include $(TOP)/py/manifest.mk

ifneq ($(USER_C_MODULES),)
# pre-define USERMOD variables as expanded so that variables are immediate
# expanded as they're added to them

# C/C++ files that are included in the QSTR/module build
SRC_USERMOD_C :=
SRC_USERMOD_CXX :=
# Other C/C++/Assembly files (e.g. libraries or helpers)
SRC_USERMOD_LIB_C :=
SRC_USERMOD_LIB_CXX :=
SRC_USERMOD_LIB_ASM :=
# Optionally set flags
CFLAGS_USERMOD :=
CXXFLAGS_USERMOD :=
LDFLAGS_USERMOD :=
LIBS_USERMOD :=

# Backwards compatibility with older user c modules that set SRC_USERMOD
# added to SRC_USERMOD_C below
SRC_USERMOD :=

# For each C module directory, scan for micropython.mk and include it.
# Accumulate USERMOD_DIRS so we can later strip each module's parent path
# from its source files while preserving the module basename in the build
# tree (e.g. build/cexample/foo.o, not build/foo.o, so files that share a
# name across modules don't collide on the same .o target).
USERMOD_DIRS :=
$(foreach _UDIR, $(USER_C_MODULES), \
    $(if $(wildcard $(_UDIR)/.),,$(error USER_C_MODULES path doesn't exist: $(abspath $(_UDIR)))) \
    $(foreach module, $(wildcard $(_UDIR)/micropython.mk) $(wildcard $(_UDIR)/*/micropython.mk), \
        $(eval USERMOD_DIR = $(patsubst %/,%,$(dir $(module))))\
        $(eval USERMOD_DIRS += $(USERMOD_DIR))\
        $(info Including User C Module from $(USERMOD_DIR))\
        $(eval include $(module))\
    )\
)

SRC_USERMOD_C += $(SRC_USERMOD)

# Strip each USERMOD_DIR's leading path from source files, keeping the module
# basename as the leading directory so build outputs land at
# BUILD/<module>/<file>.o. Uses per-directory patsubst on the paths as-is
# rather than $(abspath) so a parent directory containing whitespace doesn't
# break word-based patsubst.
SRC_USERMOD_PATHFIX_C := $(SRC_USERMOD_C)
SRC_USERMOD_PATHFIX_CXX := $(SRC_USERMOD_CXX)
SRC_USERMOD_PATHFIX_LIB_C := $(SRC_USERMOD_LIB_C)
SRC_USERMOD_PATHFIX_LIB_CXX := $(SRC_USERMOD_LIB_CXX)
SRC_USERMOD_PATHFIX_LIB_ASM := $(SRC_USERMOD_LIB_ASM)
USERMOD_DIRS := $(sort $(USERMOD_DIRS))
$(foreach _MDIR, $(USERMOD_DIRS), \
    $(eval _MBASE := $(notdir $(_MDIR))) \
    $(eval SRC_USERMOD_PATHFIX_C := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_C))) \
    $(eval SRC_USERMOD_PATHFIX_CXX := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_CXX))) \
    $(eval SRC_USERMOD_PATHFIX_LIB_C := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_LIB_C))) \
    $(eval SRC_USERMOD_PATHFIX_LIB_CXX := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_LIB_CXX))) \
    $(eval SRC_USERMOD_PATHFIX_LIB_ASM := $$(patsubst $(_MDIR)/%,$(_MBASE)/%,$$(SRC_USERMOD_PATHFIX_LIB_ASM))) \
)

# Parent directories of each USERMOD_DIR, added to vpath below so paths like
# cexample/foo.c (produced by the patsubst above) resolve to source files.
USERMOD_DIR_PARENTS := $(sort $(foreach _MDIR, $(USERMOD_DIRS), $(patsubst %/,%,$(dir $(_MDIR)))))

CFLAGS += $(CFLAGS_USERMOD)
CXXFLAGS += $(CXXFLAGS_USERMOD)
LDFLAGS += $(LDFLAGS_USERMOD)
LIBS += $(LIBS_USERMOD)

SRC_QSTR += $(SRC_USERMOD_PATHFIX_C) $(SRC_USERMOD_PATHFIX_CXX)
PY_O += $(addprefix $(BUILD)/, $(SRC_USERMOD_PATHFIX_C:.c=.o))
PY_O += $(addprefix $(BUILD)/, $(SRC_USERMOD_PATHFIX_CXX:.cpp=.o))
PY_O += $(addprefix $(BUILD)/, $(SRC_USERMOD_PATHFIX_LIB_C:.c=.o))
PY_O += $(addprefix $(BUILD)/, $(SRC_USERMOD_PATHFIX_LIB_CXX:.cpp=.o))
PY_O += $(addprefix $(BUILD)/, $(SRC_USERMOD_PATHFIX_LIB_ASM:.S=.o))
endif

# py object files
PY_CORE_O_BASENAME = $(addprefix py/,\
	mpstate.o \
	nlr.o \
	nlrx86.o \
	nlrx64.o \
	nlrthumb.o \
	nlraarch64.o \
	nlrmips.o \
	nlrpowerpc.o \
	nlrxtensa.o \
	nlrrv32.o \
	nlrrv64.o \
	nlrloong64.o \
	nlrsetjmp.o \
	malloc.o \
	gc.o \
	pystack.o \
	qstr.o \
	vstr.o \
	mpprint.o \
	unicode.o \
	mpz.o \
	reader.o \
	lexer.o \
	parse.o \
	scope.o \
	compile.o \
	emitcommon.o \
	emitbc.o \
	asmbase.o \
	asmx64.o \
	emitnx64.o \
	asmx86.o \
	emitnx86.o \
	asmthumb.o \
	emitnthumb.o \
	emitinlinethumb.o \
	asmarm.o \
	emitnarm.o \
	asmxtensa.o \
	emitnxtensa.o \
	emitinlinextensa.o \
	emitnxtensawin.o \
	asmrv32.o \
	emitnrv32.o \
	emitinlinerv32.o \
	emitndebug.o \
	formatfloat.o \
	parsenumbase.o \
	parsenum.o \
	emitglue.o \
	persistentcode.o \
	runtime.o \
	runtime_utils.o \
	scheduler.o \
	nativeglue.o \
	pairheap.o \
	ringbuf.o \
	cstack.o \
	stackctrl.o \
	argcheck.o \
	warning.o \
	profile.o \
	map.o \
	obj.o \
	objarray.o \
	objattrtuple.o \
	objbool.o \
	objboundmeth.o \
	objcell.o \
	objclosure.o \
	objcode.o \
	objcomplex.o \
	objdeque.o \
	objdict.o \
	objenumerate.o \
	objexcept.o \
	objfilter.o \
	objfloat.o \
	objfun.o \
	objgenerator.o \
	objgetitemiter.o \
	objint.o \
	objint_longlong.o \
	objint_mpz.o \
	objlist.o \
	objmap.o \
	objmodule.o \
	objobject.o \
	objpolyiter.o \
	objproperty.o \
	objnone.o \
	objnamedtuple.o \
	objrange.o \
	objreversed.o \
	objringio.o \
	objset.o \
	objsingleton.o \
	objslice.o \
	objstr.o \
	objstrunicode.o \
	objstringio.o \
	objtemplate.o \
	objtuple.o \
	objtype.o \
	objzip.o \
	opmethods.o \
	sequence.o \
	stream.o \
	binary.o \
	builtinimport.o \
	builtinevex.o \
	builtinhelp.o \
	modarray.o \
	modbuiltins.o \
	modcollections.o \
	modgc.o \
	modio.o \
	modmath.o \
	modcmath.o \
	modmicropython.o \
	modstring.o \
	modstruct.o \
	modsys.o \
	moderrno.o \
	modthread.o \
	modweakref.o \
	vm.o \
	bc.o \
	showbc.o \
	repl.o \
	smallint.o \
	frozenmod.o \
	)

# prepend the build destination prefix to the py object files
PY_CORE_O = $(addprefix $(BUILD)/, $(PY_CORE_O_BASENAME))

# this is a convenience variable for ports that want core, extmod and frozen code
PY_O += $(PY_CORE_O)

# object file for frozen code specified via a manifest
ifneq ($(FROZEN_MANIFEST),)
PY_O += $(BUILD)/frozen_content.o
endif

# Sources that may contain qstrings
SRC_QSTR_IGNORE = py/nlr%
SRC_QSTR += $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c))

# Anything that depends on FORCE will be considered out-of-date
FORCE:
.PHONY: FORCE

$(HEADER_BUILD)/mpversion.h: FORCE | $(HEADER_BUILD)
	$(Q)$(PYTHON) $(PY_SRC)/makeversionhdr.py $@

# mpconfigport.mk is optional, but changes to it may drastically change
# overall config, so they need to be caught
MPCONFIGPORT_MK = $(wildcard mpconfigport.mk)

# qstr data
# Adding an order only dependency on $(HEADER_BUILD) causes $(HEADER_BUILD) to get
# created before we run the script to generate the .h
# Note: we need to protect the qstr names from the preprocessor, so we wrap
# the lines in "" and then unwrap after the preprocessor is finished.
# See more information about this process in docs/develop/qstr.rst.
$(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) $(PY_SRC)/makeqstrdata.py mpconfigport.h $(MPCONFIGPORT_MK) $(PY_SRC)/mpconfig.h | $(HEADER_BUILD)
	$(ECHO) "GEN $@"
	$(Q)$(CAT) $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_COLLECTED) | $(SED) 's/^Q(.*)/"&"/' | $(CPP) $(CFLAGS) - | $(SED) 's/^\"\(Q(.*)\)\"/\1/' > $(HEADER_BUILD)/qstrdefs.preprocessed.h
	$(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@

$(HEADER_BUILD)/compressed.data.h: $(HEADER_BUILD)/compressed.collected
	$(ECHO) "GEN $@"
	$(Q)$(PYTHON) $(PY_SRC)/makecompresseddata.py $< > $@

# build a list of registered modules for py/objmodule.c.
$(HEADER_BUILD)/moduledefs.h: $(HEADER_BUILD)/moduledefs.collected $(PY_SRC)/makemoduledefs.py
	@$(ECHO) "GEN $@"
	$(Q)$(PYTHON) $(PY_SRC)/makemoduledefs.py $< > $@

# build a list of registered root pointers for py/mpstate.h.
$(HEADER_BUILD)/root_pointers.h: $(HEADER_BUILD)/root_pointers.collected $(PY_SRC)/make_root_pointers.py
	@$(ECHO) "GEN $@"
	$(Q)$(PYTHON) $(PY_SRC)/make_root_pointers.py $< > $@

# Standard C functions like memset need to be compiled with special flags so
# the compiler does not optimise these functions in terms of themselves.
CFLAGS_BUILTIN ?= -ffreestanding -fno-builtin -fno-lto
$(BUILD)/shared/libc/string0.o: CFLAGS += $(CFLAGS_BUILTIN)

# Force nlr code to always be compiled with space-saving optimisation so
# that the function preludes are of a minimal and predictable form.
$(PY_BUILD)/nlr%.o: CFLAGS += -Os

# optimising gc for speed; 5ms down to 4ms on pybv2
$(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT)

# optimising vm for speed, adds only a small amount to code size but makes a huge difference to speed (20% faster)
$(PY_BUILD)/vm.o: CFLAGS += $(CSUPEROPT)
# Optimizing vm.o for modern deeply pipelined CPUs with branch predictors
# may require disabling tail jump optimization. This will make sure that
# each opcode has its own dispatching jump which will improve branch
# branch predictor efficiency.
# https://marc.info/?l=lua-l&m=129778596120851
# http://hg.python.org/cpython/file/b127046831e2/Python/ceval.c#l828
# http://www.emulators.com/docs/nx25_nostradamus.htm
#-fno-crossjumping
