# # 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)