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.
Related
We're in the process of moving out Delphi XE2 apps over to Delphi XE5 (We have a window :) )
I'm wondering whether, as part of the move, I should be thinkning of adding my own Unit Scope to our internal applications. This question suggests that it's just of case of renaming units as Company.Unit.
Is it as simple as using Rename in the Project Manager?
Am I missing anything?
It's nearly that simple. You can use the Rename action in the project manager and that will rename the file, give the unit a new name, and change references in the .dpr and .dproj file. But that will not rename any references in code.
So, if you list the unit in uses clauses (seems likely that you will), or use the unit name to resolve ambiguous scope, then you will need to change the names there too.
If you don't have too many units it won't be very difficult to make the change in the project manager, and then fix all the errors that the compiler throws at you. If you have a larger project then you may be better scripting the change. I expect that you could go 99% of the way there with a simple regex based script that did the following:
Update references in the .dpr and .dproj files.
Change the file names and the unit names.
Find the uses clauses (interface and implementation sections) and update references there.
This would leave you to deal with the uses that perform scope resolution and my guess is that there would be few enough of these to let the compiler find them all.
I use a great Tool from http://www.easy-ip.net (DELPHI UNIT DEPENDENCY SCANNER) for that task.
You can change the Name of the unit and the DUPS change all your uses clause's.
I have a few scripts that I would like my program to work with. However, I would like to know if it is possible for me to store these scripts (eg. batch, javascript, vb scripts etc) in my application as a resource.
How would I go about doing this?
You can store your scripts in resource files. But for example Batch Files need to be file on disk, so you will need to unpack them before working.
There are components to store arbitrary file/files or string in DFM
For example there are such in rxLib/JediVCL but i believe many VCL libs have one or another kind of DFM Storage component.
For example i used to store Firebird Embedded database in DFM to save it into TEMP and use while running.
However that is akin for manual re-reading file into DFM each time you update it. Rather annoying to say sincerely.
One more approach is linking text into resources. You can look into DUnit sources to see how it was done. You would also have .rc file included in project, so that it would be compiler into .res when making .exe
This approach is fragile towards ansi/unicode text interpretations.
Frankly, before i found DUnit in Delphi XE2 (it was disabled due to IDE bug) i tried to make SF's vanilla DUnit to run there. And i failed - the non-unicode text files linked into resource was totally corrupt when reading with unicode-enabled Delphi.
Look here and there, try both approaches and choose the one that suits you more.
Here is a good article that explains how you can add almost anything in a resource file and compile it with your application: http://delphi.about.com/od/objectpascalide/a/embed_resources.htm
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.
I want to apply a fix from QC to a Delphi 2009 unit (DBClient as it happens). I know I need to copy the unit to another directory and make the change to the copy. How do I then get Delphi to compile that unit and use it in favour of the DCU that already exists?
If you don't want to modify the original .Pas file, I do this by copy the .Pas file into my application folder, then choose built project, it will create new dcu file in my application folder, which will be used instead of the original one.
It's kind of a last resort (and not supported by CodeGear), but I do something similar to Mohammed when necessary. Except instead of putting any modified units into the application folder, I put them into their own folder with the rest of my library code and include this folder in my library path where it will be used by all of my projects. It also prevents me from having multiple (possibly slightly different) copies hanging around.
I also make a point of checking any updates to see what has changed so I can either remove the modified units or re-apply the changes to the newer (and presumably better) units from CodeGear.
I've never did this myself but there are projects in {RAD}\source\rtl along with batch build script. I believe this makes recompiling RTL functions easy. Other units should be recompiled easier.
If the changes you want to do are local and the units aren't widely used by other RTL/VCL units, the simplest way is to place copies of modified units separately from their standard place.
Another option is run-time patching aka detouring.
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.