I have the following Makefile:
CC = gcc
CFLAGS = -ansi -Wall -g -O0 -Wwrite-strings -Wshadow \
-pedantic-errors -fstack-protector-all
PROGS = public01 public02 public03 public04 public05 public06 shell_jr
.PHONY: all clean
all: $(PROGS)
clean:
rm -f *.o $(PROGS) a.out
$(PROGS): shell_jr.c
public0%:
shell_jr < public0%.in > output
cat output
Whenever public0X is entered, the output of shell_jr.c when it is run with input coming from public0X.in should be displayed. The public0% tag is my attempt at making this happen. However, there are 3 problems. First, I can only have public0%.in as a dependency. That can be avoided by copy pasting separate commands for public01, public02, ... Second, when I do that and execute make, the command is immediately executed. How do I make sure that command is not executed until I type public01 and press enter?
First, I can only have public0%.in as a dependency.
I take this part to be asking about how to express in the recipe the correct name for the input file corresponding to the chosen target. The % of a pattern rule is expanded only in the target and prerequisites, not in the recipe, but in any make recipe, the automatic variable $# represents the complete target name being built. Since the wanted input name is formed by appending the suffix .in to the target name, it can be expressed as $#.in.
Additionally, you do not name the public0% targets as .PHONY (unlike clean and all), but your rule for them does not actually create them, either. If you are trying to both create and display these files, then you can also use $# to direct the output to the wanted file. Otherwise, you should mark these targets, too, as .PHONY.
Furthermore, if it your intention to (re)create these files regardless of whether anything has changed, then omitting the input files from the prerequisite list is appropriate. Otherwise, however, naming the input files as prerequisites will help make to skip needlessly regenerating the %public0% files.
Second, when I do that and execute make, the command is immediately executed. How do I make sure that command is not executed until I type public01 and press enter?
make is not interactive. If you want to specify a particular target or targets to build, instead of the default, then you express them as additional arguments on the make command line:
make public01
But I think what you're trying to get at may be a different problem than what you actually said. Your default target will build all of the targets named in $(PROGS), and where prerequisites do not require otherwise, GNU make running in serial mode will attempt to build the targets in the order in which they are named. Your public0% all depend on the shell_jr program, but they do not designate it as a prerequisite. (They do name shell_jr.c as a prerequisite, but that's not actually a direct dependency, and designating it as one does not serve a useful purpose.) Therefore, make will attempt to build all of the public0% targets before attempting to build shell_jr.
The correct thing to do here is to express the right dependencies. This version does that, on the assumption that the public0% are intended to be actual built files:
CC = gcc
CFLAGS = -ansi -Wall -g -O0 -Wwrite-strings -Wshadow \
-pedantic-errors -fstack-protector-all
PROGS = shell_jr
OUTPUTS = public01 public02 public03 public04 public05 public06
.PHONY: all clean
all: $(PROGS) $(OUTPUTS)
clean:
rm -f *.o $(PROGS) $(OUTPUTS)
# shell_jr is built according to a built-in rule (as was already the case)
public0%: public0%.in shell_jr
shell_jr < $#.in > $#
cat $#
Note that this will rebuild (and display) the public0% files only if their corresponding input files have changed or if shell_jr needed to be rebuilt. If you want them to be built and displayed even when nothing has changed then you can add a target with no prerequisites or recipe, and make it a prerequisite for the public0% rule:
public0%: public0%.in shell_jr FORCE
shell_jr < $#.in > $#
cat $#
FORCE:
.PHONY: FORCE
The FORCE target will be considered to have been rebuilt every time make runs, thus triggering the public0% targets to be rebuilt.
Related
I know it is not optimal at all to rely on make's implicit rules but
my goal is to understand why they are not working in this case.
I want to write the simplest makefile one can write for a C project
without having to specify the sources.
I have tried to run make -d but the ouput is too big and verbose to
really be helpful.
I have written makefiles for some time and I believe I am familiar with how it
works. I am pretty sure I have managed to get implicit rules to work for me both
compiling and linking in the past but apparently I am forgetting something.
Here's what I have tried :
SRCS = $(wildcard *.c)
OBJS = ${SRCS:.c=.o}
NAME=exe
${NAME}: ${OBJS}
clean:
rm -rf *.o
fclean: clean
rm -rf ${NAME}
re: fclean ${NAME}
.PHONY: clean fclean re
It almost works but it doesn't link.
I am using gnu make version 4.3
Your Makefile doesn't execute the link step because there is only a very simple implicit rule for linking. From the documentation:
Linking a single object file
n is made automatically from n.o by running the C compiler to link the program. The precise recipe used is $(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS).
This rule does the right thing for a simple program with only one source file. It will also do the right thing if there are multiple object files (presumably coming from various other source files), one of which has a name matching that of the executable file. Thus,
x: y.o z.o
In other words, for your Makefile to work, NAME needs to match the basename of one of your object files.
For example, if I have your Makefile and a single source file named hello.c, I can run:
make NAME=hello
And see the result:
cc -c -o hello.o hello.c
cc hello.o -o hello
I am trying to create a makefile, for the first time. I went through some tutorials and I managed to create one, but I am having trouble with a couple of things. Below are the details.
Below are the files in the order of execution:
CSV_to_txt.c - no dependency on any other files.
I want to include CSV_files/Equilibrium_trajectories.csv, which is my input, in the make file. Further, I run the command tac Chemical_Equilibrium.txt in the terminal. Can I include this in the make file as well?
fluid_profile.c - depends on pdfutil.h and beta_util.h.
I have the same problem of reading the inputs, for ex:
Enter the number of points
1000 --> to be included in the make file.
This file creates a text file called fluid_points.txt. What I want to include in the makefile is if this file already exists don't execute the command gcc fluid_points.c -o fluid_points.o -lm.
Structure of the make file:
all:
gcc CSV_to_txt.c -o CSV_to_txt.o -lm
./CSV_to_txt.o
#Include the file path and name when asked for it
#ubuntu terminal command --> tac filename.txt > filename_changed.txt
gcc fluid_profile.c -o fluid_profile.o -lm
./fluid_profile.o
#Enter the number of points when prompted to do so
#If fluid_points.txt file is already existing don't execute the above command, instead execute the below one
gcc blah.c -o blah.o -lm
./blah.o
clean:
$(RM) *.o *~
Any sort of help or even a link to a tutorial would be helpful.
A suggested makefile:
run:
.PHONY: run
CSV_to_txt: CSV_to_txt.c
gcc CSV_to_txt.c -o CSV_to_txt -lm
fluid_profile: fluid_profile.c
gcc fluid_profile.c -o fluid_profile -lm
blah: blah.c
gcc blah -o blah.c -lm
run: CSV_to_txt fluid_profile blah
echo "CSV_files/Equilibrium_trajectories.csv" | ./CSV_to_txt.o
tac Chemical_Equilibrium.txt
echo "1000" | ./fluid_profile.o
./blah.o
clean:
$(RM) *.o *~
So, a break down -- first line, predeclare target run, such that it becomes the default target (if you do make, it will run the first target ). Declare this as a phony target (This means there's no actual file called run being produced. You can look up .PHONY for more details)
Then create some rules to generate the executables. Each executable has its own rule to generate it. Typically you would use automatic variables for these like $# and $<, but I wanted to keep it simple for now.
Then the rule for run. This is dependent on the executables (so executables will finish building before this rule runs).
Then, to pass the filename into the executable, you can simply echo the filename, and then pipe that into the executable.
You have a common newbie error... this is to think that a source file depends on other source files (a .c file depends on some .h files) This is an error and probably the cause you are not getting your result.
The objective of a Makefile is to describe file dependencies in order to do the minimum set of commands to build the final target you specify. For this you need to think that a target is something you are goint to create.
Is a source .c file something you create during the build proces? Not, so it cannot be a target of a rule. The target, indeed is the result of the compilation. The source file doesn't depend on a header file... it just includes it to make the compilation of the .o target (this is, actually the target).
Let's say you have a program hello.c that includes modA.h and modB.h. (and even modB.h includes modB2.h) If you modify any of them, you need to recompile hello.c, so your rule will be:
# (1)
hello.o: hello.c modA.h modB.h modB2.h
cc -c hello.c # (2) see below.
(1) a rule line starts at column 1 and has a left hand side (the target file) and a list of sources (dependencies). Each time make sees that the target doesn't exist or has a last change date earlier than the change dates of any of the dependencies, the command lines below are executed, one after the other.
(2) a command rule starts with a <tab> char in the first column of the line. It represents a command (or a list of commands, each in it's command line) that are required to generate the target file from the sources.
a line starting with # is a comment line (also valid to start in the middle of a rule or a command line)
There is anothe type of line (a macro definition) but you need to learn first how to create dependencies and get used to them, before starting learning how to create macros. Read the make(1) doc first.
you see that we only compile hello.c, but we have to do it every time we change any of the other files above. There are two modules, modA.o and modB.o, each of them with their .c file and the includes needed in hello.c. So:
modA.o: modA.c modA.h
cc -c modA.c
modB.o: modB.c modB.h modB2.h
cc -c modB.c
so when we change any of modA.c or modA.h then modA.o will be created. And as modB.h we said above that included modB2.h, then if we modify it, it should be compiled.
Now the dependency of the program to be linked: As the program is compiled, it has just three modules: hello.o, modA.o and modB.o. To create hello all these three modules must be given to the linker.... so the Makefile needs also:
hello: hello.o modA.o modB.o
cc -o hello hello.o modA.o modB.o
and so, the complete Makefile is:
# this rule is put first to become the default target.
# the default target is the final program.
hello: hello.o modA.o modB.o
cc -o hello hello.o modA.o modB.o
# this rule is for the hello.o target only.
hello.o: hello.c modA.h modB.h modB2.h
cc -c hello.c
# this rule is for modA.o
modA.o: modA.c modA.h
cc -c modA.c
# and this one for modB.o
modB.o: modB.c modB.h modB2.h
cc -c modB.c
and with this Makefile you'll enjoy, because you can touch any file, but the compiler will compile only the correct dependencies to generate the final executable program.
Make has a lot of more functionality, but that requires you to know at least the most basic of it. Once after you have succeeded on the creation of the correct dependencies, you can start to study the other facilities of make, that are only there to abbreviate/avoid rewritting the same thing several times. But read at least the make manual page.
I'm having a problem with a C Makefile.
This is the code for the Makefile in bash:
CC=gcc
CFLAGS=-g -Wall
CCLINK=$(CC)
OBJS=flight.o runway.o airport.o main.o
RM=rm -f
# Creating the executable (airport)
airport: $(OBJS)
$(CCLINK) -o airport $(OBJS)
# Creating object files using default rules
main.o: main.c airport.h ex2.h flight.h runway.h
airport.o: airport.c airport.h ex2.h flight.h runway.h
runway.o: runway.c runway.h ex2.h flight.h
flight.o: flight.c flight.h ex2.h
# Cleaning old files before new make
clean:
$(RM) airport *.o *.bak *~ "#"* core
When I make the file, it says that:
make: `airport` is up to date.
After that - I can call "airport" in bash and it lets me enter some inputs the way I want it to be.
BUT- when I'm trying to check if "airport" is compiled by:
gcc -g -Wall -c airport
I get an error says that:
gcc: airport: linker input file unused because linking not done
Does someone know what could be the problem?
Thanks!
Gavriel.
The aim of Makefile is to avoid recompiling a file if its source is unchanged; when it happens, make says that the file is up to date.
This might be annoying if you want to check again the warnings. Then, simply call make to recompile everything, by typing
make clean ; make
Another goal of Makefile is to avoid typing the gcc commands by yourself, prone to errors. For instance, at the end of your question, you ask to make an object file from an executable (option -c), which is wrong. The good way to make an object file is to call make :
make airport.o
Finally, to produce the executable, you can either type
make airport
or, since airport: is the first target, type
make
I have the following simple problem in a Makefile:
%.o:: %.c
gcc -o $# -c $<
lib1.a: test.o
ar -r $# test.o
rm *.o
lib2.a: test.o
ar -r $# test.o
rm *.o
all: lib1.a lib2.a
make lib1.a or make lib2.a work properly. However, make all gives:
gcc -o test.o -c test.c
ar -r lib1.a test.o
rm *.o
ar -r lib2.a test.o
ar: test.o: No such file or directory
make: *** [lib2.a] Error 1
I need to do the rm *.o cause I want the object file to compile each time (in my real Makefile, I have a more complex use case where I compile with different flags).
How can I fix this problem? It seems that make compiles the object file only once.
I tried with .PHONY instead of doing the rm, but again, it compiles only once.
Your makefile is a bit against the make logic, this is why the result is not what you expect:
Here you define two targets (lib1.a and lib2.a) with a common dependency: test.o.
Then you define the rule all (which, by the way, should be .PHONY but this isn't a problem here) that depends on lib1.a and lib2.a.
So, in order to "do" all, make have to build lib1.a and lib2.a. They both depend on test.o, so make builds test.o once, then build lib1.a and lib2.a, expecting that the recipes you defined will just build those files, and nothing more.
The problem is that you delete test.o in the recipe for lib1.a and lib2.a, although this action is not needed to build them, this is something you want to do when cleaning, not building.
There are two solutions:
Move the deletion operation in a rule that is meant to do that (a .PHONY rule named clean for example).
The use of intermediate targets which will be deleted when they're not needed anymore. In fact, you can achieve that without even thinking about intermediate targets if you simply delete the first rule of your makefile (the %.o:: %.c one), because make already has an implicit rule that does that using intermediate targets.
Make is a rule-based system. Rules are declarative: you declare what you want built from what, you don't specify the order in which this happens (unless you can't avoid it). So a good Makefile is declarative: all results are declared like in a declarative programming language. They are like final variables in Java: you bind them to a value, you don't reassign them to a different value afterwards.
Make is also file-based: its "variables", targets and prerequisites are files.
So if you want to build two different things, don't call them by the same name! If you want two different test.o files, call them differently. The problem will go away without you needing to try and convince make that it should be like an imperative programming language, which it was specifically designed not to be. If you want an imperative build specification, use a shell script.
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 *~ *#