Skip to content
This repository has been archived by the owner on Feb 21, 2023. It is now read-only.

Modular build system #15

Open
wants to merge 155 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
155 commits
Select commit Hold shift + click to select a range
4b8459f
Move project information to GNUmakefile
matheusmoreira May 8, 2019
9372f0e
Define true and false variables in make/logic
matheusmoreira May 8, 2019
8b3194b
Define the boolean make function
matheusmoreira May 8, 2019
2643f3b
Define the not make function
matheusmoreira May 8, 2019
02818d6
Define user-friendly symbols for true and false
matheusmoreira May 8, 2019
f259c13
Define the boolean.symbol make function
matheusmoreira May 8, 2019
4762cfa
Create C.standard variable and default to C99
matheusmoreira May 8, 2019
073a361
Use -ffreestanding if C.freestanding is set
matheusmoreira May 8, 2019
05e03d1
Define the file? make function
matheusmoreira May 9, 2019
7d30eb9
Move directory? to make/functions/file_system
matheusmoreira May 9, 2019
a34fbd5
Define the glob make function
matheusmoreira May 9, 2019
8e92bfd
Define the recurse make function
matheusmoreira May 9, 2019
8fc66d1
Define the glob.default make variable
matheusmoreira May 9, 2019
b8b5d07
Specify the argument that the pattern must match
matheusmoreira May 9, 2019
dae47c2
Define glob.directory and glob.directory.default
matheusmoreira May 9, 2019
fb5fdf4
Define the file_system.traverse make function
matheusmoreira May 9, 2019
c83c3bb
Guard against empty inputs to directory? function
matheusmoreira May 10, 2019
545ca76
Use addsuffix function to add suffix to variable
matheusmoreira May 10, 2019
2a4d680
Define the find make function
matheusmoreira May 10, 2019
a4222e0
Move source code list variables to GNUmakefile
matheusmoreira May 10, 2019
5e0ab8e
Move header file list variable to GNUmakefile
matheusmoreira May 10, 2019
52209d9
Move examples list variable to GNUmakefile
matheusmoreira May 10, 2019
d2e1273
Move object file list variables to GNUmakefile
matheusmoreira May 10, 2019
180371a
Strip the results of the find make function
matheusmoreira May 10, 2019
fc3a13a
Move GCC spec and wrapper variables to GNUmakefile
matheusmoreira May 16, 2019
48e8de8
Move build directory variable to build section
matheusmoreira May 16, 2019
fb3d5b8
Move include directory variables to GNUmakefile
matheusmoreira May 16, 2019
dcaecf1
Move source directory variables to GNUmakefile
matheusmoreira May 16, 2019
df0eadb
Move start directory variables to GNUmakefile
matheusmoreira May 16, 2019
ac6c757
Move example directory variable to GNUmakefile
matheusmoreira May 16, 2019
da8f517
Move scripts directory variable to GNUmakefile
matheusmoreira May 16, 2019
4bc5a42
Move scripts directory variable to GNUmakefile
matheusmoreira May 16, 2019
9b3cbfa
Convert mkdir_p to a function in make/commands
matheusmoreira May 16, 2019
ef5b61e
Move download function to make/commands
matheusmoreira May 16, 2019
f5ccc92
Remove trailing dot from comment
matheusmoreira May 16, 2019
c651310
Rename make/ to .make/ and update includes
matheusmoreira May 19, 2019
c6bea5a
Include make/file if it exists
matheusmoreira May 19, 2019
0c9362f
Move system call lists functionality to make/
matheusmoreira May 19, 2019
83101fa
Move GCC wrapper and specs functionality to make/
matheusmoreira May 19, 2019
895b6f8
Define the rule_template make function
matheusmoreira May 21, 2019
91f6150
Update object_rule_template to use rule_template
matheusmoreira May 21, 2019
6e081d1
Use rule_template for dependency file rules
matheusmoreira May 21, 2019
c03b5fe
Disable all predefined make rules and variables
matheusmoreira May 21, 2019
2ea58ef
Use rule_template in start_object_rule_template
matheusmoreira May 21, 2019
58f547c
Move .make/targets/start to make/start
matheusmoreira May 21, 2019
6d727e7
Move object file rule evaluation to make/objects
matheusmoreira May 21, 2019
0b7afde
Remove useless comment
matheusmoreira May 21, 2019
8c51bcb
Improve description of dependency file rules
matheusmoreira May 21, 2019
cf205a9
Evaluate dependency file rules in make/objects
matheusmoreira May 21, 2019
77d16f3
Evaluate dependency file rules in make/examples
matheusmoreira May 21, 2019
cb2dc30
Evaluate dependency file rules in make/start
matheusmoreira May 21, 2019
ffe9852
Include dependency files in .make/dependencies
matheusmoreira May 21, 2019
deda82b
Move rule templates to .make/rules
matheusmoreira May 21, 2019
66c0417
Define phony targets in .make/phony
matheusmoreira May 21, 2019
60b45e9
Move script directory variables to make/structure
matheusmoreira May 21, 2019
5a78767
Move checkpatch functionality to make/checkpatch
matheusmoreira May 21, 2019
ccb2c42
Move include directory variables to make/structure
matheusmoreira May 21, 2019
02bcd14
Move source directory variables to make/structure
matheusmoreira May 21, 2019
6958ae2
Move sources_library make variable to make/sources
matheusmoreira May 21, 2019
842e927
Move start directory variables to make/structure
matheusmoreira May 21, 2019
19a57f2
Move examples directory variable to make/structure
matheusmoreira May 21, 2019
1dca855
Move object list variables to make/objects
matheusmoreira May 21, 2019
0baad53
Move sources_start variable to make/sources
matheusmoreira May 21, 2019
1909675
Move sources_examples variable to make/sources
matheusmoreira May 21, 2019
90d470f
Move objects_start variable to make/start
matheusmoreira May 21, 2019
c4e2ffe
Move objects variable to make/file
matheusmoreira May 21, 2019
52bce85
Move wrapper script variables to make/gcc_wrapper
matheusmoreira May 21, 2019
105ee0b
Move examples variable to make/examples
matheusmoreira May 21, 2019
8b3a741
Move project information to make/file
matheusmoreira May 21, 2019
b43cb7a
Move .DEFAULT_GOAL variable to make/file
matheusmoreira May 21, 2019
062675d
Move static_library variable to make/libraries
matheusmoreira May 21, 2019
6c5c2e3
Move dynamic_library variable to make/libraries
matheusmoreira May 21, 2019
32d9b6f
Add static library rule template
matheusmoreira May 21, 2019
c7fca38
Add dynamic library rule template
matheusmoreira May 21, 2019
9dfc019
Delete .make/targets/static_library
matheusmoreira May 21, 2019
b3f2a51
Delete .make/targets/dynamic_library
matheusmoreira May 21, 2019
c62f9ae
Define static library rules in make/libraries
matheusmoreira May 21, 2019
824c4ee
Define dynamic library rules in make/libraries
matheusmoreira May 21, 2019
9b80b82
Define and use function for GCC's include option
matheusmoreira May 21, 2019
2469522
Convert variables to recursively expanded
matheusmoreira May 21, 2019
b6926db
Update description of .make/structure
matheusmoreira May 21, 2019
f8c0649
Conditionally set the build_directory variable
matheusmoreira May 21, 2019
fb33e15
Recursively expand the build directory variables
matheusmoreira May 21, 2019
075bf33
Merge branch 'GNUmakefile-to-make-directory' into modular-build-system
matheusmoreira May 21, 2019
b6fac68
Add linkage make variable
matheusmoreira May 29, 2019
a3a1e2d
Move path conversion function to make/start
matheusmoreira May 29, 2019
27c7ed4
Define configuration variable
matheusmoreira May 29, 2019
0aad43b
Add make function for computing library file names
matheusmoreira May 29, 2019
3ccbf30
Switch to configuration-based builds
matheusmoreira May 29, 2019
f67c96b
Fix buggy implementation of the equal? function
matheusmoreira May 30, 2019
8336d59
Don't remove the source directory prefix
matheusmoreira May 30, 2019
f855a9e
Update documentation of the to_object function
matheusmoreira May 30, 2019
da1257e
Refactor the examples system to be more general
matheusmoreira May 30, 2019
e8deb27
Update documentation of the to_executable function
matheusmoreira May 30, 2019
6d6ef42
Document the to_dependency function
matheusmoreira May 30, 2019
f5eca78
Add library_rule_template make function
matheusmoreira Jun 28, 2019
4bdc5a8
Move run executable rules to .make/rules/run
matheusmoreira Jun 28, 2019
38d64b4
Define the as_library make function
matheusmoreira Jun 29, 2019
29c615e
Use executable target names unchanged
matheusmoreira Jun 29, 2019
c2f1fde
Use the .PHONY target instead of phony_targets
matheusmoreira Jul 1, 2019
0e23538
Define make variable containing a newline
matheusmoreira Jul 1, 2019
34d9ce3
Redesign the build system interface
matheusmoreira Jul 1, 2019
153bb18
Remove unused variables from make/file
matheusmoreira Jul 1, 2019
a73aef2
Set .DEFAULT_GOAL in the generated project rules
matheusmoreira Jul 1, 2019
e0716a8
Find the dependency files instead of using a list
matheusmoreira Jul 1, 2019
4c7507e
Parameterize directory creation in rule template
matheusmoreira Jul 1, 2019
65a0741
Pass source and target directly to the template
matheusmoreira Jul 1, 2019
b25176e
Pass the result of function calls to the templates
matheusmoreira Jul 1, 2019
89d329f
Generate .d files as a side effect of compilation
matheusmoreira Jul 1, 2019
bceed9a
Use correct variable name
matheusmoreira Jul 6, 2019
1314ff5
Define the dereference make function
matheusmoreira Jul 6, 2019
fadb6df
Define the space make variable
matheusmoreira Jul 6, 2019
ebc769a
Define the map make function
matheusmoreira Jul 6, 2019
bcea4a0
Define the rest make function
matheusmoreira Jul 6, 2019
b094f37
Define the resolve.name make function
matheusmoreira Jul 6, 2019
6798e8a
Define the defined? and undefined? make functions
matheusmoreira Jul 6, 2019
e950f16
Define the resolve.value make function
matheusmoreira Jul 7, 2019
3051ee5
Define the resolve make function
matheusmoreira Jul 7, 2019
c860fa6
Define the resolve.first make function
matheusmoreira Jul 7, 2019
eb2b77b
Move up the defined? and undefined? functions
matheusmoreira Jul 7, 2019
cbb5401
Rename the resolve make function to resolve.all
matheusmoreira Jul 7, 2019
a90c559
Pass the current build stack to project functions
matheusmoreira Jul 11, 2019
3d652f5
Define rule generation function for source files
matheusmoreira Jul 11, 2019
3c92ea5
Improve documentation of rule template arguments
matheusmoreira Jul 11, 2019
ac357ba
Define the reverse make function
matheusmoreira Jul 11, 2019
03103b5
Support extra dependencies in rule templates
matheusmoreira Jul 11, 2019
8176ccc
Remove unused build directory variables
matheusmoreira Jul 11, 2019
528f238
Define the coalesce make function
matheusmoreira Jul 11, 2019
be056e6
Define the path.separator make variable
matheusmoreira Jul 11, 2019
11d2b2c
Define the path.join make function
matheusmoreira Jul 11, 2019
7b3e783
Define the configuration.separator make variable
matheusmoreira Jul 11, 2019
fa74735
Define the configuration.current make variable
matheusmoreira Jul 11, 2019
1c4da58
Use path.join to define the build directories
matheusmoreira Jul 11, 2019
ac54c4b
Define the gcc.compile make function
matheusmoreira Jul 11, 2019
4610c6e
Add the compiler to the configuration
matheusmoreira Jul 11, 2019
3ea3811
Define the gcc.link function
matheusmoreira Jul 11, 2019
ca9fa38
Redesign the build system's compiler interface
matheusmoreira Jul 11, 2019
dff5fc1
Removed unused compiler variables and functions
matheusmoreira Jul 13, 2019
5b76405
Rename GCC option variables and functions
matheusmoreira Jul 13, 2019
a518523
Delete GCC option variables that are too specific
matheusmoreira Jul 13, 2019
abe5e88
Merge branch 'new-build-system-interface' into modular-build-system
matheusmoreira Jul 13, 2019
58d4bed
Fix system call list generation rules
matheusmoreira Jul 13, 2019
53464b5
Generate one include option for each parameter
matheusmoreira Nov 12, 2019
66037c6
Add new parameter to gcc.list_defined_macros
matheusmoreira Nov 12, 2019
0ff79df
Delete the gcc_common_options variable
matheusmoreira Nov 12, 2019
c40797a
Delete application-specific GCC option variables
matheusmoreira Nov 12, 2019
a2da813
Improve gcc.compile documentation
matheusmoreira Nov 12, 2019
ee49804
Improve gcc.link documentation
matheusmoreira Nov 12, 2019
f1cb0fa
Delete C.freestanding variable
matheusmoreira Nov 12, 2019
acd1ad5
Use higher level directory creation function
matheusmoreira Nov 13, 2019
da45caa
Build up an inverted build stack
matheusmoreira Nov 18, 2019
92d0c56
Define the resolve.name.first make function
matheusmoreira Nov 18, 2019
4c7fce2
Rename resolve.first to resolve.value.first
matheusmoreira Nov 18, 2019
b4f6192
Define resolve.stack+ and resolve.stack- functions
matheusmoreira Nov 18, 2019
cb32210
Adjust make/file due to new stack semantics
matheusmoreira Nov 18, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1 @@
make/** linguist-language=make
*make/** linguist-language=make
9 changes: 9 additions & 0 deletions .make/all_functions
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
include .make/functions/comparison
include .make/functions/directory
include .make/functions/file_system
include .make/functions/library
include .make/functions/list
include .make/functions/path
include .make/functions/recursion
include .make/functions/shell
include .make/functions/variables
File renamed without changes.
22 changes: 22 additions & 0 deletions .make/commands
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generates a directory creation command.
# Does not fail if the directory already exists.
# Creates all parent directories as needed.
#
# Arguments:
# $(1) = directories to create
#
# Returns:
# command line that creates $(1)
#
mkdir_p = mkdir -p $(1)

# Generates a file download command.
#
# Arguments:
# $(1) = what to download
# $(2) = where to write downloaded data to
#
# Returns:
# command line that downloads $(1) to $(2)
#
download = curl --output $(2) $(1)
1 change: 1 addition & 0 deletions .make/compiler
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include .make/compilers/gcc
79 changes: 79 additions & 0 deletions .make/compilers/gcc
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# GCC executable
gcc := gcc

# GCC option variable and function definitions
gcc.options.output = -o $(1)
gcc.options.compile := -c
gcc.options.preprocess := -E
gcc.options.dependency_generation = -MD -MF $(1) $(foreach target,$(2),-MT $(target))
gcc.options.standard = -std=$(1)
gcc.options.directory.include = -I $(1)
gcc.options.directory.library = -L$(1)
gcc.options.include.macros = $(foreach file,$(1),-imacros $(file))
gcc.options.dump.macro_names := -dN
gcc.redirect_input_to = - < $(1)
gcc.null_input := $(call gcc.redirect_input_to,/dev/null)

gcc_dialect_options = $(strip $(call gcc.options.standard,$(or $(1),c99)) $(if $(2),-ffreestanding))
gcc_warning_options := -Wall -Wextra -Wpedantic
gcc_preprocessor_options = $(call gcc.options.directory.include,$(include_directory)) $(gcc_inhibit_linemarkers_option)

# Generates a GCC command line that compiles a source file into an object file.
#
# Arguments:
# $(1) = source file
# $(2) = object file
# $(3) = dependency data file
# $(4) = options
# $(5) = GCC executable to use
#
# Returns:
# command line that uses $(5) with the options in $(4)
# to compile $(1) into $(2) and emit dependency data to $(3)
#
define gcc.compile
$(or $(5),$(gcc)) \
$(4) \
$(call gcc.options.dependency_generation,$(3),$(2)) \
$(call gcc.options.output,$(2)) \
$(gcc.options.compile) $(1)
endef

# Generates a GCC command line that links object files.
#
# Arguments:
# $(1) = object files
# $(2) = output file
# $(3) = options
# $(4) = GCC executable to use
#
# Returns:
# command line that uses $(4) with the options in $(3)
# to link $(1) into $(2)
#
define gcc.link
$(or $(4),$(gcc)) \
$(3) \
$(call gcc.options.output,$(2)) \
$(1)
endef

# Generates a GCC command line that lists all defined macros.
#
# Arguments:
# $(1) = files to include
# $(2) = options
# $(3) = GCC executable to use
#
# Returns:
# command line that uses $(3) with the options in $(2)
# to list all macros defined after including the files in $(1)
#
define gcc.list_defined_macros
$(or $(3),$(gcc)) \
$(gcc.options.preprocess) \
$(gcc.options.dump.macro_names) \
$(call gcc.options.include.macros,$(1)) \
$(2) \
$(gcc.null_input)
endef
2 changes: 2 additions & 0 deletions .make/configuration
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
configuration.separator ?= -
configuration.current = $(call coalesce,$(configuration),$(configuration.separator))
7 changes: 7 additions & 0 deletions .make/definitions
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
space :=
space +=

define \n :=


endef
17 changes: 17 additions & 0 deletions .make/dependencies
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# The wildcard function returns existing files that match its parameters.
# This prevents make from including files that don't exist.
#
# Make tries to rebuild included files, without the wildcard function
# the dependency data files would be generated with every invocation of make,
# even make clean.
#
# References:
#
# https://www.gnu.org/software/make/manual/html_node/Remaking-Makefiles.html
# https://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#include
# https://make.mad-scientist.net/constructed-include-files/
#

dependency_file? = $(call boolean,$(and $(call equal?,$(suffix $(1)),.d),$(call file?,$(1))))

include $(call find,$(build_dependencies_directory),dependency_file?)
36 changes: 36 additions & 0 deletions .make/file
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Disable all predefined rules and variables
MAKEFLAGS += --no-builtin-rules --no-builtin-variables

# Boolean logic in make
include .make/logic

# Useful variables
include .make/definitions

# Commands used by the build system
include .make/commands

# Make functions available to the entire build system
include .make/all_functions

# Build configuration
include .make/configuration

# File system structure of the build tree
include .make/structure

# Compiler and archiver configuration
include .make/compiler
include .make/archiver

# Rule templates
include $(addprefix .make/rules/,template objects executable libraries run)

# Project interface
include .make/project

# Include the user's makefile, if it exists
include $(wildcard make/file)

# Include all generated dependency files
include .make/dependencies
2 changes: 1 addition & 1 deletion make/functions/comparison → .make/functions/comparison
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# x - y = 0 ∴ x = y
equal? = $(if $(subst $(1),,$(2)),,=)
equal? = $(if $(subst $(1),,$(2))$(subst $(2),,$(1)),,=)

# x - y ≠ 0 ∴ x ≠ y
not_equal? = $(if $(call equal?,$(1),$(2)),,≠)
10 changes: 10 additions & 0 deletions .make/functions/directory
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Generates a command that makes sure the given directory exists.
# Generates the empty string if the directory already exists.
#
# $(1) = path to directory to create
#
ensure_directory_exists = $(if $(call directory?,$(1)),,$(call mkdir_p,$(1)))

# Ensures the existence of the directory where the target of a rule is located in.
# This function references an automatic variable so it should only be used inside recipes.
ensure_target_directory_exists = $(call ensure_directory_exists,$(@D))
107 changes: 107 additions & 0 deletions .make/functions/file_system
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Determines whether the given path exists and is a directory.
# Only existing directories contain a "." entry.
#
# Arguments:
# $(1) = path to check
#
# Returns:
# whether $(1) refers to an existing directory
#
# References:
# MadScientist's answer:
# http://stackoverflow.com/a/9456282/512904
#
directory? = $(if $(1),$(call boolean,$(wildcard $(addsuffix /.,$(1)))))

# Determines whether the given path exists and is a file.
# Files are defined as everything that is not a directory.
#
# Arguments:
# $(1) = path to check
#
# Returns:
# whether $(1) refers to an existing file
#
file? = $(call boolean,$(and $(wildcard $(1)),$(call not,$(call directory?,$(1)))))

# Returns a sorted list of unique paths matching the specified pattern.
#
# Arguments:
# $(1) = pattern entries must match
#
# Defaults:
# $(1) = *
#
# Returns:
# list of paths matching $(1)
#
glob = $(sort $(wildcard $(or $(1),$(glob.default))))

# By default, glob with match everything except hidden files in the current directory.
glob.default := *

# Returns a sorted list of unique paths inside the specified directory
# that match the specified pattern.
#
# Arguments:
# $(1) = list of directories to work with
# $(2) = pattern entries must match
#
# Defaults:
# $(1) = .
# $(2) = *
#
# Returns:
# list of paths in $(1) matching $(2)
#
# Example:
#
# # Enumerates all entries in the current directory.
# $(call glob.directory)
#
# Example:
#
# # Enumerates all entries in the current directory that start with ".git".
# $(call glob.directory,,.git*)
#
glob.directory = $(call glob,$(addsuffix /$(or $(2),$(glob.default)),$(or $(1),$(glob.directory.default))))

# By default, glob.directory operates on the current directory.
glob.directory.default := .

# Traverses the file system recursively.
#
# Arguments:
# $(1) = starting directory
#
# Defaults:
# $(1) = .
#
# Returns:
# list with the contents of the tree rooted in $(1)
#
file_system.traverse = $(call recurse,glob.directory,file?,$(or $(1),$(file_system.traverse.default)))

# By default, file_system.traverse operates on the current directory.
file_system.traverse.default := .

# Walks the directory and returns all files satisfying the predicate function.
# Behaves just like file_system.traverse if not given a predicate function.
#
# Arguments:
# $(1) = starting directory
# $(2) = optional predicate function
#
# Defaults:
# $(1) = .
# $(2) = true
#
# Returns:
# list containing paths in $(1) that satisfy $(2)
#
# Example:
#
# # Find all source files.
# $(call find,source,file?)
#
find = $(strip $(foreach entry,$(call file_system.traverse,$(1)),$(if $(call $(or $(2),true),$(entry)),$(entry))))
14 changes: 14 additions & 0 deletions .make/functions/library
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
library.prefix := lib
library.extension.static := .a
library.extension.dynamic := .so

# Computes the file name for the given library name and type.
#
# Arguments:
# $(1) = library name
# $(2) = linkage type: static | dynamic
#
# Returns:
# the file name for the $(1) library
#
library.file_name = $(addsuffix $(library.extension.$(2)),$(addprefix $(library.prefix),$(1)))
42 changes: 42 additions & 0 deletions .make/functions/list
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Maps the given function to all values in the given list.
#
# Arguments:
# $(1) = function to map to values
# $(2) = list of values
#
# Returns:
# results of calling the $(1) function on each value of the $(2) list
#
map = $(foreach value,$(strip $(2)),$(call $(1),$(value)))

# Removes the first element of the list and returns the rest.
#
# Arguments:
# $(1) = list of values
#
# Returns:
# the list without the first element
#
rest = $(wordlist 2,$(words $(1)),$(1))

# Inverts the order of the elements of the list.
#
# Arguments:
# $(1) = list of values
#
# Returns:
# the reversed list reversed
#
reverse = $(if $(word 2,$(1)),$(call reverse,$(call rest,$(1))) $(firstword $(1)),$(1))

# Joins all elements of the given list.
#
# Arguments:
# $(1) = list of values
# $(2) = optional separator
#
# Returns:
# elements of $(1) combined into one
#
coalesce* = $(if $(2),$(addprefix $(addsuffix $(3),$(1)),$(2)),$(1))
coalesce = $(if $(word 2,$(1)),$(call $(0)*,$(firstword $(1)),$(call $(0),$(call rest,$(1)),$(2)),$(2)),$(1))
Loading