We use many third-party Delphi libraries to build FinalBuilder and Automise, and that brings plenty of issues when upgrading compiler versions. I've been using Delphi since 1995, both as a
developer and as a component vendor, I have learned a thing or two about creating libraries that I would like to share. These are all ideas that make life easier for users, and make it
easy to migrate from one version of Delphi to another.
There's no hard and fast rules on how Delphi Libraries are supposed to be structured, these are just my preferences and things I have learned over the years. Hopefully this will
help new and existing library authors.
Folder Structure
Keep the Source and the Packages in separate folders, this makes it easier to find the correct packages to compile, e.g :
\Source
\Packages
\Demos
Under Packages, create a folder for each compiler version your library supports, e.g:
\Packages\Rad Studio XE8
\Packages\Rad Studio 10.0
\Packages\Rad Studio 10.1
Package Names
Please, do not put the Delphi version in the package project names.
Bad!!!
MyProjectRun_D10_4.dproj
MyProjectDesign270.dproj
Good
MyProjectRun.dproj
MyProjectR.dproj
MyProjectDesign.dproj
MyProjectD.dproj
Why not put the compiler version in the package project name you might ask? Well the answer is that it makes upgrading compiler versions a major pain for users who link their
projects with Runtime Packages (yes, that includes us).
The reason is that when you compile a package, it creates a packagename.dcp file and that is what your project references. So, if your package name is MyPackageRun_D10_4 then that is what
will be added to projects that use it.
package MyOwnPackage;
//...
requires
rtl,
vcl,
MyPackageRun_D10_4,
AnotherPackage_Sydney,
YetAnotherPackage_D104,
// ...
When Delphi 10.5 comes out, guess what the user has to do to upgrade their projects.... Yep, replace that all those package references with 10.5 versions (and the multitude of suffixes).
Multiply that by a number
of
projects and a number of libraries (each with potentially multiple runtime packages) and you can see why this might be a pain.
Now you might say, but we don't want 15 versions of MyPackageRun.bpl laying about on users machines, and you would be right. The solution to this is a feature that has been around
since Delphi 6 (2001) - LIBSUFFIX.
Setting LIBSUFFIX (on the Description section of project settings) will append the specified suffix to the BPL file name. So a suffix of _D10_4 will result in a package :
MyPackageRun_D10_4.bpl
however, the DCP file will still be generated as :
MyPackageRun.dcp
Remember it's the dcp file that our projects reference (for linking) - so by keeping the dcp file the same for all delphi versions, upgrading to a new compiler version just got a whole lot
easier!
So when Delphi 10.5 comes out in the future, all I need to do is install the packages, no changes to my projects.
Update : Someone pointed out that Delphi 10.4.1 support LIBSUFFIX $(Auto) - this will use the Delphi defined PackageVersion - which for 10.4 is 270. This is a nice addition
as it makes upgrading the package projects simpler. Of course if you don't like the PackageVersion suffix and use a custom one, then this is not for you.
Use Explicit rebuild, not Rebuild as needed
Have you ever encountered the error
E2466 Never-build package 'XXX' requires always-build package 'YYY'
What this means is, a package, set to Expicit rebuild, references another package, set to 'Rebuild as needed', and it's a pain in the proverbial. Rebuild as needed is also referred to
as Implicit Build - in dpk's you will see it as
{$IMPLICITBUILD ON}
If that "Rebuild as needed" package is not part of your project group, guess what, you get to waste time closing and opening projects trying to get it to compile.
I'm sure someone will correct me on this, but I cannot see a good reason to have "Rebuild as needed" set. I suspect this is a hangover from before the Delphi IDE
allowed you to specify Project Dependencies and it slows down builds.
Use Search Paths for includes
I often see includes with either hard coded paths, or relative paths like this :
{$I '..\..\MyDefines.inc'}
That's great, if the installer delivers the files in the right place - but they often don't - I hit this issue today, where the package just would not compile. I eventually
figured out that the relative path was wrong.
There's a simple fix for this, and that is to remove the path in the $I statement, and use the Project Search Paths feature instead.
I have also seen libraries where there are mulitple copies of the include file and they are slightly different!
Mark packages as Runtime only or Designtime only
Some libraries have their packages marked as "Runtime and Designtime" (the default) - the impact of this is only minor, but it's a pet peeve of mine. The Delphi IDE (in recent versions at
least) provides a nice indication of whether packages are runtime or designtime in the project tree, and for designtime packages, whether they are installed.
This makes it simple for me to determine which ones need to be installed or not.
Not Installed
Installed
Summing up
One of the major reasons people do not upgrade Delphi versions is because it's too hard to deal with the third party libraries and all the changes required just to
get to the point of compiling. That eventually results in a lack of Delphi sales which results in a lack of investment in Delphi which feeds back into.... well you get the idea ;)
Making third party libraries easier to work with in Delphi has been a bit of a crusade for me, I've been working on this for a while
now,
and I'm getting closer to a solution - DPM - A package manager for Delphi - if you are a library author, I encourage you
to take a look. For examples on how to create a package spec (dspec) take a look at our open source projects https://github.com/vsoftTechnologies/