Multiple Rules for Single Target -- Doesn't Work as Expected - makefile

Here's a shortened version of the Makefile I am fighting with on a Linux system:
VPATH=altsrc:src:obj
OBJECTS=\
nondepcode1.o \
nondepcode2.o \
nondepcode3.o \
depcode1.o \
depcode2.o \
depcode3.o
DEP_OBJS= depcode1.o depcode2.o depcode3.o
# Targets
execute: $(OBJECTS)
gfortran -o $# $^ $(LFLAGS)
$(DEP_OBJS): npts.h
obj/%.o: %.f
$(FORTRAN) $(FFLAGS) $< -o $#
obj/%.o: %.f90
$(FORTRAN) $(FFLAGS) $< -o $#
# Rules
.f.o:
$(FORTRAN) $(FFLAGS) -o obj/$# $<
%.o: %.f90
$(FORTRAN) $(FFLAGS) -o obj/$# $<
I was expecting that the three objects that depend on "npts.h" would be automatically updated on a run of make (or gmake) if npts.h was more recent than any of the objects. This just does not happen. Make (and gmake) thinks the objects are up to date. AFAICT, I am doing things the way they are described in the GNU make manual. Anyone have any idea why make/gmake is not doing what I expected? Thanks. BTW, there are tabs at the beginning of all the recipe lines in the actual Makefile. They went away here.

Major egg on my face. As I said, this was a shortened version of the Makefile. I found the bug in the real Makefile. Had some misnamed macros. Not too experienced with the finer points of this stuff. Mea culpa. Very sorry. Thanks for checking.

Related

Makefile Skipping a rule even though the filetype exists

I have a makefile with these rules.
all: $(TARGET)
OBJECTS = file.o
%.o: %.c
$(COMPILER) -c $(FLAGS) &< -o C_$(basename $#).o
%.o: %.s
$(COMPILER) -c $(FLAGS) &< -o S_$(basename $#).o
... The Linker is then called with *.o to link all the object files
I have the same filename file.c and file.s in a src directory. But make is only running the first rule for the object file. Why does it only compile once? And how can I get make to compile both file.c and file.s if they exist in my src folder?
I don't want to have to create a different object file name for a different extension. That would be silly.
Is there a way for me to compile the filename with the both .s and .c extension?
I feel like make can easily do this and I am missing something.
Thank you for the help. If I'm not clear please tell me and I will try to explain it more in depth.
You misunderstand how Make works.
There may be many ways to build a target; Make will use one of them, not all. Anyway, your makefile violates one of Mad Scientist's rules, in that your pattern rules do not build what they claim to build:
%.o: %.c
$(COMPILER) -c $(FLAGS) &< -o C_$(basename $#).o
%.o: %.s
$(COMPILER) -c $(FLAGS) &< -o S_$(basename $#).o
The first doesn't build foo.o, it builds C_foo.o; the second doesn't build foo.o, it builds S_foo.o. I don't know how your linking rule works, but if it depends on foo.o, you're in for trouble.
Try this:
C_%.o: %.c
$(COMPILER) -c $(FLAGS) &< -o $#
S_%.o: %.s
$(COMPILER) -c $(FLAGS) &< -o $#
Then give your linking rule whatever prerequisites you think it should have. If you want it to use both C_foo.o and S_foo.o (which doesn't sound like a good idea), then put both of them in the prerequisite list.

Add dependencies to existing make targets

Condition 0:
Say, I have several source codes, a.c, b.c, ..., z.c, and I want a rule to have each of them compiled. Here is a solution:
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
Condition 1:
Then I introduce a header c.h used in c.c, and another header e.h used in c.c and e.c, and things become complex:
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
c.o: c.c c.h e.h
$(CC) -c -o $# $(CFLAGS) $<
e.o: e.c e.h
$(CC) -c -o $# $(CFLAGS) $<
My question:
Based on the solution of condition 1, is there something like add_dependency in make to simplify the solution and obtain something like the following one?
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
add_dependency(c.o, c.h e.h)
add_dependency(e.o, e.h)
Or, what do you think is a better solution to condition 1?
EDITED:
Thanks for the kind notice #ctheo :)
Yes I did have a look at autotools and understood that shall satisfy all my needs. However what I'm dealing with is an existing project and its Makefile contains other directives dealing with codes in C++, and I think for now I'd better just modify a few lines instead of port the whole Makefile to autotools, unless I couldn't find a satisfying solution without introducing autotools. :)
At first I did not expected to exist a solution for this. It seemed to me that it was covered by autotools. However, after some search, I found this section of GNU/make manual.
It states that :
One file can be the target of several rules. All the prerequisites mentioned in all the rules are merged into one list of prerequisites for the target.
So there is a solution for your query
c.o: c.h e.h
e.o: e.h
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
Thanks for insisting. I learned something today :)
In addition, the .o files in your example all depend on a .h file with the same stem, so you can generalise that part of your rules too:
c.o: e.h
%.o: %.c %.h
$(CC) -c -o $# $(CFLAGS) $<
This way, your “normal” situations are covered entirely by the rule that triggers compilation and your “unusual” situations stand out because those are the only additional rules.

Use general rule as part of a specific target in Gnu Make

I am curious if it is possible to use a general rule as part of a more specific rule in Gnu Make. This is easier to explain with an example:
%.o:
$(FC) $(FLAGS) -o $# -c $<
some_file.o:
DO SOMETHING EXTRA
PASS ON TO GENERAL FOR %.o
That is, I want the target for some_file.o to first do something extra, and then do what is specified for %.o. Of course, I could just be redundant and write
some_file.o:
DO SOMETHING EXTRA
$(FC) $(FLAGS) -o $# -c $<
But that is not as convenient.
Add an extra rule that does not create the file itself:
%.o:
$(FC) $(FLAGS) -o $# -c $<
some_file.o: thing
thing:
DO SOMETHING EXTRA BUT DON'T CREATE some_file.o
Note that if thing is not created, this will cause some_file.o to be built every time.
No, that's not possible in any reasonable way. The best you can do is put the command into a variable, then reuse the variable:
FCCOMMAND = $(FC) $(FLAGS) -o $# -c $<
%.o :
$(FCCOMMAND)
some_file.o:
DO SOMETHING EXTRA
$(FCCOMMAND)

Wildcard in a pattern rule

In my Makefile I have a rule to compile Fortran source files, like so
.SUFFIXES:
%.o: %.[fF]
$(FC) $(FFLAGS) -c $< -o $#
This has worked fine on several machines. When I tried it on another machine (incidentally with a newer (GNU) make, 3.82 instead of 3.81), it did not work, and I had to replace it with two separate rules for .f and .F.
The wildcard works without the %, i.e. this works:
.SUFFIXES:
test.o: test.[fF]
$(FC) $(FFLAGS) -c $< -o $#
What is going on?
I can fully reproduce the behavior here. It is a regression in make 3.82. The discussion attached to the bug report suggests using .SECONDEXPANSION to work around the problem. I've tried it and got it to work in a simple test setup:
.SUFFIXES:
.SECONDEXPANSION:
%.o: $$(wildcard %.[fF])
$(FC) $(FFLAGS) -c $< -o $#
Using the file above and two test files named test.f and test2.F, here's a couple commands I issue and the output produced by the Makefile:
$ make -n test2.o
f77 -c test2.F -o test2.o
$ make -n test.o
f77 -c test.f -o test.o
The workaround works both with 3.81 and 3.82.

Wildcard in make dependency list

Hey I'm trying to build some files at the same time with different suffixes. Somehow it seems imposible to do this in one line. My makefile looks as follows:
ARCH=ar
ARCHFLAGS=r
F90=gfortran
F90FLAGS=-O2 -Wall
LDFLAGS=-llapack -lblas
SRCF=/Users/pm/bin/src
OBJF=/Users/pm/bin/objs
MODF=/Users/pm/bin/mods
LIBF=/Users/pm/bin/include
SOURCES=a.f b.f90 c.f90
OBJECTS=$(addprefix $(OBJF)/,$(addsuffix .o,$(basename $(SOURCES))))
MODULES=$(addprefix $(MODF)/,*.mod)
TARGET=lib_pm_math_lib.a
$(LIBF)/$(TARGET): $(OBJECTS)
$(ARCH) $(ARCHFLAGS) $# $(OBJECTS) $(MODULES)
obmod.clean :
rm $(OBJECTS) $(MODULES)
clean :
rm $(OBJECTS) $(MODULES) $(LIBF)/$(TARGET)
$(OBJECTS): $(OBJF)/%.o : $(addprefix $(SRCF)/,$(join %.,$(suffix $(SOURCES))))
$(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o$# -J$(MODF)
#$(OBJECTS): $(OBJF)/%.o : $(subst .x, ,$(addprefix $(SRCF)/,$(addsuffix .x$(suffix $(SOURCES)),%)))
# $(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o$# -J$(MODF)
#$(OBJECTS): $(OBJF)/%.o : $(SRCF)/%.f90
# $(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o $# -J$(MODF)
As you can see, I already managed to define my OBJECTS. But I'm not able to creat a construct that does the same for the building part of the object. Of course my first try was to use the join without the extra dot, but this results in only the suffix, for whatever reasons. Substituting the two dots with one dot does this as well. So I'm lost. The lines that I commanded out are another interesting try, and a working version for only .f90 suffixes. Actually I was hoping for something like the following to be working:
$(OBJECTS): $(OBJF)/%.o : $(SRCF)/%.*
$(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o $# -J$(MODF)
I hope it's not too messy. I posted the whole file since I bet you guy's see other problems which I didn't even think of so far. Thanks in advance!
If I'm understanding you correctly, you're wanting a suffix-based wildcard rule that you can run on multiple file suffixes. You can only have one wildcard per recipe, so there's no way to do it directly. You'll need separate rules for each suffix.
The easy solution is to copy-paste one rule and change the suffix. This can become unmanageable when you start to have a lot of suffixes. Another option is to create a rule template and use that to dynamically generate your rules for you:
# Template for build rules
# Pass a file extension for an argument
define build_rule
$(OBJF)/%.o: $(SRCF)/%.$(1)
$(F90) $(F90FLAGS) $(LDFLAGS) -c $$< -o$$# -J$(MODF)
endef
# Generate rules for each selected file extension
FILE_EXTS = f f90
$(foreach ext,$(FILE_EXTS),$(eval $(call build_rule,$(ext))))
This will dynamically generate a rule that differs only by the file extension used on the input file. To support a new file extension, simply add it to the FILE_EXTS list.
Note that when make initially parses the recipe template (inside call), it will expand variables. You have to double-up the $ in the template for anything that you don't want make to expand until the recipe is actually executed (like $# or $<).
You shouldn't need to do anything special to ensure that only the objects in the OBJECTS list are compiled. Since your default make target only lists $(OBJECTS) as a dependency, the files in $(OBJECTS) will be the only ones that get built.
In this case I'd probably just use two rules:
$(OBJF)/%.o: $(SRCF)/%.f
$(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o$# -J$(MODF)
$(OBJF)/%.o: $(SRCF)/%.f90
$(F90) $(F90FLAGS) $(LDFLAGS) -c $< -o$# -J$(MODF)
You could combine them into one, but it's not really worth the effort.

Resources