Well, the mystery of the duplicate object files is solved, although I don't like the answer.
Consider the following test console application that demonstrates the problem. First, the main program, which uses a class defined in another unit:
- Code: Select all
#include <vcl.h>
#include <windows.h>
#include <iostream>
#pragma hdrstop
#include <tchar.h>
#include "TestInlineProblem1Class.h"
#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
Test test ;
test.SetData(10) ;
std::wcout << L"Data is: " << test.GetData() << L'\n' ;
std::wcin.get() ;
return 0;
}
Next, the header file for the class, "TestInlineProblem1Class.h":
- Code: Select all
//---------------------------------------------------------------------------
#ifndef TestInlineProblem1ClassH
#define TestInlineProblem1ClassH
//---------------------------------------------------------------------------
class PACKAGE Test
{
private:
int data_ ;
public:
void SetData(int data) ;
int GetData() const ;
} ;
inline int Test::GetData() const { return data_ ; }
#endif
and, lastly, the cpp file for the class: TestInlineProblem1Class.cpp
- Code: Select all
#include <vcl.h>
#include <windows.h>
#pragma hdrstop
#include "TestInlineProblem1Class.h"
#pragma package(smart_init)
void Test::SetData(int data)
{
data_ = data ;
}
Build and run this in 32-bit C++Builder XE6 and it works as expected.
Remove the PACKAGE keyword from the header file, build and run it in 64-bit and, again, it works as expected.
Leave the PACKAGE keyword in, build and run it again in 64-bit mode, and the linker step fails with the following messages:
- Code: Select all
[ilink64 Error] Error: Public symbol 'Test::GetData() const' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::Test()' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::Test()' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::Test(Test const&)' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::Test(Test const&)' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::operator=(Test const&)' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::~Test()' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::~Test()' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::GetData() const' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::Test()' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::Test()' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::Test(Test const&)' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::Test(Test const&)' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::operator=(Test const&)' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::~Test()' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
[ilink64 Error] Error: Public symbol 'Test::~Test()' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\TEMP\WIN64\DEBUG\TESTINLINEPROBLEM1CLASS.O
It is not only objecting to my inline function GetData(), but also to the default ctor, copy ctor, assignment operator and dtor. So, I updated the Test class, adding definitions for the default ctor, etc, and moved the inline function back into the class body:
- Code: Select all
class PACKAGE Test
{
private:
int data_ ;
public:
Test() { }
Test(Test const& from) : data_(from.data_) { }
Test& operator=(Test const& rhs)
{ if ( this != &rhs ) data_ = rhs.data_ ; return *this ; }
void SetData(int data) ;
int GetData() const { return data_ ; }
} ;
After this, 32-bit worked, but gave me warning messages about inline functions in the package, while 64-bit worked without any warning messages.
Unfortunately, you cannot always move the inline functions into the class block. If the function body refers to another class which is defined later in the header file, then the normal answer is to define the function in the header file, with an 'inline' specifier after both class definitions.
So, sigh, the solution is to move the inline functions from the class header file to the class cpp file (removing the inline specifier). It's a pity; inlining very small functions should be good for performance.