0
votes

I'm working with a makefile system using mcs as its build command. Briefly, mcs is invoked with:

  • source files: Passed directly;
  • resources: with -resource:;
  • a target: with -target: and can be exe, winexe, library or module.

And produces an *.exe, *.dll or *.netmodule. The -target: parameter is certain in the last two cases but an *.exe can be built with either exe or winexe.

Currently, each directory's makefile includes what boils down to this:

RESOLVED_SOURCES   := $(addprefix $(srcdir)/,$(SOURCES))
RESOLVED_RESOURCES := $(addprefix $(srcdir)/,$(RESOURCES))

S_PARAM := $(RESOLVED_SOURCES)
R_PARAM := $(addprefix -resource:,$(RESOLVED_RESOURCES))

all: $(OUTPUT)

$(OUTPUT): $(RESOLVED_SOURCES) $(RESOLVED_RESOURCES)
    $(MCS) $(MCSARGS) $(S_PARAM) $(R_PARAM) -target:$(TARGET) -out:$(OUTPUT)

And in each project directory the variables OUTPUT, TARGET, SOURCES and RESOURCES are defined before inclusion.

Even with everything I've left out it's fairly complicated and suffers from only being able to build a single concrete target where it's included, without duplicating the build rule.

To avoid the duplication and increase flexibility I'd like to define some pattern rules for this complex build command but it's difficult:

  • each compilation unit generally has many inputs;
  • there's no way to incrementally add each input;
  • some inputs need different handling.

e.g. For mcs these patterns seem possible:

%.exe: %.cs
    $(MCS) $(MCSARGS) -target:$(target) -out:$@ $< 

%.dll: %.cs
    $(MCS) $(MCSARGS) -target:library -out:$@ $< 

%.netmodule: %.cs
    $(MCS) $(MCSARGS) -target:module -out:$@ $< 

As pattern rules go they aren't too bad but they aren't useful for most applications of mcs as there's only a single source file being passed.

If the user adds source file prerequisites for a target then the above $< could be swapped for $^ to pass them all but that won't work for resource files. The order only list could be used for passing resource file prerequisites but would prevent rebuilds when only resource files were updated.

Is there a general technique for turning this sort of complex command's invocation into a pattern rule or set of rules?

1
This convoluted use of Make already has one bad consequence: it makes your question unclear. Before I can even attempt to find the Right Way to do this, I have to unriddle what you're trying to do and why, and that's enough to make me go look for more rewarding problems. Also, your run-on sentences hurt my eyes. - Beta
Should be pretty clear, it's in the title. I'm trying to handle multiple prerequisite types while having VPATH work. - arfbtwn
We don't know what "multiple types of prerequisites" means. What is a "type of prerequisite"? What Beta is suggesting is that rather than provide info about problems you already solved, or at least in addition, you provide concrete examples of what you're trying to accomplish. Also, you absolutely can tell the difference between normal an order-only prerequisites; see the list of automatic variables: gnu.org/software/make/manual/html_node/Automatic-Variables.html - MadScientist
The multiple types of prerequisite is referring to the build command I need to invoke. The concrete example is actually mcs that accepts source and resource files which are passed differently. Neither of those could be considered order only. Otherwise, as you point out, that's possible with $|. - arfbtwn
Sorry but IMHO it is still not clear what you are asking. From the bullet list at the end of your new edit I take it that you are looking for an algorithm which runs on a do-what-I-want premise, converting a list of inputs in a more or less arbitrary way into a compile command. Without proper structuring of your problem you won't be able to do that, neither will someone on SO. The programmer of the original solution obviously also deemed this a too complex task and wrote each instance by hand. - Vroomfondel

1 Answers

0
votes

There are a number of problems:

  1. the build command distinguishes more than one prerequisite type;
  2. they must all be passed at once;
  3. updates to any of them must cause a rebuild, they are all regular prerequisites.

Ideas:

  • delegating the inputs you want to separate to input files and then reading them back in allows you to have a simple target invoking the build;
  • using secondary expansion you can define those input files based on the contents of "pattern variables";
  • general search should work.

For example:

multi_A := foo
multi_B := bar

all: multi.foo

%.foo: .a.% .b.%
    @echo $*: $(foreach _,$^,$(file < $_))
    @touch $@

.SECONDEXPANSION:

.a.%: $$($$*_A)
    $(file > $@,$^)

.b.%: $$($$*_B)
    $(file > $@,$(addprefix -b:,$^))

To start with using secondary expansion seems dubious. Apart from that the immediate issue with this is that the user has to know that any regular prerequisites will be read and passed to the build command.

On the other hand, knowing that, the user can supplement a target with extra input parameters by depending on a target that writes them to another input file.