Why is my very simple makefile not working - c

When I say very simple I mean it. I have a main.c and a header file called input_error.h.
main.o : main.c input_error.h
gcc -c main.c
When I run the command "make" gcc -c main.c is executed but it's not updating any changes I make to my main.c file. When I manually type in "gcc main.c" it works fine.
EDIT: It seems like I need to add another rule but I'm not sure what that entails

At the moment your makefile only builds the .o file. You can build your binary in 2 ways. Note that make requires the indentation in the targets statements to be a tab and not 4 spaces, as it may have been converted to by the browser.
build .o separately then link binary. Note that using the -c switch causes gcc to build only the object file.
main: main.o
gcc main.o -o main
main.o : main.c input_error.h
gcc -c main.c -o main.o
build in one step
main: main.c input_error.h
gcc main.c -o main
You can also avoid repetition in your makefile by using special variables to denote the target ($#), the first dependency ($<) and all (#^) the dependencies.
e.g. one of the above lines could become
main.o : main.c input_error.h
gcc -c $< -o $#
Which seems a bit cryptic at first but you get used it. The implicit rules in #kaylums answer will also help to cut down on typing.

The Makefile you have only has a single rule to compile the .o file. That is, it does not have any rule to link the final executable.
make has implicit rules for building many common targets. So your Makefile could be as simple as the following:
all: main
main.o : input_error.h
For further explanation:
all: main: Since this is the first target it is the one that will be built by default if no explicit target is provided to the make command line. It depends on a single target main.
There is no explicit rule for main but make has an implicit rule which will build it from main.c.
main.o : input_error.h: Tells make that main.o needs to be rebuilt if input_error.h changes. There is no need to put main.c here as make has that implicit knowledge. There is also no need for an explicit command as make also has that implicit.

Related

make command runs only the first row in Makefile

Hi I Have this makefile:
main.o:main.c functionsLab1.c functionsLab1.h
gcc -c main.c
functionsLab1.o: functionsLab1.c functionsLab1.h
gcc-c functionsLab1.c
now when i Run the command "make" it only executes the first command in makefile.
how can I Run all the commands at once?
Thanks in advance :)
I Tried to type "make all" command and it showed an error.
make is able to build what you need, but only if you tell it the right dependencies. In particular, your current Makefile is lying about dependencies, since main.o does not at all depend on functionsLab1.c. Rather, the final executable you are trying to build depends on functionsLab1.o. You can probably make your entire Makefile:
main: main.o functionsLab1.o
(Yes, literally one line.). That ignores the dependency on the header file, but it should work for you. Let make use its default rules; they are pretty good. If you want to include the header dependency, do something like:
main: main.o functionsLab1.o
main.o: main.c functionsLab1.h
functionsLab1.o: functionsLab1.c functionsLab1.h
If for some reason you really want to be explicit (you don't!), you can do:
main: main.o functionsLab1.o
$(CC) -o $# $? # Warning: incomplete. See note below
main.o: main.c functionsLab1.h
functionsLab1.o: functionsLab1.c functionsLab1.h
Again, letting make use its default rules to construct the object files. You can override the default rules, but there is very seldom a reason to do so. Indeed, this is an excellent example where attempting to override the default rule gives you a sub-optimal recipe. The default rule would be something like $(CC) $(LDFLAGS) -o $# $? $(LOADLIBES) $(LDLIBS), and many users would reasonably expect to be able to specify LDLIBS. The example shown above ignores LDLIBS, violating the principal of least surprise.

Makefiles in C language

Hello I'm having a hard time understanding makefiles. I play with them to understand them better but here's the issue:
all: main
main: main.o funcIO.o funcMan.o
$(CC) -o $# $^
----------------------------------
funcIO.o: funcIO.c
$(CC) -c -o funcIO.o funcIO.c
funcMan.o: funcMan.o
$(CC) -c -o funcMan.o funcMan.c
This works regardless if everything below the punctured line is there or not. I'm told that this is the right way to write makefiles but why does it work without the targets funcIO.o and funcMan.o and if it works without them, why do we write them? Can you explain it like I'm 5 years old?
Thanks for your time!
Assuming you're using GNU Make (it might be the same for other Makes), this works due to built-in rules. Make already knows how to compile a C source file, and unless you tell it otherwise, it applies this recipe to it:
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
$# is the target of the rule (the filename of the .o file) and $< is the first prerequisite (the filename of the .c file). The other variables have sensible defaults (mostly empty).
The right way to use Makefiles is to keep them as small as possible. Makefiles are about determining dependencies and only incidentally can be used to build programs. Here's how I would rewrite your Makefile:
all: main
main: main.o funcIO.o funcMan.o
And I only put the all target there because you had it to begin with. Make has a list of builtin rules that know how to build things given certain files as inputs. If you ask it for a .o file, it will look for a file of the same name, but with the extension of .c, .cpp, .f77, etc., and run the rule that builds what you asked for using that prerequisite file. You don't even need to specify how to build those, they come for free! It's the more complex relationships (such as a final binary) that need to be spelled out, as shown in my above example. There's a similar rule for building a binary out of .o files (assuming one of them has the same name as the binary, which yours does), so you don't need to specify any tasks, just the dependencies. You can control how they are run by adjusting special flags:
CFLAGS += -Wall -Wextra -Wpedantic
main: main.o funcIO.c funcMan.o
main: LDLIBS += -lm
This version builds every C-compiled file with those CFLAGS, and builds main while linking in the -lm math library.
If you are building normal C programs, I strongly recommend this approach. Specify the prerequisites of the final binary, and control builds through these Make variables.

make rules with existing target, existing prerequisites but no recipe

I was looking at the net-snmp code and I found something odd in the Makefile of the snmplib itself. The last couple of thousands of lines are nothing but rules in this form:
./dir_utils.lo: ../include/net-snmp/output_api.h
for EVERY library object and header file. Even those that are not compiled, depending on which flags are selected in the configure script.
I looked at the "make" manual but I didn't find this exact case. It may be (as stated in 5.9) that they do this to exclude the possibility that an implicit recipe is called on the target, but other than that I have no idea.
Another reason might be to "break" the compilation if the library is tampered with (deleting whatever header in the project causes in fact the makefile to crash because it can't execute the rule).
This is an educated guess but I would like to know the theory behind this. I mean the makefile already builds whatever it has to build, why include all these rules in explicit form?
Thanks
As I expect you know, the Makefile is generated by the ./configure script.
All the lines that interest you are auto-generated dependencies. Actually,
they are just the appended contents of the file Makefile.depend in the same
directory, which is part of the distribution and was generated with the aid
of gcc ahead of time.
So e.g.
./dir_utils.lo: ../include/net-snmp/output_api.h
just informs make of the vitally important fact that ./dir_utils.lo
depends on ../include/net-snmp/output_api.h. Then if ./dir_utils.lo
is older than ../include/net-snmp/output_api.h, make will re-make
./dir_utils.lo provided it has some recipe to do that, which it has.
Here is a project:
main.c
#include "hw.h"
#include <stdio.h>
int main(void)
{
puts(HW);
return 0;
}
hw.h
#ifndef HW_H
#define HW_H
#define HW "Hello World"
#endif
Makefile
CC := gcc
.PHONY: all clean
all: hw
hw: main.o
$(CC) -o $# $<
clean:
rm -f hw main.o
Build and run it:
$ make && ./hw
gcc -c -o main.o main.c
gcc -o hw main.o
Hello World
But there's a bug in the makefile. It doesn't know that main.o
depends on hw.h:
$ touch hw.h
$ make
make: Nothing to be done for 'all'.
Append that dependency to the makefile:
main.o: hw.h
and retry:
$ make
gcc -c -o main.o main.c
gcc -o hw main.o
Bug fixed.

using a method from another file without including it [duplicate]

This question already has answers here:
Why is #include <stdio.h> not required to use printf()?
(3 answers)
Closed 8 years ago.
I have two .c files which I compile over a makefile.
foo.c:
void foo()
{
printf("this is foo");
}
main.c:
#include <stdio.h>
int main()
{
printf("this is main\n");
foo();
}
the makefile looks like that:
all: main.o foo.o
gcc -o prog foo.o main.o
main.o: main.c
gcc -c main.c
foo.o: foo.c
gcc -c foo.c
So the question is:
how can foo.c use printf() without me including stdio.h AND how can main.c use the method foo() without me including foo.c.
My guess/research is that the makefile works as a linker. But I dont have prove for that and want to understand how this works excactly.
Correct me if I misunderstood something.
In the compilation phase, the compiler checks function calls against prototypes. Any function that lacks a prototype is assumed to return int and to accept any number of arguments.
If you turn up the warning level, gcc will warn you if a prototype is missing. You should add -Wall and you could also add -pedantic to get diagnostics on additional things the compiler think are suspicious.
If the compilation step succeeds, the compiler creates an object file which contains the compiled code and 2 reference tables. The first table is the export table. It contains the names of all functions and variables that are exported from the object file.
The second table is the import table. It contains a list of all functions and variables that are referenced, but where the declaration was missing.
In your case we have:
foo.o:
Export:
foo
Import:
printf
main.o
Export:
main
Import:
printf
foo
In the linker phase, the linker will take the list of imports and exports and match them. In addition to the object files and libraries you specify on the command line, the linker will automatically link with libc, which contains all functions defined by the c language.
In the makefile you can force the complier to include <stdio> or any other header:
From the docs:
-include file
Process file as if #include "file" appeared as the first line of the
primary source file. However, the first directory searched for file is
the preprocessor's working directory instead of the directory
containing the main source file. If not found there, it is searched
for in the remainder of the #include "..." search chain as normal. If
multiple -include options are given, the files are included in the
order they appear on the command line.
Just add -include filename.h in the GCC/compiler command line within the makefile.
The makefile is not a linker. It is input to make. The makefile just tells make what commands to execute under what conditions.
Your all target is running gcc in linking/linker mode gcc -o prog foo.o main.o.
The same way your foo.o and main.o targets are running gcc in compilation mode gcc -c foo.c.
For the record you can combine the two .o targets into just
%.o: %.c
gcc -c $^
which is, in fact, already a default rule in make so you need not include that rule at all.
Additionally your all target is not following bet make practices because it generates a file that does not match the name of the target. So you should use
all: prog
prog: main.o foo.o
gcc -o prog foo.o main.o
instead.
Though once again there make has you covered by default and so your entire makefile can be replaced by
all: prog
prog: main.o foo.o
and you should get the same results.

Compiling with flags in a Makefile

To clarify things, let's suppose I'm compiling a program (prg) with 3 files, main.c, person.h and person.c.
If I use a concise way of writing the makefile, like this (more specifically the two last lines):
prg : main.o person.o
gcc -Wall -o prg -c $^
main.o : person.h
person.o : person.h
Will the -Wall be applied to main.o and person.o automatically? Or that doesn't even matter?
I know that, as the file says, if person.o needs to be re-compiled, prg will need a re-build too. But, I don't know if specifying -Wall only in the main goal is enough to enable it the other targets so warnings are emitted as the others are compiled.
Maybe I'm missing something really important, or I'm saying something that makes no sense; but take it easy, I'm just a beginner :P
Since you apply the -Wall to the link phase (when collecting the object files into an executable), but the option applies to the compilation phase (converting the source files into object files), it provides no benefit where it is written.
You should modify the compilation by setting macros.
Normally, the rule for compiling an C source file to an object file looks something like:
${CC} ${CFLAGS} -c $*.c
There could be other bits in there, and the notation might use something other than $*.c to identify the source file - there are similar (roughly equivalent) methods for specifying that, but it is tangential to the point I'm making. The $(CC) notation is equivalent to ${CC} too.
So, to change the compiler, you specify 'CC=new_c_compiler' and to change to compilation options, you (cautiously) specify 'CFLAGS=-Wall'.
This can be done in the makefile, or on the command line. The command line overrides the makefile.
Hence:
CFLAGS = -Wall
prg : main.o person.o
${CC} ${CFLAGS} -o prg -c $^
main.o : person.h
person.o : person.h
Why cautiously? Because in more complex situations, there may be a complex definition of CFLAGS which build it up from a number of sources, and blithely setting CFLAGS = -Wall may lose your include paths, macro definitions, and all sorts. In your case, it looks like you can simply set it as shown.
If you use GNU Make, you can simply add -Wall to CFLAGS:
CFLAGS += -Wall
This does not necessarily work with all varieties of make.
Your link line may eventually need to collect some library-related options too.
No, the flags will not magically be applied to other targets.
Add a line like this to the top of your Makefile, above the rules:
CFLAGS=-Wall
Then try without the explicit line for prg.

Resources