Makefile implicit rules matching .c OR .cpp - makefile

I'm trying to add an implicit rule to a Makefile, and I'd like it to handle compilation of .c and .cpp files the same way. The rule I have for .c files is as follows:
%.obj: %.c
cl /c $(CFLAGS) $<
What I'd like, though, is for the right side of the pattern to match .c OR .cpp, depending on which file is available. Is this possible? I've perused the Make manual, but haven't found what I'm looking for. Any help would be greatly appreciated.

Just use two rules which is equivalent to "or" in the make language:
%.obj: %.c
cl /c $(CFLAGS) $<
%.obj: %.cpp
cl /c $(CFLAGS) $<
At the end these are two different source languages and you may well end up desiring different flags.

Related

Does the target .SUFFIX have any meaning in a Makefile?

In a Makefile I encountered:
.SUFFIX: .c
Is that a misspelling of .SUFFIXES: .c, because I can't find anything about .SUFFIX only. Does this do anything at all?
If the Makefile only uses pattern rules, do I even need that hanging around in the Makefile at all?
Assuming you are using GNU make, unless there is really a user target named .SUFFIX, this is probably a misspelling of .SUFFIXES: .c. And if there is no recipe you can safely remove it: without a recipe it's useless.
If it was .SUFFIXES: .c and if it had a recipe it would redefine the implicit rules for:
%: %.c
<recipe>
which is:
LINK.c = $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
%: %.c
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $#

Makefile decoupled dependencies

With the following makefile snippet:
main: main.o f1.o f2.o
$(CC) $(CFLAGS) -o program main.o f1.o f2.o
main.o: main.cc
$(CC) $(CFLAGS) -c main.cc
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
f2.o: f2.cc
$(CC) $(CFLAGS) -c f2.cc
If I just change one file, only that file get recompiled when I rerun make, as desired. However, I'm having a hard time generalizing this without having to list each file individually. When I try something like:
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -o $# -c $(patsubst %.o,%.cc,$#)
It builds each object file individually, but each object file depends on ALL my sources, so a change in any one file causing a full recompile. What's a good way to accomplish this?
Basically,
you do have to list each .o file's dependencies individually.
For example, each .o is likely to depend on a different bunch of headers.
Taking your f1.o, you need something like:
f1.o: include/i.h
f1.o: another.h dir/and-another.h
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
(you can have as many dependency lines for a target as you like).
Maintaining that list is a nightmare.
Broken dependency lists render your Makefile worse than useless—you might as well use a batch file.
All is not lost!
If you are tidy,
you can get the compiler to do it automatically,
and pretty much for free.
Makes your Makefile tidier to boot.
Win Win.
As Ismail Badawi commented, pattern rules provide a nice solution. They are a type of implicit rule for make. Basically, implicit rules are automatic recipes based off the file extension. For example, make knows how to convert .c files into .o files implicitly. By default make will run the following recipe for .c files (see the rule catalogue):
$(CC) $(CPPFLAGS) $(CFLAGS) -c
You can modify the process either by setting the variables CC, CPPFLAGS, and CFLAGS, or by defining a pattern rule:
%.o: %.c
$(CC) $(CFLAGS) -c $<
The "$<" above matches the name of the first prerequisite, which will be the .c file in this example. See Beta's comment and automatic variables.

Makefile pattern rules

Is it possible to write pattern rule like:
%.o: %.c %.h
<some action>
so it accepts not one but any number of headers, because I have:
main.o: main.c $(HEADERS)
so it doesen't fit to standard implicit rule, because of many .h files that main.c depends on, so is it possible to make an implicit rule, that would accept such input, or should I just write
$(CC) $(CFLAGS) $(DEFINE_OPT) $(INCLUDE) -c $<
explicitly?
You can write:
%.o: %.c $(HEADERS)
However, in general, you probably don't want all source files to be dependent on all header files. You should look into auto-generating the prerequisite lists; the Make manual talks about this a bit: http://www.gnu.org/software/make/manual/make.html#Automatic-Prerequisites.
In GNUMake you can write
main.o: $(HEADERS)
and the built-in implicit rule will work. If you want to handle dependencies automatically, Advanced Auto-Dependency Generation is superior to the one in the GNUMake manual.

Working with multiple source file extensions in a makefile

I have a c++ project with various extensions for the source files (.cpp, .c, .cc) and various extensions for the header files (.hpp, .h, .hh). The source files are located in a directory called SRC, and the header files are predictably in a directory called INC.
I would like to compile the source with a rule like
vpath %.c $(SRC)
%.o: %.c
$(COMPILER) $(FLAGS) $< $(INCFLAG)$(INC)
This of course works if I know the source file will be of the form %.c, but in the case of multiple possible file extensions, I would need to build a similar rule for %.cpp and %.cc as well. Of course three rules isn't a big deal to write, but it would be nice to be able to use this makefile as a drag and drop for any project, even in a different language, without having to re-write the rules.
So how can I write a rule (or some other construct that accomplishes the same goal) that works like:
SRC_EXT = cpp c cc
vpath %.$(SRC_EXT) $(SRC)
%.o: %.$(SRC_EXT)
$(COMPILER) $(FLAGS) $< $(INCFLAG)$(INC)
Thanks for your help.
You can't in standard POSIX make. However since you mention vpath I'll assume you're using GNU make. If you have a sufficiently new version (3.81 or newer), you can do this easily enough with call and eval:
SRC_EXT = cpp c cc
define compile_rule
%.o : %.$1
$$(COMPILER) $$(FLAGS) $$< $$(INCFLAG)$$(INC)
endef
$(foreach EXT,$(SRC_EXT),$(eval $(call compile_rule,$(EXT))))
If you don't have sufficiently new GNU make, or would prefer an alternate solution, you can do the same thing with generated makefiles.

.cu file Makefile issue

I am new to linux development.
I wrote a project using MPI and cuda. When
it gets bigger and bigger, I realize that I
need a Makefile now. So I learned how to write
one. The Makefile works, but will only compile
cpp files even if I have both of the following
lines in my Makefile:
.cpp.o:
$(CC) $(CCFLAGS) $<
.cu.o:
$(NVCC) $(CCFLAGS) $<
Any idea why this is happening? Thanks.
UNDERSTANDING MAKE
Make is all about generating missing files.
If you have TWO rules that generate the SAME file upon existence of a source then the first one in make's list that actually has a source file present will get invoked. So for instance if you have the rules:
.c.o:
$(CC) -o $# -c $<
.cpp.o:
$(CXX) -o $# -c $<
and you have two files, foo.c and bar.cpp then you can type:
$ make foo.o
it will use the first rule... and when you type
$ make bar.o
it will use the second rule.
Now suppose you have TWO files foo.c and foo.cpp
Here make has to make a choice as to which takes precedence. Make uses suffixes of files intimately for its build rules. What is considered a suffix is controlled by the .SUFFIXES directive.
The .SUFFIXES directive has a default built-in value that defines common suffixes such as .c .cpp .cc .o etc. in a particular order. If we want to change the order of precedence we clear that out with a blank line in Makefile i.e.:
.SUFFIXES:
and then follow it with our definition:
.SUFFIXES: .cpp .c .o
if you don't blank the line out, then make just appends the listed suffixes to its current list, that way multiple makefiles can simply add new suffixes without worrying about breaking each other.
Now since the .cpp is before .c the .cpp.o rule will take precedence (in case foo.cpp and foo.c are both present)
NOTE: Yes there is a "." before the words SUFFIXES and yes it is all capital letters.
Try to play with this Makefile to see the effects:
.SUFFIXES:
.SUFFIXES: .cpp .c .o
.c.o:
echo Compiling C
.cpp.o:
echo Compiling CPP
Make is very very powerful, and quite well documented so well worth the read. GNU make, which is probably the strongest implementation with amazing extensions has made me a lot of money in the past :-) enjoy the experience.
Your rule is wrong, you want something like this:
%.o : %.cu
$(NVCC) $(CCFLAGS) $< -o $#
That's assuming the command line you need to execute is something like
nvcc foo.cu -o foo.o
Otherwise, edit to suit.

Resources