mk: remove implicit build of shared libraries

This patch removes the implicit build of all shared libraries a target
depends on. Targets only depend on the respective ABIs instead. This
alleviates the need to locally build complex shared libraries (think of
Qt) when developing applications. Instead, application developers can
use binary depot archives.

The implementation splits the mk/lib.mk file into three files:
- mk/a.mk   for building one static library (.lib.a)
- mk/so.mk  for building one shared object  (.lib.so)
- mk/abi.mk for building one ABI stub       (.abi.so)

Furthermore, the commit moves messages and the collection of build
artifacts to var/libdeps, triggers the build of kernel-specific
ld-<kernel>.lib.so, and prunes the lib-dependency tree at ABIs.

Fixes #5061
This commit is contained in:
Norman Feske 2023-11-20 14:53:05 +01:00 committed by Christian Helmuth
parent c02aa759e6
commit 5ae0dab6c5
14 changed files with 465 additions and 321 deletions

View File

@ -1,19 +1,20 @@
#
# Generic ld.lib.so ABI stub library
#
# This library is used to build kernel-independent dynamically linked
# executables. It does not contain any code or data but only the symbol
# information of the binary interface of the Genode API.
# The ABI of this library is used to build kernel-independent dynamically
# linked executables. The library does not contain any code or data but only
# the symbol information of the binary interface of the Genode API.
#
# Note that this library is not used as runtime at all. At system-integration
# time, it is transparently replaced by the variant of the dynamic linker that
# matches the used kernel.
#
SHARED_LIB := yes
LD_OPT += -T$(BASE_DIR)/src/lib/ldso/linker.ld
# By adding a LIB dependency from the kernel-specific dynamic linker, we
# let dep_lib.mk generate the rule for ld-<KERNEL>.so into the var/libdeps
# file. The build of the ld-<KERNEL>.so is triggered because the top-level
# Makefile manually adds the dependency 'ld.so: ld-<KERNEL>.so' to the
# var/libdeps file for the currently selected kernel.
#
LIBS += $(addprefix ld-,$(KERNEL))
# as the stub libarary is not used at runtime, disregard it as build artifact

100
repos/base/mk/a.mk Normal file
View File

@ -0,0 +1,100 @@
##
## Rules for building a static library archive (.lib.a)
##
## The following variables must be passed when calling this file:
##
## LIB - library name
## BASE_DIR - base directory of the build system
## VERBOSE - build verboseness modifier
## VERBOSE_DIR - verboseness modifier for changing directories
## VERBOSE_MK - verboseness of make calls
## BUILD_BASE_DIR - base of build directory tree
## LIB_CACHE_DIR - library build cache location
## INSTALL_DIR - installation directory for stripped shared objects
## DEBUG_DIR - installation directory for unstripped shared objects
## SHARED_LIBS - shared-library dependencies of the library
## ARCHIVES - archive dependencies of the library
## REP_DIR - repository where the library resides
## CONTRIB_DIR - location of ported 3rd-party source codes
##
LIB_A := $(addsuffix .lib.a,$(LIB))
#
# Prevent <libname>.mk rules to be executed as default rule
#
all:
@true # prevent nothing-to-be-done message
#
# Include common utility functions
#
include $(BASE_DIR)/mk/util.inc
#
# Include specifics, for example platform, kernel-api etc.
#
include $(SPEC_FILES)
ORIG_INC_DIR := $(INC_DIR)
#
# Include library build instructions
#
# We set the 'called_from_lib_mk' variable to allow the library description file
# to respond to the build pass.
#
called_from_lib_mk = yes
include $(LIB_MK)
#
# Include lib-import descriptions of all used libraries and the target library
#
include $(foreach LIB,$(LIBS),$(call select_from_repositories,lib/import/import-$(LIB).mk))
#
# Sanity check for INC_DIR overrides
#
ifneq ($(filter-out $(INC_DIR),$(ORIG_INC_DIR)),)
all: error_inc_dir_override
endif
error_inc_dir_override:
@$(ECHO) "Error: INC_DIR overridden instead of appended" ; false
#
# Include global definitions
#
include $(BASE_DIR)/mk/global.mk
include $(BASE_DIR)/mk/generic.mk
#
# Trigger the creation of the <libname>.lib.a
#
LIB_TAG := $(addsuffix .lib.tag,$(LIB))
all: $(LIB_TAG)
#
# Trigger the build of host tools
#
# We make '$(LIB_TAG)' depend on the host tools to support building host tools
# from pseudo libraries with no actual source code. In this case '$(OBJECTS)'
# is empty.
#
$(LIB_TAG) $(OBJECTS): $(HOST_TOOLS)
#
# Rule to build the <libname>.lib.a file
#
# Use $(OBJECTS) instead of $^ for specifying the list of objects to include
# in the archive because $^ may also contain non-object phony targets, e.g.,
# used by the integration of Qt's meta-object compiler into the Genode
# build system.
#
$(LIB_A): $(OBJECTS)
$(MSG_MERGE)$(LIB_A)
$(VERBOSE)$(RM) -f $@
$(VERBOSE)$(AR) -rcs $@ $(OBJECTS)
$(LIB_TAG): $(CUSTOM_TARGET_DEPS) $(LIB_A)
@touch $@

98
repos/base/mk/abi.mk Normal file
View File

@ -0,0 +1,98 @@
##
## Create an ABI stub named '<lib>.abi.so'
##
## Invoked from the library's build directory within the lib cache.
## The following variables must be passed when calling this file:
##
## BASE_DIR - base directory of the build system
## VERBOSE - build verboseness modifier
## LIB_CACHE_DIR - library build cache location
## LIB - library name
## SYMBOLS - path of symbols file
## SPECS - build specs (i.e., CPU architecture)
##
#
# An ABI-stub library does not contain any code or data but only the symbol
# information of the binary interface (ABI) of the shared library.
#
# The ABI stub is linked by the users of the library (executables or shared
# objects) instead of the real library. This effectively decouples the library
# users from the concrete library instance but binds them merely to the
# library's binary interface. Note that the ABI stub is not used at runtime at
# all. At runtime, the real library that implements the ABI is loaded by the
# dynamic linker.
#
# The symbol information are incorporated into the ABI stub via an assembly
# file named 'symbols.s' that is generated from the library's symbol list.
#
ABI_SO := $(addsuffix .abi.so,$(LIB))
SYMBOLS := $(wildcard $(SYMBOLS))
ifeq ($(SYMBOLS),)
all:
else
all: $(ABI_SO)
endif
include $(BASE_DIR)/mk/util.inc
include $(SPEC_FILES)
include $(BASE_DIR)/mk/global.mk
include $(BASE_DIR)/mk/generic.mk
#
# Generate assembler file from symbol list
#
# For undefined symbols (type U), we create a hard dependency by referencing
# the symbols from the assembly file. The reference is created in the form of
# a '.long' value with the address of the symbol. On x86_64, this is not
# possible for PIC code. Hence, we reference the symbol via a PIC-compatible
# movq instruction instead.
#
# If we declared the symbol as '.global' without using it, the undefined symbol
# gets discarded at link time unless it is directly referenced by the target.
# This is a problem in situations where the undefined symbol is resolved by an
# archive rather than the target. I.e., when linking posix.lib.a (which
# provides 'Libc::Component::construct'), the 'construct' function is merely
# referenced by the libc.lib.so's 'Component::construct' function. But this
# reference apparently does not suffice to keep the posix.lib.a's symbol. By
# adding a hard dependency, we force the linker to resolve the symbol and don't
# drop posix.lib.a.
#
ASM_SYM_DEPENDENCY := .long \1
ifeq ($(filter-out $(SPECS),x86_64),)
ASM_SYM_DEPENDENCY := movq \1@GOTPCREL(%rip), %rax
endif
symbols.s: $(SYMBOLS)
$(MSG_CONVERT)$@
$(VERBOSE)\
sed -e "s/^\(\w\+\) D \(\w\+\)\$$/.data; .global \1; .type \1,%object; .size \1,\2; \1: .skip 1/" \
-e "s/^\(\w\+\) V/.data; .weak \1; .type \1,%object; \1: .skip 1/" \
-e "s/^\(\w\+\) T/.text; .global \1; .type \1,%function; \1:/" \
-e "s/^\(\w\+\) R \(\w\+\)\$$/.section .rodata; .global \1; .type \1,%object; .size \1,\2; \1:/" \
-e "s/^\(\w\+\) W/.text; .weak \1; .type \1,%function; \1:/" \
-e "s/^\(\w\+\) B \(\w\+\)\$$/.bss; .global \1; .type \1,%object; .size \1,\2; \1:/" \
-e "s/^\(\w\+\) U/.text; .global \1; $(ASM_SYM_DEPENDENCY)/" \
$< > $@
#
# The '.PRECIOUS' special target prevents make to remove the intermediate
# assembler file. Otherwise make would spill the build log with messages
# like "rm libc.symbols.s".
#
.PRECIOUS: symbols.s
ABI_SONAME := $(addsuffix .lib.so,$(LIB))
all: # prevent 'Nothing to be done' message
@true
$(ABI_SO): symbols.o
$(MSG_MERGE)$(ABI_SO)
$(VERBOSE)$(LD) -o $(ABI_SO) -soname=$(ABI_SONAME) -shared --eh-frame-hdr $(LD_OPT) \
-T $(LD_SCRIPT_SO) \
--whole-archive --start-group \
$(LIB_SO_DEPS) $< \
--end-group --no-whole-archive

55
repos/base/mk/dep.inc Normal file
View File

@ -0,0 +1,55 @@
#
# Common parts of dep_prg.mk, dep_lib.mk, and dep_abi.mk
#
# The target/library description file is already included.
# Hence, the LIBS variable contains the library dependencies.
#
.NOTPARALLEL:
##
# Return path to symbol file for a given library name
#
_symbol_file = $(firstword $(wildcard $(addsuffix /$1,\
$(foreach REP,$(REPOSITORIES),$(REP)/lib/symbols))))
include $(LIB_PROGRESS_LOG)
#
# Categorize LIBS into ABIs and actual libraries. Dependencies of libraries
# must be recursively discovered whereas ABIs don't have any dependencies.
#
#
# Pattern rules for generating ABI and library dependencies for var/libdeps
#
generate_abi_dep.%: log_progress
$(VERBOSE_MK)$(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_abi.mk SYMBOLS=$(call _symbol_file,$*)
generate_lib_dep.%: log_progress
$(VERBOSE_MK)$(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_lib.mk REP_DIR=$(REP_DIR) LIB=$*
generate_missing_ports:
$(if $(DEP_MISSING_PORTS),\
@echo "MISSING_PORTS += $(DEP_MISSING_PORTS)" >> $(LIB_DEP_FILE),\
@true)
generate_dep_lists:
@(echo "$(DEP_A_VAR_NAME) = $(foreach l,$(LIBS),\$${ARCHIVE_NAME($l)} \$$(DEP_A_$l))"; \
echo "$(DEP_SO_VAR_NAME) = $(foreach l,$(LIBS),\$${SO_NAME($l)} \$$(DEP_SO_$l))"; \
echo "") >> $(LIB_DEP_FILE)
log_progress:
generate: log_progress
generate: generate_missing_ports
_unvisited_libs = $(filter-out $(LIBS_READY),$1)
_abis_to_visit = $(foreach L,$(call _unvisited_libs,$1),$(if $(call _symbol_file,$L),$L))
_libs_to_visit = $(filter-out $(call _abis_to_visit,$1),$(call _unvisited_libs,$1))
deps_for_libs = $(addprefix generate_abi_dep.,$(call _abis_to_visit,$1)) \
$(addprefix generate_lib_dep.,$(call _libs_to_visit,$1)) \
$(if $1,generate_dep_lists)
UNSATISFIED_REQUIREMENTS = $(filter-out $(SPECS),$(REQUIRES))

35
repos/base/mk/dep_abi.mk Normal file
View File

@ -0,0 +1,35 @@
#
# The following variables must be defined by the caller:
#
# SYMBOLS - path to symbols file
# LIB_PROGRESS_LOG - record of visited ABIs
# LIB_DEP_FILE - destination Makefile for ABI-creation rule
#
override LIB := $(notdir $(SYMBOLS))
all:
@true
include $(BASE_DIR)/mk/dep.inc
include $(LIB_PROGRESS_LOG)
ifeq ($(filter $(ABIS_READY),$(LIB)),)
all: generate
endif
log_progress:
@echo "ABIS_READY += $(LIB)" >> $(LIB_PROGRESS_LOG)
generate:
@(echo "SO_NAME($(LIB)) := $(LIB).lib.so"; \
echo "$(LIB).lib.a:"; \
echo " @true"; \
echo "$(LIB).abi.so:"; \
echo " \$$(VERBOSE)\$$(call _prepare_lib_step,\$$@,$(LIB),)"; \
echo " \$$(VERBOSE_MK)\$$(MAKE) \$$(VERBOSE_DIR) -C \$$(LIB_CACHE_DIR)/$(LIB) -f \$$(BASE_DIR)/mk/abi.mk \\"; \
echo " SYMBOLS=$(SYMBOLS) \\"; \
echo " LIB=$(LIB) \\"; \
echo " BUILD_BASE_DIR=$(BUILD_BASE_DIR) \\"; \
echo " SHELL=$(SHELL)"; \
echo "") >> $(LIB_DEP_FILE)

View File

@ -1,73 +1,26 @@
#
# This file determines dependencies of a library from other libraries
# Determine dependencies of a library from other libraries
#
# The following variables must be defined by the caller:
#
# VERBOSE - controls the make verboseness
# VERBOSE_DIR - verboseness of directory change messages
# VERBOSE_MK - verboseness of make calls
# REPOSITORIES - source code repositories to use
# BASE_DIR - base directory of build system repository
# TARGET_DIR - target build directory
# BUILD_BASE_DIR - build directory with build config
# LIB_CACHE_DIR - destination directory for object files
# LIB_PROGRESS_LOG - library build log file
# BUILD_LIBS - list of libraries to build (without .lib.a or .lib.so suffix)
# INSTALL_DIR - destination directory for installing shared libraries
# DEBUG_DIR - destination directory for installing unstripped shared libraries
# LIB - library name
# REPOSITORIES - repository directories to search for the library
#
ACCUMULATE_MISSING_PORTS = 1
#
# Include common utility functions
#
include $(BASE_DIR)/mk/util.inc
#
# Generate dependencies only for those libs that are
# not already contained in the library build log
#
include $(LIB_PROGRESS_LOG)
ifneq ($(filter $(LIB),$(LIBS_READY)),)
already_visited:
all:
@true
else
all: append_lib_to_progress_log
endif
append_lib_to_progress_log:
@echo "LIBS_READY += $(LIB)" >> $(LIB_PROGRESS_LOG)
LIB_MK_DIRS = $(foreach REP,$(REPOSITORIES),$(addprefix $(REP)/lib/mk/spec/, $(SPECS)) $(REP)/lib/mk)
SYMBOLS_DIRS = $(foreach REP,$(REPOSITORIES),$(addprefix $(REP)/lib/symbols/spec/,$(SPECS)) $(REP)/lib/symbols)
#
# Of all possible file locations, use the (first) one that actually exist.
#
LIB_MK = $(firstword $(wildcard $(addsuffix /$(LIB).mk,$(LIB_MK_DIRS))))
SYMBOLS = $(firstword $(wildcard $(addsuffix /$(LIB), $(SYMBOLS_DIRS))))
ifneq ($(SYMBOLS),)
SHARED_LIB := yes
endif
#
# Sanity check to detect missing library-description file
#
ifeq ($(sort $(LIB_MK) $(SYMBOLS)),)
all: warn_missing_lib_mk
else
all: check_unsatisfied_requirements
endif
warn_missing_lib_mk: generate_lib_rule_for_defect_library
@$(ECHO) "Library-description file $(DARK_COL)$(LIB).mk$(DEFAULT_COL) is missing"
LIB_MK := $(firstword $(wildcard $(addsuffix /$(LIB).mk,\
$(foreach REP,$(REPOSITORIES),\
$(addprefix $(REP)/lib/mk/spec/,$(SPECS))\
$(REP)/lib/mk))))
#
# Determine the repository base directory from the absolute pathname
# of the choosen libname.mk file. We need to specify the override
# of the chosen libname.mk file. We need to specify the override
# command because REP_DIR was first set by prg.mk when building a
# program target. The repository of a library could be a different
# one.
@ -78,20 +31,31 @@ warn_missing_lib_mk: generate_lib_rule_for_defect_library
override REP_DIR := $(firstword $(foreach REP,$(REPOSITORIES),$(findstring $(REP)/,$(LIB_MK))))
override REP_DIR := $(REP_DIR:/=)
include $(BASE_DIR)/mk/base-libs.mk
include $(LIB_MK)
include $(BASE_DIR)/mk/dep.inc
ifneq ($(UNSATISFIED_REQUIREMENTS),)
WARNING_SKIP := "Skip library $(LIB) because it requires '$(UNSATISFIED_REQUIREMENTS)'"
endif
SYMBOLS := $(call _symbol_file,$(LIB))
#
# Sanity check to detect missing library-description file
#
ifeq ($(sort $(LIB_MK) $(SYMBOLS)),)
WARNING_SKIP := "Library-description file '$(LIB).mk' is missing"
endif
ifneq ($(SYMBOLS),)
SHARED_LIB := yes
endif
ifdef SHARED_LIB
BUILD_ARTIFACTS ?= $(LIB).lib.so
endif
# record creation of shared library build artifact
append_artifact_to_progress_log:
@( $(foreach A,$(BUILD_ARTIFACTS),\
echo -e "\n# Build artifact $A\n";) true \
) >> $(LIB_PROGRESS_LOG)
append_lib_to_progress_log: append_artifact_to_progress_log
ifdef SHARED_LIB
LIBS += ldso_so_support
endif
@ -111,40 +75,38 @@ DEP_SO_VAR_NAME := DEP_SO_$(LIB)
endif
#
# Check if the requirements of the target are satisfied
# Trigger the rule generation for the ABI of this library
#
UNSATISFIED_REQUIREMENTS = $(filter-out $(SPECS),$(REQUIRES))
ifneq ($(UNSATISFIED_REQUIREMENTS),)
check_unsatisfied_requirements: warn_unsatisfied_requirements
else
check_unsatisfied_requirements: generate_lib_rule
ifdef SHARED_LIB
ifneq ($(SYMBOLS),)
generate: generate_abi_dep.$(LIB)
endif
endif
warn_unsatisfied_requirements: generate_lib_rule_for_defect_library
@$(ECHO) "Skip library $(LIB) because it requires $(DARK_COL)$(UNSATISFIED_REQUIREMENTS)$(DEFAULT_COL)"
ifeq ($(filter $(LIBS_READY),$(LIB)),)
all: $(if $(WARNING_SKIP),generate_skip,generate)
endif
generate_lib_rule_for_defect_library:
log_progress:
@echo "LIBS_READY += $(LIB)" >> $(LIB_PROGRESS_LOG)
generate_skip:
@echo $(WARNING_SKIP)
@(echo "INVALID_DEPS += $(LIB)"; \
echo "$(LIB).lib:"; \
echo "$(LIB).lib.a $(LIB).lib.so:"; \
echo "") >> $(LIB_DEP_FILE)
LIBS_TO_VISIT = $(filter-out $(LIBS_READY),$(LIBS))
generate_lib_rule:
ifneq ($(DEP_MISSING_PORTS),)
@(echo "MISSING_PORTS += $(DEP_MISSING_PORTS)"; \
echo "") >> $(LIB_DEP_FILE)
generate: $(call deps_for_libs,$(LIBS))
ifdef SHARED_LIB
ifeq ($(SYMBOLS),) # if no symbols exist, the shared object is the ABI
@(echo "SO_NAME($(LIB)) := $(LIB).lib.so"; \
echo "$(LIB).abi.so: $(LIB).lib.so"; \
echo "$(LIB).lib.a:"; \
echo " @true"; ) >> $(LIB_DEP_FILE)
endif
@for i in $(LIBS_TO_VISIT); do \
$(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_lib.mk REP_DIR=$(REP_DIR) LIB=$$i; done
ifneq ($(LIBS),)
@(echo "$(DEP_A_VAR_NAME) = $(foreach l,$(LIBS),\$${ARCHIVE_NAME($l)} \$$(DEP_A_$l))"; \
echo "$(DEP_SO_VAR_NAME) = $(foreach l,$(LIBS),\$${SO_NAME($l)} \$$(DEP_SO_$l))"; \
echo "") >> $(LIB_DEP_FILE)
endif
@(echo "$(LIB).lib: check_ports $(addsuffix .lib,$(LIBS))"; \
echo " @\$$(MKDIR) -p \$$(LIB_CACHE_DIR)/$(LIB)"; \
echo " \$$(VERBOSE_MK)\$$(MAKE) $(VERBOSE_DIR) -C \$$(LIB_CACHE_DIR)/$(LIB) -f \$$(BASE_DIR)/mk/lib.mk \\"; \
@(echo "$(LIB).lib.so: check_ports $(if $(SYMBOLS),$(LIB).abi.so) $(addsuffix .lib.a,$(LIBS)) $(addsuffix .abi.so,$(LIBS))"; \
echo " \$$(VERBOSE)\$$(call _prepare_lib_step,\$$@,$(LIB),$(BUILD_ARTIFACTS))"; \
echo " \$$(VERBOSE_MK)\$$(MAKE) \$$(VERBOSE_DIR) -C \$$(LIB_CACHE_DIR)/$(LIB) -f \$$(BASE_DIR)/mk/so.mk \\"; \
echo " REP_DIR=$(REP_DIR) \\"; \
echo " LIB_MK=$(LIB_MK) \\"; \
echo " SYMBOLS=$(SYMBOLS) \\"; \
@ -156,11 +118,22 @@ endif
echo " INSTALL_DIR=\$$(INSTALL_DIR) \\"; \
echo " DEBUG_DIR=\$$(DEBUG_DIR)"; \
echo "") >> $(LIB_DEP_FILE)
ifdef SHARED_LIB
@(echo "SO_NAME($(LIB)) := $(LIB).lib.so"; \
echo "") >> $(LIB_DEP_FILE)
else
@(echo "ARCHIVE_NAME($(LIB)) := $(LIB).lib.a"; \
else # not SHARED_LIB
@(echo "$(LIB).lib.a: check_ports $(addsuffix .lib.a,$(LIBS)) $(addsuffix .abi.so,$(LIBS))"; \
echo " \$$(VERBOSE)\$$(call _prepare_lib_step,\$$@,$(LIB),$(BUILD_ARTIFACTS))"; \
echo " \$$(VERBOSE_MK)\$$(MAKE) \$$(VERBOSE_DIR) -C \$$(LIB_CACHE_DIR)/$(LIB) -f \$$(BASE_DIR)/mk/a.mk \\"; \
echo " REP_DIR=$(REP_DIR) \\"; \
echo " LIB_MK=$(LIB_MK) \\"; \
echo " LIB=$(LIB) \\"; \
echo " ARCHIVES=\"\$$(sort \$$($(DEP_A_VAR_NAME)))\" \\"; \
echo " SHARED_LIBS=\"\$$(sort \$$($(DEP_SO_VAR_NAME)))\" \\"; \
echo " BUILD_BASE_DIR=$(BUILD_BASE_DIR) \\"; \
echo " SHELL=$(SHELL) \\"; \
echo " INSTALL_DIR=\$$(INSTALL_DIR) \\"; \
echo " DEBUG_DIR=\$$(DEBUG_DIR)"; \
echo "$(LIB).lib.so $(LIB).abi.so:"; \
echo " @true"; \
echo "ARCHIVE_NAME($(LIB)) := $(LIB).lib.a"; \
echo "") >> $(LIB_DEP_FILE)
endif

View File

@ -1,21 +1,29 @@
#
# Prevent execution of any rule contained in $(TARGET_MK) as default rule
# Determine library dependencies of a program
#
all:
ACCUMULATE_MISSING_PORTS = 1
#
# Include common utility functions
#
include $(BASE_DIR)/mk/util.inc
all:
@true
#
# Include target build instructions to aquire library dependecies
#
PRG_DIR := $(dir $(TARGET_MK))
include $(TARGET_MK)
#
# Check if the requirements of the target are satisfied
#
UNSATISFIED_REQUIREMENTS = $(filter-out $(SPECS),$(REQUIRES))
ifneq ($(UNSATISFIED_REQUIREMENTS),)
WARNING_SKIP := "Skip library $(LIB) because it requires '$(UNSATISFIED_REQUIREMENTS)'"
endif
#
# Add libgcov if coverage is requested
#
@ -40,6 +48,14 @@ include $(foreach LIB,$(LIBS),$(call select_from_repositories,lib/import/import-
#
include $(SPEC_FILES)
#
# Evaluate library dependencies for this target
#
include $(BASE_DIR)/mk/dep.inc
DEP_A_VAR_NAME := DEP_A_$(TARGET).prg
DEP_SO_VAR_NAME := DEP_SO_$(TARGET).prg
#
# Names of build artifacts to appear in the 'progress.log'
#
@ -51,37 +67,18 @@ BUILD_ARTIFACTS ?= $(TARGET)
PRG_REL_DIR := $(subst $(REP_DIR)/src/,,$(PRG_DIR))
PRG_REL_DIR := $(PRG_REL_DIR:/=)
#
# Prevent generation of program rule if requirements are unsatisfied
#
UNSATISFIED_REQUIREMENTS = $(filter-out $(SPECS),$(REQUIRES))
ifneq ($(UNSATISFIED_REQUIREMENTS),)
all:
@$(ECHO) "Skip target $(PRG_REL_DIR) because it requires $(DARK_COL)$(UNSATISFIED_REQUIREMENTS)$(DEFAULT_COL)"
else
all: gen_prg_rule
WARNING_SKIP := "Skip target $(PRG_REL_DIR) because it requires '$(UNSATISFIED_REQUIREMENTS)'"
endif
include $(LIB_PROGRESS_LOG)
LIBS_TO_VISIT = $(filter-out $(LIBS_READY),$(LIBS))
all: $(if $(WARNING_SKIP),generate_skip,generate)
#
# Generate program rule
#
gen_prg_rule: append_artifact_to_progress_log
ifneq ($(LIBS),)
@for i in $(LIBS_TO_VISIT); do \
$(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_lib.mk REP_DIR=$(REP_DIR) LIB=$$i; done
@(echo "DEP_A_$(TARGET).prg = $(foreach l,$(LIBS),\$${ARCHIVE_NAME($l)} \$$(DEP_A_$l))"; \
echo "DEP_SO_$(TARGET).prg = $(foreach l,$(LIBS),\$${SO_NAME($l)} \$$(DEP_SO_$l))"; \
echo "") >> $(LIB_DEP_FILE)
endif
ifneq ($(DEP_MISSING_PORTS),)
@(echo "MISSING_PORTS += $(DEP_MISSING_PORTS)"; \
echo "") >> $(LIB_DEP_FILE)
endif
@(echo "$(TARGET).prg: check_ports $(addsuffix .lib,$(LIBS))"; \
echo " @\$$(MKDIR) -p $(PRG_REL_DIR)"; \
generate_skip:
@echo $(WARNING_SKIP)
generate: $(call deps_for_libs,$(LIBS))
@(echo "$(TARGET).prg: check_ports $(addsuffix .lib.a,$(LIBS)) $(addsuffix .abi.so,$(LIBS))"; \
echo " \$$(VERBOSE)\$$(call _prepare_prg_step,$(PRG_REL_DIR)/$(TARGET),$(BUILD_ARTIFACTS))"; \
echo " \$$(VERBOSE_MK)\$$(MAKE) $(VERBOSE_DIR) -C $(PRG_REL_DIR) -f \$$(BASE_DIR)/mk/prg.mk \\"; \
echo " REP_DIR=$(REP_DIR) \\"; \
echo " PRG_REL_DIR=$(PRG_REL_DIR) \\"; \
@ -116,8 +113,3 @@ ifeq ($(FORCE_BUILD_LIBS),yes)
@(echo ""; \
echo "all: \$$(addsuffix .lib,\$$(filter-out \$$(INVALID_DEPS), $(LIBS)))") >> $(LIB_DEP_FILE)
endif
append_artifact_to_progress_log:
@( $(foreach A,$(BUILD_ARTIFACTS),\
echo -e "\n# Build artifact $A\n";) true \
) >> $(LIB_PROGRESS_LOG)

View File

@ -133,42 +133,6 @@ binary_%.o: %
$(VERBOSE)echo ".global $(symbol_name)_start, $(symbol_name)_end; .data; .align 4; $(symbol_name)_start:; .incbin \"$<\"; $(symbol_name)_end:" |\
$(AS) $(AS_OPT) -f -o $@ -
#
# Generate assembler file from symbol list
#
# For undefined symbols (type U), we create a hard dependency by referencing
# the symbols from the assembly file. The reference is created in the form of
# a '.long' value with the address of the symbol. On x86_64, this is not
# possible for PIC code. Hence, we reference the symbol via a PIC-compatible
# movq instruction instead.
#
# If we declared the symbol as '.global' without using it, the undefined symbol
# gets discarded at link time unless it is directly referenced by the target.
# This is a problem in situations where the undefined symbol is resolved by an
# archive rather than the target. I.e., when linking posix.lib.a (which
# provides 'Libc::Component::construct'), the 'construct' function is merely
# referenced by the libc.lib.so's 'Component::construct' function. But this
# reference apparently does not suffice to keep the posix.lib.a's symbol. By
# adding a hard dependency, we force the linker to resolve the symbol and don't
# drop posix.lib.a.
#
ASM_SYM_DEPENDENCY := .long \1
ifeq ($(filter-out $(SPECS),x86_64),)
ASM_SYM_DEPENDENCY := movq \1@GOTPCREL(%rip), %rax
endif
%.symbols.s: %.symbols
$(MSG_CONVERT)$@
$(VERBOSE)\
sed -e "s/^\(\w\+\) D \(\w\+\)\$$/.data; .global \1; .type \1,%object; .size \1,\2; \1: .skip 1/" \
-e "s/^\(\w\+\) V/.data; .weak \1; .type \1,%object; \1: .skip 1/" \
-e "s/^\(\w\+\) T/.text; .global \1; .type \1,%function; \1:/" \
-e "s/^\(\w\+\) R \(\w\+\)\$$/.section .rodata; .global \1; .type \1,%object; .size \1,\2; \1:/" \
-e "s/^\(\w\+\) W/.text; .weak \1; .type \1,%function; \1:/" \
-e "s/^\(\w\+\) B \(\w\+\)\$$/.bss; .global \1; .type \1,%object; .size \1,\2; \1:/" \
-e "s/^\(\w\+\) U/.text; .global \1; $(ASM_SYM_DEPENDENCY)/" \
$< > $@
#
# Create local symbol links for the used shared libraries
#
@ -182,8 +146,8 @@ endif
# time a user of the library is linked, the ABI stub should be used instead of
# the library.
#
select_so = $(firstword $(wildcard $(LIB_CACHE_DIR)/$(1:.lib.so=)/$(1:.lib.so=).abi.so \
$(LIB_CACHE_DIR)/$(1:.lib.so=)/$(1:.lib.so=).lib.so))
select_so = $(firstword $(wildcard $(LIB_CACHE_DIR)/$(1:.lib.so=)/$(1:.lib.so=).abi.so) \
$(LIB_CACHE_DIR)/$(1:.lib.so=)/$(1:.lib.so=).lib.so)
ifneq ($(filter-out $(foreach s,$(SHARED_LIBS),$(realpath $s)), \
$(foreach s,$(SHARED_LIBS),$(call select_so,$s))),)

View File

@ -238,16 +238,6 @@ LD_SCRIPT_SO ?= $(BASE_DIR)/src/ld/genode_rel.ld
#
AS_OPT += $(AS_MARCH)
#
# Control sequences for color terminals
#
# To disable colored output, define these variable empty in your
# build-local 'etc/tools.conf' file.
#
BRIGHT_COL ?= \033[01;33m
DARK_COL ?= \033[00;33m
DEFAULT_COL ?= \033[0m
ALL_INC_DIR := .
ALL_INC_DIR += $(INC_DIR)
ALL_INC_DIR += $(foreach DIR,$(REP_INC_DIR), $(foreach REP,$(REPOSITORIES),$(REP)/$(DIR)))
@ -268,6 +258,4 @@ MSG_CONFIG ?= @$(ECHO) " CONFIG "
MSG_CLEAN ?= @$(ECHO) " CLEAN "
MSG_ASSEM ?= @$(ECHO) " ASSEMBLE "
MSG_INST ?= @$(ECHO) " INSTALL "
MSG_PRG ?= @$(ECHO) "$(BRIGHT_COL) Program $(DEFAULT_COL)"
MSG_LIB ?= @$(ECHO) "$(DARK_COL) Library $(DEFAULT_COL)"

View File

@ -73,21 +73,17 @@ endif
include $(BASE_DIR)/mk/generic.mk
include $(BASE_DIR)/mk/base-libs.mk
all: message $(TARGET)
all: $(TARGET)
ifneq ($(INSTALL_DIR),)
ifneq ($(DEBUG_DIR),)
all: message $(INSTALL_DIR)/$(TARGET) $(DEBUG_DIR)/$(TARGET) $(DEBUG_DIR)/$(TARGET).debug
all: $(INSTALL_DIR)/$(TARGET) $(DEBUG_DIR)/$(TARGET) $(DEBUG_DIR)/$(TARGET).debug
endif
endif
all:
@true # prevent nothing-to-be-done message
.PHONY: message
message:
$(MSG_PRG)$(PRG_REL_DIR)/$(TARGET)
#
# Enforce unconditional call of gnatmake rule when compiling Ada sources
#

View File

@ -1,29 +1,21 @@
##
## Rules for building a library target
## Rules for building a shared object (.lib.so)
##
## The following variables must be passed when calling this file:
## The expected variables correspond to those documented in a.mk, with
## the following addition:
##
## BASE_DIR - base directory of the build system
## REPOSITORIES - repositories providing libs and headers
## VERBOSE - build verboseness modifier
## VERBOSE_DIR - verboseness modifier for changing directories
## VERBOSE_MK - verboseness of make calls
## BUILD_BASE_DIR - base of build directory tree
## LIB_CACHE_DIR - library build cache location
## INSTALL_DIR - installation directory for stripped shared objects
## DEBUG_DIR - installation directory for unstripped shared objects
## SHARED_LIBS - shared-library dependencies of the library
## ARCHIVES - archive dependencies of the library
## REP_DIR - repository where the library resides
## CONTRIB_DIR - location of ported 3rd-party source codes
## SYMBOLS - path of symbols file
##
LIB_SO := $(addsuffix .lib.so,$(LIB))
include $(BASE_DIR)/mk/base-libs.mk
#
# Prevent <libname>.mk rules to be executed as default rule
#
all:
@true # prevent nothing-to-be-done message
#
# Include common utility functions
@ -35,73 +27,37 @@ include $(BASE_DIR)/mk/util.inc
#
include $(SPEC_FILES)
ORIG_INC_DIR := $(INC_DIR)
#
# Include library build instructions
#
# We set the 'called_from_lib_mk' variable to allow the library description file
# to respond to the build pass.
#
BACKUP_INC_DIR := $(INC_DIR)
called_from_lib_mk = yes
include $(LIB_MK)
#
# Sanity check for INC_DIR overrides
#
ifneq ($(filter-out $(INC_DIR),$(BACKUP_INC_DIR)),)
all: error_inc_dir_override
endif
error_inc_dir_override:
@$(ECHO) "Error: $(LIB_MK) overrides INC_DIR instead of appending" ; false
#
# Include lib-import descriptions of all used libraries and the target library
#
include $(foreach LIB,$(LIBS),$(call select_from_repositories,lib/import/import-$(LIB).mk))
#
# Sanity check for INC_DIR overrides
#
ifneq ($(filter-out $(INC_DIR),$(ORIG_INC_DIR)),)
all: error_inc_dir_override
endif
error_inc_dir_override:
@$(ECHO) "Error: INC_DIR overridden instead of appended" ; false
#
# Include global definitions
#
include $(BASE_DIR)/mk/global.mk
ifneq ($(SYMBOLS),)
SHARED_LIB := yes
endif
#
# If a symbol list is provided, we create an ABI stub named '<lib>.abi.so'
#
# The ABI-stub library does not contain any code or data but only the symbol
# information of the binary interface (ABI) of the shared library.
#
# The ABI stub is linked by the users of the library (executables or shared
# objects) instead of the real library. This effectively decouples the library
# users from the concrete library instance but binds them merely to the
# library's binary interface. Note that the ABI stub is not used at runtime at
# all. At runtime, the real library that implements the ABI is loaded by the
# dynamic linker.
#
# The symbol information are incorporated into the ABI stub via an assembly
# file named '<lib>.symbols.s' that is generated from the library's symbol
# list. We create a symbolic link from the symbol file to the local directory.
# By using '.symbols' as file extension, the pattern rule '%.symbols.s:
# %.symbols' defined in 'generic.mk' is automatically applied for creating the
# assembly file from the symbols file.
#
# The '.PRECIOUS' special target prevents make to remove the intermediate
# assembler file. Otherwise make would spill the build log with messages
# like "rm libc.symbols.s".
#
ifneq ($(SYMBOLS),)
ABI_SO := $(addsuffix .abi.so,$(LIB))
ABI_SONAME := $(addsuffix .lib.so,$(LIB))
$(LIB).symbols:
$(VERBOSE)ln -sf $(SYMBOLS) $@
.PRECIOUS: $(LIB).symbols.s
endif
include $(BASE_DIR)/mk/generic.mk
#
# Link libgcc to shared libraries
@ -109,19 +65,7 @@ endif
# For static libraries, libgcc is not needed because it will be linked
# against the final target.
#
ifdef SHARED_LIB
LIBGCC = $(shell $(CC) $(CC_MARCH) -print-libgcc-file-name)
endif
#
# Print message for the currently built library
#
all: message
message:
$(MSG_LIB)$(LIB)
include $(BASE_DIR)/mk/generic.mk
#
# Name of <libname>.lib.a or <libname>.lib.so file to create
@ -129,16 +73,12 @@ include $(BASE_DIR)/mk/generic.mk
# Skip the creation and installation of an .so file if there are no
# ingredients. This is the case if the library is present as ABI only.
#
ifdef SHARED_LIB
ifneq ($(sort $(OBJECTS) $(LIBS)),)
LIB_SO := $(addsuffix .lib.so,$(LIB))
INSTALL_SO := $(INSTALL_DIR)/$(LIB_SO)
DEBUG_SO := $(DEBUG_DIR)/$(LIB_SO)
LIB_SO_DEBUG := $(LIB_SO).debug
DEBUG_SO_DEBUG := $(DEBUG_SO).debug
endif
else
LIB_A := $(addsuffix .lib.a,$(LIB))
ifneq ($(sort $(OBJECTS) $(LIBS)),)
ABI_SO := $(wildcard $(addsuffix .abi.so,$(LIB)))
INSTALL_SO := $(INSTALL_DIR)/$(LIB_SO)
DEBUG_SO := $(DEBUG_DIR)/$(LIB_SO)
LIB_SO_DEBUG := $(LIB_SO).debug
DEBUG_SO_DEBUG := $(DEBUG_SO).debug
endif
#
@ -153,11 +93,14 @@ ifneq ($(LIB_SO),)
endif
#
# Trigger the creation of the <libname>.lib.a or <libname>.lib.so file
# Trigger the creation of the <libname>.lib.so file
#
LIB_TAG := $(addsuffix .lib.tag,$(LIB))
all: $(LIB_TAG)
$(LIB_TAG):
@touch $@
#
# Trigger the build of host tools
#
@ -172,29 +115,20 @@ $(LIB_TAG) $(OBJECTS): $(HOST_TOOLS)
#
$(LIB_TAG): $(CUSTOM_TARGET_DEPS)
$(LIB_TAG): $(LIB_A) $(LIB_SO) $(LIB_CHECKED) $(ABI_SO) $(INSTALL_SO) $(DEBUG_SO) $(DEBUG_SO_DEBUG)
@touch $@
#
# Don't link shared object it BUILD_ARTIFACTS are declared as empty (ld.lib.so)
#
BUILD_ARTIFACTS ?= $(LIB).lib.so
#
# Rule to build the <libname>.lib.a file
#
# Use $(OBJECTS) instead of $^ for specifying the list of objects to include
# in the archive because $^ may also contain non-object phony targets, e.g.,
# used by the integration of Qt's meta-object compiler into the Genode
# build system.
#
$(LIB_A): $(OBJECTS)
$(MSG_MERGE)$(LIB_A)
$(VERBOSE)$(RM) -f $@
$(VERBOSE)$(AR) -rcs $@ $(OBJECTS)
ifneq ($(BUILD_ARTIFACTS),)
$(LIB_TAG): $(LIB_SO) $(LIB_CHECKED) $(INSTALL_SO) $(DEBUG_SO) $(DEBUG_SO_DEBUG)
endif
#
# Link ldso-support library to each shared library to provide local hook
# functions for constructors and ARM
#
ifdef SHARED_LIB
override ARCHIVES += ldso_so_support.lib.a
endif
#
# Don't link base libraries against shared libraries except for ld.lib.so
@ -234,14 +168,6 @@ $(LIB_SO): $(STATIC_LIBS) $(OBJECTS) $(wildcard $(LD_SCRIPT_SO)) $(LIB_SO_DEPS)
--end-group --no-whole-archive \
$(LIBGCC)
$(ABI_SO): $(LIB).symbols.o
$(MSG_MERGE)$(ABI_SO)
$(VERBOSE)$(LD) -o $(ABI_SO) -soname=$(ABI_SONAME) -shared --eh-frame-hdr $(LD_OPT) \
-T $(LD_SCRIPT_SO) \
--whole-archive --start-group \
$(LIB_SO_DEPS) $< \
--end-group --no-whole-archive
$(LIB_CHECKED): $(LIB_SO) $(SYMBOLS)
$(VERBOSE)$(BASE_DIR)/../../tool/check_abi $(LIB_SO) $(SYMBOLS) && touch $@

View File

@ -233,11 +233,12 @@ init_progress_log:
.PHONY: init_libdep_file
init_libdep_file: $(dir $(LIB_DEP_FILE))
@echo "checking library dependencies..."
@(echo "#"; \
echo "# Library dependencies for build '$(DST_DIRS)'"; \
echo "#"; \
echo ""; \
echo ".NOTPARALLEL:"; \
echo ""; \
echo "export SPEC_FILES := \\"; \
for i in $(SPEC_FILES); do \
echo " $$i \\"; done; \
@ -250,17 +251,31 @@ init_libdep_file: $(dir $(LIB_DEP_FILE))
echo "INSTALL_DIR ?= $(INSTALL_DIR)"; \
echo "DEBUG_DIR ?= $(DEBUG_DIR)"; \
echo "SHELL ?= $(SHELL)"; \
echo "PROGRESS_LOG := $(LIB_PROGRESS_LOG)"; \
echo "MKDIR ?= mkdir"; \
echo "BRIGHT_COL ?= \033[01;33m"; \
echo "DARK_COL ?= \033[00;33m"; \
echo "DEFAULT_COL ?= \033[0m"; \
echo ""; \
echo "export MK_BUILD_STAGE := 1"; \
echo ""; \
echo "_log_artifacts = \$$(foreach A,\$$1,echo -e \"\\nBUILD_ARTIFACTS += \$$A\" >> \$$(PROGRESS_LOG);)"; \
echo ""; \
echo "# args: target file, libname, artifacts"; \
echo "_prepare_lib_step = ( echo -e \" \$$(DARK_COL)Library\$$(DEFAULT_COL) \$$1\"; \\"; \
echo " \$$(MKDIR) -p \$$(LIB_CACHE_DIR)/\$$2; \\"; \
echo " \$$(call _log_artifacts,\$$3) )"; \
echo ""; \
echo "# args: target path, artifacts"; \
echo "_prepare_prg_step = ( echo -e \" \$$(BRIGHT_COL)Program\$$(DEFAULT_COL) \$$1\"; \\"; \
echo " \$$(MKDIR) -p \$$(dir \$$1); \\"; \
echo " \$$(call _log_artifacts,\$$2) )"; \
echo ""; \
echo "all:"; \
echo " @true # prevent nothing-to-be-done message"; \
echo " @true"; \
echo ""; \
echo "") > $(LIB_DEP_FILE)
#
# We check if any target.mk files exist in the specified directories within
# any of the repositories listed in the 'REPOSITORIES' variable.
#
$(dir $(LIB_DEP_FILE)):
@mkdir -p $@
@ -300,20 +315,20 @@ endif
#
traverse_dependencies: $(dir $(LIB_DEP_FILE)) init_libdep_file init_progress_log
$(VERBOSE_MK) \
for lib in $(LIBS); do \
for libname in $(LIBS); do \
$(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_lib.mk \
REP_DIR=$$rep LIB=$$lib \
BUILD_BASE_DIR=$(BUILD_BASE_DIR) \
DARK_COL="$(DARK_COL)" DEFAULT_COL="$(DEFAULT_COL)"; \
echo "all: $$lib.lib" >> $(LIB_DEP_FILE); \
REP_DIR=$$rep LIB=$$libname \
BUILD_BASE_DIR=$(BUILD_BASE_DIR); \
echo "all: $$libname.lib.a $$libname.lib.so" >> $(LIB_DEP_FILE); \
done; \
[ -n "$(KERNEL)" ] && echo "ld.lib.so: ld-$(KERNEL).lib.so" >> $(LIB_DEP_FILE); \
for target in $(TARGETS_TO_VISIT); do \
for rep in $(REPOSITORIES); do \
test -f $$rep/src/$$target || continue; \
$(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_prg.mk \
REP_DIR=$$rep TARGET_MK=$$rep/src/$$target \
BUILD_BASE_DIR=$(BUILD_BASE_DIR) \
DARK_COL="$(DARK_COL)" DEFAULT_COL="$(DEFAULT_COL)" || result=false; \
|| result=false; \
break; \
done; \
done; $$result;

View File

@ -171,6 +171,7 @@ $(BUILD_CONF): checked_src_archive checked_api_archives
( echo "GENODE_DIR := $(GENODE_DIR)"; \
echo "BASE_DIR := $(GENODE_DIR)/repos/base"; \
echo "override CCACHE := $(BUILD_CONF_CCACHE)"; \
echo "override KERNEL :="; \
echo "REPOSITORIES := $(SRC_DIR)"; \
for api in $(USED_APIS); do \
echo "REPOSITORIES += $(DEPOT_API_DIR)/$$api"; done \

View File

@ -61,7 +61,7 @@ proc build {targets} {
}
# record the build artifacts created during the build process
set artifacts_log [exec sed -n "/^#/s/^# Build artifact //p" progress.log]
set artifacts_log [exec sed -n "/BUILD_ARTIFACTS/s/^.*= //p" progress.log]
lappend _collected_build_artifacts {*}[split $artifacts_log "\n"]
puts "genode build completed"