2

I've recently decided to start using makefiles instead of typing each command into a bash file but I've come across a problem while trying to compile while using one.

I'm trying to compile a few C and assembly files but keep getting this error. I've triple checked all the files and there is nothing wrong with them, so I'm assuming it's my makefile.

Here's the error that I'm getting:

…
i686-elf-gcc -T linker.ld -o bin/kernel.bin -ffreestanding -O2 -nostdlib src/boot.o \
     src/gdt.o src/cgdt.o src/kernel.o -lgcc
src/cgdt.o: In function `gdt_set_gate':
cgdt.c:(.text+0x0): multiple definition of `gdt_set_gate'
src/gdt.o:gdt.c:(.text+0x0): first defined here
src/cgdt.o: In function `gdt_install':
cgdt.c:(.text+0x70): multiple definition of `gdt_install'
src/gdt.o:gdt.c:(.text+0x70): first defined here
src/gdt.o: In function `gdt_install':
gdt.c:(.text+0x17a): undefined reference to `gdt_flush'
src/cgdt.o: In function `gdt_install':
cgdt.c:(.text+0x17a): undefined reference to `gdt_flush'
collect2: error: ld returned 1 exit status
Makefile:17: recipe for target 'link' failed
make: *** [link] Error 1

And here's the makefile:

CC=i686-elf-gcc
AS=i686-elf-as
LINKER=i686-elf-gcc

CFLAGS=-std=gnu99 -ffreestanding -O2 -Wall -Wextra -I./src/include
LDFLAGS=-T linker.ld

C_SOURCES = $(shell ls src/*.c)
ASM_SOURCES = $(shell ls src/*.s)
OBJECTS = $(ASM_SOURCES:.s=.o) $(C_SOURCES:.c=.o)

all: $(OBJECTS) link
clean:
    -rm ./src/*.o

link:
    $(LINKER) $(LDFLAGS) -o bin/kernel.bin -ffreestanding -O2 -nostdlib $(OBJECTS) -lgcc

.c.o:
    $(CC) $(CFLAGS) -c $< -o $@

.s.o:
    $(AS) $< -o $@
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 3
    Well, are those functions defined in both gdt.c and cgdt.c? – aschepler Feb 10 '16 at 00:44
  • `LDFLAGS=-T linker.ld` doesn't look right. Shouldn't it just be `LDFLAGS=-T`? – Fiddling Bits Feb 10 '16 at 00:50
  • 1
    The problem is nothing to do with `make` or your `makefile` per se, and is everything to do with how your code in `src/gdt.c` and `src/cgdt.c` both define an externally visible symbol `gdt_set_gate()`, etc. Did you forget to use [`static` in front of `inline`](https://stackoverflow.com/questions/6312597/is-inline-without-static-or-extern-ever-useful-in-c99) when you specified your functions as as `inline`? – Jonathan Leffler Feb 10 '16 at 01:16
  • The two files are gdt.s and gdt.c one being an assembly file and the other a c file and no, the function isn't defined twice. I dont know why its displaying gdt.c when that file doesnt exist – FlabbyLlama Feb 10 '16 at 01:22
  • You should try `nm -Ag src/gdt.o src/cgdt.o` and compare the sets of symbols defined. There'll be overlap — the ones the linker specified — and some omissions too (again, ones the linker specified). – Jonathan Leffler Feb 10 '16 at 01:22
  • 1
    You said _"no, the function isn't defined twice"._ Your linker disagrees with you. You may disagree with me as much as you like, but you've got to persuade your linker that you're correct. Also, in general, you should either be linking just the assembler or just the C code if they're meant to define the same things implemented two ways. Or if they're defining complementary sets of functions, then the base names of the two source files should be different so that the default name of the object files is different. (So, if they're both meant to be linked, you could have `cgdt.c` and `gdt.s`). – Jonathan Leffler Feb 10 '16 at 01:23
  • Where is `gdt_flush()` supposed to be defined? And just linking whatever object files happen to be in a directory is a recipe for unhappiness in my experience. – Jonathan Leffler Feb 10 '16 at 01:28
  • Ok I have no idea what happened but it's suddenly working and I haven't changed anything. I compiled each file individually then linked them all and it worked fine so I decided to try the make file again and it suddenly worked. Thanks for the help though – FlabbyLlama Feb 10 '16 at 01:32
  • 1
    You possibly just overwrote one object with the other by the manual build. Check your files and - as @JonathanLeffler wrote, if they implement different things, don't use the same basename. – too honest for this site Feb 10 '16 at 01:42
  • @FiddlingBits it is correct. _LD_ can take the `-T` option followed by a linker script file. – Michael Petch Feb 10 '16 at 02:21
  • 1
    `LDFLAGS`, etc. exist for a reason: to have all flags in one place. Therefore you should not have flags lateron in the actual call. – too honest for this site Feb 10 '16 at 02:27

1 Answers1

2

It looks like this isn't a make problem, it's that your gcc command doesn't work. What command were you using successfully in your bash script?


Make has implicit rules for making a .o from a .c, and for making a .o from a .s. You can customize what happens by customizing some variables.

Also, use .phony: link so it still happens if there's a file called link. Give it a dependency on $(OBJECTS) so it gets done as appropriate. Or tell make the real name of the target that will be built.

bin/kernel.bin: $(OBJECTS)
    some_command -o $@  ...
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847