Page 1 of 2

Advanced makefile wizardry

Posted: Thu Jul 29, 2010 4:48 am
by Candy
Hi,

I'm trying to get make to do as much as possible. First I define a rule that derives an object name for each pair of (existing source file, target architecture). Then I define generic targets that have generic dependencies on these objects. That last thing is causing a bit of a headache.

Concretely, I'm trying to add a line to build

bin/os/bin/%

which depends on all files in obj/apps/os/%/ . The files there aren't actual, they're virtual. That means that I need to depend on them. All those objects are in $(OBJECTS) so I can filter them out. There's where I'm stuck:

bin/os/bin/%: $(filter obj/apps/os/%/%, $(OBJECTS))

Filter uses its own %, so I can't refer back to the matched rule. I tried to do that by abusing $@ but it isn't assigned until it starts executing the rules.



How do I get this dependency working?

Re: Advanced makefile wizardry

Posted: Thu Jul 29, 2010 8:30 am
by Owen
$(call)? Would allow you to "rename" %

Re: Advanced makefile wizardry

Posted: Thu Jul 29, 2010 12:47 pm
by Candy
berkus wrote:Just $subst the path out?
How do I get the path in there? There's no way to refer to it that I can seem to get working, other than % - which doesn't work inside filter.

Re: Advanced makefile wizardry

Posted: Thu Jul 29, 2010 6:53 pm
by coreybrenner
.SECONDEXPANSION:
bin/os/bin/% : $$(filter obj/os/$$(patsubst bin/os/bin/%,%,$$@)/%,$(OBJECTS))

GNU Make 3.81+

Re: Advanced makefile wizardry

Posted: Fri Jul 30, 2010 3:38 am
by Candy
coreybrenner wrote:.SECONDEXPANSION:
bin/os/bin/% : $$(filter obj/os/$$(patsubst bin/os/bin/%,%,$$@)/%,$(OBJECTS))

GNU Make 3.81+
Haven't tried yet, but two things:

What does .SECONDEXPANSION do?
Why the double $'s?

Re: Advanced makefile wizardry

Posted: Fri Jul 30, 2010 4:35 am
by Thomas
Hi,
I not a build expert at all , however just a simpel search gives me this :) : http://www.gnu.org/software/automake/ma ... nsion.html

--Thomas

Re: Advanced makefile wizardry

Posted: Fri Jul 30, 2010 10:04 am
by Candy
Just a small problem - it doesn't work.

bin/os/bin/%: $$(patsubst obj/apps/os/$$*/%,%,obj/apps/os/$$*/f)

should be a pretty simple f. It doesn't replace it at all. As soon as I include both % and $$* in one line it messes up somehow.


Even worse:

bin/os/bin/%: $(filter obj/apps/os/false/%,obj/apps/os/false/main.o)

that works.

bin/os/bin/%: $$(filter obj/apps/os/false/%,obj/apps/os/false/main.o)

That doesn't.

Any ideas?

Re: Advanced makefile wizardry

Posted: Fri Jul 30, 2010 6:05 pm
by coreybrenner
Did you remember the bit about

.SECONDEXPANSION:
...

Re: Advanced makefile wizardry

Posted: Fri Jul 30, 2010 11:04 pm
by coreybrenner
I hacked on it a while, and what I came up with was:

Code: Select all

OBJS := obj/apps/os/ls/main.o obj/apps/os/ls/junk.o obj/apps/frobnitz/glarch.o
BINS := bin/os/bin/ls

all : ${BINS}

.SECONDEXPANSION:
bin/os/bin/% : $$(filter $$(patsubst bin/os/bin/%,obj/apps/os/$$*/%,$$@),$(OBJS))
        @echo "@: '$@'"
        @echo "?: '$?'"
        touch $@
This seemed to do what you had in mind...

--Corey

Re: Advanced makefile wizardry

Posted: Sat Jul 31, 2010 1:42 am
by Candy
I'm impressed! Still don't understand why the filter command up there doesn't work with two $'s... that just seems to defy logic.

Now there's just two major things I can't get Make to do. First of, somehow not have to check all the timestamps to find out what to rebuild. That's not currently my problem but it's going to be a major slowdown.

Second of all,

bin/apps/%/bin/%: obj/apps/%1/%2/*

I'm pretty certain (like, 99.99%) that you can't get GNU make to do this.

Re: Advanced makefile wizardry

Posted: Sat Jul 31, 2010 3:21 am
by Owen
You can, just not as you would expect. Liberally apply
  • $(eval ($call myfunc, args...))
  • $(foreach ...)
  • $(wildcard ...)
GNU Make is a very funny language, but you can definitely do procedural stuff with it.

Re: Advanced makefile wizardry

Posted: Sat Jul 31, 2010 10:19 am
by coreybrenner
Candy wrote:I'm impressed! Still don't understand why the filter command up there doesn't work with two $'s... that just seems to defy logic.

Now there's just two major things I can't get Make to do. First of, somehow not have to check all the timestamps to find out what to rebuild. That's not currently my problem but it's going to be a major slowdown.

Second of all,

bin/apps/%/bin/%: obj/apps/%1/%2/*

I'm pretty certain (like, 99.99%) that you can't get GNU make to do this.
Checking timestamps is not a slow-down. System calls are not going to be a dominating time factor in your build, and GNU make caches stuff from stat(), to a certain degree.

You'll find it fairly tough to do:

Code: Select all

bin/apps/%/bin/%: obj/apps/%1/%2/*
The current version of GNU make only works with one percent-substitution in its pattern rig. I think the head of the CVS version of GNU make might allow multiple replacements in a pattern, but that's not exactly widely distributed.

You might be able to do something like this:

Code: Select all

.SECONDEXPANSION:
depend = $(eval bin/apps/$(strip $1)/bin/% : obj/apps/$(strip $1)/$$$$(strip $$$$*)/*)

BINS := ls more cat true false

$(foreach b,${BINS},$(call depend,$b))
However, depending on '*' is a recipe for confusing mistakes and muddled builds. You're much better off keeping an explicit list of object files, or sources which can be patsubst'ed into object file names, than depending on '*'. For instance, what if you want to keep a pristine source tree, and keep build artifacts in obj/... so you can just blow those away at any time? Consider what happens when you want to do source code generation (a la lex/yacc or somesuch.) The logical place for those to land is in your obj/ cache, where intermediate files live, if you wish to keep your source tree read-only. And keeping a read-only source tree, at least as far as the build is concerned, is a good idea. But now, with the rule listed above, you'll try to link lex.yy.c into your program, and that won't work. :-)

--Corey

Re: Advanced makefile wizardry

Posted: Sat Jul 31, 2010 12:33 pm
by coreybrenner
(by the way, your SFS link is broken, Candy.)

Re: Advanced makefile wizardry

Posted: Sun Aug 01, 2010 1:25 am
by Candy
coreybrenner wrote:The current version of GNU make only works with one percent-substitution in its pattern rig. I think the head of the CVS version of GNU make might allow multiple replacements in a pattern, but that's not exactly widely distributed.
I'll go and check the current CVS version. That's been something I've been looking for for a number of years. CVS versions will come out some day.
However, depending on '*' is a recipe for confusing mistakes and muddled builds. You're much better off keeping an explicit list of object files, or sources which can be patsubst'ed into object file names, than depending on '*'. For instance, what if you want to keep a pristine source tree, and keep build artifacts in obj/... so you can just blow those away at any time? Consider what happens when you want to do source code generation (a la lex/yacc or somesuch.) The logical place for those to land is in your obj/ cache, where intermediate files live, if you wish to keep your source tree read-only. And keeping a read-only source tree, at least as far as the build is concerned, is a good idea. But now, with the rule listed above, you'll try to link lex.yy.c into your program, and that won't work. :-)
I already have the makefile setup such that everything in src/ and static/ is read-only for the build. bin/, obj/ and root/ are writable. The build is set up such that all temporaries (obj files etc.) end up in obj/, all build results end up in /bin. The makefile then has two implicit rules that assemble my build output either from /static or /bin, depending on which exists. That means I can copy out a part of the build & have a quicker build, stuff like that. The build then takes the root/ directory and builds that into a bootable disk image with grub, and starts bochs through a symlink.

I avoid * rules if I can. I'm going to look into the $foreach thing that Owen recommended. If that allows me to foreach over variables and define rules that way, I'm completely done.

Re: Advanced makefile wizardry

Posted: Tue Aug 03, 2010 10:16 pm
by Solar
As if any Make would work without checking the timestamps. That's what Make systems are about.