Building with runtime packages. Which BPLs are needed? - delphi

I want to compile my program with 'Link with runtime packages'.
It tells me that I need some DB-related packages. But I don't use DB in my program.
How do I figure out which BPLs are needed?
There is some kind of dependencies viewer?

I expect there are more sophisticated/user-friendly dependency viewers available, but you can use the TDump.Exe utility that comes with Delphi to do this. E.g. from the CMD line in the containing folder
tdump dbgrids2.bpl > dump.txt & notepad dump.txt
then search for entries in the imports section of the result.

Another good tool if you use GExperts (RAD Studio IDE Expert) is the "PE information" included in this tools. Inside the IDE you can obtain the dependencies (BPL's and DLL's) of an EXE/BPL/DLL. And other information about the necessary pachages.
If you select and EXE on this tool, you can obtain a result like this:

How I 'solved' the problem:
Link with runtime packages:
In 'Project Options' I put all BPIs in 'Packages->Runtime packages->Runtime package import libraries'. BCB will only link the PBLs that are actually needed.
The BPI must ALSO be added to the project (just drag and drop it in the ProjectManager).
Distribution:
When you place a new control on your form, that resides on a different BPL, you need to add that BPL also to your distribution package. If you forget to distribute your BPL, the program will crash and burn. So, testing is easy. Just run the application.
Dependency viewer
As dependency viewer I used 'Project info' but that is limited. Process Explorer is way better.
That's it. I made a test and it works great.
Link: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Loading_Packages_in_an_Application

Related

How can I link a static lib generated by DCC32 with the option -JL in C++builder?

I'm trying to use a static library in my C++ Builder project. The lib is created by using DCC32 to compile Delphi source code with -JL option. My Delphi source code is design as a "Designtime and runtime" package, which mean s all the code is built into one package. I want to know how can I use this static library in our C++ Builder project? Thanks in advance.
As David said, the Delphi compiler can't create static lib files at all. What you are trying to link to is an import library for a designtime/runtime package.
Delphi (and C++Builder) packages are not static libs, they are DLLs with a lot of extra information onboard, which makes it easy for Delphi and C++Builder code to link to them and the types inside. They are more or less equivalent to C# assemblies (guess where the C# people got the idea ;-).
To use such a package, in case you really want to use them, select the "build with packages" option from the project options and select this package too.
But if you want to create a single, standalone application, you don't build with packages and the Pascal files get linked into your application as if they came from a static library. But instead of specifying one lib file, you simply specify the .pas files in the project manager, i.e. you simply add the bunch of .pas (or .obj) files to your application directly.
The project will take care of compiling the Pascal files and linking them to your application.
Note that to install components into the IDE, you need a design time package (and that might link to a runtime package). But you don't need packages for your application.
These are some steps for your consideration:
Use -JP to generate obj files
Add these obj files in link step into your ilink32 command
If you use IDE and do not which ilink32 params then you may consider procexp or procmon to see these params.

Delphi - How to build a package for distribution

Using Embarcadero RAD Studio XE7, I wrote a runtime package containing a VCL component (it's a TGraphic descendent). Now I want to distribute this component, but only the compiled package without his source code. I cannot include it in the distribution because I wrote this package for a company that want to sell it and keep the control on his sources, so distributing the source code isn't an alternative in this case.
The component package depends on 2 other packages I also wrote. All of these packages are runtime, however a graphic filter is registered. After the package is installed, this filter allows me to open a new kind of image file from several native VCL components like TImage on my development computer. This behavior is very important and I want to keep it on the target IDEs.
Ideally I want my package to be installed on all RAD Studio platforms between XE and 10.2 Berlin. However I recently tried to compile my package in release on my devel computer and deploy it manually on another computer installed with RAD Studio XE4. The result was unconvincing:
Trying to install the .bpl file using the Component->Install packages... failed with a "The specified module could not be found" error. When opening the .bpl file with the Dependency Walker tool, I noticed that several dependencies like RTL210.bpl were missing
I also read somewhere that only design time package may be installed this way, it is exact?
Putting all the files (.bpl, .lib, .hpp, ...) of one of my package manually in the XE4 common dirs, I was able to compile a test project successfully. However several functions in my package were unavailable (resulting to an unresolved external when trying to use them)
Although I have several past experience about software and package distribution, I must confess that I have absolutely no idea about how to build a such package for deployment. In all my past scenarios I always distributed the package projects and source codes, and let the user install them on their own IDE.
I searched information about that in the past days but I found nothing. So if somebody can explain how to achieve a such package, or can point me to a document or website describing the process, or eventually give the name of a tool that can do the job, I would be very grateful to him.
Regards
If you don't want to to distribute the source files, you then need to provide the .dcu and bpl files. As Uwe says, you need different packages for each Delphi distribution.
What I have done in the past is to create an installer which builds and registers the packages. You can find the full description here:
http://www.kouraklis.com/2016/10/build-and-install-packages-in-delphi-ide-using-innosetup/
I think you can modify the script to skip the call to MSBuild.
Hope this helps.

Can one build an EXE project against a BPL/DCP with "Build With Runtime Packages" unchecked, based solely on the BPLs/DCPs?

I have a BPL project (with some base stuff) and an EXE project which has in it's Search Path the location of the other project's output (BPL and DCP). When the EXE project is built with "Build With Runtime Packages", it builds fine. However, it requires me to deploy the EXE and the BPL. So far so good.
Since I'd rather deploy just the EXE (no matter it gets bigger), I'd guess that I'd just uncheck "Build With Runtime Packages" and that'd be it, but it's not the case. It won't build, and start complaining about the missing classes. The only way I can compile the EXE project is if I add the path to the actual BPL project's DCUs to the EXE project's Search Path. I can do that, but why am I forced to point to the DCUs? Can't Delphi just take them from the BPL? It's not just a matter of taste, if I go this way, and link to the DCU's, when it comes to DCUs belonging to forms, it will then ask me for the forms DFMs, forcing me to also include my sources folder to the EXE project's Search Path, and now it would seem as they are getting compiled, which is prohibitive. I can't recompile my BPL project codebase each time I want to compile my EXE project.
I hope I have made myself clear.
Any help on how to achieve what is asked in the title is appreciated.
Thank you.
There are two ways to link external libraries: static and dynamic.
When you are using runtime packages, this is a dynamic linking. Actual implementation is in the BPL file (which is a simple dll actually), methods and classes are imported from it on the process start. This reduces exe size, but requires BPL file to be shipped (same as usual dll). DCU files are not needed, because everything is already compiled and linked, linker need only to create import section.
When runtime packages are disabled, linker has to take object files for all classes and methods and combine it into the one executable. It could not extract this data from the BPL, because its is already linked executable. It would have to unlink it first, separating different modules implementation, which is basically impossible. So you have to provide DCU files, containing compiled object code to link your program.
So answer for your question title is simple - no it is not possible.
No, you can't. If you want to use runtime packages you have to turn on the compiler option to build with runtime packages.
As to the second part of your question:
Building with runtime packages uses the *.dcp files to compile (the .dfm streams are linked into packages' resources so the *.dfm files are not needed directly).
Building without runtime packages needs the *.dcu and *.dfm files (and any other required files).
In either case, you need to have the required files in your library/search path to be able to compile/build.
It is possible, but is very hard to implement.
And you will need to create a third project for this purpose - a loader.
You need to turn your original EXE project to a DLL built with runtime pckages.
The loader can include your DLL project, rtl.bpl, vlc.bpl and your BPL project as resources inside loader executable.
Loader will need to manually do all things that are done by LoadLibrary Windows API.
You can read more about how to load DLLs from memory and find some code samples to start with here.

What is the best way to install components?

Installing components under Delphi XE3 is a nightmare.
First I need to add source files to
Tools -> Options -> Library
then I need to find a normal package and compile it
finally I need to find design time package and install it.
This is just quite tedious and error prone. Is there a nicer way to install components?
I have found Delphi Package Installer. Unfortunately it doesn't support Delphi XE3 or above.
I have heard that there is something similar which produces exe packages that install themselves (something like Inno Setup) but I can't find such thing.
No. The steps above are required.
First, adding the file path to Tools->Options->Delphi Options->Library Path is so the compiler knows where to find the files to compile them. (Actually, it's not required - you can eliminate this step by making sure that the .dpk files are in the same folder as the .pas files, and that all .pas file names are listed in the includes section in the .dpk. If the .pas files are in a different location, you'll need to either use relative paths in the .dpk (eg., MyComponents in '..\Source\MyComponents.pas') or add the location of the .pas files to Project->Options->Delphi Compiler->Search Path.)
The next step (finding the "normal package") is in order to build the runtime package. It's required, because the design-time package (next step) requires the code that's in that package in order to function in the Form Designer. It's also needed when you decide to build your application with runtime packages, if you use the third-party components and want to distribute the runtime package for it.
The separate design-time package (the third step) is required because designtime code can only be used at design-time; there's nothing that can be distributed with an application if it's built with runtime packages and the package build in step 2 is one of them.
This has been the way components are installed since around Delphi 3 or so, and the requirement to separate out designtime code into it's own package started being advised in Delphi 5 and enforced in Delphi 6 (when they relocated much of the IDE designtime support into their own separate packages and stopped distributing the source for them).
There really are no other options, unless the vendor supplies pre-build designtime and runtime packages for you, or supplies an installer that will do all of the above steps. (Most don't.) But if you update your Delphi version, you'd still have to go through the steps above.
What about the built-in component installer? It is part of Delphi XE, XE2 and XE3 and a description can be found here (I wrote it). It will even install components in C++Builder. You can instal into an existing package or into a new one, which it will create for you.
I would say that the best way to install components is to use your build manager (for example FinalBuilder) and add each component to a manager-project file which sets the necessary paths, builds the DPK files, and 'installs' the component in the IDE by making a registry entry. That way you have a documented procedure which allows you reliably to set up or repair your complete, tested, Delphi development environment. You can simply re-run the project when a component has been updated and tested. It is also quite easy to tweak an existing project to handle a new Delphi version.
The big disadvantage of a vendor-supplied installer is that all the ones I have seen simply overwrite the previous version on updates. I prefer to control the install myself, so that I have previous component source versions archived and available for comparison, in case testing reveals a problem with an upgrade. The 'one-click install' sounds fine, until a minor component upgrade suddenly causes your application to stop working.
Take a look at "Lazy Delphi Builder". It was created to simplify build/installation of many components at once. It resolves packages dependencies automatically. Free to use.
Link to some old tutorial

Custom component dependency hell

I'm trying to make a package for a custom component I made. It's based on several libraries, including Graphics32, GraphicEx and CCR.Exif.
I created a Package project, wrote the unit including its Register procedure, added some extra references Delphi notified me about to the requires section (including dbrtl.dcp, inet.dcp, soaprtl.dcp, vclimg.dcp, xmlrtl.dcp and dclGraphicEx140.dcp) and added many units to the contains section to avoid warnings about it happening implicitly. The project compiles and can be installed and used on my own machine without issues. However, when I want to install it on another machine, the troubles begin. In the end, I had to copy about all DCUs from all 3rd party components I used, plus both the DCP and BPL from GraphicEx, which I had to install even.
Supplying a lot of files is a bummer, yet surmountable, but having to install other packages as well is a no go. I could get rid of that DCP and BPL by putting even more units in the contains section, but that resulted in error messages on my own machine where GraphicEx is actually installed. This is confusing to me, because with Graphics32 nothing like that occurs...
Anyway, how do I keep my distribution to a minimum and avoid such situations? I want other developers on my team to be able to use the package without worrying about what I used to build it. For a start, can't all the 3rd party units be compiled into my own DCU?
What you experienced is an usual thing to the ones who write components. The distribution is always like that. Packages do not carry other packages, insted they reference them. It´s in their nature.
In order to overcome such a situation I always treat my components in the same way I would if they were a product to sell: I build a setup wizard that distributes and registers everything the package needs.
In my case InnoSetup works very well (http://www.jrsoftware.org/isinfo.php).
Summary
Haven't use Delphi for a while, but, did develop my custom visual controls (Last version I work was Delphi 6).
There are 2 issues when dealing with packages dependencies. One is installing at the Delphi enviroment, making controls appear on the component palette, plus, component editors & property editors.
And another when distributing the compiled packages into customers machines.
It also depends, on which version on Delphi you are running.
Design Time
When developing a custom package, there is a tab for package options, that indicates the destination folders.
The manuals usually tell the developers to leave those textboxes empty. That sometimes works, sometimes doesn't. I explicity write each folder path, in the respective textbox.
There is a textbox path for the ".dcp" files, other for the ".dcu", and so on.
If you have visual controls and stuff like property editors or component editors, its better to split the code in 2 packages ("Runtime" & "Designtime").
I usually put the delphi (packages) projects outside the delphi installation folder.
Run Time
Usually, the quick way is to put the "*.bpl" ".dcp" files in the Windows (32) / system folder, or similar "DLL" windows folder.
Packages folder structure source code suggestion
Managing packages can be difficult. I don't know how much the installation process has changed with Embarcadero, and the newer versions of Delphi. The following chart,is an example on how organize the source code. Hope it helps.
[-]--+--c:
.....|
.....+--[-]--+--software
.............|
.............+--[+]-----java
.............|
.............+--[+]-----php
.............|
.............+--[-]--+--delphi (not the delphi folder in program files)
.....................|
.....................+--[+]-----apps (source code for delphi programs)
.....................|
.....................+--[+]-----other
.....................|
.....................+--[-]--+--packages (all delphi packages source code here)
.............................|
.............................+--[+]-----lib (a single package for non visual controls, libraries)
.............................|
.............................+--[+]-----tools (package pair for non visual tcomponent descendants)
.............................|
.............................+--[+]-----json (example)
.............................|
.............................+--[+]-----xml (example)
.............................|
.............................+--[-]--+--mycontrols (folder custom visual controls)
.............................|.......|
.............................|.......+--[-]--+--delphi40 (folder for delphi40 version of "mycontrols")
.............................|.......|.......|
.............................|.......|.......+----------dsgvclctrls40.dpk (design-time package "mycontrols")
.............................|.......|.......|
.............................|.......|.......+----------runvclctrls40.dpk (run-time package "mycontrols")
.............................|.......|.......|
.............................|.......|.......+--[+]--+--demos (individual example for each "mycontrol")
.............................|.......|.......|
.............................|.......|.......+--[+]--+--design ("*.pas" component editors destination folder)
.............................|.......|.......|
.............................|.......|.......+--[+]--+--sources ("*.pas" source code destination folder)
.............................|.......|.......|
.............................|.......|.......+--[+]--+--bin ("*.dcu" destination folder)
.............................|.......|........
.............................|.......+--[+]--+--delphi50 (folder for delphi50 version of "mycontrols")
.............................|.......|........
.............................|.......+--[+]--+--delphi60 (folder for delphi60 version of "mycontrols")
.............................|.......|........
.............................|.......+--[+]--+--delphi70 (folder for delphi70 version of "mycontrols")
.............................|................
.............................+--[-]-----etc...
Cheers.
Thijs, you simply cannot do that with only a package. The target developer will require almost everything you added to the package. But there is an alternate way of doing what you want: Build a DLL with all the components/libraries you are using in your own component and wrap all those external components/libraries into some code you will export from the DLL. Then build your component without using the external components directly but the DLL you've built. You cannot in you component "use" any unit of the other external components/Libraries. You have to build a new unit with all the datatypes and required declaration for anything you export from your DLL. All this is perfectly working but will quickly becomes very complex for a large number of external components or libraries.
I think AlexSC has the best answer, but I think there might be an alternative if you ansolutely must have a custom component that has no dependencies.
I ran into the Delphi dependency frustrations a little while back trying to create an in-house component for our developers. My suggestion:
Uninstall all dependencies your component uses
In your component package, remove the above dcp from the requires section from your package.
Copy the source files of your dependencies to your components
When you distribute the component, you'll have to distibute it with the code of the required dependecies
You'll run into issues if you want to use the dependcies separately since Delphi won't allow you to have duplicate unit names in installed packages.
Also, the reason you don't want to use DCUs is the fact that the DCUs are compiled for a specific platform and compiler. So unless you are sure that all devolpers are on the same platform ad using the same version of Delphi, dependency code needs to be recompiled.
Again, AlexSC has the best answer and InnoStudio is a great little tool.

Resources