Advanced makefile wizardry
Advanced makefile wizardry
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?
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?
- Owen
- Member
- Posts: 1700
- Joined: Fri Jun 13, 2008 3:21 pm
- Location: Cambridge, United Kingdom
- Contact:
Re: Advanced makefile wizardry
$(call)? Would allow you to "rename" %
Re: Advanced makefile wizardry
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.berkus wrote:Just $subst the path out?
-
- Posts: 22
- Joined: Thu Jul 15, 2010 11:47 pm
Re: Advanced makefile wizardry
.SECONDEXPANSION:
bin/os/bin/% : $$(filter obj/os/$$(patsubst bin/os/bin/%,%,$$@)/%,$(OBJECTS))
GNU Make 3.81+
bin/os/bin/% : $$(filter obj/os/$$(patsubst bin/os/bin/%,%,$$@)/%,$(OBJECTS))
GNU Make 3.81+
$ :(){ (:|:)& };:
Re: Advanced makefile wizardry
Haven't tried yet, but two things:coreybrenner wrote:.SECONDEXPANSION:
bin/os/bin/% : $$(filter obj/os/$$(patsubst bin/os/bin/%,%,$$@)/%,$(OBJECTS))
GNU Make 3.81+
What does .SECONDEXPANSION do?
Why the double $'s?
Re: Advanced makefile wizardry
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
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
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?
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?
-
- Posts: 22
- Joined: Thu Jul 15, 2010 11:47 pm
Re: Advanced makefile wizardry
Did you remember the bit about
.SECONDEXPANSION:
...
.SECONDEXPANSION:
...
$ :(){ (:|:)& };:
-
- Posts: 22
- Joined: Thu Jul 15, 2010 11:47 pm
Re: Advanced makefile wizardry
I hacked on it a while, and what I came up with was:
This seemed to do what you had in mind...
--Corey
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 $@
--Corey
$ :(){ (:|:)& };:
Re: Advanced makefile wizardry
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.
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.
- Owen
- Member
- Posts: 1700
- Joined: Fri Jun 13, 2008 3:21 pm
- Location: Cambridge, United Kingdom
- Contact:
Re: Advanced makefile wizardry
You can, just not as you would expect. Liberally apply
- $(eval ($call myfunc, args...))
- $(foreach ...)
- $(wildcard ...)
-
- Posts: 22
- Joined: Thu Jul 15, 2010 11:47 pm
Re: Advanced makefile wizardry
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.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.
You'll find it fairly tough to do:
Code: Select all
bin/apps/%/bin/%: obj/apps/%1/%2/*
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))
--Corey
$ :(){ (:|:)& };:
-
- Posts: 22
- Joined: Thu Jul 15, 2010 11:47 pm
Re: Advanced makefile wizardry
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.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 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.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 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
As if any Make would work without checking the timestamps. That's what Make systems are about.
Every good solution is obvious once you've found it.