Creating a make file - c

I know there is infinite amount of resources on the Internet with regards makefiles, but it is something that I still do not understand it. At the moment I have 3 c files PolyCalculatorMain.c PolyCalculator.c PolyCalculator.h and Polyfunctions.c
So far I have
PolyCalculator: PolyCalculator.o PolyCalculatorMain.c
gcc -Wall -ggdb -o PolyCalculator PolyCalculatorMain.c PolyCalculator.o
PolyCalculator.o: PolyCalculator.c
gcc -Wall -ggdb -c PolyCalculator.c PolyCalculator.h
clean:
rm PolyCalculator *.o *~ *#
Any help or explanation on were to go to complete this file would be much appreciated.
Note Im only beginning so I dont want any complex code as I will not understand it

In compile command you don't normally specify .h files. They are included by the preprocessor (which runs before the compiler) as it encounters #include statements. That is the only thing I can see.
The .h files do show up in Makefiles as dependencies since changes to them can require code that uses them to need to be recompiled.
I would say the basic rule is to include anything on the dependency line which would cause a recompile to be necessary if they changed.
PolyCalculator: PolyCalculator.o PolyFunctions.o PolyCalculatorMain.c
gcc -Wall -ggdb -o PolyCalculator PolyCalculatorMain.c PolyCalculator.o PolyFunctions.o
PolyCalculator.o: PolyCalculator.c PolyCalculator.h
gcc -Wall -ggdb -c PolyCalculator.c
PolyFunctions.o: PolyFunctions.c PolyFunctions.h
gcc -Wall -ggdb -c PolyFunctions.c
clean:
rm PolyCalculator *.o *~ *#
Makefiles allow you to have variables that can be reused. For example, you can have your
compiler options in a variable:
options=-Wall -ggdb
and then you use them with brackets and a dollar sign
gcc ${options}
You can also break them up:
debug=-ggdb
warnings=-Wall
options=${warnings} ${debug}
You can also combine all your object files into a variable:
obj_files=PolyCalculator.o PolyFunctions.o
PolyCalculator: ${obj_files} PolyCalculatorMain.c
gcc -Wall -ggdb -o PolyCalculator PolyCalculatorMain.c ${obj_files}
PolyCalculator.o: PolyCalculator.c PolyCalculator.h
gcc -Wall -ggdb -c PolyCalculator.c
PolyFunctions.o: PolyFunctions.c PolyFunctions.h
gcc -Wall -ggdb -c PolyFunctions.c
clean:
rm PolyCalculator *.o *~ *#

Because you didn't give really clear detains of what you would want changed / modified, I giving you what I would write the makefile as below, although some might (will?) disagree with me in places.
I see that you edited you original post and mention a PolyFunctions.cpp (and I guesssing that there
is a PolyFunctions.h)
CC=gcc
CCFLAGS=-ansi -Wall -pedantic
INCS=
LK=gcc
LKFLAGS=
LIBS=
OBJS = PolyCalculator.o PolyCalculatorMain.o PolyFunctions.o
PROG = PolyCalculator
$(PROG) : $(OBJS)
$(LK) $(LKFLAGS) $(OBJS) $(LIBS) -o $(PROG)
rebuild : clean $(PROG)
PolyCalculatorMain.o : PolyCalculatorMain.cpp PolyCalculator.h PolyFunctions.h
$(GCC) -c $(CCFLAGS) $(INCS) PolyCalculatorMain.cpp -o PolyCalculatorMain.o
PolyCalculator.o : PolyCalculator.cpp PolyCalculator.h
$(GCC) -c $(CCFLAGS) $(INCS) PolyCalculator.cpp -o PolyCalculator.o
PolyFunctions.o : PolyFunctions.c PolyFunctions.h
$(GCC) -c $(CCFLAGS) $(INCS) PolyFunctions.cpp -o PolyFunctions.o
clean:
rm -f $(OBJS) $(PROG) *.o *~ *#
OK, the changes that I made (and why)
First I like using variables that are then expanded as rules are fired. I find this a convenient way to insure that all steps use the same settings. Also, I have added variables that you can use if you need to add headers to compilation (i.e. the INCS variable). I have broken out the commands and flags for the linker as well, the LK, LKFLAGS and LIBS variable. Currently most of these are empty.
I added a variable for the various object files that are created, I like doing this because if I add a new source file to the project I have to do two things, the first would be to write a rule for it and the second would be to add it to the OBJS variable. In my opinion, the more things I need to do when adding a new source file, the greater the chance that I will forget something.
I added a variable for the final program name. Again, makes it simple if I want to change it…and I'm lazy — typing $(PROG) is easier and less error prone than typing PolyCalculator :)
Ordering of targets is a personal choice, I always put the target to rebuild the main program as the first (or default) target in the makefile. That way when I run make I just build what has changed since my last build. I put a rule near the top to do a total rebuild of the application, in the above this is the rebuild rule. Running make rebuild is operationally equivalent to make clean; make; but I prefer a single target to accomplish this
I rewrote your rules using the variable I defined in point 1.
I added the -f flag to rm so clean will do everything even if it can't find a file. Again, this tends to be personal preference.

I make sure to use macros extensively, because you can redefine macros on the make command line if need be. There are also many standard macros, such as CC for the name of the C compiler and CFLAGS for the (majority) of the flags passed to the compiler. Also, make has built-in rules for many operations, such as converting a .c file into a .o file.
The philosophy behind make is that compilation is expensive, so you do as little of it as possible, but as much as necessary. Thus, make is typically commanded to build object files, and then links the object files with libraries to build programs.
You say you have three source files and one header. So, my makefile for your program would include:
FILES.c = PolyCalculatorMain.c PolyCalculator.c Polyfunctions.c
FILES.o = ${FILES.c:.c=.o}
PROGRAM = PolyCalculator
CFLAGS = -Wall -ggdb
all: ${PROGRAM}
${PROGRAM}: ${FILES.o}
${CC} -o $# ${CFLAGS} ${FILES.o} ${LDFLAGS} ${LDLIBS}
PolyCalculatorMain.o: PolyCalculator.h
PolyCalculator.o: PolyCalculator.h
Polyfunctions.o: PolyCalculator.h
clean:
rm -f ${PROGRAM} *.o *~ *# core a.out
The choice between $(XYZ) and ${XYZ} is arbitrary; I chose to use curly brackets 30 years ago, and don't see a reason to change. Being consistent is what matters.
The FILES.c macro (yes, macro names may contain dots, despite the fact that vim doesn't colour them as macros) lists a set of three file names. If I needed to add a fourth, then I'd add it to this list. If the list got too long for a single line, I'd use a macro of the format:
FILES.c = \
PolyCalculatorMain.c \
PolyCalculator.c \
Polyfunctions.c
This allows editing of one line affected when a file is added unless you add it at the end of the list. I normally keep such lists in sorted order.
The FILES.o macro is defined by applying a suffix-transformation rule to the FILES.c macro. The part after the : is .c=.o; it means replace the names that end with .c with .o at the end.
The PROGRAM macro is what I use in a single-program makefile. For a multi-program makefile, each program gets its own macro in all caps. (Although make macros are not constrained to all caps, it is normal to use all caps for macros.) The CFLAGS macros sets your chosen options for the C compiler. Good marks for using -Wall. I use more stringent options like -Wextra -Werror and specify a standard (-std=c11), but -Wall is a good start.
It is conventional to have the first rule in your makefile called all. It says "everything is up to date when ${PROGRAM} is up to date".
The next rule says that the program depends on the object files. If any of the object files is newer than the program, you rebuild the program using the command line shown. The $# hieroglyph is the same as ${PROGRAM} in this rule. Formally, it is the name of the target being built. It makes the command line generic — everything except the -o is a macro. This tends to be the way that makefiles work; the information is almost all in macros. The ${LDFLAGS} and ${LDLIBS} macros are semi-standard; they allow you to pass options to the linker (ld, invoked by the C compiler), and are used to specify library-related options. For example, you might have:
LDFLAGS = -L ${OTHERLIBDIR}
LDLIBS = -l${OTHERLIB}
to link with a library not located in /usr/lib and other standard locations. The macros OTHERLIBDIR and OTHERLIB would be defined earlier in the makefile, of course.
The next three lines say that the object files (note that it is the object files, not the source files) depend on the header file. make is quite capable of deducing that PolyCalculatorMain.o is built from PolyCalculatorMain.c, so you don't have to specify that dependency explicitly. It can't deduce the header dependency so you have to specify it. Note that I've not specified a custom command, so the default command will be used. That's usually:
${CC} -c ${CFLAGS} $*.c
where the $* is a shorthand for the basename of the file being compiled.
I modified the clean command to use rm -f (which won't complain if the arguments are missing), and added a.out and core to the list of debris files.
You can add endless extra stuff to a basic makefile like this. You might add a depend rule to automatically generate the header dependencies; that is useful when your code begins to get complex with multiple headers, and different source files using different sets of headers. If you have a multi-lingual source tree, you have to worry about multiple lists of files. If you have multiple programs, you have to separate the files specific to one program from those common to several, and then think about whether to build the common object files into a local convenience library so that you don't have to list the exact dependencies for each program.
But this outline will get you going.
If you're using GNU make, you might well add a line:
.PHONY: all clean
This tells GNU make that there won't be files called all and clean created.
I note in passing that the name Polyfunctions.c is inconsistent with the other two; the F should be capitalized for consistency.

Here is a proper GNU make file for your project:
# set macro with list of source files in current directory using wildcard
# note: the ':=' states that the list is to only be generated once
# if only '=' were used, the the list would be re-generated each time referenced
SRCS := $(wildcard: *.c)
# set macro with list of object files using pattern substitution
OBJS := $(SRCS:.c=.o)
# set macro with list of header files in the current directory using wildcard
HDRS := $(wildcard: *.h)
# set macro with list of compiler flags
# there are many other very useful compiler flags
# but this list will result in:
# all warnings displayed
# compile only
# debug info being include
# (there are other forms of the -g parameter to get more debug info)
# no optimization
# look for some included files in the current directory
CFLAGS := -Wall -c -g -O0 -I.
# set macro with list of linker flags
# all warnings displayed
# debug info being included
LFLAGS := -Wall -g
# set macro with path+name of pre-processor/compiler/linker utility
# by convention, the utility is referenced by $(CC)
CC := /usr/bin/gcc
# by 'make' design, the make utility is referenced by $(MAKE)
# set macro with path+name of file deletion utility
# by convention, the utility is referenced by $(RM)
RM := /usr/bin/rm -f
# by convention, there are (at least) two phony target names
# tell 'make' that 'all' and 'clean' are targets that will NOT produce an output file
# with those names
.PHONY: all clean
# this is first target so will be performed if:
# user enters 'make' with no parameters
# or user enters 'make all'
# the PolyCalculator executable is stated to be a pre-requisite
all: PolyCalculator
# this is a real target
# state that this target has a pre-requisite of the files listed in the OBJS macro
# the executable name is defined by the '-o' and following name
# use the parameters listed in the LFLAGS macro
PolyCalculator: $(OBJS)
gcc $(LFLAGS) -o PolyCalculator $(OBJS)
# this is a real target (PolyCalculator.o)
# state that this target has a pre-requisite of file: PolyCalculator.c
# state that this target has a pre-requisite of the files listed in the HDRS macro
# use the parameters listed in the CFLAGS macro
# target 'PolyCalculator' lists PolyCalculator.o as a pre-requisite
# so it can be performed automatically
# it can also be performed directly when the user enters 'make PolyCalculator.o'
PolyCalculator.o: PolyCalculator.c $(HDRS)
gcc $(CFLAGS) -o PolyCalculator.o PolyCalculator.c
# this is a real target (PolyCalculatorMain.o)
# state that this target has a pre-requisite of file: PolyCalculatorMain.c
# state that this target has a pre-requisite of the files listed in the HDRS macro
# use the parameters listed in the CFLAGS macro
# target 'PolyCalculator' lists PolyCalculatorMain.o as a pre-requisite
# so it can be performed automatically
# it can also be performed directly when the user enters 'make PolyCalculatorMain.o'
PolyCalculatorMain.o: PolyCalculatorMain.c $(HDRS)
gcc $(CFLAGS) -o PolyCalculatorMain.o PolyCalculatorMain.c
# this is a real target (PolyFunctions.o)
# state that this target has a pre-requisite of file: PolyFunctions.c
# state that this target has a pre-requisite of the files listed in the HDRS macro
# use the parameters listed in the CFLAGS macro
# target 'PolyCalculator' lists PolyFunctions.o as a pre-requisite
# so it can be performed automatically
# it can also be performed directly when the user enters 'make PolyFunctions.o'
PolyFunctions.o: PolyFunctions.c $(HDRS)
gcc $(CFLAGS) -o PolyFunctions.o PolyFunctions.c
# this is a phony target (see .PHONY, above)
# it is performed when the user enters 'make clean'
clean:
$(RM) PolyCalculator *.o *~ *#

Related

How do I tell Make to ignore files which haven't been updated?

I am new to using Make and I am having some trouble figuring out the syntax. I went through a few examples and I essentially combined a few of them to create my own file. I am not sure how to tell make to ignore already compiled source or header files that haven't changed. How can I get make to compile only the files that have changed?
I looked on the GNU website: https://www.gnu.org/software/make/manual/html_node/Avoiding-Compilation.html
I tried some of those flags, but I still am not getting the results I wanted.
# specify compiler
CC=gcc
# set compiler flags
CFLAGS=-Igen/display -Igen/logic -Iman -Ilib/include -pipe -march=native
# set linker flags
LDFLAGS=-lglut32 -loglx -lopengl32 -Llib
# include all sources
SOURCES=gen/display/*.c gen/logic/*.c man/*.c
# create objects from the source files
OBJECTS=$(SOURCES:.cpp=.o)
# specify the name and the output directory of executable
EXECUTABLE=win32/demo
all: $(SOURCES) $(EXECUTABLE)
# compile the target file from sources
# $# = placeholder for target name
$(EXECUTABLE): $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) $(LDFLAGS) -o $#
.c.o:
$(CC) $(CFLAGS) $< -o $#
I have a number of header and source files in different directories that are being compiled, but no matter what I do everything recompiles.
Okay, let's do it, as it ought to be done ;-)
# set up our variables
# note: you may also prefer := or ?= assignments,
# however it's not that important here
CC=gcc
CFLAGS=-Igen/display -Igen/logic -Iman -Ilib/include -pipe -march=native
# linker's flags are different from compiler's
LDFLAGS=
# these are really libs, not flags
LDLIBS=-Llib -lglut32 -loglx -lopengl32
# 1) make is not your shell - it does not expand wildcards by default
# 2) use := to force immediate wildcard expansion;
# otherwise make could perform it several times,
# which is, at the least, very ineffective
SOURCES:=$(wildcard gen/display/*.c gen/logic/*.c man/*.c)
# use the right extensions here: .c -> .o
OBJECTS=$(SOURCES:.c=.o)
# note: it's okay to omit .exe extension if you're using "POSIX"-like make
# (e.g. cygwin/make or msys/make). However, if your make was built on Windows
# natively (such as mingw32-make), you'd better to add '.exe' here
EXECUTABLE=win32/demo
# don't forget to say to make that 'all' is not a real file
.PHONY: all
# *.c files are what you write, not make
# note: in fact, you don't need 'all' target at all;
# this is rather a common convention
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
# note: 1) suffix rules are deprecated; use pattern rules instead
# 2) this doesn't add much to the built-in rule, so you can even omit it
# 3) .o files are created in the same directories where .c files reside;
# most of the time this is not the best solution, although it's not
# a mistake per se
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#

Makefile: "ld: can't link with a main executable file" in C

I am trying to compile two c files, calutil.c and calutil.h into one executable. Here is my makefile:
CC = gcc
CFLAGS = -Wall -std=c11 -DNDEBUG
all: caltool
caltool: calutil.o caltool.o
$(CC) $(CFLAGS) calutil.o caltool.o
caltool.o: caltool.c
$(CC) $(CFLAGS) caltool.c -o caltool.o
calutil.o: calutil.c
$(CC) $(CFLAGS) -c calutil.c -o calutil.o
clean:
rm -rf *.o *.out
calutil.c has no main, while caltool.c has a main. I get the error
ld: can't link with a main executable file when I make. What is the cause of this?
The main problem is that some your recipe for linkage is missing the output file, and that your compilation is missing -c.
In case you're using GNU make, the following Makefile would be sufficient to do what you want to do:
CFLAGS:=-Wall -std=c11
CPPFLAGS:=-DNDEBUG
.PHONY: all
all: caltool
caltool: caltool.o calutil.o
.PHONY: clean
clean::
$(RM) *.o
Explanation:
When you're not using target-specific variables, you should use := instead of = to assign variables so that they're expanded at assignment and not at evaluation.
When your Makefile grows and you split it, you might want to have multiple targets called clean which all would be executed. In that case use clean:: instead of clean:.
There's a predefined variable to call rm, it is $(RM) and it includes the -f flag to prevent the Makefile from failing in case one or more of the files to be removed do not exist in the first place.
The pattern for clean should be *.[adios] (that's really easy to remember, adios is Spanish for goodbye) so that it removes intermediate archives (.a when you build your own static libraries), dependency files (.d), preprocessor output (.i) and assembler files (.s) in case you use -save-temps to see what the compiler is doing.
GNU make has built-in rules to compile and link, see http://git.savannah.gnu.org/cgit/make.git/tree/default.c?id=3.81
The built-in rule for compilation calls $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $< so you don't need to write your own rule.
The built-in rule for linkage calls $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $#
Targets which are not files themselves should be declared .PHONY to prevent confusion when a user creates a file with the same name, like all or clean.
I do not see how any of your commands would create a file matching the glob pattern *.out, so I removed that part of the clean rule.
Flags for the preprocessor should go into CPPFLAGS instead of CFLAGS. Preprocessor flags typically are all those -D and -I flags and would also be passed to other tools that use a C preprocessor in the same project, like splint or PC-Lint.
When the Makefile is run, it is looking how to make all, and it finds that for all it has to make caltool. For caltool it finds that it has to first make calutil.o and caltool.o. When it tries to make calutil.o and caltool.o, it finds that it can make them from calutil.c and caltool.c and will do so. Then it will link caltool.o and calutil.o into caltool.
From your naming I guessed that it's caltool.c that contains the main() function. It is helpful to place the object which contains main() first once you use static link libraries.
Edit: Here's some more magic for you. I assume that you have a header file calutil.h which is included by caltool.c to access extern symbols provided by calutil.c. You want to rebuild all objects that depend on these header files. In this case, add the following lines to your Makefile:
CPPFLAGS+=-MMD
-include caltool.d calutil.d
In order to not have the list of objects multiple times, you could add a variable objects like this:
objects:=caltool.o calutil.o
You would then build the application with this rule:
caltool: $(objects)
And include the dependency files like this:
-include $(objects:.o=.d)
In case you keep your working tree "clean", i.e. do not "pollute" it with "alien" code, i.e. you always want to include all .c files in your project, you can change the definition of objects as follows:
sources:=$(wildcard *.c)
objects:=$(sources:.c=.o)
In case you wonder why it is CPPFLAGS (uppercase) but objects (lowercase): it is common to use uppercase for all variables which configure the recipes of rules and control the built-in behavior of make, tools built on top of it, and classic environment variables, and lowercase variables for everything else.
I just removed the .o files from the directory, and edited my makefile to add -c to the caltool.o line.

Unix: Project Management with Make

My instructions are:
The steps necessary to produce this program are:
Compile cpp2html.c to produce cpp2html.o. (Important: the source code in this project is C, not C++, and so must be compiled and linked with gcc, not g++.)
Run the command
flex cppscanner.l
to produce the file lex.yy.c from the language description in cppscanner.l.
Compile lex.yy.c to produce lex.yy.o. (This often produces a warning message about extra tokens. Ignore it.)
Link the .o files to produce an executable program named cpp2html
Write a makefile that will carry out these steps. Your makefile should result in only the minimum required amount of steps when any input file to this process is changed. (Note: you will probably not be able to base this makefile upon my self-updating makefile as in the earlier part of the assignment. Instead, you will probably find it necessary to write this one from scratch.
Here is my makefile:
cpp2html: cpp2html.o lex.yy.o
gcc -g -DDEBUG cpp2html.o lex.yy.o
mv a.out cpp2html
lex.yy.o: lex.yy.c
gcc -g -DDEBUG lex.yy.c
lex.yy.c:
flex cppscanner.l
cpp2html.o: cpp2html.c
gcc -g -DDEBUG cpp2html.c
What am I doing wrong here? I get an error message saying:
collect2: error: ld returned 1 exit status
make: *** [cpp2html.o] Error 1
Your makefile does not build 'cpp2html' when invoked:
gcc -g -DDEBUG cpp2html.c
This is due tonight, so any suggestions would be greatly appreciated.
It's complaining about the following:
cpp2html.o: cpp2html.c
gcc -g -DDEBUG cpp2html.c
This line is trying to compile cpp2html.c to a.out.
Change that to
cpp2html.o: cpp2html.c
gcc -g -DDEBUG -c cpp2html.c
Do the same thing for the line that compiles lex.yy.c to lex.yy.o. The -c option tells gcc to only generate the object file and write it to the .o file.
You can take advantage of other options and some built-in variables. Here's a suggestion:
cpp2html: cpp2html.o lex.yy.o
gcc -g -DDEBUG -o $# $?
$# evaluates to the name of the target. $? evaluates to the list of dependencies (the .o files). The -o option tells gcc to write the resulting binary to the specified file name instead of a.out.
You can also take advantage of implicit rules:
%.o : %.c
gcc -g -DDEBUG -c $<
This will build any .c file to the corresponding .o file, so you don't need to repeat the same commands for cpp2html.c and lex.yy.c.
Edit
FWIW, here's how I'd structure the makefile (with annotations; assumes Gnu make):
# Variables used by implicit rules
CFLAGS=-g -DDEBUG -Wall -Werror # flags for gcc
LFLAGS= # flags for flex, currently none
LEX=flex # lexer
CC=gcc # C compiler
# Variables to make life easier
LSRCS=cppscanner.l # All of our flex source files
SRCS=cpp2html.c $(patsubst %.l,%.c,${LSRCS}) # All of our C source files
OBJS=$(patsubst %.c,%.o,${SRCS}) # All of our object files
TARGET=cpp2html # Final target name
${TARGET} : ${OBJS}
${CC} ${CFLAGS} -o $# $^ # Explicit rule to build target
# $# expands to target name
# $^ expands to list of all prerequisites
clean:
rm -rf *.o $(patsubst %.l,%.c,${LSRCS})
That's it. We're relying on implicit rules to build the .l file to a .c file, and to build the .c files to .o files. The implicit rules use the LEX, CC, LFLAGS and CFLAGS variables to run the right commands with the right options. We only need the single explicit rule to build our final executable.
The advantage of structuring a makefile like this is that you can add files to the project without having to add new rules.
I think all of the above is correct; my main box is shut down at the moment so I can't test it. Refer to the Gnu Make manual for more details.

how to manage c files dependencies in make

i'm starting with make and i was searching how to automaticly generate dependencies for my c files, i found this piece of code :
# pull in dependency info for *existing* .o files
-include $(OBJS:.o=.d)
# compile and generate dependency info
%.o: %.c
gcc -c $(CFLAGS) $*.c -o $*.o
gcc -MM $(CFLAGS) $*.c > $*.d
what i don't understand is when i generate the dependencies file %.d, i already have built the %.o file, so what it the point to creating this dependencies file, and the -include i executed before everything so no dependencies file will exist.
-include means to include the dep file if it is there but not fail if it isn't.
The trick, and this is common in make dependency tracking, is that your dependencies are actually one build out of date. You're including, if they are there, the dependency files that were built the last time around.
This is not a problem because for dependencies to change, changes have to be made to something that the target depended on during the last build -- so even though make doesn't know the full new dependencies, it knows that it has to rebuild the target (and generate a new dependency file in the process).
Addendum: By the way, gcc and clang have a -MD option that can generate a dependency file while building the .o (by default with a .d suffix). This means that you can do automatic dependency tracking with implicit rules and cut down your Makefile to the bare minimum like so (for a simple project with .c files in a flat directory):
#!/usr/bin/make -f
# name of the binary to build
TARGET = target
CC = gcc
# These flags are used by the implicit rules for C preprocessor flags,
# C compiler flags, linker flags, and libraries to link (-lfoo options)
# -MD in CPPFLAGS means that the implicit rules for .o files will also
# generate a corresponding .d file that contains the dependencies.
# The values here are just examples (thank you, Rear Admiral Obvious!)
CPPFLAGS = -MD -I somewhere/include
CFLAGS = -O2 -g
LDFLAGS = -L somewhere/lib
LDLIBS = -lsomelibrary
# SRCS is a list of all .c files in the directory, the other two are
# pattern substitution expressions that take SRCS and replace the .c with .o
# and .d, respectively
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
DEPS = $(OBJS:.o=.d)
all: $(TARGET)
$(TARGET): $(OBJS)
# Look, Ma, no explicit rules for .o files!
clean:
rm -f $(TARGET) $(OBJS)
.PHONY: all clean
# include dep files (if available).
-include $(DEPS)
I usually add phony target depend, like this:
depend: $(SOURCES)
makedepend -Y. $(CFLAGS) $^ 2>/dev/null
and run make depend time to time to update depenencies.
See man makedepend for details.

Why does this makefile not apply includes to all objects?

This makefile does not behave as I expect. I want it to build .o files for each .c file in the current directory and subdirectories, and put them in a static library. However, it stops applying my $(INCS) after the first or second file. When it tries to build the second .o file, I don't see the -I paths in the build line and it complains about not finding a header file therein. Names have been genericized to simplify things. I'm using cygwin on Windows XP. I'm using an ARM cross compiler that is not under the cygwin tree. I based this makefile off an answer here. There are only about two dozen .c files so the overhead of creating the dependency files this way isn't a big deal.
# Project specific options
CC = my-cross-gcc
INCS := -I. -Iinc
INCS += -Imy/inc/path
CFLAGS := -Wall -fPIC -static -cross-compiler-specific-options
OUT := bin/libmylib.a
MKDIR:=mkdir -p
### Generic C makefile items below:
# Add .d to Make's recognized suffixes.
SUFFIXES += .d
NODEPS:=clean
#Find all the C files in this directory, recursively
SOURCES:=$(shell find . -name "*.c")
#These are the dependency files
DEPFILES:=$(patsubst %.c,%.d,$(SOURCES))
OBJS:= $(patsubst %.c,%.o,$(SOURCES))
#Don't create dependencies when we're cleaning, for instance
ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
-include $(DEPFILES)
endif
#This is the rule for creating the dependency files
%.d: %.c
$(CC) $(INCS) $(CFLAGS) -MM -MT '$(patsubst %.c, %.o,$(patsubst %.c,%.o,$<))' $< > $#
#This rule does the compilation
%.o: %.c %.d %.h
$(CC) $(INCS) $(CFLAGS) -o $# -c $<
# Now create a static library
all: $(OBJS)
#$(MKDIR) bin
ar rcsvq $(OUT) $(OBJS)
clean:
rm -rf $(OBJS) $(OUT) $(DEPFILES)
Why does this makefile not apply $(INCS) when building subsequent .o files? How do I fix it? Output resembles this:
$ make all
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o firstfile.o -c firstfile.c
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o secondfile.o -c secondfile.c
my-cross-gcc -<compiler flags> -o thirdfile.o -c thirdfile.c
thirdfile.c:23:18: fatal error: myinc.h: No such file or directory
compilation terminated.
When I go to the command line and type in the gcc line to build thirdfile.o and use the -I paths, the object file is successfully built.
There are two different mechanisms for handling header files at work here:
When the compiler is trying to build foo.o from foo.c, and in foo.c it encounters #include "foo.h", it goes looking for foo.h. The -I flags tell it where to look. If it is invoked without the flags it needs to find foo.h, it will complain and die.
When Make is trying to build foo.o, and considering which rule to use, it looks at the prerequisites. The prerequisites for your rule are foo.c foo.d foo.h, so it goes looking for those prerequisites. How is it to know where foo.h is? Note that the compiler flag inside one of its commands is of no use-- it won't make any deductions about that. If it can't find (and doesn't know how to make) a prerequisite, it will reject that rule and look for another one, such as the implicit %.o rule which knows nothing about your $(INCS) variable, and that leads you to the problem described above.
If this is the problem (and you can check by looking at the locations of the headers and doing some experiments) you have a couple of options:
A) You can use the implicit rule, and it's variables. Just add INCS to CFLAGS and you'll probably get the results you want. This tells the compiler what to do, but it still leaves Make in the dark about the dependencies, so you'll probably have to double-check that your dependency handling is correct.
B) You can tell Make where to find the header files:
vpath %.h inc my/inc/path
(You may notice that this is redundant with your INCS variable, and redundancy is bad-- you can eliminate this redundancy, but I urge you to get it working first.)
I'm going to guess that you have files named firstfile.h, secondfile.h, but no file named thirdfile.h?
I would then suppose that make cannot use the rule you gave it because and can't find or build the .h file. So it decides to use the default implicit rule instead.
All I can imagine is that for "thirdfile" your depfile is somehow out-of-date or corrupt. Perhaps it is bad enough that it's confusing make into calling some other default target.

Resources