Make: Compile .c files of rule - makefile

Say I have the following rule in my Makefile:
foo: foo1.c foo2.c head1.h head2.h
gcc -o $# foo1.c foo2.c
As you can see, in this case - as in most cases- the .c files in the rule correspond to the .c files you pass to gcc. My question is, is there a variable that can be passed to a Makefile which would evaluate to "all the .c files in the rule"?
Personally, I use the following:
CFILES=$(filter %.c,$^)
foo: foo1.c foo2.c head1.h head2.h
gcc -o $# $(CFILES)
but I'm not sure if this is the correct way...

I guess your filter is fine, but I'd rather define separately the lists of .c and .h files and use those lists where appropriate:
CFILES=foo1.c foo2.c
HFILES=head1.h head2.h
foo: $(CFILES) $(HFILES)
gcc -o $# $(CFILES)
If you don't mix .c and .h in the first place, there's no need to separate them afterwards.

Related

How to write Make rules for *.h files as dependencies

I'm trying to understand how to handle header file dependencies in Make rules. Let me give you a specific example.
I'm building application called myap using GNU Make. It consists of various *.h and *.c files.
Directory inc/ contains defs.h and util.h header files.
Directory src/ contains main.c, cmd.c and win.c files.
Directory obj/ contains all generated object files.
I have multiple applications that need different build options. So I don't want to rely on any implicit rules and would like to specify my own rules for all object files, etc.
I would like to specify the following rules:
Object files depend on specific *.h and *.c files. If any of them change, all object files must be regenerated. However, even though *.h files are part of the prerequisites list, I don't want to pass them to the compiler. I only want to compile *.c files.
Executable myapp depends on specific *.o files. If any of them change, executable file must be regenerated.
So far, the following Makefile with a static pattern rule seems to work correctly:
myapp_inc := inc/defs.h inc/util.h
myapp_src := src/main.c src/cmd.c src/win.c
myapp_obj := $(patsubst src/%.c,obj/%.o,$(myapp_src))
myapp_bin := obj/myapp
.PHONY: all
all:
# Create obj/main.o obj/cmd.o and obj/win.o from various *.c files
# If any *.h files in $(myapp_inc) list change, all objects are regenerated.
# If any *.c files in $(myapp_src) list change, all objects are regenerated.
$(myapp_obj): obj/%.o: src/%.c $(myapp_inc) $(myapp_src)
gcc -c -o $# $<
# Create obj/myapp from various *.o files
# If any *.o files in $(myapp_obj) list change, executable is regenerated.
$(myapp_bin): $(myapp_obj)
gcc -o $# $^
all: $(myapp_bin)
.PHONY: clean
clean:
rm -f obj/*
I don't quite understand how Make rules should be written correctly in order to handle such use case. Is the above static pattern rule, the only way that works correctly?
Specifically, I have tried the following combinations, as given in various simple examples on the Internet, and they all failed for various reasons.
This rule causes $< to always pass the name of the first prerequisite, which doesn't work with multiple *.c files:
$(myapp_obj): $(myapp_src) $(myapp_inc)
gcc -c -o $# $<
$ make
gcc -c -o obj/main.o src/main.c
gcc -c -o obj/cmd.o src/main.c
gcc -c -o obj/win.o src/main.c
gcc -o obj/myapp obj/main.o obj/cmd.o obj/win.o
/bin/ld: obj/cmd.o: in function `main':
main.c:(.text+0x0): multiple definition of `main'; obj/main.o:main.c:(.text+0x0): first defined here
/bin/ld: obj/win.o: in function `main':
main.c:(.text+0x0): multiple definition of `main'; obj/main.o:main.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [Makefile:18: obj/myapp] Error 1
This rule causes $^ to always pass the names of all prerequisites, which fails:
$(myapp_obj): $(myapp_src) $(myapp_inc)
gcc -c -o $# $^
$ make
gcc -c -o obj/main.o src/main.c src/cmd.c src/win.c inc/defs.h inc/util.h
gcc: fatal error: cannot specify ‘-o’ with ‘-c’, ‘-S’ or ‘-E’ with multiple files
compilation terminated.
make: *** [Makefile:13: obj/main.o] Error 1
Now I understand the difference between $< and $^ variables, but a lot of documentation is not clear on how they should be used when dealing with a list of multiple *.c and *.h files as prerequisites.
What are the recommended usage pattern for this?
Why is it that when using $< only *.c files get passed to the recipe, but not *.h files? Is Make doing some internal filtering? Is this documented anywhere? Is it possible to modify this behavior for custom suffixes?
Is the above static pattern rule, the only way to make objects depend on *.h and *.c files, but exclude *.h files during compilation?
I don't understand the goal of trying to avoid implicit rules. But in any event, it doesn't matter to the recipe you write whether the rule was implicit or explicit: the same automatic variables are set either way. The $< automatic variable is always the first prerequisite, so if you write your rules such that the first prerequisite is the appropriate .c file then you can always use $< in your recipe to mean the .c file and no other files. All the following will work:
%.o : %.c $(headers)
gcc -c -o $# $<
foo.o: foo.c $(headers)
gcc -c -o $# $<
foo.o : %.o : %.c $(headers)
gcc -c -o $# $<
%.o : %.c
gcc -c -o $# $<
$(srcs) : $(headers)
and others.
Does this mean that all of the prerequisites apply, but only those that match the pattern get passed to the recipe?
I don't understand the question, really. The value of variables and the expansion of the recipe happens only AFTER make has decided to run the rule and is not really related (except for some special automatic variables like $?). Once make has decided that the target is out of date and the recipe needs to be run, it will assign the appropriate automatic variables, expand the recipe, then pass the recipe to the shell to be run.
The automatic variables are assigned as described in the manual: $# is the target, $< is the first prerequisite, $^ is all the prerequisites, etc.
ETA
You still haven't really explained why you don't want to use static pattern rules. They are a perfectly fine and reasonable way to do things.
If you explain what you don't like about static pattern rules, or what you wish you could do differently, then we can probably suggest alternatives that meet those requirements.
Specifically, I have tried the following combinations, as given in various simple examples on the Internet,
$(myapp_obj): $(myapp_src) $(myapp_inc)
Wherever you found this as a recommended example on the Internet, you should immediately delete from any bookmarks as that site doesn't know anything about make.
We see this paradigm at least once a week on SO. I've never really understand why people think it will work: I guess they think make is much more "magical" than it is. Consider, what does the above expand to? Suppose myapp_obj contained foo.o bar.o biz.o and myapp_src contained foo.c bar.c biz.c and myapp_inc contained foo.h bar.h, then make sees:
foo.o bar.o biz.o: foo.c bar.c biz.c foo.h bar.h
I suppose some people think make will intuit that the ".o" files should somehow match up with the ".c" files and will generate a bunch of rules that make that true. That's not what make does. The above line is exactly identical to writing this:
foo.o: foo.c bar.c biz.c foo.h bar.h
bar.o: foo.c bar.c biz.c foo.h bar.h
biz.o: foo.c bar.c biz.c foo.h bar.h
That is, if you have multiple targets make creates one copy of the rule for each target, with the same prerequisites and recipe.
This is obviously not what you want, and that's why none of the examples that try to do things this way can ever work properly.
Why is it that when using $< only *.c files get passed to the recipe, but not *.h files? Is Make doing some internal filtering? Is this documented anywhere? Is it possible to modify this behavior for custom suffixes?
None of that is the case. As I described above, the $< expands to the first prerequisite. That's all. It doesn't matter whether the first prerequisite is a .c file, a .h file, or some other file; whatever it is, $< will be that value. If you write your rule as:
foo.o : foo.c foo.h ; $(CC) -c -o $# $<
then your compiler will be invoked with foo.c. If you write your rule as:
foo.o : foo.h foo.c ; $(CC) -c -o $# $<
then your compiler will be invoked with foo.h. There's no magic here.

Make a rule to compile all files .c and link

Make a rule called all to compile and link in once file called "dinam" all files .c.
I have tried:
All:
gcc -c *.c
I need to kink all .o in one file.
This will suffice:
dinam:
gcc -c *.c
gcc *.o -o dinam
You can write more sophisticated makefiles when you are ready.

Given a target's name, get all of its prerequisites

If I have a makefile with e.g.:
foo.o: foo.c a.h b.h c.h
cc -c foo.c -o foo.o
Now, in some other part of the makefile, I want to get all the prerequsites of foo.o, like I'd do with $^ in the recipe. Something like:
$(info $(call GET_TARGET_PREREQS(foo.o))) # prints "foo.c a.h b.h c.h"
Basically, I have dependency files (generated by -M) for all my object files, and from there I want a list of all the header files that are included by a given object.
I'm hoping for a more or less pure make solution, and not a sed script that parses the *.d files and outputs makefile fragments.
If you want to print all prerequsites, you can always use $^
.PONY: all
all: a b c
#echo $^
a:
b:
c:

Get filename without extension within makefile

My makefile looks like this:
SRCS = $(wildcard *.asm)
OBJS = ${SRCS:.asm=.o}
# define a suffix rule for .asm -> .o
.asm.o : $(SRCS)
nasm -f elf $<
all: $(OBJS)
gcc -o ?? $<
^need the name of the target without file extension here ($* is blank)
However, $* is working within .asm.o but is blank within all.
How would I go about setting the gcc output filename to the filename of the object file without any extension?
For example, I want it to execute the following (after the .o file is generated by nasm)
gcc filename filename.o
I think you are looking for
.PHONY: all
all: $(patsubst %.o,%,$(OBJS))
%: %.o
gcc -o $# $<
Your attempt would define a target all which depended on all the object files as if it contained them all; I presume you really want each object file to be independent, and for the all target to depend on them all being made.
(Technically you could now use $* because it is identical to $# in this case, but that's just obscure.)
This is by and large isomorphic to your existing nasm rule, except when there is no suffix, you cannot use the suffix syntax. In other words, your rule is equivalent to
OBJS = $(patsubst %.asm,%.o,$(SRCS))
%.o: %.asm
nasm -f elf $<
The only remaining difference is the .PHONY declaration which just documents that all isn't a file name.
Use VAR = $(basename your_file.ext) <=> $(VAR) = your_file
Let's say that you want to remove .o from test.o
VAR = $(basename test.o)
resulting in $VAR containing "test"
See More Functions Here

.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