Compiler directive in IDE rather than Project files? - delphi

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.

Related

How to remove unused units from all source files on Delphi XE2?

How to automatically remove unused units from uses section on all source files of the project on Delphi XE2?
P.S. IDE will work much faster after that.
There is no way to fully automate this.
There are a few tools I'm aware of that take a wizard approach:
CnPack Uses Units Cleaner
Peganza's Pascal Analyzer (and it's sidekick icarus).
The Lazarus IDE has a "Unused Units" dialog in it's CodeTools package.
Peganza's tools simply show a report. CnPack will prompt to remove the unused units for you but you must confirm. Lazarus presents you with a list of unit's it thinks are unused and gives you the choice of removing some or all of them.
Why isn't it automated?
Because this is static analysis. Even the most sophisticated tools cannot determine with 100% certainty whether a specific line of code will be used at runtime let alone an entire unit. These tools have implemented their own parsers to accomplish this feat but they aren't fool proof.
In any case the main benefit of cleaning up the uses clause is removing visual clutter from both the source itself and the code completion feature. Yes there is some performance gained during compiling and certain IDE background operations will speed up slightly but I think you'll be disappointed if you think the IDE will miraculously speed up.
You'll see better IDE and compiler performance by:
Breaking your projects into smaller pieces that can be worked on independently.
Eliminating duplicate code.
Disabling unneeded IDE packages.
I'm certainly not trying to dissuade you from removing unused unit references. As I said it will help unclutter your source. Just make sure you're doing it for the right reasons.
We have a utility called the Delphi Unit Dependency Scanner (DUDS). It scans your entire project and builds a fully searchable tree of the units and dependencies. It can be very useful in finding unused units.
The application is Freeware and you can find it here.
Disclaimer-I am the author.
Don't think I would want a tool that would automatically rip out unnecessary units in the Uses section...
but there are tools out there to identify them...look at Icarus...freeware that you can get at http://www.peganza.com/downloads.htm
CnPack has "Use Cleaner..." option that I have used unit by unit basis without a problem. It also has the ability to do the entire project - which I haven't tried due to the size of the project.
Use reFind.exe utility provided since Delphi XE, use this command
reFind *.pas /X:unuse.txt
And unuse.txt is a text file with something like this:
#unuse Unit1
#unuse Unit2
#unuse Unit3
And that's it. It will remove the units in the uses clause taking care if the unit is the last one used and there is a ; after the unit.

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 can I set the $RTTI directive for the entire project?

I'm working on migrating an old project from Delphi 2007 to Delphi 2010. One thing I've found is that the resulting executable has more than doubled in size, and the original was already quite big. (Over 50 MB.) I suspect that a lot of it has to do with extended RTTI.
Since the project predates Delphi 2010, it doesn't use extended RTTI anywhere, and I'd like to be conservative about including it. Is there any way to use the Project Options dialog to globally set {$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])} as the default? I'd have expected there to be an option for this (and for $WEAKLINKRTTI) somewhere, but I don't see them.
Does anyone know if this can be done from the "Additional options to pass to the compiler" field, or some other way? I'd really prefer not to have to add an include file to every single unit in the project, as there are a few thousand of them...
The behavior of the $RTTI directive has been changed since XE6 because actually it was a bug because it was supposed to be local to the current unit (and it was actually documented as that since Delphi 2010).
Also it could have fatal affects using the directive at all even in one unit because due to the bug it basically switched a global flag affecting the following units (as in the order of compilation).
You can try with the dcc32 –$weaklinkrtti command-line option. (like {$WEAKLINKRTTI ON}).
But that has not the impact of {$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])} in each unit.
Your best bet would be to have it at the top of each unit in an include file.
But then it wouldn't do it for the VCL/RTL which would still be inflated....
Update: Also make sure you compare what's comparable. For instance verify if you don't include debug information in the Linker Options in the new D2010 project where you may not have it in the D2007 one...
In a comment on Mason's own blog, in response to a comment of mine, Mason answered this question.
Try putting these two lines at the top
of your DPR, before the USES clause:
{$WEAKLINKRTTI ON}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
This will make sure that no RTTI gets
generated for your own code or any
third-party libraries you use, unless
they’re in a unit where RTTI
generation is explicitly enabled. You
can’t turn it off for the RTL or VCL,
but that shouldn’t add very much to
your size anyway.
Are you certain this is caused by the new RTTI info? While it's a lot of data it shouldn't really double the size of your application.
Check that it's not including debug info in the release build executable.
(Project options -> Delphi Compiler -> Debug information should be False)
As for the question, I use {$WEAKLINKRTTI ON} before the uses clause in the dpr file and it seems to work fine.
I don't know of such an option, but I still would use an include file.
I wont be a problem for any experienced Delphi programmer to write a small program to add an {$i ProjectIncludeFile.inc} to any unit in your folders (immediatly after the unit line).
And that way you can use it for whatever purpose you like.
I myself use if f.i. to set a WriteTempFiles compiler directive (which I use f.i. to save stringlist contents at various places when developing the program), that way I can disable it in one place when the program is ready for deployment.
Since most of my projects involve multiple executables and/or dll's, this is the easiest way to accomplish this globaly for the whole project.

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

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.

Resources