0

While implementing three files (tree.h, tree.cpp, and node.h) into an existing project, I've run into "multiple definition of" errors when trying to reference them in my parser.h and parser.cpp files. I am using include guards to prevent multiple inclusion but I don't think that is doing what I want it to. I am also using plain C++99 and compiling on a Linux machine, I don't have control over that.

The getNode() is defined with the node_t struct in node.h and both need to be available to parser.cpp, parser.h, tree.cpp, and tree.h.

[user]$ make
g++ -g -Wall -Wno-unused-variable -o frontend main.o scanner.o parser.o tree.o
scanner.o: In function `getNode(std::string)':
/home/user/Compilers/P2/node.h:21: multiple definition of `getNode(std::string)'
main.o:/home/user/Compilers/P2/node.h:21: first defined here
parser.o: In function `getNode(std::string)':
/home/user/Compilers/P2/node.h:21: multiple definition of `getNode(std::string)'
main.o:/home/user/Compilers/P2/node.h:21: first defined here
tree.o: In function `getNode(std::string)':
/home/user/Compilers/P2/node.h:21: multiple definition of `getNode(std::string)'
main.o:/home/user/Compilers/P2/node.h:21: first defined here
collect2: error: ld returned 1 exit status
make: *** [frontend] Error 1

Makefile I tried adding node.h and token.h to the OBJFILES but that only caused those files to be deleted when I did make clean

CC = g++
CFLAGS = -g -Wall -Wno-unused-variable
CXXFLAGS = -g

OBJFILES = main.o scanner.o parser.o tree.o 
TARGET = frontend

all: $(TARGET)


$(TARGET): $(OBJFILES)
    $(CC) $(CFLAGS) -o $(TARGET) $(OBJFILES)


.PHONY: clean
    
clean:
    rm -f $(OBJFILES) $(TARGET) *~

node.h

#include <stdio.h> 
#include <stdlib.h> 
#include <string>

#include "token.h"

#ifndef NODE_H_
#define NODE_H_

struct node_t
{
    std::string label;
    Token* token1;
    Token* token2;
    //struct node_t *left;
    //struct node_t *right;
    struct node_t *child;
};

node_t* getNode( std::string functionName )
{
    // Create the node
    node_t* node = (struct node_t*)malloc(sizeof(struct node_t)); 
    node->label = functionName;
    node->child = NULL;
    node->token1 = NULL;
    node->token2 = NULL;

    return node;
}

#endif

I took all my files and their #include statements and header guards and mocked up a diagram of what all is happening. visual representation of my files

Exho
  • 113
  • 2
  • 9
  • 2
    That's hardly a matter of the makefile. Any template class definitions in one of the cpp files? – πάντα ῥεῖ May 04 '21 at 21:27
  • 2
    To optimise compilation time, move all includes inside the include guard. – eerorika May 04 '21 at 21:28
  • 3
    The bug appears to be in `node.h`. My expectation is you have defined a free function named `getNode(std::string)` in the header and multiple translation units are including this header causing a violation of the ODR – drescherjm May 04 '21 at 21:32
  • 1
    You're going to need to provide a [mre], or at least the code of `node.h` – ChrisMM May 04 '21 at 21:33
  • Added the content of node.h, how do I go about getting this opened? – Exho May 04 '21 at 22:16
  • 1
    If you put a definition (function or variable, not type) in a header file, **use the `inline` keyword**. Include guards don't apply when the header is included in multiple compilation units, which is your case. They just prevent reprocessing the same header many times in a single compilation. – Ben Voigt May 04 '21 at 22:18
  • More detail can be read here: https://stackoverflow.com/q/1759300/103167 It would be pointless to open your question just to mark it as a duplicate of that one. – Ben Voigt May 04 '21 at 22:20
  • 1
    Put `node_t* getNode( std::string functionName );` in the header and move the definition to a cpp file. – drescherjm May 04 '21 at 22:34
  • `node_t* node = (struct node_t*)malloc(sizeof(struct node_t));` probably should not use `malloc` in `c++` – drescherjm May 04 '21 at 22:35

0 Answers0