Organizing the search path - delphi

We create via "Tools | Options | Environment Variables" Variables like that:
$(Sources) = D:\Sources\Delphi
$(OurLib) = $(Sources)\OurLib\Src
$(OurApp1) = $(Sources)\Applications\App1\3.x
$(ThirdParty) = $(Sources)\ThirdPartyComponents
We use these Variables in the project search path like that:
($OurApp1)\Src\Core;($OurApp1)\Src\GUI;($OurApp1)\Src\Plugins;$(ThirdParty)\JVCL
But this is broken (meanwhile fixed) since Delphi 2009 as these variables are not evaluated completely anymore (see QC #73276). So the files in the directories are not found by the compiler. A workaround: Use only complete directories in the environment variables.
We use this approach because on all developer machines and the build servers the files can be found and we only have to point $(Sources) to the right place.
We don't have anything in our global library path (except the Delphi defaults), because that wouldn't be in the version control and isn't reflected on other developers or build machines.
One problem is: If one unit in $(OurLib) decides to include another new unit maybe in a new path, all projects break because they don't find this new unit. Then we have to go through all projects and add the search path. (BTW: I really hate the search path editor...wouldn't be a simple memo field much better to edit than this replace/add/delete logic?)
Another thing we do is not adding many units to our project. Especially everything from $(OurLib), but we often have units like plugins which add functionality only by including them. For different editions of our products, we want to include different units. As Delphi always messes up $IFDEFs in the uses clause in the .dpr we help us by including units named like "IncludePlugins" which then include the units depending on IFDEFs.
But not including units in the project makes navigating to a pain. The units don't appear in the project, they are not found by Ctrl+12 (Show Units), they are not shown in code completion etc.
Has anybody a better way to cope with these problems?

We use only relative paths, any libraries are always below the libs subdirectory while the project source code resides in the src subdir. So our search paths always look like:
..\libs\library1;..\libs\library2\common;
etc.
All libraries are added as svn:external to each project, so checking out the project will automatically check out the libraries as well and the search path will always point to the correct version of the library for that project.
Not perfect, but it works most of the time.
I have to agree about the search path editor, it is even worse for relative paths because you must not use the "..." buttons otherwise Delphi will insert an absolute path.

We use standard drive mappings.
Our current project is always on W: regardless if it is a network drive or a substitute.
This works great.
When you need to work on a different project, swap the W: and you can continue.

You can copy the search path out to an editor, modify it and then copy it back.

Your search path is much too big. It should contain only the things you want Delphi to recompile with your project. You don't really want to recompile the Jedi VCL every day, do you?
I create a single directory where all compiled units go. Say, C:\dcu. Specify that as the "unit output directory" in all packages. My "search path," then, is always just this:
$(Delphi)\Lib;C:\dcu
The compiler finds everything it needs, and it never finds any source code. The only source code it ever sees is in the files that directly belong to whatever project I'm compiling. The project's own source directories don't need to be on the search path because all of those files are already direct members of the project. The compiler knows exactly where they are.
For me, all a project's source files go in a single directory. If you want separate directories for different parts, like Core and GUI, then I would put those in separate packages so I could work on them and compile them separately. Even if the final program doesn't use the resultant BPLs, packages are still a good way of segmenting your project and defining dependencies.
When compiling units for one project doesn't automatically compile units for all the other projects, you're forced to change active projects. It takes a moment of your time, but it also serves as a mental reminder that you're "changing hats," too.
Although you're producing just one product, that doesn't mean you should have just one project in Delphi. You should have at least one project for each executable module (EXE, DLL, BPL) in your product. Use project groups to manage multiple projects in a single IDE session. No unit should be a member of more than one project.
I don't understand your part about plug-ins and different editions of your project. When you say "plug-in," I assume you're talking about separate executable modules, like DLLs or packages, that the customer can choose to include or not. Couldn't you turn your different editions' features into plug-in modules that simply don't include in the lesser editions? Then you don't have to worry about conditional compilation of your project; just have several different installer packagers that grab different sets of plug-ins.

I have always found it odd that this has never been addressed adequately. I suggested recently to David I that Delphi should allow the user to set up some sort of preferred development structure and that third party library publishers could be made aware of this so that they could automatically adjust their installers to install correctly in the preferred development framework. If the preferred development structure was stored in an XML file or similar, then, it could be copied from one computer to another on a development team.
As an alternative, it could make an interesting project to create a Delphi application that would allow a user to "refactor" their library installation in a high level way. You specify which folders on your system contain source or compiled components or whatever and where you want to keep source files or compiled units, hit Go and your system gets rearranged for you, while updating your Delphi environment so that when you start Delphi, it finds everything it should.

I've just recently discovered a way to have project specific environment variables in delphi builds using XE6, it's not quite as good as a full blown #define like in C but at least I can now have consistent search paths across multiple projects and create some shared option sets.
What I've done is setup environment variables in the same manner as the original poster and then override them in the dproj or optionset.
The BuildPaths.optset added to the project looks like
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SVN_Root>..\..\..</SVN_Root>
<SVN_Riemann>$(SVN_Root)\Riemann</SVN_Riemann>
<SVN_Library>$(SVN_Root)\Library</SVN_Library>
<SVN_ThirdParty>$(SVN_Library)\Third Party</SVN_ThirdParty>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>OptionSet</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality/>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
</Project>

Related

Setting up a large software system in Delphi

We have a software package which is about 16 years old. It's gone through just about every version of Delphi (besides .NET ones). Over the years, things have become very confusing when it comes to cross-referencing and keeping proper setup for additional packages (like third-party libraries). I was wondering if there is some standard practice when it comes to keeping large projects (and groups of projects) like this organized.
So to explain the current setup...
This is a multi-application system. Meaning, there are 12 executable projects (and a few DLL and service projects) involved. We also keep things in SourceSafe and multiple developers work on the same code on different computers. All of these projects are more-so dumped into a central folder. The "Root" folder contains THE major EXE project (along with about 20 folders, all containing units and forms) and it almost seems like an endless hierarchy of folders and files. This one project alone has half a million lines of code involved.
Then all the additional applications aren't necessarily separated properly from this major project. Each of these projects has its own folder based in the main project's root.
The two major concerns of mine are:
How to properly set up the DCU files so that they aren't mixed in with the projects? DCU's should NOT be placed in the SourceSafe (and any similar file, for that matter) or otherwise, any file compiled from the project. Visual SourceSafe makes files read-only when they're not checked out, and DCU files (and EXE files and more) cannot be written to in this case. So how to properly separate any of such file to a remote location to avoid any mixture with the source code?
How to properly set up packages and libraries? We have the following:
QuickReports 5.05
NativeJpg library V302 -
Another anonymous reporting library
Our own component package, which requires QuickReports, NativeJpg, and the other anonymous library
All 4 of those libraries are stored in completely different places of each computer, and need some centralization. The biggest pain of setting up each new developer's computer is locating these from the lead developer's computer and copying them to the same place on each other computer (and making sure the library path is correct, etc.).
We also need to keep completely separate environments for different versions of Delphi on the same computer. This means a copy of the projects on each computer, a copy of packages and libraries on each computer, a copy of the projects and packages and libraries in the SourceSafe, etc. Each computer needs to have an identical setup. We already utilize environment variables to direct our projects where to look for certain project files (and libraries).
Another new concern: XE2 introduces 64bit capabilities. We don't plan on 64bit compiling yet, but we certainly will in the future. How do I properly differentiate 32bit from 64bit in all these projects?
What I'm really asking for is a reference to a good tutorial on how to optimize such an environment and keep it organized the best. I don't expect anyone to take the time and answer all this in the question. The projects are over 15 years old, have had the hands of 200+ developers from around the world in it, and has a LOT of cross-referencing between projects. For example, one project may use a unit from another project, and vice-versa. I personally don't like this concept, but I also didn't design it to begin with. I've been given the task to get this system organized and thoroughly documented how to set up Delphi on a new computer for new developers to work on our projects. As I'm looking at our projects (as I'm not necessarily a developer of the system, but am being pulled into development), I'm seeing a lot of confusion in how the code is organized.
I am assuming that possibly Embarcadero has some guidelines and standards on setting up such an environment?
Location of DCU files
Regarding the DCUs that are the output of the compilation process, you should specify a DCU output directory in each project file. The default value for this, in the latest version of Delphi would be fine: .\$(Platform)\$(Config). This results in sub-folders of the project directory like this: Win32\DEBUG or Win64\RELEASE.
If you set-up your project files using option sets then you will be able to control this setting (and all others) from a small number of option files.
Location of 3rd party code
You should always use 3rd party library as code. If the vendor charges more to receive the library as code, pay up. Once you have done so you simply include the source code into your version control system (VCS) and treat it largely the same way as you treat your own code. I say largely because you should avoid modifying it.
Once you have all your code in the VCS then you can put the entire source code onto a new machine with a single checkout operation.
Organisation of your projects
I personally have a strong aversion to using compiler search paths. I don't use them and include every unit that is required in a project in the .dpr file.
If you do use search paths then you make it impossible to work on variant projects.So for example, suppose you have a client that has discovered a bug in the version of the software you released 2 years ago. You would like to address that bug by releasing an upgrade to the 2 year old version of the software. It is perfectly plausible that asking them to upgrade to the latest version is not viable. Perhaps they have not paid for the upgrades. Perhaps the full upgrade has breaking changes that they do not want to tackle right now. A perfect example would be all the Delphi developers still using Delphi 7.
Now, having motivated the scenario, how would you create a build environment for the 2 year old project? If you are using search paths then they will refer to today's libraries. You would be forced to change your search path, or copy the old libraries over the top of today's libraries.
That entire headache is trivially side-stepped by not using search paths and by including all your source in the VCS.
What you should be aiming for is to be able to checkout any historic version of your program and have it build immediately. You should be able to do this with full confidence that you are building identical software to what was built at the time that version was released. This also requires you to have build automation but I can't imagine you are lacking that for a project of this size.
I'll address folder organisation. This comes from a software suite which has 50+ exe's and dll's and plenty third party libraries, so I guess I know where you are coming from...
We use Perforce as a source control system, so my default workspace's root folder is called Perforce, but I also have a couple of other workspaces set up and they are in Perforce2, Perforce3, etc.
General folder setup (starting from the workspace root folder)
General
Components
Delphi
Indy
Indy9
Indy10
MadCollection
v2.5.8.0
v2.6.0.0
Plugins
Releases
Released
... a folder for each release we publish ... (and equal to a branch in Perforce)
Work
Acceptance
Sub1
Sub2
My Environment library path in the IDE is empty (not even the BDE standard paths are in there). This ensures that a project's paths declare all path's needed and that projects are not reliant upon a particular machine's IDE setup.
We have an environment var (ie MRJ) set up in our IDE's that points to "General\Components\Delphi" so in a project's options we declare the paths to our components as $(MRJ)\MadCollection\2.6.0.0.
General holds IDE plugins and components used by our projects. We keep all versions we use in source control. That way when I have to switch back to an old release to track down a problem, I can simply pull it and build it as its library paths will still point to the version of the components that this specific release needs.
The organisation of folders in a particular work branch (Acceptance or one of its subbranches) follows this pattern:
General
Includes
MainComponent1
Project1
Project2
Shared
MainComponent2
Project3
Project4
Shared
Shared
Windows
SoftwareSuite
Scripts
Tools
MainComponent1
Project1
Dcus
Project2
Dcus
MainComponent2
Tools
Tool1
Dcus
Tool2
Dcus
The General folder holds all platform independent sources/files, the Windows folder holds all Windows specific files. Each component can hold multiple projects and will have a share folder for sources shared between those projects. The shared folder directly under General holds sources shared by all projects. The Windows folder is set up in a similar manner.
Note that each project has its own dcus folder. This is configured in the project options. As the path can be entered as .dcus, we (at least I) have this set up as the default for any new project. Each project sending its dcus to a unique folder ensures two things:
it is easy to keep dcu's out of version control by simply setting up a filter in your version control software.
more importantly it ensures that compilation/build of a project never interferes with the compilation/build of another project. I can safely change settings and build knowing that I won't be bothered by dcu's lying around from a previous build from another project.
I recommend the following practices:
Keep your library path simple, and make sure everything in the library path is either a folder that ships with delphi, or a DCU binary (library) folder in your d:\Components\ folder.
Use a MODERN type of version control. I recommend Mercurial over others. Source Safe is crap, stop using it.
Back up your environment (export registry keys etc) and restore it to the other developer PCs in a standardized way. You can keep a few .reg and .cmd (batch) files around to automate setup of a new system. you can put these scripts in your component repository in your version control system.
Outside the scope that was largely discuss before, I would recommend :
Unit testing - with DUnit for example
Continuous integration. Just to be sure that all these projects can compile on another machine and that tests are ok.
So this is heavily related to project organization and VCS strategy.
For a similar setup, a company I worked for found this configuration useful:
all third party libraries (components etc.) go to a fixed location (C:\Delphi\name-version)
Delphi projects can be checked out from version control anywhere (drive C: or D: and folder name does not matter), as all projects and scripts use relative paths
all projects are sub folders of one main project folder so checking out this one will bring the Delphi projects and other relevant resources to the workstation, and a version control update is easy to do
we use a build script (written in Apache Ant) which sits in the main folder, and iterates over all folders to build the Delphi apps and run unit and integration tests against a development database server, to verify all changes work before checking in to source control
the build script can also be run automatically on a build server (Hudson CI) on every commit to see if something broke
And a note about component libraries: avoid package installation where possible, prefer creation of components at run time. If you quickly need to apply a fix to a five year old version of a project, uninstalling / installing a dozen of packages can become frustrating. At least for non-visual components, run-time creation is a huge time saver.
Checking in third party code in source control can be very helpful, for example to share fixes which are not yet available as new official releases. Best practices are covered in the Subversion documentation chapter Vendor Branches.
Plus, with Subversion you can use svn:externals to place a specific version (tag) right into a project directory structure. This can be used both with third party library and with your own source code, and makes dependency management easier and workstation setup easier.
p.s. the Ant build script defines the search paths for everything, so it is 'the reference' for all developers how to configure the IDE, where to put the third party libs and which compiler flags to use
p.p.s. your project sounds like a lot of fun - I am open for contract work :)
My team use virtualization and when we see back it was a real good move.
We use MacBook Pro laptops and VmWare Fusion, but I'm sure other packages work fine as well like VirtualBox or VirtualPC.
It is always a good feeling to know that when a new developer starts or an old installation got trouble it is just to copy a new VM image from the master image and the setup is exactly as the original. The master image is stored on a fast USB2-disk. Now when Thunderbolt and USB3 is coming it would be even faster to copy an image. And there is no real concern about performance on a modern computer as long as there is memory. 8 GB should be enough to run 2 images in parallell. Another advantage of virtualization is that it is so easy to try What if scenario. Experiment with different configuarations and versions without any risk to disturb the real working environment.
Btw I also think that SourceSafe is crap... :-)
Somé tips:
Make one groupproject file for all the apps belonging to the project, each app in its own dir under the groupproj file
You should be able to specify which file types to include into your version control system. Make sure you set Delphi to write DFM files in text format.
You could tell Delphi to output DCUs in subdirs named 'dcu' under each app (less visaul clutter).
Third party stuff often insists on installing in distinct locations, there's not much you can do about it. Make a document describing how to setup a complete working environment and keep it up-to-date
Develop in virtual machines. A new developer gets a copy of the VM.
Maintaining for different Delphi versions? Rethink that, try to go to one version. If you absolutely must have two groupprojects and directory structures for each version. [I'm assuming you're not compiling the same app with two Delphi version, that's developer hell]
Delphi XE2 will output to different 32/64 subdirectories, that should give no problems.

The best approach to modular programming in Delphi

this is a continuation of the discussion I started here. I would like to find the best way to modularize Delphi source code as I'm not experienced on this field. I will be gratefull for all your suggestions.
Let me post what I have already written there.
The software developed by the company I work for consists of more than 100 modules (most of them being something like drivers for different devices). Most of them share the same code - in most cases classes. The problem is that those classes are not always put into separate, standalone PAS units. I mean that the shared code is often put into units containing code specific to a module. This means that when you fix a bug in a shared class, it is not enough to copy the PAS unit it is defined in into all software modules and recompile them. Unfortunately, you have to copy and paste the fixed pieces of code into each module, one by one, into a proper unit and class. This takes a lot of time and this is what I would like to eliminate in the nearest future by choosing a correct approach - please help me.
I thought that using BPLs distributed with EXEs would be a good solution, but it has some downsides, as some mentioned during the previous discussion. The worst problem is that if each EXE needs several BPLs, our technical support people will have to know which EXE needs which BPLs and then provide end users with proper files. As long as we don't have a software updater, this will be a great deal for both our technicians and end users. They will certainly get lost and angry :-/.
Also compatibility issues may occur - if one BPL is shared by many EXEs, a modification of that BPL can bee good for one EXE and bad for some other ones.
What should I do then to make bug fixes quicker in so many projects? I think of one of the following approaches. If you have better ideas, please let me know.
Put shared code into separate and standalone PAS units, so when there is a bug fix in one of them, it is enough to copy it to all projects (overwrite the old files) and recompile all of them. This means that each unit is copied as many times as many projects it is used by.
This solution seems to be OK as far as a rarely modified code is concerned. But we also have pas units with general use functions and procedures, which often undergo modifications. It would be impossible to do the same procedure (of copying and recompiling so many projects) every time someone adds a new function to this file.
Create BPLs for all the shared code, but link them into EXEs, so that EXEs are standalone.
For me it seems the best solution now, but there are some cons. If I make a bug fix in a BPL, each programmer will have to update the BPL on their computer. What if they forget to do that? However, I think it is a minor problem. If we take care of informing each other about changes, everything should be fine. What do you think?
And the last idea, suggested by CodeInChaos (I don't know if I understood it properly). Sharing PAS files between projects. It probably means that we would have to store shared code in a separate folder and make all projects search for that code there, right? And whenever it is necessary to modify a project, it would have to be downloaded from SVN together with the shared files folder, I guess. Each change in the shared code would have to cause recompilation of each project that uses that code.
Please help me choose a good solution. I just don't want the company to lose much more time and money than necessary on bugfixes, just because of a stupid approach to software development. So far nobody has cared about it and you can imagine how many problems it causes.
Thank you very much.
You say:
Create BPLs for all the shared code, but link them into EXEs, so
that EXEs are standalone.
You can't link BPLs into an executable. You are simply linking in the separate units that are also in the BPL. That way you don't actually use or even need the BPL at all.
BPLs are meant to be used as shared code, i.e. you put the code that is shared into one or several BPLs and use that from each of the .exes, .dlls or other .bpls. Bugfixes (if they don't change the public interface of the BPL) merely require the redistribution of that one fixed BPL.
As I said, decide on the public interface of a DLL and then don't change it. You can add routines, types and classes, but you should not modify the public interfaces of any existing classes, types, interfaces, constants, global variables, etc. that are already in use. That way, a fixed version of the BPL can easily be distributed.
But note that BPLs are highly compiler version dependent. If you use a new version of the compiler, you will have to recompile the BPL too. That is why it makes sense to give BPLs suffixes like 100, 110, etc., depending on the compiler version. An executable compiled with compiler version 15.0 will then be told to use the BPL with suffix 150, and an executable compiled with version 14.0 will use the BPL with suffix 140. That way, different versions of the BPLs can peacefully co-exist. The suffix can be set in the project options.
How do you manage different versions? Make a directory with a structure like I have for my ComponentInstaller BPL (this is the expert you can see in the Delphi/C++Builder/RAD Studio XE IDE under menu Components -> Install Component):
Projects
ComponentInstaller
Common
D2007
D2009
D2010
DXE
The Common directory contains the .pas files and resources (bitmaps, etc.) shared by each version, and each of the Dxxxx directories contains the .dpk, .dproj, etc. for that particular version of the BPL. Each of the packages uses the files in the Common directory. This can of course be done for several BPLs at once.
A versioning system might make this a lot easier, BTW. Just be sure to give each version of the BPL a different suffix.
If you actually want standalone executables, you don't use BPLs and simply link in the separate units. The option "compile with BPLs" governs this.
From my point of view trying to manage artifacts like Delphi units, libraries and executable files, you search at wrong place. I suggest you to turn around and start with refactoring of code, based on Design patterns implementation.
E.g. all common functions can be placed into one Singleton class, instances of common classes can be constructed with Abstract Factory, classes can interact through native Delphi implementation of interfaces instead of direct usage and so on. Even you can choose to implement Facade for all common parts of projects.
Of course, concrete choice of patterns and details of implementation depends on project specific and only you can decide what applicable in your case.
I suppose, that after looking to project in this vein you can find more natural ways of code organization and solution for your problems.
Some other things:
Of course, you must follow #CodeInChaos suggestion and share one copy of source file between all projects instead of copying it to each project manually. It may be useful if you adopt some standard for building environment, which will be mandatory for all developers (same folder structure, location of libraries, environment settings).
Try to analyze building and deployment process: for me it's looking abnormal when solution not built with latest version of code and not tested before deployment. (it's for your "If I make a bug fix in a BPL, each programmer ..." phrase).
Variant with standalone executable files looks better because significantly simplifies organization of testing environment and project deployment. Just choose adequate conventions for versioning.

Adding files to the DPR file vs project paths in Delphi 2010

We are just migrating from D7 to D2010 and are having a debate about cleaning up the project paths. We have a number of directories with a large number of Pas files that are included on some project paths, but only a few of the files are actually used by any single project.
One option is to eliminate the project paths completely and only have all used files in the dpr.
The second option is to keep only the needed files in the dpr and have project paths to the directories for the rest of the files.
Is there any argument for one option over the other?
Having all your units explicitly in the dpr immensely improves compilation time, code completion, error insight and general navigation.
It does not prevent you from keeping your files organized in folders and sub-folders, but just don't rely on the different paths to find them.
On a big project with millions LOC, it makes a huge difference.
I'm in favor of separating "library units" from "project units" and keeping all "library units" in the search path, with all the "project units" in the project file. Here's why:
Our line-of-business projects are large, almost million-LOC type of projects, but besides those there are literally hundreds of smaller projects for all sorts of tiny little things. Having the "library units" available on the search path makes it really easy to just use those units without adding them to the project: One less step that adds up!
Using the search path makes moving PAS files around easier. This matters allot to me since I'm in the process of re-organizing our whole "build environment" to make better use of version control systems.
When you change one of the shared units and it becomes dependent on yet an other shared unit, you don't need to updates lots of projects, they just work.
I'd never consider adding third-party components (or VCL components) to my project, so why add my "library units" to the project? We need to draw the line somewhere, because if we'd add absolutely all files to the project hoping for faster compile times we'd end up with unmanageably large projects!
Delphi automatically changes the name of the files in it's DPR file to be relative file names. Because of this you can't really move your project from it's current position. Now try "branching" and keeping two copies of the project alive at the same time, on the same machine (a "release" and a "work-in-progress"). (this is me tring preparing my build enviroment for GIT, with the sole purpose of being able to BRANCH).
For reference, my "library units" are those units that are used in unrelated projects (think: components and utilities).
I would argue in favor of including all files that the project uses in the project itself. This will improve performance of the "Insights" by ensuring that used units are part of the project. In addition, this will enable you to more easily manage your code inside the Project Manager. Having large complicated paths is fragile and can be hard to manage.
The comments about speeding up Insights got me intrigued and I will give that a try but so far I never included shared units in the projects that used them. Instead I created packages for each library and added them to the project group (mostly for organizational purposes only, i.e. I never actually compile them as runtime packages). I found this easier to manage (especially with all the recent improvements in the project manager) than having all files in one project as the folder hierarchies inside the individual (package-)projects won't be as deep and especially there's no ".."-level that way.
Reasons to not include all files in the project:
less time to open/close a project (forms and datamodules need extra time)
faster file refactorings (renaming/moving of files and directories does not require to edit all projects)
easier to find the units which are the core requirements and the entry point location for the application logic (uses MyInterfaces, MyTypes, MymMainUnit;)
And this QC entry:
Report No: 77687 (RAID: 273031)
Status: Open Editing in the .dpr
source gets slower with more units in
the project
http://qc.embarcadero.com/wc/qcmain.aspx?d=77687
Update: Now I know that there are many ways to open the project file :) - But my point is that in a dpr with 500 unit references, it is hard to find the 'important' (or 'main') units, which are the starting point to drill down into the source - and it is easier to investigate code if it is a 'lightweight' project file which contains only the necessary unit references.

In Delphi do you use include paths or explicity include all required files?

Looking at our codebase some code is included in a project explicitly and is pulled in from the search path. Does anyone have an opinion as to which is best practise and why?
Update:
I thought I would clarify my question. All our paths are relatives, so we can have multiple branches that all refer to code within their branches. So I'm not asking about relative paths, but whether units should be in the .dpr or picked up using the search path, which is why the previously asked questions don't quite answer my needs. Thanks to everyone
I have a very basic way of determining this... If the code is specific to the project (not used elsewhere) I include it explicitly. All shared code gets pulled from the library path.
best regards,
don
I don't think I can count the number of times I've helped someone who discovered that the compiler was finding a duplicate copy of a unit somewhere on their search path where they did not expect to find it. They couldn't understand why they were changing their code in the editor (on a copy of the units not found in the search path) and not seeing any change in the behavior of the application. Explicitly including the unit and not setting a search path means there can only be one copy of the unit found by the compiler.
This has been covered here before:
In Delphi, should I add shared units to my projects, to a shared package, or neither?
What is the best way to share Delphi source files among projects?
My answer to the first question is also my answer to your question.
my libraries are in SVN, and I usually check them out for (branch them into) a project at ../libraries relative to the project. This keeps the scope of the includes dirs small and to the point.
In the real source (.pas), paths are totally forbidden.
no project related paths in global delphi searchpath (only per project, or they are truly universally shared sources/components)
I hate poluting source with hardcoded paths, so I usually have only a few units in the project, always with relative paths. Not the VSS w:\ drive substitutes hack please! Typically these are the units that pull in framework parts or are needed due to visual inheritance or form initialization.
Unfortunately, relative paths can be dangerous with Delphi, because they are relative to the working directory, which can change according to Delphi dialogs (e.g. Open). The solution is simple, have an include file with an unique name in the main project.
The shared code vs specific code is a good rule.
I use VSSConnextion a lot, so files that I usually need to check out/in together, naturally belongs to the same project.
After upgrading Delphi twice and moving my project to new computers twice, I've learned that hard-coded paths are evil because root directories tend to change. Doubly so if you're working on a shared project.
I had the same problem. The blue-dots where not showing up in the gutter.
Simple solution (one of):
Menu > Project > Compiler > Build Configuration... set to DEBUG instead of release.
Delphi 2007
PS: well, I thought I was done coding. Someone had requested a new feature. :)

In Delphi, should I add shared units to my projects, to a shared package, or neither?

This question is similar to this one, but not a duplicate because I'm asking about issues not discussed in that question.
I have a client-server project in Delphi 7 with the following directory structure:
\MyApp
\MyClientApp
\MyServerApp
\lib
There are 2 actual Delphi projects (.dpr), one each in the MyClientApp and MyServerApp folders.
The lib folder has .pas units that have common code to the client and server apps. What I'm wondering is if I should include those .pas files in the client and server projects? Or should I create a package in the lib folder which includes those units? Or should I just leave the .pas files sitting in the lib folder and not add them to any app/package?
What are the pros/cons of each approach? Which way is "best"? Is there any issue with having those units from the lib folder be included in more than one project?
Right now the units in the lib folder are not a part of any app/package. One disadvantage of this is that when I have my client app open in Delphi, for example, and I want to search in all files in the project for something, it doesn't also search in the units in the lib folder. I get around this by opening those units and doing a find in all open files, or using grep search (but I'd prefer a better solution).
I would also greatly prefer a solution where I will not have to go and open some separate package and recompile it when I make changes to those files in the lib folder (is this where I should use a project group?).
Sharing units between applications always carries the risk of incompatible changes done in one application that breaks the other. On the other hand, making copies of these units is even worse, so your approcach of moving them to their own subdirectory at least adds a psychological barrier to changing them without considering other programs.
As for adding them to the project files: I usually add some units which I frequently access (either for expanding or for reference) from the IDE to the project, and leave others out for the compiler to pick using the search path. I do that on per project basis, that means, some units may be part of several projects, why not?
Putting them into a package only makes sense, if you actually want to create a package based application, otherwise, why bother?
For more info on how I organize my projects and libraries, see http://www.dummzeuch.de/delphi/subversion/english.html
I dislike having files shared by projects. All too often, you'll be tempted to edit one of the shared files, and you'll either break something in the other project, or you'll forget that you have to rebuild the other project at all.
When the shared files are instead separated into their own library (package), then there's a little extra barrier to editing them. I consider that a good thing. It will be a light reminder that you're switching from project-specific code to shared code. You can use project groups to let you keep every together in a single IDE instance. arrange the library projects ahead of the executable projects. The "build all" command will build everything in order, starting with the first project.
Keep your DCU files separate from your PAS files. You can do this easily by setting the "DCU output directory" project option to send your package's units to some other location. Then put that destination directory on your other projects' "search path." They'll find the DCU, but they won't find the PAS file, and so no other project will accidentally recompile a unit that isn't really a member.
Having a separate package also discourages use of project-specific conditional defines. Those cause all sorts of trouble when you're sharing units between projects. Find a way to instead keep all project-specific options within the respective projects. A shared library shouldn't require project-specific modifications. If a library needs to act differently based on who's using it, then employ techniques like callback functions that the library user can set to modify the library's behavior.
I would need to have a very good reason to add shared code to a package. If you just have a few shared files stick them all in a directory called Shared. This should make it obvious the files are shared between projects.
Also use a good build tool to do automated builds so you will find out soon enough if you break something.
.bpl files are fine for components, but bring in serious added complexity for things like this, unless you have a huge amount of shared files.
I usually create a package with all shared unit, and just use the units.
If you do not explicitly mark "Build with run time packages" the package content (all used dcu's) will be linked to your project as any other unit.
I would only use runtime packages if you actually had two binaries that were supposed to run on the same physical machine and that shared some code. Keep in mind that runtime packages are mostly an all-or-nothing approach. Once you decide to use them you will also no longer be able to link the RTL and VCL units straight into your projects and will instead have to deploy those separately as well.
However, packages might still be a good solution to your problem when combined with project groups which is exactly what I'm doing. I hate having shared units included in multiple projects. Including the shared units in a package (but not compiling your actual projects with runtime packages) allows you to add that package to your project group so you (and the IDE!) will always have them easily accessible yet nicely separated from the project-specific code. Strictly speaking you don't even ever have to compile those packages. They can merely serve as an organisational unit in the project manager.
Note that for the Find in Files, you can also specify "in all files in project group"

Resources