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.
Related
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.
My teacher is not the best at explain C so I'm having a bit of trouble understanding the connection of makefiles. I have already added the code for complex.c, complex.h, and main.c. I'm just having trouble compiling it all using the make command. I followed the example on the powerpoint he handed up and I don't understand why its failing to get to complex.
makefile
complex: main.o complex.o
gcc -o complex main.o complex.o
main.o: main.c complex.h
gcc -c main.c -lm
complex.o: complex.c complex.h
gcc -c complex.c -lm
clean:
rm*.o complex
ls
main.o
main.o: complex.h
gcc -c main.c
complex.o
complex.o: complex.h
gcc -c complex.c
Error
mason% make
gcc -o complex main.o complex.o
ld: fatal: file main.o: unknown file type
ld: fatal: file processing errors. No output written to complex
collect2: error: ld returned 1 exit status
*** Error code 1
make: Fatal error: Command failed for target `complex'
It looks like you have put Makefile fragments inside main.o and complex.o. These should be generated by the compiler, not by you.
Delete these files, and make again.
Additionally, your make clean rule is missing a space.
clean:
rm *.o complex
ls
One more thing. No need for -lm in the compile lines.
main.o: main.c complex.h
gcc -c main.c
complex.o: complex.c complex.h
gcc -c complex.c
You should add -lm at the linking phase.
complex: main.o complex.o
gcc -o complex main.o complex.o -lm
The "Makefile" defines and controls the build dependencies.
For example, you can't build the main executable binary without first building the binary object/module files that go with it. In this case, those are main.o and complex.o.
Generally any object file you need also needs a rule (though some rules can use "wildcards" to build more).
This is all rather academic. Best to take errors at their word and try to disprove them (this one basically says that main.o exists and is incorrect). In this case the hypothesis that main.o exists is supported by the fact that it didn't compile when you ran the make command.
Until you learn more you could invoke "make" using "targets". Like: make clean and make complex. It might help bring clarity.
A lot of makefiles put an "all" target to sort of reset the build. That then depends on "clean" and the executable and library targets. Like:
all: clean complex
So then you "make all" to clean and build.
A good tutorial is here. Mrbook Makefile Tutorial
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
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.
See, the problem is that I'm supposed to use an executable driver program (vdriver) to test the C source file I wrote (myfile.c) containing a collection of methods the driver program will use. I used gcc to compile them together (and also any files they depend on) and then ran "gdb vdriver"
Apparently, I am getting a segfault somewhere in myfile.c. The "dissasemble"-produced assembly code can even display the whole method in assembly and point to which instruction just segfaulted.
However, due to the complexity (and length) of the assembly code, I think it would be much more effective to view this line where the segfault occurred in C.
However, running the command "list *$eip" results in:
No source file for address 0x804a3d3
Does anyone know how to make this work?
Compile with debugging info.
gcc -ggdb -c source.c -o source.o ...
Update: It looks like you're having trouble invoking GCC as well. I suggest writing a Makefile, and taking a quick look through the GCC manual for what -c and -o mean.
CC = gcc
CFLAGS = -ggdb -Wall # or whatever flags you want, read the manual
# List all files, with *.c changed to *.o (Make will figure the rest out)
my_app : file1.o file2.o file3.o file4.o
$(CC) -o my_app $^
# The above line should start with a tab, not spaces
clean :
rm -f my_app *.o
# List dependencies like this (technically optional)
# But if you don't do it, "make" might not re-make things that need it
file1.o : file1.c header.h header2.h
file2.o : file2.c header.h