back to char* for lexer_lexstring
[henge/webcc.git] / make / lib / rules.mk
1 ################################################################################
2 # Desc: Make functions for creating rules (Make making Make)
3 # Author: Ken Grimes
4 # Date: 2016
5 ################################################################################
6 # This file consists of library functions for make-making-make functionality
7 ################################################################################
8
9 # A long function definition to grab deps from the source's compiler and route
10 # errors to /dev/null if the rule generator expresses bogus errors
11 define SRC_LANG_FLAGS_OPT_DEPS =
12 $(filter-out \ %:,$(shell $($2_C) $3 $4 -MG $1 2> /dev/null))
13 endef
14
15 #SRC_LANG_RULE###################################################################
16 # Given a source and a language, generate a rule to make the object. The second
17 # invocation of gcc per file lists only its local includes, and filters out
18 # anything already caught. Anything remaining should be considered to be
19 # available in the current working directory of the source file(i.e. if you
20 # '#include "something.h"' in 'mymodule/horseradish.c', you would expect to
21 # include 'mymodule/something.h'. this check lets that happen), otherwise it is
22 # some kind of user error #######################################################
23 define SRC_LANG_RULE =
24 $(if $($1),,$(eval $1 := t)\
25 $(eval MOD := $(filter $(MODULES),$(firstword $(subst /, ,$(subst $(SRC_DIR),,$(dir $1))))))\
26 $(eval FLG := $(MOD:%=-I$(SRC_DIR)/% ))\
27 $(if $(wildcard $1),
28 $(eval DEPS := $(filter-out \ %:,$(shell $($2_C) $(FLG) -M -MG $1)))\
29 $(eval DDEPS := $(filter $(DRIVER_DIR:$(SRC_DIR)/%=%/%),$(DEPS)))\
30 $(eval MDEPS := $(filter $(MODULES:%=%/%),$(DEPS)))\
31 $(eval DEPS := $(filter-out $(DDEPS) $(MDEPS),$(DEPS)))\
32 $(eval MDEPS := $(MDEPS:%=$(SRC_DIR)/%))\
33 $(eval DDEPS := $(DDEPS:%=$(SRC_DIR)/%))\
34 $(eval LOST := $(filter-out \ %: $(DRIVER_DIR:./%=%)/% $(MODULES:%=$(SRC_DIR:./%=%)/%/%),$(shell $($2_C) $(FLG) -MM -MG $1)))\
35 $(eval MDEPS += $(LOST:%=$(dir $1)%))\
36 $(eval MDEPS := $(shell echo $(MDEPS) | sed -e 's@[a-zA-Z0-9\-\+/]*\.\./include@$(LIBINC_DIR)@g'))\
37 $(eval ALLDEPS := $(DDEPS) $(MDEPS) $(DEPS)),\
38 $(error Cannot generate deps for: $1, file not found))\
39 $(eval SRC_OBJ := $(basename $1).$($2_OBJ))\
40 $(eval MAKE_TARGETS += $(SRC_OBJ))
41 # Assume that lost dependencies are in the folder with the source
42 $(foreach lost,$(LOST),
43 $(eval ALLDEPS := $(subst $(lost), $(dir $1)$(lost),$(ALLDEPS))))
44
45 # Find relative deps in our local LIBINC_DIR, if available. Otherwise they
46 # should be expected in the src directory
47 $(eval RELDEPS := $(filter-out $(SRC_DIR:./%=%)/% ./% /%,$(ALLDEPS)))
48 $(foreach dep,$(RELDEPS),
49 $(eval ALLDEPS := $(subst $(dep),\
50 $(if $(wildcard $(LIBINC_DIR)/$(dep)),$(LIBINC_DIR),$(SRC_DIR))/$(dep),$(ALLDEPS))))
51
52 # Find any deps that aren't built yet, which the compiler has flagged
53 # as missing, but which we know the expected location of libs for
54 # this language should have their includes in 'LIBINC_DIR'
55 $(eval BUILDDEPS := $(filter $($2_LIBS:%=%/%),$(ALLDEPS)))
56 $(eval ALLDEPS := $(filter-out $(BUILDDEPS),$(ALLDEPS)) $(BUILDDEPS:%=$(LIBINC_DIR)/%))
57 # Object for $1
58 $(SRC_OBJ): $(ALLDEPS)
59 $($2_C) $$($2_FLAGS) $(FLG) -c -o $$@ $1
60 $(if $($2_DBG),\
61 $(eval DBG_OBJ := $(dir $1).$($2_DBG)/$(basename $(notdir $1)).$($2_OBJ))\
62 $(if $(findstring $(dir $(DBG_OBJ)),$(MAKE_DIRS)),,\
63 $(eval MAKE_DIRS += $(dir $(DBG_OBJ))))
64 $(eval MAKE_TARGETS += $(DBG_OBJ))
65 # Object for $1 with $($2_DBG) symbols
66 $(DBG_OBJ): $(ALLDEPS) | $(dir $(DBG_OBJ))
67 $($2_C) $$($2_FLAGS) $(FLG) -Og -g$($2_DBG) -c -o $$@ $1
68 ))
69 #/SRC_LANG_RULE##################################################################
70 endef
71
72 #SRC_LANG_DRVRULE################################################################
73 # establish a build and link rule given a source driver and language ############
74 define SRC_LANG_DRVRULE =
75 $(eval DRIVER_NAME := $(basename $(notdir $1)))
76 $(eval DRIVER_TARG := $(1:$(SRC_DIR)/%.$2=$(ROOT_DIR)/%$($2_OUT)))
77 $(eval DRIVER_TARG_D := $(DRIVER_TARG)-d)
78 $(eval DRIVER_SOB := $(basename $1).$($2_OBJ))
79 $(eval DRIVER_SOB_D := $(DRIVER_SOB:$(dir $(DRIVER_SOB))%=$(dir $(DRIVER_SOB)).$($2_DBG)/%))
80
81 # Generate a rule for the driver object
82 $(eval $(call SRC_LANG_RULE,$1,$2))
83
84 # Modules can be implicitly specified by a driver if its dependencies include
85 # ANY files from any module directory. The 'MDEPS' var is set by SRC_LANG_RULE
86 # and expresses the dependencies required to build the object file only.
87 $(foreach module_dep,$(MDEPS),
88 $(eval DRIVER_MODULES += $(firstword $(subst /, ,$(module_dep))))
89 )
90 $(eval DRIVER_MODULES := $(filter-out $(DRIVER_DIR) . ..,$(sort $(DRIVER_MODULES))))
91
92 # Read associated linking data for the driver. If no link data is available,
93 # all libraries are assumed to be statically linked by the build system. files
94 # prefixed with 'test' will first attempt to find a 'ld' file matching its
95 # basename with the 'test' prefix removed (i.e. ./src/bin/testscanner.c will
96 # first attempt to find ./src/bin/scanner.ld for its ld information. if not
97 # available, it will instead use ./src/bin/testscanner.ld. if still not
98 # available, all libraries will attempt static linking - and if those static
99 # libs are not available, the system will attempt to retrieve the source code
100 # and build the static lib
101 $(eval DRIVER_LDFILE := $(1:%.$2=%.ld))
102 $(if $(filter test%,$(DRIVER_NAME)),
103 $(eval DRV_LD := $(subst $(DRIVER_NAME).$2,$(DRIVER_NAME:test%=%).ld,$1))
104 $(if $(wildcard $(DRV_LD)),
105 $(eval DRIVER_LDFILE := $(DRV_LD))
106 ))
107 $(eval $1_LD := $(file <$(DRIVER_LDFILE)))
108 $(eval undefine DRIVER_LDINFO)
109 $(eval undefine DRIVER_LDINFO_D)
110 $(eval DRIVER_LDINFO += $(1:%.$2=%.$($2_OBJ)))
111 $(eval DRIVER_LDINFO_D += $(1:$(dir $1)%.$2=$(dir $1).$($2_DBG)/%.$($2_OBJ)))
112 $(foreach ldobj,$($1_LD),
113 $(if $(filter -l%,$(ldobj)),
114 $(eval ldlibname := $(ldobj:-l%=%))
115 $(if $(filter $(ldlibname),$($($2_C)_LDLIBS)),
116 $(eval DRIVER_LDINFO += $(ldobj))
117 $(eval DRIVER_LDINFO_D += $(ldobj)),
118 $(info Statically linking '$(ldobj:-l%=lib%)', linker '$($($2_C)_LD)' for compiler '$($2_C)' cannot link this lib.)
119 $(if $($(ldlibname)_INIT),,$(call LANG_LIB_INIT,$2,$(ldlibname),$1))
120 $(foreach deplib,$($(ldlibname)_DEPS) $(ldlibname),
121 $(eval DRIVER_LDINFO += $(LIB_DIR)/$(deplib).$($2_AROBJ))
122 $(eval DRIVER_LDINFO_D += $(LIB_DIR)/.$($2_DBG)/$(deplib).$($2_AROBJ)))
123 ),
124 $(if $(findstring $(ldobj),$(MODULES)),
125 $(eval DRIVER_LDINFO += $(SRC_DIR)/$(ldobj).$($2_AROBJ))
126 $(eval DRIVER_LDINFO_D += $(SRC_DIR)/.$($2_DBG)/$(ldobj).$($2_AROBJ)),
127 $(info Resolving static dependencies for '$(ldobj:%=lib%)'.)
128 $(if $($(ldobj)_INIT),,$(call LANG_LIB_INIT,$2,$(ldobj),$1))
129 $(foreach deplib,$($(ldobj)_DEPS) $(ldobj),
130 $(eval DRIVER_LDINFO += $(LIB_DIR)/$(deplib).$($2_AROBJ))
131 $(eval DRIVER_LDINFO_D += $(LIB_DIR)/.$($2_DBG)/$(deplib).$($2_AROBJ)))
132 ))
133 )
134
135 # Directory setup
136 $(eval MAKE_DIRS += $(dir $(DRIVER_TARG)))
137 $(if $($2_DBG),
138 $(eval MAKE_DIRS += $(dir $(DRIVER_TARG_D))))
139
140 # Add the driver target to this language's targets for cleaning
141 $(eval SCRUB_TARGETS += $(DRIVER_TARG) $(DRIVER_TARG_D))
142 $(DRIVER_TARG): $(filter-out -l%,$(DRIVER_LDINFO)) | $(dir $(DRIVER_TARG))
143 $($2_C) $($2_FLAGS) $(DRIVER_LDINFO) -o $$@
144 # Output a rule for building with debug flags
145 $(eval MAKE_DIRS += $(DRIVER_TARG_DIR).$($2_DBG)/)
146 $(DRIVER_TARG_D): $(filter-out -l%,$(DRIVER_LDINFO_D)) | $(dir $(DRIVER_TARG_D))
147 $($2_C) $($2_FLAGS) $(DRIVER_LDINFO_D) -o $$@
148
149 #/SRC_LANG_DRVRULE###############################################################
150 endef
151
152 #MODULE_ARCRULE##################################################################
153 # generate rule for turning an entire module's collection of binary objects into
154 # a single locally-linked (no external -L libs) object (for simplified linking
155 # modules as static libs).#######################################################
156 define MODULE_ARCRULE =
157 $(eval ARCDEPS := $(filter $(SRC_DIR)/$1/%.$(c_OBJ),$(foreach lang,$(LANGS),$($(lang)_MOD_TRG))))\
158 $(eval MAKE_TARGETS+= $(SRC_DIR)/$1.$(c_AROBJ))\
159
160 $(SRC_DIR)/$1.$(c_AROBJ): $(ARCDEPS)
161 $(c_AR) cr $$@ $$^
162 $(if $(c_DBG),
163 $(eval undefine DBGARCDEPS)
164 $(foreach arcdep,$(ARCDEPS),$(eval DBGARCDEPS += $(dir $(arcdep)).$(c_DBG)/$(notdir $(arcdep))))
165 $(eval MAKE_TARGETS+= .$(c_DBG)/$1.$(c_AROBJ))\
166
167 $(SRC_DIR)/.$(c_DBG)/$1.$(c_AROBJ): $(DBGARCDEPS) | .$(c_DBG)/
168 $(c_AR) cr $$@ $$^
169 )
170 #/MODULE_ARCRULE#################################################################
171 endef
172
173 # LANG_LIB_PARENT_BUILDRULE######################################################
174 # define rules for creating unknown libraries in the local build environment for
175 # either binary or bytecode representation given a library name and, optionally,
176 # a parent lib that included it for error reporting #############################
177 define LANG_LIB_PARENT_BUILDRULE =
178 $(eval CONF_FLAG := --prefix=$(abspath $(LIB_DIR)).trash)
179 $(eval CONF_FLAG += --includedir=$(abspath $(LIBINC_DIR)))
180 # Setup installation rule steps for this lib
181 $(eval
182 BUILDSTEPS := $(if $(AUTOGEN),$(AUTOGEN) && )
183 BUILDSTEPS += $(if $(CONFIGURE),$(CONFIGURE) $(CONF_FLAG) --libdir=$(abspath $(LIB_DIR)) && )
184 $(if $(MKCMD),\
185 BUILDSTEPS += $(MKCMD),
186 $(error $2.mk requires a valid MKCMD definition))
187 $(if $(MKINSTALL),\
188 INSTALLCMD := $(MKINSTALL),\
189 $(error $2.mk requires a valid MKINSTALL definition))
190 CLEANCMD := $(MKCLEAN)
191 )
192 # Construct the download method, or error if there isn't a valid one
193 $(if $(GITADDR),$(eval LIBDL := git clone $(GITADDR) $2),\
194 $(if $(HGADDR),$(eval LIBDL := hg clone $(HGADDR) $2),\
195 $(if $(CVSADDR),\
196 $(eval LIBDL := export CVSROOT=$(CVSADDR))\
197 $(eval LIBDL += && echo '$(CVSPASS)' > ~/.cvspass)\
198 $(eval LIBDL += && cvs $($2_CVSGET))
199 $(eval LIBDL += && $(if $(CVSPASS_BAK),echo $(CVSPASS_BAK) > ~/.cvspass,rm ~/.cvspass)),\
200 $(if $(WEBADDR),$(eval LIBDL := wget -O $(WEBTARG) $(WEBADDR)),\
201 $(eval $(error No way to download $2 needed by $3 for $1 language ))))))
202 # '$2' Download Rule
203 $(LIBDL_DIR)/$2:
204 mkdir -p $$@
205 cd $(LIBDL_DIR) && $(LIBDL) $(if $(WEBINIT),&& $(WEBINIT))
206 # '$2' Make and install rule, and ensure it isn't marked "clean"
207 $(LIB_DIR)/lib$2.$($1_AROBJ): $(LIBDEPS:%=$(LIB_DIR)/lib%.$($1_AROBJ)) | $(LIBDL_DIR)/$2
208 @mkdir -p $(LIB_DIR)
209 cd $(LIBDL_DIR)/$2 && export LD_RUN_PATH=$(LIBLDPATH) && $(BUILDSTEPS)
210 cd $(LIBDL_DIR)/$2 && $(INSTALLCMD)
211 @rm -f $(LIBDL_DIR)/$2.clean
212
213 # '$2' Rule for building under debug mode
214 $(if $($1_DBG),\
215 $(eval LIBDBG_DIR := $(LIB_DIR)/.$($1_DBG))\
216 $(eval $(if $(findstring $(LIBDBG_DIR),$(MAKE_DIRS)),,MAKE_DIRS += $(LIBDBG_DIR)))\
217 $(eval LIBDBG_TARG := $(LIBDBG_DIR)/lib$2.$($1_AROBJ))\
218 $(eval LIBDBG_DEPS := $(LIBDEPS:%=$(LIB_DIR)/.$($1_DBG)/lib%.$($1_AROBJ)))\
219 $(eval DBGBUILDSTEPS := $(if $(AUTOGEN),$(if $(AUTOGENDBG),$(AUTOGENDBG),$(AUTOGEN)) && ))\
220 $(eval DBGBUILDSTEPS += $(if $(CONFIGURE),$(if $(CONFIGUREDBG),$(CONFIGUREDBG),$(CONFIGURE)) $(CONF_FLAG) --libdir=$(abspath $(LIB_DIR))/.$($1_DBG)))\
221 $(eval DBGBUILDSTEPS += $(if $(MKDBGCMD),$(MKDBGCDM),$(MKCMD)))\
222
223 # '$2' Make and install rule for debugging
224 $(LIBDBG_TARG): $(LIBDBG_DEPS) | $(LIBDL_DIR)
225 @mkdir -p $(LIBDBG_DIR)
226 cd $(LIBDL_DIR)/$2 && export LD_RUN_PATH=$(LIBLDPATH:$(LIB_DIR)%=$(LIBDBG_DIR)) && $(DBGBUILDSTEPS)
227 cd $(LIBDL_DIR)/$2 && $(INSTALLCMD)
228 @rm -f $(LIBDL_DIR)/$2.clean
229 )
230
231 # '$2' Clean rule - drop a marker in the directory so we don't bother cleaning
232 # things that are clean... by default there is no real way of tracking this in a
233 # makefile
234 clean_$2:
235 $$(if $$(wildcard $(LIBDL_DIR)/$2),$$(if $$(wildcard $(LIBDL_DIR)/$2.clean),,\
236 cd $(LIBDL_DIR)/$2 && $(CLEANCMD) && touch $(abspath $(LIBDL_DIR))/$2.clean))
237
238 #/LANG_LIB_PARENT_BUILDRULE######################################################
239 endef
240
241
242 #LANG_LIB_INIT###################################################################
243 # For every library in this language, we need to determine how, and if, to link
244 # its data. This could potentially be done recursively as libraries have
245 # dependencies upon each other. We call a recursive macro here to expand out
246 # all the libs for this language, and then flatten the tree by removing
247 # duplicates with shell commands. We can't use make's 'sort' function because
248 # we actually care about the ordering so that interdependent libraries can link
249 # back up the tree ##############################################################
250 define LANG_LIB_INIT =
251 # Initialize per-library data, then import data from an accompanying file that
252 # can overwrite these vars
253 $(eval
254 # Implicit defaults for lib.mk files
255 AUTOGEN := ./autogen.sh
256 AUTOGENDBG := ./autogen.sh --enable-debug
257 CONFIGURE := ./configure
258 MKCMD := make -k
259 MKINSTALL := make -k install
260 MKCLEAN := make clean
261 MKDBGCMD := make -k
262 LIBDEPS :=
263 LIBLANGS := c cpp go
264 LIBLDPATH := $(if $($($1_C)_LD),$(if $(LD_LIBRARY_PATH),$(LD_LIBRARY_PATH):,/usr/lib:)$(abspath $(LIB_DIR)))
265 # One of these must be defined in the .mk file imported
266 $(foreach var, GITADDR WEBADDR HGADDR CVSADDR,\
267 $(eval undefine $(var)))
268 # Other, optional, variables to clear
269 $(foreach var, WEBTARG WEBINIT CVSGET CVSPASS CONFIGUREDBG,
270 $(eval undefine $(var)))
271 )
272 # If there is a .mk file for this lib, import it. Otherwise, we'll try to link
273 # it later, unless there is no linker for the language's compiler.
274 $(if $(wildcard $(CONF_DIR)/$2.mk),$(eval $(file <$(CONF_DIR)/$2.mk)),\
275 $(if $($($1_C)_LD),\
276 $(warning No $2.mk for lib$2, attempting to link from the system),\
277 $(error No $2.mk for lib$2 and '$($1_C)' is not configured for linking)))\
278
279 # Add dependencies we found (potentially recursively, ignore repeats until later
280 # so we can preserve ordering information for interdependency build ordering)
281 $(if $(LIBDEPS),\
282 $(eval $1_LIBS += $(LIBDEPS))\
283 $(if $3,$(eval $3_DEPS += $(LIBDEPS)))\
284 $(eval $2_DEPS += $(LIBDEPS))\
285 )
286 # languages that can link this library (typically any lang that shares the
287 # object format (ELF by default, but this is compiler-dependent (e.g. emcc uses
288 # llvm bitcode, which is just an intermediary representation of data that can
289 # link to anything else statically, or as an archive)))
290 $(if $(findstring $1,$(LIBLANGS)),,\
291 $(error $2.mk must specifically set LIBLANGS := $1 if it is compatible with $1))
292 # Mark this lib as available for all its other compatible languages. This list
293 # is assumed to be sorted later, so we will ignore repeats for speed
294 $(foreach lang,$(LIBLANGS),\
295 $(if $(findstring $2,$($(lang)_LIBS)),,\
296 $(eval $(lang)_LIBS += $2)))
297 # Generate a build rule for this lib, unless it's already built
298 $(if $(findstring $2,$(BUILTLIBS)),,\
299 $(eval $(call LANG_LIB_PARENT_BUILDRULE,$1,$2,$3))\
300 $(eval BUILTLIBS += $2))
301 # Recurse this function for every libdep encountered
302 $(foreach libdep,$(LIBDEPS),\
303 $(call LANG_LIB_INIT,$1,$(libdep),$2))
304 $(eval $2_DEPS := $(shell echo "$($2_DEPS)" | $(call AWK_REVERSE_SQUASH)))
305 $(eval $2_INIT := t)
306 #/LANG_LIB_INIT#################################################################
307 endef
308
309 # Initialize data for supported lanaguages #####################################
310 define LANG_INIT =
311 $(eval
312 $1_OBJ := $($($1_C)_OBJ)
313 $1_OUT := $($($1_C)_OUT)
314 $1_AROBJ := $($($1_C)_AROBJ)
315 $1_SOURCES := $(shell find $(SRC_DIR) -name "*.$1" -not -name ".*")
316 $1_DBG := $($($1_C)_DBG)
317 $1_AR := $($($1_C)_AR)
318 )
319 # Find save language-specific driver and module sources and targets
320 $(eval $1_DRV_SRC := $(filter $(DRIVER_DIR)/%,$($1_SOURCES)))
321 $(eval $1_DRV_TRG := $(patsubst $(SRC_DIR)/%.$1,$(ROOT_DIR)/%$($1_OUT),$($1_DRV_SRC)))
322 $(eval $1_MOD_SRC := $(filter-out $(DRIVER_DIR)/%,$($1_SOURCES)))
323 $(eval $1_MOD_TRG := $(addsuffix .$($1_OBJ),$(basename $($1_MOD_SRC))))
324 # Add those sources and targets to a language-irreverant var
325 $(eval
326 DRV_SRC += $($1_DRV_SRC)
327 DRV_TRG += $($1_DRV_TRG)
328 MOD_SRC += $($1_MOD_SRC)
329 MOD_TRG += $($1_MOD_TRG)
330 )\
331 # First, initialize language-module, module, and language relative data. Then,
332 # filter out each source file from the module and generate Dependency Rules and
333 # Module Object Rules for each of them.
334 $(foreach module,$(MODULES),
335 # Evaluate the module sources for this language
336 $(eval $(module)_$1_SRC := $(filter $(SRC_DIR)/$(module)/%,$($1_MOD_SRC)))
337 # Evaluate module targets for this language
338 $(eval $(module)_$1_TRG := $($(module)_$1_SRC:%.$1=%.$($1_OBJ)))
339 # Add these language-specific sources and targets to the module's src/targs
340 $(eval
341 $(module)_SRC += $($(module)_$1_SRC)
342 $(module)_TRG += $($(module)_$1_TRG)
343 )
344 # For every source file, create a build rule for it for our language
345 $(foreach src,$(filter $(SRC_DIR)/$(module)/%,$($1_MOD_SRC)),\
346 $(eval $(call SRC_LANG_RULE,$(src),$1))\
347 ))
348 #/LANG_INIT#####################################################################
349 endef
350
351 # Create a phony target and rule for the specified source driver
352 define DRVSRC_DRIVERPHONY
353 $(eval PH_TARG := $(basename $(notdir $1)))
354 $(eval PH_TARGS += $(PH_TARG))
355 $(eval PH_LANG := $(lastword $(subst ., ,$1)))
356 $(eval RL_TARG := $(basename $(subst $(SRC_DIR),$(ROOT_DIR),$1))$($(PH_LANG)_OUT))
357 .PHONY: $(PH_TARG) $(PH_TARG:%=%-d)
358 $(PH_TARG): $(RL_TARG)
359 @echo Built [$$@] at ./$$<
360 $(PH_TARG:%=%-d): $(RL_TARG:%=%-d)
361 @echo Build [$$@] with debugging information at ./$$<
362 #/SRC_SIMLIST_PHONYRULE ########################################################
363 endef