Compiler and Linker

Blog about Compiler and Linker

We aimed for code migration to the new C++ Builder 2010 from Embarcadero. We had to work through few problems STL which is provided from Dikumware.com. Specially the CodeGuard throws many exceptions when using STL. Therefore we had to change our TFileOutputStream and TFileInputStream and removed the fstream classes. Following code illustrates the problem


int _tmain(int argc, _TCHAR* argv[])
{
  //This code works!!!!
  
  return 0;
}

The Embarcadero C++ Builder 2010 has a new option to compile projects (EXE and DLL's) as Wide (TCHAR = wchar_t). This switches to Unicode. Unfortunately if a DLL Project is build with TCHAR=wchar_t and uses dynamic runtime library (RTL) there are annoying message saying "two different CRTDLLs are loaded. CG might report false errors (c:\windows\system32\cc32100mt.dll)([name of the DLL-Project])".

You can get rid of the message by switching the TCHAR back to char. Place UNICODE and _UNICODE to the defines. In general Embarcadero says the dynamic RTL should be turned off for DLL projects. This in fact helps too, but sometimes its not an option. Specially when using DLL's as Class Libraries which are loaded on startup (2nd binding), the dynamic RTL must be truned on. otherwise you'll get a CodeGuard message saying that the memory you are releasing was allocated in a different RTL.

Be sure that the error message does not show the two CRTDLLs cc32100mt.dll and cc32100.dll. In this case one project uses multithreading where as the multithreading is disabled by an other project.

The issue is reported to Embarcadero with Report #86335 (Quality Central)

Lately we had a problem passing an enumeration as parameter of an interface method. We had following configuration: The application was written in Borland C++ using the Zeus-Framework. We were using a native COM interface where its implementation was written in Visual Studio C++. The method we were calling looked something like


virtual HRESULT STDMETHODCALLTYPE methodA(LPWSTR szVar1, EnumTyp eType, LPWSTR __RPC_FAR* szRetval) = 0;

Every time we called this method with a valid enumeration value, we got some weird value on the VC++ side.

The problem was that Borland uses dynamically sized enumeration, witch means the compiler looks at the value range first and then allocated 8bit, 16bit or 32bit for the enumeration. So when pushing the arguments to the stack, first the szRetval was pushed using EAX register (32bit). Then the second argument is pushed using the AX register only. The upper 16bits are not overwritten, therefore the upper part is dirty. On the otherside reading from the stack (in VC++ module) all 32 bit are read, since this compiler handles enumerations as 32bit in general.

To fix this problem, the borland compiler must be used with the option -b. Now all enumerations are handled as int-values (32bit on 32bit platforms). I don't know if the whole thing works for 64bit platforms in the same way.

For all Borland projects using Zeus-Framework I added following lines to BCB_Config.h:


//The compiler option -b must be set for BCB projects otherwise enum's are not
// handled properly passing as interface method parameters. Specially for VC
// projects the problem is known, since they handle enums as int.
#pragma defineonoption ENUM_AS_INT -b

#ifndef ENUM_AS_INT
  #error Compiler does not handle enums as int (Option -b not set). ...
#endif

This error is caused if by linker if he finds more than one expression having the same signature.

GNU Compiler and MS VC++ Compiler will throw this error also if you have a method implementation in a header. Because the header will be included by other modules, this causes that the method will doublicated.

To avoid this use the key word inline in front of the method.


class TTest : public TZObject
{
  public:
    ...
    
    //Not a problem here. Compiler will handle this.
    Int getValue() const 
    { return m_iValue; }
      
    Int getInverseValue() const;  
    Int getInverseValue2() const;  
  private:
    Int m_iValue;
};

//Correct use
inline Int TTest::getInverseValue() const
{
  return -m_iValue;
}

//Causes problems for GNU and MS Compilers
Int TTest::getInverseValue2() const
{
  return -m_iValue;
}

See also blog entry: C++ Programming - Inline methods