#!/usr/bin/make -f # # \brief Function implementation creation tool for DDE Linux # \author Stefan Kalkowski # \date 2021-03-11 # help: $(ECHO) "" $(ECHO) "Create function implementation dummies for DDE Linux" $(ECHO) "" $(ECHO) "usage:" $(ECHO) "" $(ECHO) " create_dummies [VARIABLES]" $(ECHO) "" $(ECHO) "--- available commands ---" $(ECHO) "help - shows this help" $(ECHO) "show - shows missing symbols of given TARGET" $(ECHO) "generate - generates DUMMY_FILE for given TARGET" $(ECHO) "" $(ECHO) "--- used variables ---" $(ECHO) "TARGET - denotes the Genode build target" $(ECHO) "BUILD_DIR - optional path to Genode build directory," $(ECHO) " used to build the TARGET" $(ECHO) " (default is the current path)" $(ECHO) "LINUX_KERNEL_DIR - path to the Linux kernel build" $(ECHO) "DUMMY_FILE - path to the file that shall be generated" $(ECHO) "ARCH - is optional, normally it is tried" $(ECHO) " to extract it from BUILD_DIR" $(ECHO) "" COMMAND := $(firstword $(MAKECMDGOALS)) SHELL = bash BRIGHT_COL = \033[01;33m DEFAULT_COL = \033[0m ECHO = @echo -e BUILD_DIR ?= $(PWD) # There are some expensive commands defined underneath, # which shouldn't be executed when calling for help ifneq ($(COMMAND),help) # # Sanity checks # ifeq ($(TARGET),) $(error You have to state a valid build TARGET, try help) endif ## # Return $(2) if $(1) is empty, "" else # check_nonempty_f = $(if $(1),,$(info $(2))$(2)) CTAGS_OK = $(call check_nonempty_f,$(shell which ctags),\ Need to have ctags installed.) TOOLS_OK = $(CTAGS_OK) ifneq ($(strip $(TOOLS_OK)),) $(error Please install missing tools.) endif ifneq ($(realpath $(BUILD_DIR)/etc/specs.conf),) ARCH ?= $(word 3,$(shell grep "SPECS" $(BUILD_DIR)/etc/specs.conf)) endif ifeq ($(ARCH),arm_v6) TOOL_ARCH = arm LX_ARCH = arm else ifeq ($(ARCH),arm_v7a) TOOL_ARCH = arm LX_ARCH = arm else ifeq ($(ARCH),arm_v8a) TOOL_ARCH = aarch64 LX_ARCH = arm64 else ifeq ($(ARCH),x86_32) TOOL_ARCH = x86 LX_ARCH = x86 else ifeq ($(ARCH),x86_64) TOOL_ARCH = x86 LX_ARCH = x86 else $(error ARCH=$(ARCH) is not supported) endif endif endif endif endif # The following eager commands should only be evaluated when generating dummies ifeq ($(COMMAND),generate) ifeq ($(realpath $(LINUX_KERNEL_DIR)),) $(error You have to state a valid LINUX_KERNEL_DIR, try help) endif ifeq ($(DUMMY_FILE),) $(error You have to state a DUMMY_FILE, try help) endif endif # COMMAND=generate # # Prepare object database whenever LINUX_KERNEL_DIR is specified # ifneq ($(realpath $(LINUX_KERNEL_DIR)),) # determine kernel source dir if an out-of-tree build directory is specified LINUX_SRC_DIR := $(LINUX_KERNEL_DIR) ifneq ($(shell grep "^\# Automatically generated by" $(LINUX_KERNEL_DIR)/Makefile),) LINUX_SRC_DIR := $(shell sed -n "/^include/s/.* \(.*\)\/Makefile/\\1/p" $(LINUX_KERNEL_DIR)/Makefile) endif CROSS_DEV_PREFIX ?= /usr/local/genode/tool/current/bin/genode-$(TOOL_ARCH)- # gather list of : pairs, strip first path element (build dir) NM = $(CROSS_DEV_PREFIX)nm --print-file-name --defined-only C_FILE_DEF := $(shell cd $(LINUX_KERNEL_DIR); $(NM) `find -name "*.o" -printf "%P\n" | grep -v vmlinux.o` | grep -i " [tD] " | sed -e 's/o:[0-f]* [tTD] /c:/') # query C_FILE_DEF database for a given symbol symbol_to_c_file = $(addprefix $(LINUX_SRC_DIR)/, $(firstword $(subst :, ,$(filter %:$(1),$(C_FILE_DEF))))) # # Ctags database # HEADER_DECL := $(shell cd $(LINUX_SRC_DIR)/include; ctags -R -x --kinds-c=p --_xformat="%N:%F" .) GLOBAL_VAR := $(shell cd $(LINUX_SRC_DIR)/include; ctags -R -x --kinds-c=x --_xformat="%N:%F" .) func_to_h_file = $(lastword $(subst :, ,$(filter $(1):%,$(HEADER_DECL)))) do_func_to_def = $(subst :, ,$(subst typename:,,$(subst $(1): ,,$(shell ctags -x --kinds-c=f --_xformat="%N: %t %N%S" $(2) | grep "^\<$(1)\>:")))) check_func_to_def = $(if $(2),$(call do_func_to_def,$(1),$(2)),) func_to_def = $(call check_func_to_def,$(1),$(call symbol_to_c_file,$(1))) var_to_h_file = $(lastword $(subst :, ,$(filter $(1):%,$(GLOBAL_VAR)))) do_var_to_def = $(subst ];,] = {};,$(subst \/,/,$(subst extern ,,$(subst $$/,,$(subst $(1): /^,,$(shell ctags -x --kinds-c=x --_xformat="%N: %P" $(LINUX_SRC_DIR)/include/$(2) | grep "^\<$(1)\>:")))))) check_var_to_def = $(if $(2),$(call do_var_to_def,$(1),$(2)),) var_to_def = $(call check_var_to_def,$(1),$(call var_to_h_file,$(1))) endif # LINUX_KERNEL_DIR specified # # Collect undefined references for target # # use 'env - ' to reset environment, especially TARGET because it will be used by Genode's build sytem # during linking later on and not point to the actual build TARGET (GNU Make 4.4+) # UNDEF_REFS := $(sort $(subst `,,$(subst ',,$(shell env - PATH=$(PATH) make -C $(BUILD_DIR) $(TARGET) 2>&1 | grep " undefined reference to " | sed -e "s/.* reference to //")))) define print_file_header echo "/*" > $(2); echo " * \\brief Dummy definitions of Linux Kernel functions" >> $(2); echo " * \\author Automatically generated file - do no edit" >> $(2); echo " * \\date $(1)" >> $(2); echo " */" >> $(2); echo "" >> $(2); echo "#include " >> $(2); echo "" >> $(2); endef define print_var echo "" >> $(3); echo "#include <$(1)>" >> $(3); echo "" >> $(3); echo "$(2)" >> $(3); echo "" >> $(3); endef define print_func_only echo "" >> $(2); echo "extern $(1);" >> $(2); echo "$(1)" >> $(2); echo "{" >> $(2); echo " lx_emul_trace_and_stop(__func__);" >> $(2); echo "}" >> $(2); echo "" >> $(2); endef define print_func echo "" >> $(3); echo "#include <$(1)>" >> $(3); echo "" >> $(3); echo "$(2)" >> $(3); echo "{" >> $(3); echo " lx_emul_trace_and_stop(__func__);" >> $(3); echo "}" >> $(3); echo "" >> $(3); endef define print_error echo "Cannot create dummy for symbol $(1), maybe a macro?!" >&2; endef check_vdef = $(if $(3),$(call print_var,$(2),$(3),$(DUMMY_FILE)),$(call print_error,$(1))) check_var = $(if $(2),$(call check_vdef,$(1),$(2),$(call var_to_def,$(1))),$(call print_error,$(1))) check_not_func = $(call check_var,$(1),$(call var_to_h_file,$(1))) check_fdef_only = $(if $(2),$(call print_func_only,$(2),$(DUMMY_FILE)),$(call check_not_func,$(1))) check_fdef = $(if $(3),$(call print_func,$(2),$(3),$(DUMMY_FILE)),$(call check_not_func,$(1))) check_func = $(if $(2),$(call check_fdef,$(1),$(2),$(call func_to_def,$(1))),$(call check_fdef_only,$(1),$(call func_to_def,$(1)))) ifeq ($(realpath $(LINUX_KERNEL_DIR)),) show_symbol = "$1" else show_symbol = "$1 $(foreach F,$(call symbol_to_c_file,$1),(found at $(subst $(LINUX_SRC_DIR)/,,$(F:.c=.o))))" endif show: $(ECHO) "Missing symbols:" @$(foreach sym,$(UNDEF_REFS),echo $(call show_symbol,$(sym));) $(ECHO) "Total sum of missing symbols is $(words $(UNDEF_REFS))" generate: @$(call print_file_header,$(shell date +"%F"),$(DUMMY_FILE)) @$(foreach sym,$(UNDEF_REFS),$(call check_func,$(sym),$(call func_to_h_file,$(sym)))) .PHONY: generate show help # COMMAND!=help endif