I am trying to create a simple makefile. I have one headerfile: "guiBuilder.h". I have another file that will be using it: "client.c". The makefile that I am using is:
HEADERS = guiBuilder.h
default: program
program.o: client.c $(HEADERS)
gcc -c client.c -o client.o
program: client.o
gcc client.o -o Client
I found the code for the makefile here:
How do I make a simple makefile for gcc on Linux?
I now get this error when i run it:
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:9: recipe for target 'program' failed
make: *** [program] Error 1
Rules in a make file are of the form:
target: dependency1 dependency2 etc
command to build target
target is the name of the file you want to build. So the line
program: client.o
gcc client.o -o Client
Is trying to build a file called program. However, the command does not create a file called program, it creates a file called Client. This is less of a problem than you might think, it just means that the rule is always executed whether Client is up to date or not. However, you should change it so the target is the file you are building.
Client: client.o
gcc client.o -o Client
By the way, in most *nixes, file names are case sensitive Client and client are different files on Linux, for example.
That rule has a single dependency: client.o. Unfortunately, your make file does not know how to build client.o - there is no target called client.o.
I am speculating the cause of your error is that you have an old client.o hanging about that doesn't have a main() function in it. This is why the link (the gcc command in the program target) is failing.
The target program.o has the same problem as the target program. You are not building program.o, you are building client.o. This target needs to be changed to
client.o: client.c $(HEADERS)
gcc -c client.c -o client.o
which is happily the dependency for your Client target.
Note The indentation for the command part of a make rule has to be done with a tab. If copy-pasting my answer or any of the other answers, or the answers in the linked question, please make sure your indents are tabs, not spaces.
Update (the issue with test() being an undefined reference)
If you have a function in guiBuilder.c that has a prototype in guiBuilder.h you'll need to compile guiBuilder.c and add it to the link phase.
Your rule for guiBuilder.o will look very similar to the rule for client.o
guiBuilder.o: guiBuilder.c $(HEADERS)
gcc -c guiBuilder.c -o guiBuilder.o
Then you need to add guiBuilder.o as a dependency of Client
Client: client.o guiBuilder.o
gcc client.o guiBuilder.o -o Client
You may have noticed that you now have two rules for creating .o files that are identical other than the names of the source and object files. The accepted answer to the question that you linked shows how you modify the make file so you only need to define the rule once.
I will suggest you to read the GNU Make manual to get a better understanding of how make command and makefile works.
To answer your question, in short, Makefile consists of several things out of which the basic things are target, dependency and recipe. In the following manner
target: dependency
recipe
When you run make command, it searches for a file with name Makefile or makefile and it starts parsing target and dependency and executes the recipe for that target.
In your makefile you want to create final binary with name program but you don't have program.c so your makefile should go something like below:
HEADERS = guiBuilder.h
all: program
client.o: client.c $(HEADERS)
gcc -c client.c
program: client.o
gcc client.o -o program
Related
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.
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.
I can compile my two files serveur.c and client.c separately but when I try to use a makefile, it shows me an error. What I want is very simple : two compiled files : serveur.o and client.o.
Here is the code when I compile my two files separately :
gcc -lpthread serveur.c -o serveur.o
And
gcc -lpthread client.c -o client.o
Here is my makefile :
chatroom: serveur.o client.o
gcc serveur.o client.o -o chatroom
serveur.o: serveur.c
gcc -lpthread serveur.c -o serveur.o
client.o: client.c
gcc -lpthread client.c -o client.o
And here is the error when I write : "make -f makefile" in the terminal
gcc serveur.o client.o -o chatroom
duplicate symbol _main in:
serveur.o
client.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [chatroom] Error 1
Thanks for your help ! :)
If you successfully managed to build the two separate parts into a program each, it implies that both of the source files contain a main() or main(int, char*[]). However, you can have only one main() function per program (the restriction that you can have each function defined just once actually applies to all functions).
If each of the two files contains a complete program it is unlikely that you can just link them together: aside from the duplicate main() each of the programs will have some set up and some control. That is, simply getting rid of one of the main() functions is unlikely to result in a working program.
If you just added a main() function to one of the sources because otherwise it wouldn't "compile", you'll need to get rid of this main() and make sure that you actually compile the code into object files by passing the -c option. You'd leave the -c option off when linking the code.
Maybe there is some missunderstanding in the way compiler, assembler and linker work in creating an executable.
The usual convention is to give the .o extension to object files generated after the assembler stage not to executables!
As gcc will act as compile, assemble and link manager performing all steps in one run without beeing told to stop at an earlier stage, gcc -lpthread serveur.c -o serveur.o and
gcc -lpthread client.c -o client.o will both create executables not object files.
To make gcc stop after the assembly stage you have to pass it the -c switch. gcc -c serveur.c and gcc -c client.c. In this case giving -o serverveur.o and -o client.o is not necessary, as gcc will use them by default.
To link the generated object files the last thing to do would be gcc -lpthread serveur.o client.o -o chatroom
A Makefile to accomplish all that could look like that:
chatroom: serveur.o client.o
gcc -lpthread $^ -o $#
Unfortunately this will still not fix your problem of having two definitions of a main() function, one in serveur.c and one in client.c.
As gcc -lpthread serveur.c -o serveur.o and gcc -lpthread client.c -o client.o would have been rejected by the linker with an unresolved reference to main without, I am quite sure both of your sources contain a definition.
If instead of building one executable all you wanted to do is have make create two executables, serveur and client for you, your Makefile should look something like this.
.PHONY: all
all: serveur client