Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

[OT] Making GNU make do what I mean

by afoken (Chancellor)
on Sep 14, 2022 at 15:36 UTC ( [id://11146880]=perlquestion: print w/replies, xml ) Need Help??

afoken has asked for the wisdom of the Perl Monks concerning the following question:

(Also posted on Stackoverflow, with suboptimal results and at least one deleted answer so far.)

I have a Makefile like this:

default: exe %.obj: %.src # dummy compiler @echo link $< to $@ cat $< > $@ exe: main.obj foo.obj bar.obj # dummy linker @echo link $^ to $@ cat $^ > $@ main.obj: main.src foo.obj: /some/dir/1/foo.src bar.obj: /some/dir/2/bar.src

Make can't compile foo.obj and bar.obj (and 20+ other objects), because it does not use the %.obj: %.src rule. The directories of foo.obj and foo.src resp. bar.obj and bar.src do not match, so the rule does not match.

To make that Makefile work, I copied the compiler lines from the pattern rule to the foo.obj and bar.obj rules (and the 20+ other object rules). That's anything but clean and maintainable. Using a canned receipe shortens the copied receipe, but it is still a copy. I don't want to repeat myself. make should be smart enough to find a receipe to compile *.src to *.obj, no matter where those files are.

Essentially, I need a pattern rule that ignores the source and object directories when comparing.


Why, oh why, am I doing this?

foo.src and friends are scattered across a big third-party "SDK" directory tree that is NOT part of the source code in the directory with the Makefile. (Think of it as a christmas tree with a lot of candles. Ripping off the candles is a no-no, as is spraying a few liters of highly flameable liquid onto the tree.) If you want to compile software using the SDK, you are expected to compile the required SDK source files and link them with your code. Note that there are many more source files than really needed, so compiling and linking all of them causes a lot of conflicts and extra compile time. Ultimately, linking will fail.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Replies are listed 'Best First'.
Re: [OT] Making GNU make do what I mean
by Perlbotics (Archbishop) on Sep 14, 2022 at 18:26 UTC

    Try this rule (verified with GNU Make 4.2.1):

    %.obj: $(filter %.src,$<) # obj dummy compiler @echo compile $< to $@ cat $< > $@
    Simpler/more brutal: Remove the %.src part from your original rule to compile anything into an *.obj file if all possible source files can be compiled by the same sequence of instructions.

      It works great, but I don't fully understand why. It even works better than specified in my post, because I want the compiled SDK files in a subdirectory. This is my working test dummy:

      default: all all: exe clean: rm -f foo.obj bar.obj sdk-objects/baz.obj main.obj exe %.obj: $(filter %.src,$<) @mkdir -p "$(dir $@)" @echo "Compile $< to $@" cat $< > $@ exe: main.obj foo.obj bar.obj sdk-objects/baz.obj @echo link $^ to $@ cat $^ > $@ main.obj: main.src foo.obj: subdir/foo.src bar.obj: subdir/bar.src sdk-objects/baz.obj: /tmp/baz.src

      It just does what I mean! But how does it work? The filter function should just return $< - but at that point, the filter function has processed the source pattern %.src, so the rule is no longer a simple pattern rule. And then, something magic happens ... ;-)

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

        ... the rule is no longer a simple pattern rule.
        Right. Since all your targets have no receipt, make tries to find an implicit rule to create the target using a complex Implicit-Rule-Search algorithm.

        The filter-rule is not a simple pattern rule, it is an implicit rule. The prerequisite is computed. Here filter returns the full(!) prerequisite path as a prerequisite of this computed rule as if you have written the explicit rule
        foo.obj: some/dir/foo.src. A computed rule that matches your initial dependency but this time one that also delivers a receipt. The filter just narrows the potential prerequisite candidates to the wanted group of *.src files. You could even perform complex string manipulation here (GNU make).

        The %.src within the filter expression is not a pattern in the sense of a simple pattern rule. Here, it is a match against $< when the filter function is executed - something like grep { /\.src$/ } @prerequisites. During the test, $< is the full path (dir + filename) of the initial prerequisite.

        Running make ; rm foo.obj ; LANG=C make -d shows the whole drama when make starts recursing to find an implicit rule to make some/dir/foo.src which is now treated as a target/dependency of the matching filter expression. But finally make comes to the conclusion that some/dir/foo.src is not a dependency that needs treatment and the filter-receipt is executed:

        ... Considering target file 'foo.obj'. File 'foo.obj' does not exist. Looking for an implicit rule for 'foo.obj'. Trying pattern rule with stem 'foo'. Trying pattern rule with stem 'foo'. Found an implicit rule for 'foo.obj'. <-- + the "filter" rule matched Considering target file 'some/dir/foo.src'. Looking for an implicit rule for 'some/dir/foo.src'. ... dramatic search for a rule to make 'some/dir/foo.src' ... No implicit rule found for 'some/dir/foo.src'. Finished prerequisites of target file 'some/dir/foo.src'. No need to remake target 'some/dir/foo.src'. Finished prerequisites of target file 'foo.obj'. Must remake target 'foo.obj'. Putting child 0x5582f63d0120 (foo.obj) PID 9420 on the chain. Live child 0x5582f63d0120 (foo.obj) PID 9420 === compile some/dir/foo.src to foo.obj Reaping winning child 0x5582f63d0120 PID 9420 cat some/dir/foo.src > foo.obj Live child 0x5582f63d0120 (foo.obj) PID 9421 Reaping winning child 0x5582f63d0120 PID 9421 Removing child 0x5582f63d0120 PID 9421 from chain. Successfully remade target file 'foo.obj'. ...

        Update: Run make -p to identify the rule that matched. My test Makefile where the rule is at line #13 returned something like:

        foo.obj: some/dir/foo.src # Implicit rule search has been done. # Implicit/static pattern stem: 'foo' # Last modified 2022-09-17 11:10:23.135420027 # File has been updated. # Successfully updated. # recipe to execute (from 'Makefile', line 14): @echo === compile $< to $@ cat $< > $@

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11146880]
Approved by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2024-04-19 05:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found