0
votes

I have inherited a large branched project? that requires a volatile set of .a archives $(LIB_FILES) to be included into link target, located in some directories $(LIB_DIRS). I can write an expression like this:

LIBDEP = $(foreach ldir, $(LIB_DIRS), \
    $(filter $(addprefix %/, $(LIB_FILES)), $(wildcard $(ldir)/* )))

The problem is that they might not exist at moment of make's invocation and would be built by invoking $(MAKE) inside of another target's rule, which is a prerequisite to the link step.

The problem is actual list of files that should be created varies on external factors determined at their build steps, that I can't hard-code it properly, without turning makefile into a spaghetti mess and said variable is not re-evaluated at the moment of link command invocation.

I have suspicion that $(eval ) function can be used somehow, but manual is not very forthcoming as well as I didn't found examples of its use in this way.

Toolchain: GCC and binutils, make 3.81

2
You mean, it appears in the prerequisites of the link rule? - Vroomfondel
@Vroomfondel no, as parameter of command - Swift - Friday Pie
Saw your response too late - while my answer works, I think your problem is elsewhere. You are using a recursive variable which is expanded only when it is used - so if there are wrong/missing libraries at the time of invocation of the link command then there are wrong/missing libraries. - Vroomfondel
The other possibility is that your makefile is lying to itself and that the contents of $(LIB_FILES) at the point of linking doesn't really display what is to be linked. - Vroomfondel
@Vroomfondel Nah, it doesn't, libfiles are list of filenames possible, but there is no info where they might be exactly (not full paths, file with same name may exist in several directories). It always links properly on second run. This is a little weird ECS architecture with self-registering subsystems. Legacy of programmers who copy-paste and don't look for consequences - Swift - Friday Pie

2 Answers

2
votes

Another solution is to create an explicit dependency of your make script on the output of the step which currently creates the variable $(LIB_FILES). This is what the manual is dealing with in the chapter How makefiles are remade and it aims at the technique which make is best at, namely deriving dependencies from the existence and timestamp of files (instead of variables). The following hopefully depicts your situation with the process of deducing a new set of libraries simulated by the two variables $(LIBS_THIS_TIME) and $(LIB_CONFIG_SET).

LIBS_THIS_TIME = foo.a:baz.a:bar.a
LIB_CONFIG_SET = $(subst :,_,$(LIBS_THIS_TIME))

include libdeps.d

linkstep:
    @echo I am linking $^ now
    touch $@

libdeps.d: $(LIB_CONFIG_SET)
    -rm libdeps.d
    $(foreach lib,$(subst :, ,$(LIBS_THIS_TIME)),echo linkstep: $(lib) >> libdeps.d;)

$(LIB_CONFIG_SET):
    touch $@

If make finds that libdeps.d is not up to date to your current library configuration it is remade before make executes any other rule, although it is not the first target in the makefile. This way, if your build process creates a new or different set of libraries, libdeps.d would be remade first and only then make would carry on with the other targets in your top makefile, now with the correct dependecy information.

1
votes

It sometimes happens that you need to invoke make several times in succession. One possibility to do this is to use conditionals:

ifeq ($(STEP),)
all:
    <do-first-step>
    $(MAKE) STEP=2 $@
else ifeq ($(STEP),2)
all:
    <do-second-step>
    $(MAKE) STEP=3 $@
else ifeq ($(STEP),3)
all:
    <do-third-step>
endif

In each step you can generate new files and have them existing for the next step.