Delphi 2007 and {$IFDEF...} directive, fails to see our conditional - delphi

We have the following in our codebase, in a component file:
{$IFDEF ADO}
FDatabase : TADODatabase;
{$ELSE}
FDatabase : TODBCDatabase;
{$ENDIF}
The reason is that for various legacy applications, one or the other type of database connection and set of classes is to be used.
However, while configuring a new machine, it seems that our conditionals aren't taken into account. In the project settings, it says "ADO;DEBUG", and yet it compiles the above code with the odbc type instead.
The odd thing is that it isn't consistent. Two different units built as part of the same project uses separate settings. In other words, in one place our conditional is visible, in another it is not.
The file that compiles wrong does not have any {$UNDEF or similar directives, nor does it include any files.
What am I missing here?
Solved (ugh): Right, Delphi is just being boneheaded, or whatnot.
We found these:
I get “F1026 File not found”, OR some compiler options are not passed to the compiler from the IDE.
Configuration='Debug' Platform='BNB'
Which both mention the "Platform=BNB" setting. By enabling the diagnostic output, we see that exact value. So we try to override it per the articles, no luck, still BNB. Then we go to the project settings, turns out it can be overriden there as well, so we do that too, still no luck.
Turns out the Delphi installer, or whatnot, has added a "Platform=BNB" environment variable on operating system level, removing that, restarting Delphi, and all is well.
Well, as well as can be expected. We still have to use Delphi though.

You should always make a "build all" when you change those conditions.

It could be that one unit is actually not re-compiled. Check the following:
Is the .pas file included into the project?
Is there another file (.pas or .dcu) with the same name in the search path? It's possible the IDE sees a different file than the compiler.
Is the file actually compiled? Compare the timestamps of the .pas and the .dcu file.
Do you compile for another platform? Some compiler options are not passed unless the platform is "AnyCPU".
Whenever I encounter problems like this I brute-force delete every .dcu file in my project and component folders just in case the "Build all" doesn't remove all stale .dcus. The following recompile either solves the problem or reveals if any wrong .dcu was used.

Related

Extracting project file from delphi.exe

I have all the files needed to open the unit and code but I can't make any changes or compile because the Project.dproj and Project.dpr files are missing. However, I have the .exe file. Is there any way by which the aforementioned files can be extracted from the .exe file?
If you have all of the source files, meaning the .pas and .dfm files, then the first thing I'd do is add them all into a new project and try to compile it. It'll either work, meaning you've got everything you need, or it will generate errors.
There would be three kinds of errors:
The first is the most likely -- the forms might use components that you don't have installed. This will be obivous if you try to open the forms in the IDE. If they open without fanfare, GREAT! If you get a warning box saying "Cannot locate component: remove references to it?" or something like that, then you're probably hosed.
The second is version-specific errors -- stuff that's old and crufty and no longer supported by the language.
Third, the program may use run-time libraries that you don't have.
The compiler adds RTTI metadata, including unit names, when it builds, and if you know about how the RTTI tables are laid out it's possible to extract this. The unit list is the principal component of the DPR file, but it takes some serious work to access it and I'm not aware of any tools out there that read the RTTI tables that have been kept up to date beyond the Delphi 7 era.
As for the .dproj file, you're out of luck. That doesn't actually contain any code that gets "compiled in" to the EXE; it's a set of build instructions for how to produce the EXE. But if the Delphi IDE doesn't have one, it can generate a default .dproj from the .dpr, if you can produce that.
I'm curious, though. How did you obtain the .pas files but not the .dpr?

How to change VCL code?

I need (to make some quick and dirty tests) to modify the code of Variants and SysUtils.
What I need to do to "compile" the changes?
I can of course open those units in the IDE, but if I change them and I buoild a project again I don't see those units recompiled.
What is needed to be done?
The problem is you would need to compile ALL of the RTL/VCL against the 'new' units.
Instead modify a copy of the units in question and add them to your project when you want to use them. Delphi should use these over those in the RTL/VCL.
Unless you do not change the interface part of the unit (that is, you only modify the implementation side), you can make your own version of the RTL units (only exception is System.pas and SysInit.pas, but this is not in your scope - see our blog site for some enhancements of those units).
What you need is to put your own version of Variants.pas and SysUtils.pas in the search path of your project. They will be taken in account instead of the default RTL.
But be aware that you may easily break anything.
For testing purpose, this is OK, but if you want to use those modifications, you shall better use some automated regression tests, and know explicitly what you are doing.
Please note that you can use the "debug" version of the RTL units (from the project options), then step with the debugger within the official source code. It may help finding issues without touching the source.
If you change the interface part of the unit, you'll have to recompile all units which call the modified unit - for SysUtils and Variants, this is almost all RTL.
Delphi runtime DCUs are precompiled. It would be a waste of time to compile them at every build.
If the code you are trying to modify is a method of a built-in class, then a class helper may help:
http://docwiki.embarcadero.com/RADStudio/en/Class_and_Record_Helpers
So the question is which part of code do you want to modify in the runtime?
If you really wish to recompile the RTL you can do so (Make a backup first!). Versions of Delphi prior to Delphi 2010 had a makefile in the source folder that could be run from the command line to rebuild the rtl/vcl. I don't know for sure (I'm still using D2009) but from what I've heard this file is no longer present in newer versions. Hopefully there is an alternative. Otherwise you would wind up wasting a lot of time trying to guess that the compiler settings for each unit.
If you wish to "patch" a bug in the rtl for your project only you can copy the unit you want to modify into your project's folder and make your change. If the unit your modifying is used throughout the RTL/VCL you may find yourself copying quite a few dependent units into your project folder in order for it to compile.
If this significantly slows down the compile time for your project you can always do your initial compile then remove the "patched" units, leaving behind the compiled dcus.

Design-time package fails to build - File not found: 'Graphics.dcu'

In Delphi XE2, I have a single control in a pair of design/run time packages. Originally, everything was working fine. I've built each of them many times already. Suddenly without warning, the design time package started complaining in one of my units that the Graphics unit is missing when I build. Graphics is a standard unit, but it's not found from this one place. I haven't even made any changes to this unit, and as far as I know, any changes that could affect this.
Here's just the uses at the top (interface) of this unit:
uses
Graphics, ColorConv, Classes, Dialogs, ZLib;
As you can see, it's a very simple unit, and I only make very simple changes to this project. What could make it start complaining about this out of nowhere?
The strange thing is that it all works fine if I install it, it just doesn't build.
There's quite a bit of code, and I'd hate to have to post the entire thing.
Wild guess: it needs the Vcl. namespace prefix?
if there are several declaration of graphics(or other VCL units like:controls,forms ...)in your project, you can add VCL namespace to your project
as follows:
project menu-->options-->delphi compiler->>add in "unit scope names" value "Vcl"
Check your paths in Tools->Options->Environment Options->Delphi Options->Library, in particular the Library Path and Browsing Path settings. The defaults for my installation of XE2 (excluding those added by third-party components and my own stuff):
Library:
c:\program files (x86)\embarcadero\rad studio\9.0\lib\Win32\release;c:\program files (x86)\embarcadero\rad studio\9.0\Imports;C:\Users\Public\Documents\RAD Studio\9.0\Dcp;c:\program files (x86)\embarcadero\rad studio\9.0\include;
Browsing:
$(BDS)\SOURCE\VCL;$(BDS)\source\rtl\common;$(BDS)\SOURCE\RTL\SYS;$(BDS)\source\rtl\win;$(BDS)\source\ToolsAPI;$(BDS)\SOURCE\IBX;$(BDS)\source\Internet;$(BDS)\SOURCE\PROPERTY EDITORS;$(BDS)\source\soap;$(BDS)\SOURCE\XML;$(BDS)\source\db;$(BDS)\source\Indy10\Core;$(BDS)\source\Indy10\System;$(BDS)\source\Indy10\Protocols;$(BDS)\source\fmx;$(BDS)\source\databinding\components;$(BDS)\source\databinding\engine;$(BDS)\source\databinding\graph;$(BDS)\source\fmi;$(BDS)\source\data;$(BDS)\source\data\ado;$(BDS)\source\data\bde;$(BDS)\source\data\cloud;$(BDS)\source\data\datasnap;$(BDS)\source\data\dbx;$(BDS)\source\data\dsnap;$(BDS)\source\data\Test;$(BDS)\source\data\vclctrls;
Also, since you're new to XE2, you may want to check to see (outside the IDE) if you have an environmental variable for PLATFORM defined. Some PC manufacturers (HP as a particular example) define this variable on their computers, and it interferes with the IDE's requirements. (The IDE uses PLATFORM as a temporary environmental variable in paths used for different platforms, which fails if there's one predefined outside the IDE.) You can check by opening a command prompt and typing SET PLATFORM and hitting Enter. If there's one pre-defined, it can cause various hard to track down problems; you can remove it safely on every machine I've run across. (Right-click My Computer or Start->Computer, choose Properties, Advanced System Settings, Environmental Variables.)

How to prevent Delphi modifying its DPR (project source) unexpectedly

To maintain its project, Delphi sometimes adds or removes stuff from the DPR file (project source). I quite like to format my stuff in the DPR as if it is an ordinary unit, for example to group together the 'used' frame references and project source files. I make copies of it and can go back when this happens but every so often, I'll notice that the DPR has had all its source file references smashed into a single block.
Anyone else suffer from this? Is there any way of preventing this from happening (other than a read-only file).
Thanks
What I do for most of my projects is to have these 2 files:
MyProgram.dpr
MyProgramUnit.pas
MyProgramUnit has a public method Main that contains all the logic from the .dpr (including any conditional defines)
MyProgram just calls Main.
Edit 1:
You can put uses lists in MyProgramUnit.pas, but they don't automatically become part of your project.
That might or might not be an issue, it depends if you like having Delphi finding units in a search path, or add files to your project to make them visible.
What you can do, is to document the uses-lists in MyProgramUnit.pas and group them by cause. This is what I normally do in most units anyway, not only in the main unit.
Edit 2:
Don't go the {$I MyIncludeFile.inc} way.
Delphi - especially the IDE - is bad with include files. Code Completion, etc, fail at irregular places.
I've been heavy on include files in the past; not so any more. I even stopped using them for defines, and moved from {$IFDEF define} ... {$ENDIF} towards {$IF Constant1 >= Constant2} ... {$IFEND}.
The .dpr is a normal Delphi file, alright, but once it is opened in the IDE, it is more or less "owned" by the IDE. There is no way to stop the IDE from adding or removing code from it, when the IDE thinks that is necessary (e.g. when you added a unit, changed some settings, etc.). That can also mean it reformats parts of the code.
If you want "immutable" code, put it in a unit.
I think Rudy's got this one right.
IMO, it's wiser to keep hands off the dpr uses block in the editor - the project manager is designed to do that - by hand you're liable to corrupt your project settings and introduce some hard to track down bugs in large projects. As for formatting, in Delphi XE there is autoformat that will do your whole project and is configurable.
I often edit the 'program' section of the dpr (that also requires some knowledge and caution) but not the uses block.
One additional point: some of what happens in the dpr can be controlled from your project options settings.
HTH
Personally I make a copy of my uses clause in a giant comment at end of my DPR file.
So when Delphi modifies it, I "restore" it from the comment.
Of Course I have to be cautious of maintaining my "uses comment" up to date.
Note :
I'm using external tools that scan the project file so I cannot use the "external unit" approach, although it seems the cleanest solution.

Compiler directive in IDE rather than Project files?

Delphi 7: Is it possible to put a compiler conditionals in the IDE (like Tools, Environment options) rather than in a project under Project, Options, Conditionals?
We have a compiler directive that needs to be defined when compiling on developers' machines, but undefined when we build releases.
We don't want to use IFDEF DEBUG, since occasionally we ship code with debugging on.
We don't want to use an include file, because we'd risk it getting swept up into our source code control system.
Ideally, we would be able to create a compiler directive like we can an IDE environment variable where it wouldn't be saved in our source tree.
Any suggestions??
The solution is to use a build tool like FinalBuilder to do your building. This way you can be completely sure that you ship a good build every time, and not forget to set some option back to what it should be. I used to take a real day doing builds, now it is a click and I'm done.
Automating it will be hard (although your restriction on include files sounds a bit artifical, simply put the thing in source control and replace the version on disk with a different one during build script), why not force your individual developers to turn it on manually?
Introduce an extra DEFINE in the build script (e.g. FINAL_BUILD)
Introduce a compile time error in the source code forcing your developers to turn it on.
{$IFNDEF FINAL_BUILD}
{$IFNDEF VERY_SPECIAL_COMPILER_DIRECTIVE_YOU_WANT_TURNED_ON
You should have really turned option X on. Now things don't compile.
{$ENDIF}
{$ENDIF}
Finally, introduce a similar compile time error to make sure the FINAL_BUILD and special directive are never turned on at the same time.
You can use Conditional defines in project options
this will pass your custom defines to compiler when begin compile of project
follow this in Delphi IDE
Project > Options > Delphi Compiler > Conditional defines
Of course, adding {$DEFINE MYCONDITION} in your code would add a custom directive which you could check with {$IFDEF MYCONDITION} but this you should already know. However, if you compile your project from the commandline DCC32 -D MYCONDITION ... then you can compile it with (or without) that option.

Resources