I'm maintaining the VirtualTreeView component for Delphi and C++Builder. With Delphi everything is okay but when I compile the packages with the C++Builder the code in the initialization part in the Delphi units is not called. Any ideas?
When a Delphi unit's initialization/finalization sections are not being called in a C++Builder project, it usually means the Delphi unit is not being linked into the final executable, typically because the C++ code is not directly referencing any code in the unit, so it gets optimized out. C++Builder is a bit more aggressive about removing unused code than Delphi is. In Delphi, simply adding a unit to a uses clause forces that unit to be linked to. That is not the case in C++. #includeing a Delphi unit's .hpp file in C++ code is not enough to guarantee the unit is linked to, if the C++ code does not use anything from the .hpp file.
Indy ran into this problem in several of its units, most notably IdAllAuthentications, IdAllFTPListParsers, and IdAllHeaderCoders. These units all contain only initialization/finalization code, no interface code, so their generated .hpp files were basically empty. To force linkage, I had to add {$HPPEMIT} statements to the interface section to output #pragma link statements in the generated .hpp files. For example:
unit IdAllAuthentications;
interface
{
Note that this unit is simply for listing ALL Authentications in Indy.
The user could then add this unit to a uses clause in their program and
have all Authentications linked into their program.
ABSOLUTELY NO CODE is permitted in this unit.
}
{$I IdCompilerDefines.inc}
// RLebeau 2/14/09: this forces C++Builder to link to this unit so
// the units can register themselves correctly at program startup...
{$IFDEF HAS_DIRECTIVE_HPPEMIT_LINKUNIT}
{$HPPEMIT LINKUNIT}
{$ELSE}
{$HPPEMIT '#pragma link "IdAllAuthentications"'}
{$ENDIF}
implementation
// uses units that self-register in their initialization sections ...
end.
{$HPPEMIT LINKUNIT} was introduced in XE5 Update 2, to help with linking units that use unit-scope names:
New: You can now use HPPEMIT Delphi compiler directives for linking and generating C++ namespace declarations.
...
{$HPPEMIT LINKUNIT} replaces #pragma link for the iOS device target platform.
For more information, see HPPEMIT.
For C++ applications, {$HPPEMIT LINKUNIT} replaces #pragma link on mobile platforms.
The Delphi run time has units that must be linked in order to enable some functionality. In C++, auto-linking was previously achieved using the following directive:
{$HPPEMIT '#pragma link "<unitname>"'}
Now you should use the following directive instead:
{$HPPEMIT LINKUNIT}
LINKUNIT generates a #pragma link statement that references the calling unit using the correct decorated/namespaced unit name.
Related
I work in a Project Group composed by 3 projects with common units.
in project 1, i wrote in the project source :
program Project1;
{$DEFINE FIRSTPROJECT}
uses
.....
in project 2, i wrote in the project source :
program Project2;
{$DEFINE SECONDPROJECT}
uses
.....
Then in the differents units code i wrote :
...
{$IFDEF FIRSTPROJECT}
do this
{$ELSE}
do that
{$ENDIF}
...
The first project code is never compiled (it's just ignore). But if i put the {$DEFINE FIRSTPROJET} in same unit then it work... (in Delphi2009).
How can i spread my compilation directive threw all the file used ? Just depending on which project i want to compile...
$DEFINE directives are local to the unit in which they are defined. If you place them in a project source file, a .dpr file, then they apply in that .dpr file only.
You need to add the conditional defines to each of your projects by using the Project Options dialog.
My old Delphi 7 application is using IdStreamVCLWin32 unit in one pas file. This unit is located at following location.
C:\Program Files\Indy 10 for Delphi\Source\System\IdStreamVCLWin32.pas
When I am running same code in my Delphi XE4 environment, I am getting error IdStreamVCLWin32 not found.
Note: Delphi 7 is using Indy 10 but Delphi XE4 is using Indy which comes default with it. I have not installed indy explicitly in Delphi XE4 environment.
I searched my entire C drive where Delphi XE4 is installed but found no IdStreamVCLWin32.pas file.
How to get rid from this error?
From what I can tell, you were never meant to include that unit directly. The unit IdStreamVCL would delegate to either IdStreamVCLDotNet or IdStreamVCLWin32. And so it appears to me that IdStreamVCLWin32 is an implementation detail that you are shielded from by using IdStreamVCL.
These units have, nowadays, all been coalesced into IdStreamVCL. And so you could include that. However, it's not clear to me that you should even do that. Take a look at IdStream:
unit IdStream;
interface
{$I IdCompilerDefines.inc}
uses
{$IFDEF DOTNET}
IdStreamNET
{$ELSE}
IdStreamVCL
{$ENDIF};
type
{$IFDEF DOTNET}
TIdStreamHelper = TIdStreamHelperNET;
{$ELSE}
TIdStreamHelper = TIdStreamHelperVCL;
{$ENDIF}
implementation
end.
It seems pretty clear that you are meant to use IdStream and let the compiler work out whether that implementation is provided by IdStreamNET or IdStreamVCL.
So, the answer to your question is probably that you should replace your use of IdStreamVCLWin32 with IdStream. Note that the functionality in IdStream is implemented differently now. You no longer instantiate an instance of a stream class. The modern Indy offers you a helper class TIdStreamHelper which contains class functions. So you end up writing code like this:
BytesWritten := TIdStreamHelper.Write(Stream, Bytes, Count);
However, I cannot be sure that's the right approach since I don't know what you actually use from IdStreamVCLWin32. It's quite plausible that your code uses nothing from there and the use of IdStreamVCLWin32 is simply a stray hangover from some older version of your code.
So my advice is:
Remove IdStreamVCLWin32 from your uses.
Deal with any subsequent compiler errors by studying the code and working out the right way to do it with the current Indy code.
I have a utility unit with code shared between a few applications and DLLs. I'd like to selectively compile portions of this unit based upon the current project type: Application, Package, or Library. I couldn't find any conditional definitions for a library or package in the System unit, and Google didn't find anything relevant. So, are there any conditional defines such as IsLibrary or IsPackage set by the compiler? I'm aware of the IsLibrary variable, by the way.
There is no such pre-defined conditional, and there could not be such a conditional. That's because at compilation time it is impossible to know whether the unit will, ultimately, be linked into an executable, a library or a package.
In fact, the same compiled unit could be linked into any or all of the above project types. And indeed you can see this yourself when you link the RTL into your projects. You link the same System unit, the same compiled .dcu file, into all your projects, irrespective of the project type.
IMHO there is absolutly no need for such conditionals because of existing conventions.
Compiling an Application or Library (the same on this compiling aspect) or a Package differs like so:
Application/Library will compile only the used parts from the unit
Package will compile all parts from the unit referenced by the interface part of the unit
Example Unit
unit foo;
interface
procedure foo1;
procedure foo2;
implementation
procedure foo3;
begin
// used by foo2, compile depends on foo2 compilation
end;
procedure foo4;
begin
// will never be compiled, because is never used
end;
procedure foo1;
begin
// Package: will always be compiled
// Application/Library: will be compiled if used
end;
procedure foo2;
begin
// Package: will always be compiled
// Application/Library: will be compiled if used
foo3;
end;
end.
That is also a reason, why using packages may result in bigger exe files, because it can contain unused code parts from precompiled dcu files.
I was trying to use the EXIF library in one of my packages. It worked before but now I get strange messages:
[DCC Fatal Error] F2051 Unit GIFImg was compiled with a different
version of CCR.Exif.Consts.SOutOfResources
I don't really get it... Why Delphi tries to recompile one of its files? How do I fix this?
GifImg is located here:
c:\Program Files\Embarcadero\RAD Studio\8.0\source\vcl\GIFImg.pas
Update:
I looked at the date of that file (1 PAS and 2 DCUs) and it has the same date as any other file in RAD Studio\8.0\source\vcl folder. So, the file was not accidentally modified.
Update2:
This is my uses clause:
USES Windows, SysUtils, AnsiStrings, Graphics, Dialogs, Classes, jPeg,
pngImage,
janFX, //CCR.Exif,
{$IFDEF VER150}
GIFImageFinn {Delphi 7}
{$ELSE}
GIFImg {Delphi 2010/XE}
{$ENDIF}
;
If I comment the CCR.EXIF unit, it starts to compile my package. So, adding EXIF to my package breaks something.
What you report doesn't quite add up. The GIFImg unit that is part of the Delphi source does not refer to CCR.Exif.Consts.SOutOfResources. And none of the units used by GIFImg refer to it either.
So the explanations that seem plausible to me are:
You are including a unit called GIFImg somewhere in your project.
You've found a compiler bug.
The error message F2051 is emitted typically, in my experience, when you attempt to recompile an RTL/VCL unit but fail to set the project options to match that used by the true RTL/VCL. Alternatively it will be emitted when you recompile an RTL/VCL unit that has modifications in its interface section.
Solved:
I removed the dots in the name of the files.
CCRExif instead of CCR.Exif.
That was a nasty one.
I have converted my 2 GUI apps from Delphi to Lazarus.
Both apps compile for Win32 platform, i386 and with GUI.
Main form were converted using Lazarus tool and can be edited from IDE.
But when I run such application main form does not appear, only blank form without any controls.
I tried to debug this. It runs all code in initialization sections,
and runs code from .lpr project, but something wrong happens in CreateForm() because
it doesn't run code in the main form OnCreate event. In event log I can see all
texts I write to it with '<App.Run' appearing after I close this empty form.
Code in .lpr project:
Application.Initialize;
AddToEventLogInfo('App.CreateForm');
Application.CreateForm(TfrmTst, frmTst);
AddToEventLogInfo('App.Run>');
Application.Run;
AddToEventLogInfo('<App.Run');
I checked that I am able to create simple GUI apps from the Lazarus, but both converted GUI
apps do not work as expected. What can be wrong? Have I missed something?
Maybe one of many warnings and hints Lazarus write is important?
When I run my app Lazarus writes this:
windres: warning: 14: "MAINICON": 1045: duplicate value
windres: warning: 16: 1: 1045: duplicate value
Project "Tst_fpc" successfully built. :)
EDIT:
Lazarus conversion tool converted .dfm -> .lfm, but has some problems with .pas file. I had to manually:
add Lazarus units to uses:
uses
{$IFDEF FPC}
LCLIntf, LResources,
{$ENDIF}
Conditional compile Delphi form {$R *.dfm}:
{$IFNDEF FPC}
{$R *.dfm}
{$ENDIF}
Add .lrs resource in initialization code:
initialization
{$IFDEF FPC} {$i myunit.lrs} {$ENDIF}
I suspect that the mainform unit (I assume it is called utest) doesn't have a {$I utest.lrs} in its initialization section. The .lrs is the lazarus resource file, created from the lfm (dfm) in delphi.
The empty form is the form of for the current project as you used the convert Delphi project from tools which means the current project is active.
Try this:
On the project option close the current project.
On the small main window named as project wizard, use the convert Delphi project option.
I'm sorry I can't give you a straight answer. From what I understand there's a problem a problem with the resource file. In delphi that's the *.res, I don't know what they look like in Lazarus. Use a program like resedit, http://www.resedit.net/, to open the resource file. I tried it and found a "folder" Icon where there was a post MAINICON. I'm guessing you have two. In that case remove one of them.