Home > Mobile >  Linker says a function is already defined if I try to define it in another file (running tests)
Linker says a function is already defined if I try to define it in another file (running tests)

Time:12-26

I have the following files in a testing project:

Test.cpp:

#include "pch.h"
#include "CppUnitTest.h"
#include <iostream>
#include "PrintOne.cpp"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace PointandVectorCreationTest
{
    TEST_CLASS(PointandVectorCreationTest)
    {
    public:
        
        TEST_METHOD(TestMethod1)
        {
            std::string expected = "1\n";

            std::stringstream buffer;
            std::streambuf* sbuf = std::cout.rdbuf(); // Save cout's buffer
            std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to the stringstream buffer

            int result = printOne();

            // When finished, redirect cout to the original buffer 
            std::cout.rdbuf(sbuf);
            std::cout << "std original buffer: \n";
            std::cout << buffer.get();

            // Test
            Assert::AreEqual(expected, buffer.str());
        }
    };
}

PrintOne.cpp:

#include <iostream>

int printOne() {
    std::cout << 1 << std::endl;
    return 0;
}

When I try to run this test in Visual Studio, the linker throws the following error:

Error LNK2005 "int __cdecl printOne(void)" (?printOne@@YAHXZ) already defined in PrintOne.obj

This error is thrown when linking Test.obj.

I'm not defining printOne anywhere in Test.cpp. In fact, if I just copy the definition of the function to Test.cpp and eliminate the PrintOne.cpp file like so:

Test.cpp:

#include "pch.h"
#include "CppUnitTest.h"
#include <iostream>

int printOne() {
    std::cout << 1 << std::endl;
    return 0;
}

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace PointandVectorCreationTest
{
    TEST_CLASS(PointandVectorCreationTest)
    {
    public:
        
        TEST_METHOD(TestMethod1)
        {
            std::string expected = "1\n";

            std::stringstream buffer;
            std::streambuf* sbuf = std::cout.rdbuf(); // Save cout's buffer
            std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to the stringstream buffer

            int result = printOne();

            // When finished, redirect cout to the original buffer 
            std::cout.rdbuf(sbuf);
            std::cout << "std original buffer: \n";
            std::cout << buffer.get();

            // Test
            Assert::AreEqual(expected, buffer.str());
        }
    };
}

The test runs just fine. I'd rather avoid writing all the functions I use in the same file I test them, so to me this shouldn't be a solution.

Why does the linker throw this exception? How can I fix this so I can keep my function definitions separate from the testing file?

CodePudding user response:

I'm not defining printOne anywhere in Test.cpp.

Actually, you are, when you #include the source code of PrintOne.cpp into Test.cpp. If you then compile and link both Test.cpp and PrintOne.cpp together, the linker indeed sees 2 definitions of printOne(), one in each .obj file.

For what you are attempting to do, you need to add a .h file that just declares printOne(), and then you can #include that file into both .cpp files, where only one of them defines printOne(), eg:

Test.cpp:

#include "pch.h"
#include "CppUnitTest.h"
#include <iostream>
#include "PrintOne.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace PointandVectorCreationTest
{
    TEST_CLASS(PointandVectorCreationTest)
    {
    public:
        
        TEST_METHOD(TestMethod1)
        {
            std::string expected = "1\n";

            std::stringstream buffer;
            std::streambuf* sbuf = std::cout.rdbuf(); // Save cout's buffer
            std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to the stringstream buffer

            int result = printOne();

            // When finished, redirect cout to the original buffer 
            std::cout.rdbuf(sbuf);
            std::cout << "std original buffer: \n";
            std::cout << buffer.get();

            // Test
            Assert::AreEqual(expected, buffer.str());
        }
    };
}

PrintOne.h

#pragma once
int printOne();

PrintOne.cpp:

#include "PrintOne.h"
#include <iostream>

int printOne() {
    std::cout << 1 << std::endl;
    return 0;
}

CodePudding user response:

When you have a line like #include "PrintOne.cpp" in your Test.cpp file, then the entire contents of PrintOne.cpp (including the definition of the printOne() function) will be included in Test.cpp's source code; thus, the Test.obj file will contain a definition of the printOne() function.

If you then also have the PrintOne.cpp file included in your project - as it seems from the fact that the linker is referencing a PrintOne.obj module - then there will also be a definition of the printOne() function in that object file, too.

So, you have multiple (though identical) definitions of the function, as signalled by the linker.

To avoid this, replace the inclusion of the PrintOne.cpp source file with one for a header (say #include "PrintOne.h") that provides a declaration (prototype/signature) for the printOne function (The contents of the source file will be added, anyway, if it is part of the project.)

Generally, it is not advisable to #include ... source (cpp) files (though there are some circumstances where it can be useful). Worth reading: When do I need to #include .cpp files?

  • Related