Problem testing 64-bit package code in XE6

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Problem testing 64-bit package code in XE6

Postby PaulW » Tue Jun 17, 2014 8:22 am

I am in the the process of testing a C++ run-time package with XE6 and have many test cases that compile and test parts of the package as standalone code - i.e. I include unit(s) from the package separately in a test project.

The header file(s) for the unit(s) still contain the PACKAGE keywords that are required when the actual package is being built. This has never caused any problem with 32-bit packages in XE or earlier versions, and is still not a problem with 32-bit packages in XE6.

However, when building the test case in 64-bit mode, a strange thing happens. If the test case is a VCL application (with a form), then there is no problem. However, if the test case is a console application (specifying the VCL as target framework), the linker complains bitterly about multiple occurrences of the object modules from the part of the package under test.

I can bypass this with

Code: Select all
#undef PACKAGE
#define PACKAGE

after all the standard header files and before the header file(s) for my package unit(s) that are actually included in the test project, but its a damned nuisance.

Has anyone else encountered this and maybe dealt with in in a better fashion?
PaulW
Active Poster
Active Poster
 
Posts: 14
Joined: Wed Sep 08, 2010 4:24 am

Re: Problem testing 64-bit package code in XE6

Postby rlebeau » Tue Jun 17, 2014 4:11 pm

PaulW wrote:However, when building the test case in 64-bit mode, a strange thing happens. If the test case is a VCL application (with a form), then there is no problem. However, if the test case is a console application (specifying the VCL as target framework), the linker complains bitterly about multiple occurrences of the object modules from the part of the package under test.


Where does the linker say the multiple occurrences are actually coming from? Are you including the actual package in the same project that is using the package's units directly?
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Problem testing 64-bit package code in XE6

Postby PaulW » Wed Jun 18, 2014 12:36 am

First, embarassingly, I have to correct part of my previous message: the problem does occur with VCL forms applications as well as console applications (at least that makes it consistent).

Remy, in answer to your question, I am not including the package in the project--in fact I can't because it's not yet built and the process of converting it to 64-bit is turning out to be long and frustrating. So, what is included in a typical console application test project is the main unit of the test plus one unit borrowed from the package project. In addition, the main unit of the test includes the header file for the unit from the package project.

An example of the messages from the 64-bit linker are (there are an awful lot of these, so I have only included three):

Code: Select all
[ilink64 Error] Error: Public symbol 'fen::BitArray::operator[](unsigned int) const' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\PACKAGES\FENUTILS\TESTBITARRAY\WIN64\RELEASE\FENBITARRAY.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\PACKAGES\FENUTILS\TESTBITARRAY\WIN64\RELEASE\TESTBITARRAY.O
[ilink64 Error] Error: Public symbol 'fen::BitArray::index(unsigned int)' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\PACKAGES\FENUTILS\TESTBITARRAY\WIN64\RELEASE\FENBITARRAY.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\PACKAGES\FENUTILS\TESTBITARRAY\WIN64\RELEASE\TESTBITARRAY.O
[ilink64 Error] Error: Public symbol 'fen::BitArray::mask(unsigned int)' defined in both module E:\DEV\RAD STUDIO\14.0\PROJECTS\PACKAGES\FENUTILS\TESTBITARRAY\WIN64\RELEASE\FENBITARRAY.O and E:\DEV\RAD STUDIO\14.0\PROJECTS\PACKAGES\FENUTILS\TESTBITARRAY\WIN64\RELEASE\TESTBITARRAY.O

The other major, time consuming problem I am encountering with the conversion to 64-bit, is that the 64-bit compiler does not seem to like a derived class calling a protected method in its base class.
Code: Select all
class base
{
protected:
void baseMethod() ;
}
template<typename T>
class derived : public base
{
public:
void derivedMethod() { baseMethod() ; }
}

The 32-bit compiler (and another compiler on Windows plus one on another platform I have used, are quite happy with this, but to get it past the XE6 64-bit compiler, I have to change the references in the derived class to
Code: Select all
template<typename T>
class derived : public base
{
public:
void derivedMethod() { this->baseMethod() ; }
}
PaulW
Active Poster
Active Poster
 
Posts: 14
Joined: Wed Sep 08, 2010 4:24 am

Re: Problem testing 64-bit package code in XE6

Postby PaulW » Wed Jun 18, 2014 5:15 am

It looks like the problem with the duplicate object files may only be occurring with template classes, although I am not completely certain of this yet.

The units from the package are defining a non-template base class plus template classes derived from the base (and in some cases further template classes derived from the "level one" template class(es)).

The non-template base class contains methods that are independent of the actual type specified in the derived template classes, although it may call virtual functions in those derived classes.

The base class is declared with PACKAGE specified.

The derived template classes are not declared with PACKAGE specified, my reasoning being that since the templates are instanciated at the time of compiling an application that uses the run time package and not when the run-time package is built, they should not be declared as PACKAGE classes. Perhaps this is wrong.
PaulW
Active Poster
Active Poster
 
Posts: 14
Joined: Wed Sep 08, 2010 4:24 am

Re: Problem testing 64-bit package code in XE6

Postby PaulW » Wed Jun 18, 2014 9:26 am

I think I may have found the answer to my problem of duplicate object files.

Public symbol 'x' defined in both module A and B
[ilink64 Error] Error: Public symbol 'triplet::sum' defined in both module C:\USERS\WIN764\NODES.O and C:\USERS\WIN764\UNIT1.O
Static data members should be declared in a header, and defined only once in a source file (not the header).

at http://docwiki.embarcadero.com/RADStudi ... d_Warnings

If so, apologies for time wasting. The page also refers to the need for qualifying base class references in templates with "this->".
PaulW
Active Poster
Active Poster
 
Posts: 14
Joined: Wed Sep 08, 2010 4:24 am

Re: Problem testing 64-bit package code in XE6

Postby 2ffat » Wed Jun 18, 2014 9:40 am

See if this video from the Developer Skill Sprints Webinar Series helps.
James P. Cottingham

Look at me still talking
when there is science to do.
User avatar
2ffat
Forum Mod
Forum Mod
 
Posts: 427
Joined: Wed Jun 23, 2004 7:07 am
Location: South Hill, VA

Re: Problem testing 64-bit package code in XE6

Postby PaulW » Thu Jun 19, 2014 2:43 am

Thank you 2ffat for your link:
See if this video from the Developer Skill Sprints Webinar Series helps.

However, I am pretty sure now that my problem is all to do with templates in 64-bit packages and probably with the use of static members in the template. I shall persevere.
PaulW
Active Poster
Active Poster
 
Posts: 14
Joined: Wed Sep 08, 2010 4:24 am

Re: Problem testing 64-bit package code in XE6

Postby PaulW » Fri Jun 20, 2014 3:22 am

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.
PaulW
Active Poster
Active Poster
 
Posts: 14
Joined: Wed Sep 08, 2010 4:24 am

XE10 C++ Builder ilink64 error is reported for GetDIB and Ge

Postby tshinn » Tue Nov 24, 2015 4:32 pm

XE10 C++ Builder ilink64 error is reported for GetDIB and GetDIBSizes but works in ilink32.

I can see where previous forums have reported this error in XE3 and was reportedly fixed in XE4.

Is there a known work around for this issue?

Graphics::TBitmap *FormImage = GetFormImage();
try {
SIZE const form_size = {frmMainForm->Width, frmMainForm->Height};
HDC const hScreenDC = GetDC(0);
FormImage->Handle = CreateCompatibleBitmap(hScreenDC, form_size.cx,form_size.cy);

HPALETTE hPal = NULL;
if ((GetDeviceCaps(hScreenDC, RASTERCAPS) & RC_PALETTE) &&
(GetDeviceCaps(hScreenDC, SIZEPALETTE) == 256))
{
const std::size_t size =sizeof(LOGPALETTE) + 255 * sizeof(PALETTEENTRY);
unsigned char* const pBuffer = new unsigned char[size];
LPLOGPALETTE pPal = reinterpret_cast(pBuffer);
pPal->palVersion = 0x300;
pPal->palNumEntries = 256;
GetSystemPaletteEntries(hScreenDC, 0, 256, pPal->palPalEntry);
hPal = CreatePalette(pPal);
delete[]pBuffer;
}
ReleaseDC(0, hScreenDC);
if (hPal != NULL) {
FormImage->Palette = hPal;
}
HDC const hWindowDC = GetWindowDC(frmMainForm->Handle);
BitBlt(FormImage->Canvas->Handle, 0, 0, FormImage->Width,FormImage->Height, hWindowDC, 0, 0,SRCCOPY);
// --------------------------------------------------------
unsigned int iInfoHeaderSize = 0;
unsigned int iImageSize = 0;

GetDIBSizes(FormImage->Handle, iInfoHeaderSize, iImageSize);
// ilink64 error here:


BITMAPINFO *pBitmapInfoHeader;
pBitmapInfoHeader = new BITMAPINFO[iInfoHeaderSize];
unsigned char *pBitmapImageBits;
pBitmapImageBits = new unsigned char[iImageSize];

GetDIB(FormImage->Handle, FormImage->Palette, pBitmapInfoHeader,pBitmapImageBits);
// ilink64 error here:

// --------------------------------------------------------
ReleaseDC(frmMainForm->Handle, hWindowDC);
Clipboard()->Assign(FormImage);
TPrinter *Prntr = Printer();
TRect r = Rect(200, 200, Prntr->PageWidth - 200,
Prntr->PageHeight - 200);
Prntr->BeginDoc();
Prntr->Canvas->Font->Size = 7;
float fPrinterVert = (float)GetDeviceCaps(Printer()->Handle, VERTRES);
float fPrinterHorz = (float)GetDeviceCaps(Printer()->Handle, HORZRES);
scale = FMIN((fPrinterHorz / form_size.cx),(fPrinterVert / form_size.cy));
int iHeight = form_size.cy * scale - 400;
int iWidth = form_size.cx * scale - 400;
int iStartY = 200;
int iLineHeight = Prntr->Canvas->TextHeight(" ");
Prntr->Canvas->Brush->Color = clWhite;
iStartY = Prntr->Canvas->PenPos.y + iLineHeight;
StretchDIBits(Printer()->Canvas->Handle, 200, iStartY, iWidth, iHeight,0, 0, FormImage->Width,
FormImage->Height, pBitmapImageBits,pBitmapInfoHeader, DIB_RGB_COLORS, SRCCOPY);
iStartY = iStartY + iHeight;
Prntr->Canvas->Brush->Color = clBlack;
Prntr->Canvas->FrameRect(r);
Prntr->Canvas->Brush->Color = clWhite;
Prntr->EndDoc();
}
__finally {
delete FormImage;
}
}

//Two ilink64 errors are reported
[ilink64 Error] Error: Unresolved external 'Vcl::Graphics::GetDIBSizes(HBITMAP__*, unsigned int&, unsigned int&)' referenced from D:\____DEBUG_BUILD\MAINFORM.O
[ilink64 Error] Error: Unresolved external 'Vcl::Graphics::GetDIB(HBITMAP__*, HPALETTE__*, void*, void*)' referenced from D:\______\DEBUG_BUILD\MAINFORM.O
tshinn
 
Posts: 4
Joined: Fri Jan 27, 2012 7:50 pm

Re: Problem testing 64-bit package code in XE6

Postby alone53 » Fri Aug 04, 2017 1:14 pm

I upgraded from X4 to Berlin.
Most of my projects build fine without any problem in 64 bit setting.
But some DLL-projects compiles fine, but the linker throws error like this:

[ilink64 error] error: unresolved external 'vcl::forms::application.

I hope that I find source of this error:
if your project not include visual object (like TForm), compiler not linked run-time VCL
library needed for use methods and objects from this visual object (like Application->Exename etc).
It's true for DLL- and console projects.

I try two methods for correct tis error:
First method: By any text editor find in project file *.cbproj line
.
<FrameworkType> None </FrameworkType>

and change it to:

<FrameworkType>VCL</FrameworkType>

After that compiler include all needed run-time VCL library (rtl.lib) and project linked without errors.

Second method: Add to project (from IDE) TForm object and then remove it. TForm object sucsessfuly removed,
Compiler changed *.cbproj file and include all needed run-time VCL library.
This changes stay in project and project linked without errors too.

I think, second method maybe used for other ojects too.

Add object (by IDE) to project and then remove it. We force compiler to include needed library.
alone53
 
Posts: 1
Joined: Fri Aug 04, 2017 12:59 pm


Return to Technical

Who is online

Users browsing this forum: No registered users and 15 guests