summaryrefslogtreecommitdiffstats
path: root/clink.mk
blob: e9582ac4bfe4bb8eadb30c6f8c56e6da674d553f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#
# clink.mk
# written by Kaz Kylheku 
# June 2005
#
# This a GNU Make include file that provides a system for creating a new CLISP
# linking set by adding modules to an existing one. These rules meet several
# objectives.  They:
#
# - replace the arcane old 'clisp-link add-module-set' script;
# - create a lisp image directly, without file copying, symbolic
#   links, generated shell scripts and other such things;
# - do not require the added module to be located in a particular
#   directory setup with a link.sh script; all the files and dependencies
#   are handled by these rules;
# - eliminate the use of clumsy symbolic links, since the new Lisp image
#   is linked directly out of the source directory, using relative paths.
#
# This makefile is intended to be included into another Makefile. It requires
# certain inputs in the form of certain variables being set prior to the
# inclusion. It produces outputs by assigning to variables.
#
# Input variables:
#
# CLK              A string serving as the namespace for all internal
#                  variables. This allows multiple independent instantiations 
#                  of the rules within a single GNU make process. If 
#                  you leave out this variable, it's set to CLINK_,
#                  and so all the $(CLK)X variables become just CLINK_X.
# $(CLK)SOURCE_LS  The name of the existing CLISP linking set, such as
#                  "base" or "full" (without the quotes). This makefile
#                  will find the linking set by itself, provided that the
#                  clisp executable is in the executable search path.
#                  If this variable is not set, it takes on the default
#                  value "base".
# $(CLK)TARGET_DIR The directory where to place the resulting lisp.run
#                  and lispinit.mem, with trailing slash!
# $(CLK)MODULES    Names of FFI modules with no .c or .lisp suffix.  
#                  It's assumed that for each of these, there is a .lisp
#                  file containing CLISP FFI definitions, and is compiled
#                  compiled to produce a .c file and a .fas file.
#                  It's possible, but pointless, to leave this variable unset.
# $(CLK)OBJECTS    Optional names of additional object files and libraries to 
#                  load into the new CLISP executable.
# $(CLK)PRELOAD    If this is not empty, then the boostrapping process
#                  will use an intermediate lispinit.mem, which will be
#                  stuffed with the specified Lisp modules. Probably the 
#                  biggest use for this is to set up packages. If you are 
#                  using DEF-CALL-OUT to make Lisp functions callable from C,
#                  and those functions are named by packaged symbols, then
#                  the package has to exist in the lispinit.mem, otherwise
#                  the lisp.run will fail to run at all. It will iterate
#                  over its global linked list of modules and bail when
#                  it sees references to nonexistent packages. But at this
#                  point we haven't had a chance to build our lispinit.mem.
#                  The way out of this chicken-egg problem is to build
#                  an intermediate lispinit.mem.
# $(CLK)LOAD       List of Lisp modules to load into the final memory image,
#                  not including those listed in $(CLK)MODULES.
#
# Output variables:
#
# $(CLK)CLEAN      List of intermediate files to be blown away by
#                  a "make clean".
#

# -- internals start here --

#
# Set up a default namespace
#

ifeq ($(CLK),)
CLK := CLINK_
endif

ifeq ($($(CLK)SOURCE_LS),)
$(CLK)SOURCE_LS := base
endif

#
# $(CLK)CLISP_DIR holds the CLISP library directory, underneath which
# one finds the linkkit and linking sets. E.g. /usr/local/lib/clisp
#

$(CLK)CLISP_DIR := $(shell clisp -q -norc -x \
                     '(progn (princ *lib-directory*) (values))')

#
# $(CLK)SOURCE_DIR is the source linking set, e.g. /usr/local/lib/clisp/full
#

$(CLK)SOURCE_DIR := $($(CLK)CLISP_DIR)$($(CLK)SOURCE_LS)/

#
# $(CLK)SOURCE_RUN is the Lisp executable in the source linking set.
# It could be lisp.run, or lisp.exe on Cygwin. So we just get it
# using wildcard expansion. (The GNU Make $(wildcard) function
# doesn't expand variables in the pattern, so we use shell echo).
#

$(CLK)SOURCE_RUN := $(filter-out %lisp.a,\
                                 $(shell echo $($(CLK)SOURCE_DIR)lisp.*))

$(CLK)LISPRUN := $(notdir $($(CLK)SOURCE_RUN))

#
# $(CLK)RUN_TGT is the target lisp.run that we want to build. 
# $(CLK)MEM_TGT is the target lispinit.mem that we want to build. 
# The rules in this makefile update that target, as well as the memory image.
# It's up to the parent makefile to hook these targets as dependencies in its
# own set of rules, so that these targets actually get updated.
#

$(CLK)RUN_TGT := $($(CLK)TARGET_DIR)$($(CLK)LISPRUN)
$(CLK)MEM_TGT := $($(CLK)TARGET_DIR)lispinit.mem
$(CLK)MOD_TABLE_TGT := $($(CLK)TARGET_DIR)modules.o
$(CLK)MOD_HEADER_TGT := $($(CLK)TARGET_DIR)modules.h
$(CLK)PRELOAD_FAS_TGTS := $(addsuffix .fas,$($(CLK)PRELOAD))
$(CLK)PRELOAD_LIB_TGTS := $(addsuffix .lib,$($(CLK)PRELOAD))
$(CLK)LOAD_FAS_TGTS := $(addsuffix .fas,$($(CLK)LOAD))
$(CLK)LOAD_LIB_TGTS := $(addsuffix .lib,$($(CLK)LOAD))
$(CLK)FAS_TGTS := $(addsuffix .fas,$($(CLK)MODULES))
$(CLK)C_TGTS := $(addsuffix .c,$($(CLK)MODULES))
$(CLK)OBJ_TGTS := $(addsuffix .o,$($(CLK)MODULES))
$(CLK)LIB_TGTS := $(addsuffix .lib,$($(CLK)MODULES))
$(CLK)VARS_MKF := $($(CLK)TARGET_DIR)vars.mk
$(CLK)CLEAN := $($(CLK)RUN_TGT) $($(CLK)MEM_TGT) $($(CLK)MOD_TABLE_TGT) \
               $($(CLK)VARS_MKF) $($(CLK)FAS_TGTS) $($(CLK)C_TGTS) \
               $($(CLK)OBJ_TGTS) $($(CLK)LIB_TGTS) $($(CLK)MOD_HEADER_TGT) \
               $($(CLK)PRELOAD_FAS_TGTS) $($(CLK)PRELOAD_LIB_TGTS) \
               $($(CLK)LOAD_FAS_TGTS) $($(CLK)LOAD_LIB_TGTS)
$(CLK)ALL_OBJ_TGTS := $($(CLK)OBJ_TGTS) $($(CLK)MOD_TABLE_TGT)

#
# Rule to create the vars.mk file in the target directory.
# This rule also creates the target directory, if it does
# not exist. Since vars.mk is a dependency of this makefile
# itself by way of include, this rule is processed first,
# and so ensures that the target directory exist.
#


$($(CLK)VARS_MKF):
        mkdir -p $(CLINK_TARGET_DIR)
        . $(CLINK_SOURCE_DIR)makevars ; \
          echo "\$$(\$$(CLK)RUN_TGT): CFLAGS += $$CFLAGS" > $@ ; \
          echo "\$$(\$$(CLK)ALL_OBJ_TGTS): CPPFLAGS += $$CPPFLAGS" >> $@ ; \
          echo "\$$(\$$(CLK)RUN_TGT): CLFLAGS += $$CLFLAGS" >> $@ ; \
          echo "\$$(CLK)LIBS := $$LIBS" >> $@

$($(CLK)MOD_TABLE_TGT): CFLAGS += -I$(CLINK_TARGET_DIR)

$($(CLK)MOD_TABLE_TGT): $($(CLK)CLISP_DIR)linkkit/modules.c \
                               $($(CLK)MOD_HEADER_TGT)
        $(CC) $(CFLAGS) -c -o $@ $<

$($(CLK)MOD_HEADER_TGT):
        $(RM) $@
        for mod in $(CLINK_MODULES) ; do echo "MODULE($$mod)" >> $@ ; done

ifneq ($(MAKECMDGOALS),clean)
include $($(CLK)VARS_MKF)
endif

#
# $(CLK)SOURCE_ARS is the list of archive files in the source linking
# set. We get this by way of the $(CLK)LIBS variable in the makevars file
# in that directory, rather than by wildcard globbing. The reason for
# that is that we don't want to mistakenly include libnoreadline.a.
#

$(CLK)SOURCE_ARS := $(foreach LIB,$($(CLK)LIBS),\
                              $(if $(filter -%,$(LIB)),,$($(CLK)SOURCE_DIR)$(LIB)))

#
# $(CLK)SOURCE_LIBS is a list of additional libraries that need
# to be linked. Like $(CLK)SOURCE_ARS, this comes from the $(CLK)LIBS variable
# in the makevars file of the source linking set. 
#

$(CLK)SOURCE_LIBS := $(foreach LIB,$($(CLK)LIBS),\
                               $(if $(filter -%,$(LIB)),\
                                  $(LIB),))

$($(CLK)RUN_TGT): $($(CLK)SOURCE_ARS) $($(CLK)MOD_TABLE_TGT) \
                  $($(CLK)OBJ_TGTS) $($(CLK)OBJECTS)
        $(CC) $(CFLAGS) $(CLFLAGS) -o $@ $^ $(CLINK_SOURCE_LIBS)

$($(CLK)OBJ_TGTS): $($(CLK)C_TGTS)
        $(CC) $(CFLAGS) -I$(CLINK_CLISP_DIR)linkkit -o $@ $^ -c

$($(CLK)C_TGTS): %.c: %.lisp
        "$(CLINK_SOURCE_RUN)" -B "$(CLINK_CLISP_DIR)" \
          -M "$(CLINK_SOURCE_DIR)lispinit.mem" -q -c $<

$($(CLK)PRELOAD_FAS_TGTS): %.fas: %.lisp
        "$(CLINK_SOURCE_RUN)" -B "$(CLINK_CLISP_DIR)" \
          -M "$(CLINK_SOURCE_DIR)lispinit.mem" -q -c $<

$($(CLK)LOAD_FAS_TGTS): %.fas: %.lisp
        "$(CLINK_RUN_TGT)" -B "$(CLINK_CLISP_DIR)" \
          -M "$(CLINK_INTERMEDIATE_MEM)" -q -c $<

#
# If $(CLK)PRELOAD contains something, then we need to set up rules that
# make an intermediate memory image by loading these files using the original
# linking set. The new CLISP binary is then used in conjunction with this
# intermediate image to load more Lisp code and dump the final image.
#

ifeq ($($(CLK)PRELOAD),)
$(CLK)INTERMEDIATE_MEM := $($(CLK)SOURCE_DIR)lispinit.mem
else
$(CLK)INTERMEDIATE_MEM := $($(CLK)TARGET_DIR)intermediate.mem

$(CLK)CLEAN += $($(CLK)INTERMEDIATE_MEM)

$($(CLK)INTERMEDIATE_MEM): $($(CLK)PRELOAD_FAS_TGTS)
        "$(CLINK_SOURCE_RUN)" -B "$(CLINK_CLISP_DIR)" \
          -M "$(CLINK_SOURCE_DIR)lispinit.mem" -norc -q -i \
          $(CLINK_PRELOAD) -x "(saveinitmem \"$@\")"
endif

$($(CLK)MEM_TGT): $($(CLK)RUN_TGT) $($(CLK)INTERMEDIATE_MEM) \
                  $($(CLK)FAS_TGTS) $($(CLK)LOAD_FAS_TGTS)
        "$(CLINK_RUN_TGT)" -B "$(CLINK_CLISP_DIR)" \
          -M "$(CLINK_INTERMEDIATE_MEM)" -norc -q -i \
          $(CLINK_MODULES) $(CLINK_LOAD) -x "(saveinitmem \"$@\")"

#
# Hack: GNU Make has a problem. Variables that occur in
# rule action bodies are expanded when those rules are run, not when
# they are defined, and there doesn't appear to be a way to change
# the behavior. So the namespace trick $($(CLK)VAR) won't work
# within rule bodies; the value of the global variable CLK will be taken at the
# time the rule is run to update its target, not at the time the makefile is
# read out.  The target-specific-assignment mechanism, however, gives us a kind
# of dynamic scoping namespace surrounding a target, so here we exploit that to
# create target-local ``bindings'' of all our global namespaced variables. We
# use those bindings in rule bodies.
#

$($(CLK)CLEAN): CLINK_TARGET_DIR := $($(CLK)TARGET_DIR)
$($(CLK)CLEAN): CLINK_CLISP_DIR := $($(CLK)CLISP_DIR)
$($(CLK)CLEAN): CLINK_SOURCE_DIR := $($(CLK)SOURCE_DIR)
$($(CLK)CLEAN): CLINK_SOURCE_RUN := $($(CLK)SOURCE_RUN)
$($(CLK)CLEAN): CLINK_MODULES := $($(CLK)MODULES)
$($(CLK)CLEAN): CLINK_SOURCE_LIBS := $($(CLK)SOURCE_LIBS)
$($(CLK)CLEAN): CLINK_PRELOAD := $($(CLK)PRELOAD)
$($(CLK)CLEAN): CLINK_LOAD := $($(CLK)LOAD)
$($(CLK)CLEAN): CLINK_INTERMEDIATE_MEM := $($(CLK)INTERMEDIATE_MEM)
$($(CLK)CLEAN): CLINK_RUN_TGT := $($(CLK)RUN_TGT)