Solving "undefined reference to" errors in a makefile

12,062

I've spend nearly my entire day to figure out that i missed the linker parameter -L. TARGET. In my case my final linking routine ended up looking something like:

avr-g++ lib/core.a \
    obj/bot_life.o \
    obj/bot_port.o \
    obj/bot_serial.o \
    obj/bot_time.o \
    obj/bot_tacho.o \
    obj/bot_main.o \
    -o bin/bot.elf \
    -L. lib/core.a

A lot of time spend, seemingly a lot of hours wasted but a valuable lesson learned so I guess it became worth my while.

Detail, detail, detail...

Share:
12,062
vidbina
Author by

vidbina

Maker 👷🏿‍♂️/hacker 👨🏿‍💻/goofball 🥳 tinkering w/ cloud ☁️, electronics 🤖 & ML 🧠🖥️ , discovering how much I don't know. 📚🤷🏿

Updated on June 04, 2022

Comments

  • vidbina
    vidbina almost 2 years

    I have a few custom source files in my src directory and a few source files from the Arduino project in my src/base directory.

    I compile all source files into objects which are stored in my obj directory using the following make rules:

    PATHOBJ := obj/
    PATHSRC := src/
    PATHBIN := bin/
    PATHLIB := lib/
    PATHTMP := tmp/
    PATHARDUINO = $(PATHSRC)base/
    enter code here
    $(PATHOBJ)core_%.o : $(PATHARDUINO)%.c
        @mkdir -p $(dir $@)
        $(GCC) $(ALL_CORE_CFLAGS) -c $< -o $@
    
    $(PATHOBJ)bot_%.o : $(PATHSRC)%.c
        @mkdir -p $(dir $@)
        $(GCC) $(CFLAGS)-c $< -o $@
    

    As you can see it would compile src/tacho.c to obj/bot_tacho.o and src/base/wiring_analog.c to obj/core_wiring_analog.o.

    In my makefile I compile all of my source files without any problems. In one of these files (namely src/tacho.c) I have added the following include: #include "base/wiring.h" which contains the prototype to analogRead.

    The funny thing is that wiring.h only contains the prototype to the 'analogRead' function. It doesn't even bother to include the files that actually define the function, but some nosing around led me to discover that the definition of the function was to be found in src/base/wiring_analog.c.

    I reckoned it would suffice to compile the file that does declare the function and link it along with all other necessary Arduino object files into a single library. I arbitrarily chose to name it lib/core.a. I made lib/core.a by executing the following:

    avr-ar rcs lib/core.a obj/core_wiring.o \
        obj/core_wiring_analog.o \
        obj/core_wiring_digital.o \
        obj/core_wiring_pulse.o \
        obj/core_wiring_shift.o
    

    Needless to say I first made sure that the prerequisites for this make rule were in order.

    That worked without a problem; however, the problem is that attempting to generate my binary leaves me with a "undefined reference" error.

    avr-g++ lib/core.a \
        obj/bot_life.o \
        obj/bot_port.o \
        obj/bot_serial.o \
        obj/bot_time.o \
        obj/bot_tacho.o \
        obj/bot_main.o \
        -o bin/bot.elf
    /home/david/src/botPMA/src/tacho.c:13: undefined reference to `analogRead'
    /home/david/src/botPMA/src/tacho.c:14: undefined reference to `analogRead'
    make[1]: *** [bin/bot.elf] Error 1
    make[1]: Leaving directory `/home/david/src/botPMA'
    make: *** [all] Error 2
    

    I did a objdump of the core_%.o objects, and I did notice that core_wiring_analog.o made mention of analogRead. If the way I thought it worked was correct core.a which contains core_wiring_analog.o should therefore contain the definition for analogRead. I went back to compile src/tacho.c which uses the function analogRead and that compiled fine every time I tried (the preprocessor didn't see the need to complain about my include). It's the linking that causing problems, I suppose.

    I've read a lot of stuff online, but I still can't seem to figure this one out by myself. Probably a stupid mistake, but I just can't see it. How can I solve this problem?

    For the sake of completeness, I've dropped my entire project here: googlecode repository for my project