How split a Delphi solution into reusable run-time packages? - delphi-xe5

I'm starting with Delphi XE5 and I would like to split my application in one exe and multiple reusable libraries. That means I don't want to split the running *.exe application in DLLs or runtime Packages.
To achieve this, I have seen that in delphi we can create runtime packages and I followed the following steps:
I have created a new VCL Forms Application project (EXE project).
I have added a new Package project (BPL project) to the project group and I have modified its project options to set usage options to 'Runtime only' and build control to 'Explicit rebuild'.
I have added a dependency betwen the EXE project and the BPL project (EXE project depends on BPL project).
Finally I have compiled the BPL project and added the generated DCP file as a runtime package in the EXE project (Project options/Package/Runtime Packages).
But when I add a reference on the EXE project to use a module (moduleX for example) from the BPL project, compiler give me an error like this:
[dcc32 Fatal Error] ModuleX.pas(7): F1026 File not found: 'C:\DDDProject\MyEXEProject\ModuleX.dcu'
If I mark as checked the 'Link with runtime packages' option in the EXE project (MyEXEProject) the solution compiles without errors but I can't run or debug the application.
Please, can anyone help me?

I don't want to split the running *.exe application in DLLs or runtime Packages.
Runtime Package BPL files are DLLs. That is what allows them to be shared amongst multiple EXEs. They are just normal DLLs with special VCL/FMX handling built in.
When you enable the "Link with runtime packages" option, you are linking the EXE file to your BPL file (or DYLIB or SO file, if compiling for platforms other than Windows), so you MUST distribute the BPL file (and any other BPL files it depends on, like rtl190.bpl and vcl190.bpl) with your EXE file. So they have to be in the EXE's folder, or at least in the OS search path, in order for the EXE to run.
When you disable the "Link with runtime packages" option, your package's code is statically linked directly into the EXE file, so you need to make sure the EXE project's search paths include the folder were your package's DCU file(s) are located.
If you want to create a reusable library but not a BPL, then create a Static Library (a LIB file) instead of a Runtime Package. You can then add the LIB file to multiple projects as needed.

Related

Can dfm files be linked into bpl files?

My project setup looks like this:
There are multiple runtime packages. I'm not using design time packages.
Each runtime package has its DCP, package and unit output directory set to .\Library\$(Platform)\$(Config). I'm not outputting them to the global IDE locations to gain co-installability of different versions of the packages.
Also there is a Pre-build event in each package that calls a script file which copies all the dfm files from the source folders to a directory called .\Library\Dfm.
In order to build dependent packages and executables I add the output paths for the dfm and the other files to each dependencies local search path, for example:
..\Package1\Library\$(Platform)\$(Config)
..\Package1\Library\Dfm
..\Package2\Library\$(Platform)\$(Config)
..\Package2\Library\Dfm
..\Package3\Library\$(Platform)\$(Config)
..\Package3\Library\Dfm
Technically I only need to add the Dfm directories to the final executables search path since dfm files are linked into the PE executables resource section.
Still it seems like an unneccessary extra step to have two paths for each package.
So I am asking: Is it possible to link the dfm files into the bpl file for each package instead of the final executable?
One problem I can think of myself is that this would only work when runtime packages are enabled for the executable, because the compiler couldn't move the resources from the bpls to the exe otherwise?!
Is it even in principle possible to have the dfm resources in a different module than the one of the executable?
When compiling an executable with runtime packages enabled the compiler does not need access to the dfm files for forms inside the packages.
They are indeed linked into the bpl files.
When compiling with runtime packages disabled the compiler complains about the missing dfm files. So it apparently can not pull the resources from the compiled package file (bpl).

Delphi BPL search path

Every BPL-related question found by me in Internet refers to some BPL already shipped with Delphi or at least installed globally, into Delphi folders.
I would like to make my own application to find a run-time BPL file made by me, without saving global paths anywhere, without registering my package in Delphi globally. Only put BPL file into "packages" subdirectory, define search path and compile.
Project Options
Delphi Compiler
Search path: I defined relative path to my BPLs (packages folder) here
Packages
Runtime Packages
Link with runtime packages = True
Runtime packages: defined my BPL's name here, without extension
The problem is that compiler can't find my package although I have added the packages subdirectory to Project Options.
How to make it find my package?
The compiler doesn't need your BPL file. It needs the corresponding DCP file, as well as the DCU files for the units you use. Make sure those files' directories are on your search path, and your project should compile fine.

What project options to use for open source Delphi packages?

I've written some Delphi code I would like to share on GitHub. All code is contained in runtime and designtime packages as required. There are many "Project Options" to set for each project. (Output directories, search paths, compilation options, etc.) I've managed to find some default options that work well for my situation but reading other Q&As here it's clear there are multiple ways of working.
What project options should be used to allow the open source packages to easily be incorporated into individual projects?
I've recently started using NodeJS. The NPM package manager makes it super easy to use third-party packages in a project. Packages are installed with one simple command on the command line. Packages will automatically install any required dependencies.
PS: Feel free to edit this question if you would like to add extra things to consider.
Let's say you have this structure
MyComponent
Packages
DelphiXE7
Package2.dpr
source
bin
Delphi XE7
then set
Search Path
..\..\..\source
Unit output directory
..\..\..\bin\Delphi XE7\$(Platform)\$(Config)
After compilation for all supported platforms and both Release and Debug you will have this structure in the bin directory
MyComponent
Packages
DelphiXE7
Package2.dpr
source
bin
Delphi XE7
Android
Release
Debug
Win32
Release
Debug
Win64
Release
Debug
For installation you have to setup some path inside the IDE.
Environment
MYCOMPONENT => [root path to the files]
Library
Repeat that for all supported platforms
Library Path
$(MYCOMPONENT)\bin\Delphi XE7\$(Platform)\Release
Search Path
$(MYCOMPONENT)\source
Debug-DCU-Path
$(MYCOMPONENT)\bin\Delphi XE7\$(Platform)\Debug
If there are some language related units there is also a place to add (see Library - translated)
This ensures, that you have full debug feature (with Use Debug-DCU option set) and on release you have no debug code in your application.
Just a sidenote on libraries you should not want to install because you only use them in some projects.
Simply use the Optionset combined with a environment variable.
Here my SuperObject.optionset ($(USRLIB) points to a directory, where I collect all common used source code. And $(USRLIB)\ext is the place for all of the external libraries).
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DCC_UnitSearchPath>$(USRLIB)\ext\superobject;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>OptionSet</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality/>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
</Project>
To use the superobject library I simply add the optionset to the project (right mouse click on build configuration) and everything is fine.

Installing Indy - which folders should be added to Delphi's Library list?

The directions on how to install Indy10 are (at least to me) a little vague in one place, and I'm hoping someone here can clarify a little.
The installation directions (From http://www.indyproject.org/sockets/Docs/Indy10Installation.en.aspx) state:
After Compiling
In your Indy directory you should now see some compiled .dcu files.
Open the IDE and go to the "Tools > Environment options > Select
Library" dialog tab. Now add the path to your files into the filepath
collection. Click Ok.
My Indy10 folder does not have any .dcu files in the root folder. It does have a bunch of DCU files in C:\code\Indy10\Output\DCU\Win32\Debug ... does this mean I should be adding C:\code\Indy10\Output\DCU\Win32\Debug to my library path? (And for that matter, should I be building Indy in Debug or Release mode, or does it matter?) Are there any other subfolders I need to add to the library path? Indy 10 has a much more complex folder structure than Indy 9 and I'm not convinced I've configured things "correctly".
Nearly every component package I install I touch the project options for the runtime package(s) to get a clean install.
Project Options
General Configuration
Output directory {componentpath}\lib\XE4\$(platform)\$(config)
Release Configuration
Output directory {componentpath}\lib\XE4\$(platform)
After that I compile the whole package for all target platforms in release and debug mode. Using a Build-Group is very useful to do that.
Now it is time to add the library paths (for each platform)
Library path {componentpath}\lib\XE4\$(platform)
Debug DCU path {componentpath}\lib\XE4\$(platform)\debug
Browse path all directories containing the source
In your own projects you can control which .dcu versions are used by setting the Use Debug-DCU option.

How not to compile installed packages everytime anew with the Application that uses it?

When I install a package in the IDE and use it in a project, it gets recompiled (DCUs are replaced) everytime I compile my project.
I can't imagine that this is intended - the RTL and VCL are not compiled each time either, are they?
I have played a bit with the paths in Tools > Options > Environment Options > Delphi Options > Library, but without success.
I have found a construction allowing compilation of my project without recompiling the package having DCUs and PASs in diffenent paths, but in this construction Delphi is not able to locate the sources at all from the Code Editor (SHIFT-clicking for example), so this is not an option.
To avoid recompilation you have to have separate folders for .dcu files and .pas files.
Usually this is done by settings the output dir in a package contained in the library. You build the package and it will produce the .dcu files in a output folder that is different from the source folder.
To use the package you then:
have to point the library path to the output folder (with the compiled .dcu files).
can optionally point the search path to the source folder (with the .pas files).
This gets a little more complicated when you have .dfm files in the package as well.
Every .pas file that the compiler sees in the library path is recompiled. (Actually only the last instance, because you can have the same unit in different directories that are listed in the library path).
To enable IDE features like CTRL-click you have to set the {$Y+} compiler switch in your package which can be done in the IDE Compiling options:
http://docwiki.embarcadero.com/RADStudio/XE4/en/Compiling#Debugging_Options

Resources