# ==========================================================================
# Support for building klibc programs and klibc library
# ==========================================================================
#
# To create a kbuild file for a userspace program do the following:
#
# Kbuild:
#
# static-y := cat
# # This will compile a file named cat.c -> the executable 'cat'
# # The executable will be linked statically
#
# shared-y := cats
# # This will compile a file named cats.c -> the executable 'cats'
# # The executable will be linked shared
#
# If the userspace program consist of composite files do the following:
# Kbuild:
#
# static-y := kinit
# kinit-y  := main.o netdev.c
# So kinit will be linked statically using the two .o files
# specified with kinit-y.
#
# Are part of the program located in a sub-directory do like this:
# kinit-y += ipconfig/
#
# And in the subdirectory:
# ipconfig/Kbuild:
# lib-y := packet.o dhcp_proto.o
# # All .o files listed with lib-y will be used to create a single .a file.
# # The .a file is created before any subdirectories are visited so it
# # may be used in the sub-directory programs.
#
#####
# For a klibc libary file do like this
# klibc/Kbuild
# klib-y := error.o pipe.o zlib/
#
#####
# Handling of compiler/linker options
#
# To set directory wide CFLAGS use:
# EXTRA_KLIBCCFLAGS := -DDEBUG
# To set directory wide AFLAGS use:
# EXTRA_KLIBCAFLAGS := -DDEBUG
#
# To set target specific CFLAGS (for .c files) use
# KLIBCCFLAGS-main.o := -DDEBUG=3
# To set target specific AFLAGS (for .s files) use
# KLIBCAFLAGS-main.o := -DDEBUG=3

src := $(obj)
# Preset target and make sure it is a ':=' variable
targets :=

.phony: __build
__build:

# Read .config if it exist, otherwise ignore
-include .config

# Generic Kbuild routines
include $(srctree)/scripts/Kbuild.include

# Defines used when compiling early userspace (klibc programs)
# ---------------------------------------------------------------------------

KLIBCREQFLAGS     := $(call cc-option, -fno-stack-protector, )
KLIBCARCHREQFLAGS :=
KLIBCOPTFLAGS     :=
KLIBCWARNFLAGS    := -W -Wall -Wno-sign-compare -Wno-unused-parameter
KLIBCSHAREDFLAGS  :=
KLIBCBITSIZE      :=
KLIBCLDFLAGS      :=
KLIBCCFLAGS       :=

# Arch specific definitions for klibc
include $(KLIBCSRC)/arch/$(KLIBCARCHDIR)/MCONFIG

# include/asm-* architecture
KLIBCASMARCH	  ?= $(KLIBCARCH)

# klibc version
KLIBCMAJOR        := $(shell cut -d. -f1 $(srctree)/usr/klibc/version)
KLIBCMINOR        := $(shell cut -d. -f2 $(srctree)/usr/klibc/version)

# binutils
KLIBCLD          := $(LD)
KLIBCCC          := $(CC)
KLIBCAR          := $(AR)
KLIBCRANLIB      := $(RANLIB)
KLIBCSTRIP       := $(STRIP)
KLIBCNM          := $(NM)
KLIBCOBJCOPY	 := $(OBJCOPY)
KLIBCOBJDUMP	 := $(OBJDUMP)

# klibc include paths
KLIBCCPPFLAGS    := -nostdinc -iwithprefix include \
		    -I$(KLIBCINC)/arch/$(KLIBCARCHDIR)	\
                    -I$(KLIBCINC)/bits$(KLIBCBITSIZE)	\
		    -I$(KLIBCOBJ)/../include		\
                    -I$(KLIBCINC)
# kernel include paths
KLIBCKERNELSRC	 ?= $(srctree)/
KLIBCCPPFLAGS    += -I$(KLIBCKERNELSRC)include		\
                     $(if $(KBUILD_SRC),-I$(KLIBCKERNELOBJ)include2 -I$(KLIBCKERNELOBJ)include -I$(srctree)/include)    \
		     $(KLIBCARCHINCFLAGS)

# klibc definitions
KLIBCDEFS        += -D__KLIBC__=$(KLIBCMAJOR)          \
		    -D__KLIBC_MINOR__=$(KLIBCMINOR)    \
		    -D_BITSIZE=$(KLIBCBITSIZE)
KLIBCCPPFLAGS    += $(KLIBCDEFS)
KLIBCCFLAGS      += $(KLIBCCPPFLAGS) $(KLIBCREQFLAGS) $(KLIBCARCHREQFLAGS)  \
                    $(KLIBCOPTFLAGS) $(KLIBCWARNFLAGS)
KLIBCAFLAGS      += -D__ASSEMBLY__ $(KLIBCCFLAGS)
KLIBCSTRIPFLAGS  += --strip-all -R .comment -R .note

KLIBCLIBGCC_DEF  := $(shell $(KLIBCCC) $(KLIBCCFLAGS) --print-libgcc)
KLIBCLIBGCC	 ?= $(KLIBCLIBGCC_DEF)
KLIBCCRT0        := $(KLIBCOBJ)/arch/$(KLIBCARCHDIR)/crt0.o
KLIBCLIBC        := $(KLIBCOBJ)/libc.a
KLIBCCRTSHARED   := $(KLIBCOBJ)/interp.o
KLIBCLIBCSHARED  := $(KLIBCOBJ)/libc.so
# How to tell the linker main() is the entrypoint
KLIBCEMAIN	 ?= -e main

#
# This indicates the location of the final version of the shared library.
# THIS MUST BE AN ABSOLUTE PATH WITH NO FINAL SLASH.
# Leave this empty to make it the root.
#
SHLIBDIR = /lib

export KLIBCLD KLIBCCC KLIBCAR KLIBCSTRIP KLIBCNM
export KLIBCCFLAGS KLIBCAFLAGS KLIBCLIBGCC KLIBCSHAREDFLAGS KLIBCSTRIPFLAGS
export KLIBCCRT0 KLIBCLIBC SHLIBDIR

# kernel configuration
include .config

# Add $(obj)/ for paths that is not absolute
objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))

# Kbuild file in the directory that is being build
include $(obj)/Kbuild

#####
# static-y + shared-y handling
kprogs := $(static-y) $(shared-y)
# kprogs based on a single .o file (with same name + .o)
kprog-objs := $(foreach p, $(kprogs), $(if $($(p)-y),,$(p)))
kprog-objs := $(addsuffix .o, $(kprog-objs))
# kprogs which is based on several .o files
kprog-multi := $(foreach p, $(kprogs), $(if $($(p)-y),$(p)))
# objects used for kprogs with more then one .o file
kprog-objs += $(foreach p, $(kprog-multi), $($(p)-y))
# objects build in this dir
kprog-real-objs := $(patsubst %/,,$(kprog-objs))
# Directories we need to visit before kprogs-objs are up-to-date
kprog-dirs :=  $(patsubst %/,%,$(filter %/, $(kprog-objs)))
# replace all dir/ with dir/lib.a
kprog-objs := $(patsubst %/, %/lib.a, $(kprog-objs))

targets += $(static-y) $(shared-y)

#####
# klib-y handling
# .o files to build in this dir
klib-real-objs := $(patsubst %/,,$(klib-y))
# Directories we need to visit before libs are up-to-date
klib-dirs := $(patsubst %/,%,$(filter %/, $(klib-y)))
# replace all dir/ with dir/klib.list
klib-objs := $(patsubst %/, %/klib.list, $(klib-y))

# $(output-dirs) are a list of directories that contain object files
output-dirs := $(dir $(kprog-dirs) $(kprog-objs))
output-dirs += $(foreach f, $(hostprogs-y) $(targets), \
               $(if $(dir $(f)), $(dir $(f))))
output-dirs += $(dir $(klib-objs))
output-dirs := $(strip $(sort $(filter-out ./,$(output-dirs))))

# prefix so we get full dir
static-y        := $(addprefix $(obj)/,$(static-y))
shared-y        := $(addprefix $(obj)/,$(shared-y))
kprog-objs      := $(addprefix $(obj)/,$(kprog-objs))
kprog-real-objs := $(addprefix $(obj)/,$(kprog-real-objs))
output-dirs     := $(addprefix $(obj)/,$(output-dirs))
kprog-dirs      := $(addprefix $(obj)/,$(kprog-dirs))
subdir-y        := $(addprefix $(obj)/,$(subdir-y))
always          := $(addprefix $(obj)/,$(always))
targets         := $(addprefix $(obj)/,$(targets))
lib-y           := $(addprefix $(obj)/,$(lib-y))
klib-y          := $(addprefix $(obj)/,$(klib-y))
klib-objs       := $(addprefix $(obj)/,$(klib-objs))
klib-real-objs  := $(addprefix $(obj)/,$(klib-real-objs))
klib-dirs       := $(addprefix $(obj)/,$(klib-dirs))

#####
# Handle options to gcc. Support building with separate output directory

__klibccflags    = $(KLIBCCFLAGS) $(EXTRA_KLIBCCFLAGS) $(KLIBCCFLAGS_$(*F).o)
__klibcaflags    = $(KLIBCAFLAGS) $(EXTRA_KLIBCAFLAGS) $(KLIBCAFLAGS_$(*F).o)

ifeq ($(KBUILD_SRC),)
_klibccflags    = $(__klibccflags)
_klibcaflags    = $(__klibcaflags)
else
_klibccflags    = $(call flags,__klibccflags)
_klibcaflags    = $(call flags,__klibcaflags)
endif

klibccflags     = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(_klibccflags)
klibcaflags     = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(_klibcaflags)

# Create output directory if not already present
_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))

# Create directories for object files if directory does not exist
# Needed when lib-y := dir/file.o syntax is used
_dummy := $(foreach d,$(output-dirs), $(shell [ -d $(d) ] || mkdir -p $(d)))

# Do we have to make a lib.a in this dir?
ifneq ($(strip $(lib-y) $(lib-n) $(lib-)),)
lib-target := $(obj)/lib.a
endif

__build: $(subdir-y) $(lib-target) $(always)
	$(Q):

# Compile C sources (.c)
# ---------------------------------------------------------------------------

quiet_cmd_cc_s_c = KLIBCCC $@
      cmd_cc_s_c = $(KLIBCCC) $(klibccflags) -S -o $@ $<

%.s: %.c FORCE
	$(call if_changed_dep,cc_s_c)

quiet_cmd_cc_o_c = KLIBCCC $@
      cmd_cc_o_c = $(KLIBCCC) $(klibccflags) -c -o $@ $<

%.o: %.c FORCE
	$(call if_changed_dep,cc_o_c)

quiet_cmd_cc_i_c = CPP     $@
      cmd_cc_i_c = $(KLIBCCC) -E $(klibccflags) -o $@ $<
%.i: %.c FORCE
	$(call if_changed_dep,cc_i_c)

# Compile assembler sources (.S)
# ---------------------------------------------------------------------------

quiet_cmd_as_o_S = KLIBCAS $@
      cmd_as_o_S = $(KLIBCCC) $(klibcaflags) -c -o $@ $<

%.o: %.S FORCE
	$(call if_changed_dep,as_o_S)

targets += $(real-objs-y)

#
# Rule to compile a set of .o files into one .o file
#
ifdef lib-target
quiet_cmd_link_o_target = LD      $@
# If the list of objects to link is empty, just create an empty lib.a
cmd_link_o_target = $(if $(strip $(lib-y)),\
                    rm -f $@; $(KLIBCAR) cru $@ $(filter $(lib-y), $^),\
                    rm -f $@; $(KLIBCAR) crs $@)

$(lib-target): $(lib-y) FORCE
	$(call if_changed,link_o_target)
targets += $(lib-target) $(lib-y)
endif # lib-target

#
# Create klib.list
#
# Do we have to create a klibc library file in this dir?
ifneq ($(strip $(klib-y) $(klib-n) $(klib-)),)
klib-target := $(obj)/klib.list
endif

ifdef klib-target
# include this in build
__build: $(klib-target) $(klib-dirs)

# descend if needed
$(sort $(addsuffix /klib.list,$(klib-dirs))): $(klib-dirs) ;

# create klib.list
quiet_cmd_klib-list = LIST    $@
      cmd_klib-list = echo $(klib-real-objs) > $@
$(klib-target): $(klib-objs) FORCE
	$(call if_changed,klib-list)
targets += $(klib-target) $(klib-real-objs)
endif # klib-target

ifdef kprogs
# Compile klibc-programs for the target
# ===========================================================================

__build : $(kprog-dirs) $(static-y) $(shared-y)

# Descend if needed
$(sort $(addsuffix /lib.a,$(kprog-dirs))): $(kprog-dirs) ;

# Define dependencies for link of progs
# For the simple program:
#	file.o => file
# A program with multiple objects
#	filea.o, fileb.o => file
# A program with .o files in another dir
#	dir/lib.a filea.o => file

stripobj  = $(subst $(obj)/,,$@)
addliba   = $(addprefix $(obj)/, $(patsubst %/, %/lib.a, $(1)))
link-deps = $(if $($(stripobj)-y), $(call addliba, $($(stripobj)-y)), $@.o) \
	    $(call objectify,$($(stripobj)-lib))

quiet_cmd_ld-static = KLIBCLD $@
      cmd_ld-static = $(KLIBCLD) $(KLIBCLDFLAGS) -o $@		\
                       $(EXTRA_KLIBCLDFLAGS)			\
                       $(KLIBCCRT0)				\
		       --start-group				\
                       $(link-deps)				\
                       $(KLIBCLIBC)				\
		       $(KLIBCLIBGCC)				\
		       --end-group ;				\
                      cp -f $@ $@.g ;				\
                      $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $@


$(static-y): $(kprog-objs) $(lib-target) $(KLIBCCRT0) $(KLIBCLIBC) FORCE
	$(call if_changed,ld-static)

quiet_cmd_ld-shared = KLIBCLD $@
      cmd_ld-shared = $(KLIBCLD) $(KLIBCLDFLAGS) -o $@		\
                       $(EXTRA_KLIBCLDFLAGS)			\
                       $(KLIBCEMAIN) $(KLIBCCRTSHARED)		\
                       --start-group				\
                       $(link-deps)				\
                       -R $(KLIBCLIBCSHARED)			\
	               $(KLIBCLIBGCC)				\
		       --end-group ;				\
                      cp -f $@ $@.g ;				\
                      $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $@


$(shared-y): $(kprog-objs) $(lib-target) $(KLIBCCRTSHARED) \
                                         $(KLIBCLIBCSHARED) FORCE
	$(call if_changed,ld-shared)

# Do not try to build KLIBC libaries if we are building klibc
ifeq ($(klibc-build),)
$(KLIBCCRT0) $(KLIBCLIBC): ;
$(KLIBCCRTSHARED) $(KLIBCLIBCSHARED): ;
endif

targets += $(kprog-real-objs)
endif

# Compile programs on the host
# ===========================================================================
ifdef hostprogs-y
include $(srctree)/scripts/Makefile.host
endif

# Descending
# ---------------------------------------------------------------------------

.PHONY: $(subdir-y) $(kprog-dirs) $(klib-dirs)
$(sort $(subdir-y) $(kprog-dirs) $(klib-dirs)): $(lib-target)
	$(Q)$(MAKE) $(klibc)=$@

# Add FORCE to the prequisites of a target to force it to be always rebuilt.
# ---------------------------------------------------------------------------

.PHONY: FORCE

FORCE:

# Linking
# Create a reloctable composite object file
# ---------------------------------------------------------------------------
quiet_cmd_klibcld = KLIBCLD $@
      cmd_klibcld = $(KLIBCLD) -r $(KLIBCLDFLAGS) \
                                $(EXTRA_KLIBCLDFLAGS) $(KLIBCLDFLAGS_$(@F)) \
                                $(filter-out FORCE,$^) -o $@


# Link target to a new name
# ---------------------------------------------------------------------------
quiet_cmd_ln = LN      $@
      cmd_ln = rm -f $@ && ln $< $@

# Strip target (remove all debugging info)
quiet_cmd_strip = STRIP   $@
      cmd_strip = $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $< -o $@


# 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

# Shorthand for $(Q)$(MAKE) -f scripts/Kbuild.klibc obj
# Usage:
# $(Q)$(MAKE) $(klibc)=dir
klibc := -rR -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Kbuild.klibc obj
