0

[SOLVED]
So I have a compiler/translator for a programming language I'm working on.
In the past the project was unmanaged and I used some clever (but probably terrible) tricks for compiling the thing and it all worked and ran fine.
Recently however, I got a CLion Student license and I fell in love with the IDE, so I decided to migrate my compiler to a CLion project.
Right now I'm having an issue getting it to compile, the linker throws me a bunch of "Undefined Reference" errors. I've looked over my include guards, includes and other things but I can't seem to find what's causing this...
This is a part of the output the linker is giving me

[ 86%] Linking CXX executable Compiler.exe
C:/.../Compiler/src/Parser/Parser.cpp:133: undefined reference to `void Dragoon::AST_Node::add_child<Dragoon::For_Node>(std::shared_ptr<Dragoon::For_Node>)'
C:/.../Compiler/src/Parser/Parser.cpp:134: undefined reference to `void Dragoon::AST_Node::add_child<Dragoon::For_Body_Node>(std::shared_ptr<Dragoon::For_Body_Node>)'

Parser.cpp is quite a long file but here's some of the relevant parts:

#include "Parser.hpp"

namespace Dragoon
{
    std::vector<Error_Msg> Parser::parse(Statement stm, std::shared_ptr<AST_Node> par_node, uint level)
    {

That's the beginning of the file, the only lines before that are comment lines with author, date, ...
I also left out the parser's constructor and the parse method that kick-starts the parsing process. These are both inside the namespace but before the shown method. (The method shown is the one throwing the error)

            par_ptr->add_child(for_node);
            for_node->add_child(body_node);
            this->m_current_node = body_node;

            std::vector<Error_Msg> parse_errors = this->parse(init, for_node, level + 1);

These are lines 130 through 135 (the ones generating the error)

Now, AST_Node.hpp:

#include <string>
#include <memory>
#include <vector>
#include "Node_Classes.h"
#include "../Constants/Aliases.h"

#ifndef COMPILER_AST_NODE_HPP
#define COMPILER_AST_NODE_HPP

namespace Dragoon
{
    class AST_Node
    {
        protected:
            std::string m_class;

            std::shared_ptr<AST_Node> m_parent;

            std::vector<std::shared_ptr<AST_Node>> m_children;

        public:
            AST_Node();

            AST_Node(std::shared_ptr<AST_Node> m_parent, std::string node_class);

            std::shared_ptr<AST_Node> get_parent(void);

            std::shared_ptr<AST_Node> get_child(uint index);

            int num_children(void);

            template<typename T>

            void add_child(std::shared_ptr<T> ch);

            std::string node_class(void);

            virtual std::string to_string(void);

            virtual std::string get_type(void);

            void print(uint level);
    };
}

#endif //COMPILER_AST_NODE_HPP

and AST_Node.cpp (I've again left some parts out to not overload you with irrelevant code, if anyone wants to see different parts, I'll update the question)

#include "AST_Node.hpp"

namespace Dragoon
{

And the problem method:

template<typename T>

void AST_Node::add_child(std::shared_ptr<T> ch)
{
    this->m_children.push_back(ch);
}

My project structure is as follows:

Compiler
    \_cmake-build-debug (default cmake dir, haven't touched it)
    \_Example Code (My programming language, will be used to test the compiler)
    \_src
        \_Collections (Arrays of constants and such)
        \_Constants (Things like error codes etc.)
        \_Lexer (All Lexer-relevant code)
        \_Parser (All Parser-relevant code, this is where both of the shown files are)
        \_Symbol Table (Symbol and Function Table)
        \_Utils (Several utility functions, like concatenating an array to a string etc., A bunch of the other "undef. reference" errors also point here)
        \_Some C++ code that doesn't really fit in any folder (Error_Msg class for instance)
        \_CMakeList.txt

My CMakeList.txt:

cmake_minimum_required(VERSION 3.6)
project(Compiler C CXX)

add_definitions(-D_WIN32)

set(SOURCE_FILES    ...
                    "src/Parser/Parser.cpp"
                    ...
                    "src/Parser/AST_Node.cpp"
                    ...)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")

add_executable(Compiler ${SOURCE_FILES})

I've left out most of the files in the source file list for easy reading, The files I've shown are in the same order though.

I've gone through this thread: What is an undefined reference/unresolved external symbol error and how do I fix it?

But the only thing I can think of I haven't done is check the order in which my source files are listed (if that's even relevant?)

If anyone has any tips on why this is happening, it'd be greatly appreciated

I'm not using any external libraries aside from the C++ std. libs and STL libs.

I'm running CLion 2016.3 with g++ 4.9.3 on Windows 10.

SOLUTION I forgot that in C++ you can't have a template's definition/declaration separated. Thanks to axalis for answering my question

Community
  • 1
  • 1
shmoo6000
  • 495
  • 4
  • 22

1 Answers1

0

The problem is, that your templated method is in the *.cpp file. That does not work, because at the time the .cpp file is being compiled, the compiler does not know, what template parameters it will be instantiated with.

There are two basic solutions of this problem:

1) Put the method definition in the header file along with the template declaration (recommended)

2) Add explicit template instantiation in the .cpp file:

template class Dragoon::AST_Node<Dragoon::For_Node>;
template class Dragoon::AST_Node<Dragoon::For_Body_Node>;

That is not so recommended, because as you can notice, the template needs to be explicitly instantiated for every set of parameters it will be ever used with, which is not practical in general (as you might not even know - if anything else will be used as template argument in the future, the explicit instantiation would need to be added).

EmDroid
  • 5,918
  • 18
  • 18