24

I am having issue getting my makefile to work without errors. The first issue i have is with an undefined reference to main. I have main in my producer.c file as a function. The second issue is an undefined reference to SearchCustomer().

error:

bash-4.1$ make
gcc -Wall -c producer.c shared.h
gcc -Wall -c consumer.c shared.h
gcc -Wall -c AddRemove.c shared.h
gcc -pthread -Wall -o producer.o consumer.o AddRemove.o
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
AddRemove.o: In function `AddRemove':
AddRemove.c:(.text+0xb1): undefined reference to `SearchCustomer'
AddRemove.c:(.text+0x1e9): undefined reference to `SearchCustomer'
AddRemove.c:(.text+0x351): undefined reference to `SearchCustomer'
collect2: ld returned 1 exit status
make: *** [producer] Error 1

makefile:

COMPILER = gcc
CCFLAGS = -Wall
all: main

debug:
    make DEBUG=TRUE


main: producer.o consumer.o AddRemove.o
    $(COMPILER) -pthread $(CCFLAGS) -o producer.o consumer.o AddRemove.o
producer.o: producer.c shared.h
    $(COMPILER) $(CCFLAGS) -c producer.c shared.h
consumer.o: consumer.c shared.h
    $(COMPILER) $(CCFLAGS) -c consumer.c shared.h
AddRemove.o: AddRemove.c shared.h
    $(COMPILER) $(CCFLAGS) -c AddRemove.c shared.h


ifeq ($(DEBUG), TRUE)
    CCFLAGS += -g
endif

clean:
    rm -f *.o
user2644819
  • 1,787
  • 7
  • 28
  • 41
  • The code is **too** long. Narrow your problem down and provide a [Short, Self Contained, Correct (Compilable), Example](http://sscce.org/). – Yu Hao Dec 11 '13 at 08:56
  • 1
    A couple of suggestions: in the `main` recipe, you can write: `$(COMPILER) -o $@ $^ $(LDFLAGS)` and put `-pthread` in `LDFLAGS`. In the other rules you can write **once**: `%.o: %.c` and as recipe: `$(COMPILER) $(CCFLAGS) -c -o $@ $<` (and **not** give the `.h` to the compiler!) and later add dependency for special targets, for example: `producer.o: shared.h other_header.h` and `consumer.o: shared.h yet_another_header.h` etc. – Shahbaz Dec 11 '13 at 09:42
  • 1
    A couple other suggestions: Use `$(MAKE)` instead of just `make` to keep the command line flags for the invoked make. You may also want to give `--no-print-directory` to prevent couple lines of useless output. Also, use `CFLAGS` for C (instead of `CCFLAGS` which could be mistaken for C++). – Shahbaz Dec 11 '13 at 09:46
  • And more: Add `.PHONY: all clean debug` and other targets that are not actually files, to let `make` know that it shouldn't expect an actual file to come out of the recipe. You can also use `@$(MAKE) DEBUG=TRUE` (adding `@`) to prevent make from echoing the command. – Shahbaz Dec 11 '13 at 09:47
  • And finally, you can benefit from reading the manual: https://www.gnu.org/software/make/manual/make.html – Shahbaz Dec 11 '13 at 10:10

3 Answers3

20

This rule

main: producer.o consumer.o AddRemove.o
   $(COMPILER) -pthread $(CCFLAGS) -o producer.o consumer.o AddRemove.o

is wrong. It says to create a file named producer.o (with -o producer.o), but you want to create a file named main. Please excuse the shouting, but ALWAYS USE $@ TO REFERENCE THE TARGET:

main: producer.o consumer.o AddRemove.o
   $(COMPILER) -pthread $(CCFLAGS) -o $@ producer.o consumer.o AddRemove.o

As Shahbaz rightly points out, the gmake professionals would also use $^ which expands to all the prerequisites in the rule. In general, if you find yourself repeating a string or name, you're doing it wrong and should use a variable, whether one of the built-ins or one you create.

main: producer.o consumer.o AddRemove.o
   $(COMPILER) -pthread $(CCFLAGS) -o $@ $^
Jens
  • 69,818
  • 15
  • 125
  • 179
7

This error means that, while linking, compiler is not able to find the definition of main() function anywhere.

In your makefile, the main rule will expand to something like this.

main: producer.o consumer.o AddRemove.o
   gcc -pthread -Wall -o producer.o consumer.o AddRemove.o

As per the gcc manual page, the use of -o switch is as below

-o file     Place output in file file. This applies regardless to whatever sort of output is being produced, whether it be an executable file, an object file, an assembler file or preprocessed C code. If -o is not specified, the default is to put an executable file in a.out.

It means, gcc will put the output in the filename provided immediate next to -o switch. So, here instead of linking all the .o files together and creating the binary [main, in your case], its creating the binary as producer.o, linking the other .o files. Please correct that.

Jens
  • 69,818
  • 15
  • 125
  • 179
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
1

Here's another possible bug that could lead to this error:

I had some code in a namespace, so my header file looked like namespace MY_NAMESPACE { ... }

In the c file, I foolishly did this same thing, writing namespace MY_NAMESPACE { ... main() ... }.

On compilation, it failed with the given error. Instead, I changed the code in my c file to using namespace MY_NAMESPACE {... main() ...}. This worked because now, instead of writing main to a distinct namespace, it was just using definitions from another namespace.

Alex Li
  • 11
  • 1