Search code examples
cgccmakefilecompiler-errors

GCC error undefined reference to function but function is defined, implemented, compiled


I'm trying to compile an executable with GCC but I'm getting an undefined reference to error even though the function in question is defined in another header file, compiled in another source file and compiled to a .o file.

The error is raised by a call to a defined function in an intermediary .o file (file graph.o).

Here's the code:

makefile:

kosaraju: kosaraju.o string_linked_list.o graph.o [...]
    gcc -o ../kosaraju kosaraju.o string_linked_list.o graph.o [...] -Wall
    make clean
    
kosaraju.o: 
    gcc -o kosaraju.o kosaraju.c -c -Wall
    
graph.o:
    gcc -o graph.o graph.c -c -Wall
    
string_linked_list.o:
    gcc -o string_linked_list.o string_linked_list.c -c -Wall

...

graph.c

#include "string_linked_list.h"
#include "graph.h"
#include ...

...


void dfs1_step(char * node, string_linked_list * topological_sort, /*more stuff*/)
{

    {
     // DFS_step implementation
    }

    // after iteration marks as visited
    string_linked_list_push(topological_sort, node);
}

string_linked_list.h

#ifndef STRING_LINKED_LIST
#define STRING_LINKED_LIST
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

typedef struct string_linked_list_node
{
    char * value;
    struct string_linked_list_node * next;
} string_linked_list_node;

typedef struct string_linked_list
{
    struct string_linked_list_node * head;
    struct string_linked_list_node * tail;
    uint16_t count;
} string_linked_list;

bool string_linked_list_push(string_linked_list * list, char * value);
// more prototypes
#endif 

string_linked_list.c

#include "graph.h"
#include "string_linked_list.h"
#include //more stuff


// Problematic function
bool string_linked_list_push(string_linked_list * list, char * value)
{
    string_linked_list_node * new_node = malloc(sizeof(string_linked_list_node));
    new_node->value = calloc(1, NODE_ID_LEN);
    if (new_node == NULL || new_node->value == NULL)
    {
        return false;
    }
    strncpy(new_node->value, value, NODE_ID_LEN);
    new_node->next = list->head->next;
    list->head->next = new_node;
    return true;
}

// more functions

the error I get after executing make:

gcc -o ../kosaraju kosaraju.c scanner.o map.o string_linked_list.o graph.o -Wall
/usr/bin/ld: graph.o: in function `dfs1_step':
graph.c:(.text+0x48a): undefined reference to `string_linked_list_push'
collect2: error: ld returned 1 exit status

Any insights on the reason? I've also tried to link string_linked_list directly into graph.o but had the same error.

I have implemented the string_linked_list_push in the correct file, I've checked if the signature matched it's definition in the header file, I've tried to link it directly into graph.o multiple times:

graph.o: string_linked_list.o
    gcc -o graph.o string_linked_list.o graph.c -Wall

and also:

graph.o:
    gcc -o graph.o string_linked_list.c graph.c -Wall

(I've actually tried with and without the -c option.


Solution

  • make doesn't know that it needs to re-compile string_linked_list.o whenever string_linked_list.c changes, because you didn't tell it that.

    You asked it to link the program, so it does that, with the perfectly good .o files it already has, which don't have a string_linked_list_push function because you hadn't written that function last time you compiled that file.

    And make doesn't see that you changed the file and added the next function, because you didn't tell it to do that. Solution: Tell it to do that.

    Change:

    string_linked_list.o:
    

    to:

    string_linked_list.o: string_linked_list.c
    

    and do the same for the rest of the .o files.

    There are shorter ways to write makefiles, but I'll leave you to explore them yourself when you get around to it.