Recent

Author Topic: Compiling a unit  (Read 1840 times)

Riccardo Ferrari

  • New member
  • *
  • Posts: 8
Compiling a unit
« on: January 21, 2024, 05:51:31 am »
I have written some units which, when compiled and placed in the appropriate directories (i.e. C:\FPC\3.2.2\units\x86_64-win64\ and C:\FPC\3.2.2\units\i386-win32\), allow the compilation of the executable which calls them.
So far, so good.
Except that I have written a unit (let's call it Alpha) that calls other units. After compiling the main unit (i.e. Alfa), I thought it would be enough to just put it in the above directories.
But no, by compiling an executable that calls Alfa, the units called by Alfa are also called.
What does this mean? Once an EXE has been compiled, the units it calls could also be deleted, the EXE works on its own. If I compile a unit instead, why does it have to keep the units it contains?
I wonder if, among the thousands of switches that can be activated during compilation, there is one that causes the called units to be included in the main unit, so as not to multiply the files needed for subsequent compilations.
Thanks for your attention.

ccrause

  • Hero Member
  • *****
  • Posts: 958
Re: Compiling a unit
« Reply #1 on: January 21, 2024, 06:28:32 am »
Think of the whole process of producing an executable as compiling all referenced units (including the main program file) to individual object files (and corresponding ppu files with extra information used by the compiler), followed by linking all the object files into the final executable. Only during the linking stage will all the various bits of code from different units be combined into a single file.

Riccardo Ferrari

  • New member
  • *
  • Posts: 8
Re: Compiling a unit
« Reply #2 on: January 21, 2024, 08:36:11 am »
Thank you for your attention.
So it's not possible. If I understood you correctly (English is not my language).
Quite surprising.
I have the Alpha unit calling the Beta unit.
The Gamma program uses the Alpha unit, but only Alpha, not Beta.
If I compile Gamma, I must also have Beta.
There is no other way. Have I got it right?
But if I copy and paste Beta into Alpha and compile, I get an Alpha unit.
When you compile Gamma, you no longer need Beta, just Alpha.
Beta doesn't exist anymore.
I think that's what I'll end up doing.
I wonder why there isn't a compile instruction to do this automatically. Commad line switch or {$ Something}.

TRon

  • Hero Member
  • *****
  • Posts: 3463
Re: Compiling a unit
« Reply #3 on: January 21, 2024, 08:48:40 am »
I wonder why there isn't a compile instruction to do this automatically. Commad line switch or {$ Something}.
There isn't such a compiler option because logically that idea is flawed (f.e. it complicates and slows down the compilation process by margins). Having said that you can 'simulate' your inclusion of beta into alpha by using the $include directive.

That way the copy-paste as you write it can be done at compilation time by the compiler automatically. Using a define could then make that 'simulation' optional as a define can be 'passed' to the compiler.
« Last Edit: January 21, 2024, 08:53:20 am by TRon »
This tagline is powered by AI

ccrause

  • Hero Member
  • *****
  • Posts: 958
Re: Compiling a unit
« Reply #4 on: January 21, 2024, 09:45:41 am »
Thank you for your attention.
So it's not possible. If I understood you correctly (English is not my language).

Correct, it is not possible. Except of course with alternative techniques, as mentioned by TRon or as a library.

The whole point of the unit system in Pascal is to modularize the code. You can read up on the concept here: https://en.wikipedia.org/wiki/Modular_programming
But to me that article doesn't really explain the technical reason why your requirement of folding a sub unit into a unit is not considered smart.

As an example, lets consider a unit A, which uses unit B. Then a main program uses both unit A and unit B.  After compilation the following object files would be created if combining units as early as possible: A (containing a copy of B), B, program. Here the code for B would be repeated in A, inflating the size of A.  It seems beneficial because object A contains all the code it requires, but it leads to wasted space.  There are two copies of the code for B, which is a waste of space.

Another way to look at it - if unit B contains code that is only ever used by unit A, there is no point in splitting the code into two units.  If unit B contains code that can be called by any other unit/program, it doesn't make sense to combine the units early, since it could lead to code duplication and wasted space.

An alternative idea would be to create a library, which can be seen as a collection of units compiled into a single file. Of course this library usually stays a separate file, except when using static linking. But this could also lead to code duplication if unit A is used both in the library and the program linking to the library (at least I think so, not checked).

Riccardo Ferrari

  • New member
  • *
  • Posts: 8
Re: Compiling a unit
« Reply #5 on: January 21, 2024, 09:58:48 am »
There isn't such a compiler option because logically that idea is flawed (f.e. it complicates and slows down the compilation process by margins). Having said that you can 'simulate' your inclusion of beta into alpha by using the $include directive.
Thanks for the suggestion, but it's not possible. Unless there are techniques I don't know about.
Having a finished unit, i.e. compilable, it is not possible to use {$INCLUDE filename} and leave the source code as it is.
There would be conflicts between the different sections (implementation, interface and variable declaration), also possible duplicate names.
You will have to do a selective copy and paste, editing the source code, so you will have to work on it a bit more.
If it were possible to include the units at compile time, all this would be avoided. But apparently that's not possible. My low culture as a programmer (non-professional) doesn't allow me to understand why.

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1174
Re: Compiling a unit
« Reply #6 on: January 21, 2024, 10:43:08 am »
Quote
Except that I have written a unit (let's call it Alpha) that calls other units.
@Ricardo do you mean uses other units?

Another thing I'd like to mention since you are new is that its possible to do circular reference to units in pascal without trouble by hiding references to units in uses after the implementation keyword.
« Last Edit: January 22, 2024, 12:20:18 pm by Joanna »
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

egsuh

  • Hero Member
  • *****
  • Posts: 1468
Re: Compiling a unit
« Reply #7 on: January 21, 2024, 10:45:14 am »
I do not understand you exactly, but a unit is compiled when it is included in "uses" clause. So, if your unit alpha uses unit beta, there is no way not compiling beta.

Code: Pascal  [Select][+][-]
  1. unit Alpha;
  2.  
  3. uses classes, sysutils, BETA;  // <== here.
  4.  

If you want not to compile Beta in a program called Gamma which call alpha, beta will be compiled.
And if it is possible to exclude BETA in Gamma, why is it included in the uses clause from the beginning?
I cannot understand this, but if this is true anyway, you can define custom options in project options.
And let's assume that your first program has definition of ALPHA as a custom options. Then

Code: Pascal  [Select][+][-]
  1. unit Alpha;
  2.  
  3. uses classes, sysutils {$ifdef ALPHA}, BETA{$end};  // <== here.
  4.  

BETA will not compile in project Gamma.

Riccardo Ferrari

  • New member
  • *
  • Posts: 8
Re: Compiling a unit
« Reply #8 on: January 21, 2024, 12:46:59 pm »
I do not understand you exactly, but a unit is compiled when it is included in "uses" clause. So, if your unit alpha uses unit beta, there is no way not compiling beta.
I know, and I have compiled Alfa, which also compiles Beta.
So I thought that the Beta code was contained in Alfa.

If you want not to compile Beta in a program called Gamma which call alpha, beta will be compiled.
And if it is possible to exclude BETA in Gamma, why is it included in the uses clause from the beginning?
Beta is not used by Gamma, only by Alfa.
I have a program called Gamma which uses Alfa but not Beta.
When I try to compile Gamma, FPC asks me for Beta.
I thought that Alfa would be sufficient as it contains the Beta code.
This does not seem to be possible: I need both Alfa and Beta to compile Gamma,  even Gamma doesn't call Beta.
Thanks for your attention.

cdbc

  • Hero Member
  • *****
  • Posts: 1571
    • http://www.cdbc.dk
Re: Compiling a unit
« Reply #9 on: January 21, 2024, 01:54:11 pm »
Hi
I'd recommend this light reading for you: http://www.copperwood.com/pub/FreePascalFromSquareOne.pdf
...And the one from Marco Cantu, that I've attached...
HTH
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

MarkMLl

  • Hero Member
  • *****
  • Posts: 7864
Re: Compiling a unit
« Reply #10 on: January 21, 2024, 04:08:33 pm »
OP: I suspect that you're labouring under the misapprehension that anything that starts "unit" builds a library containing all referenced units, and something labelled "program" builds the main unit and orchestrates the linker ("link editor" or "binder" on some platforms).

That's wrong: each source file creates a .o, .ppu etc. containing only what was in that file, and then the linker pulls them all together into an executable. As such it's very similar to C etc. and for that matter to pre-Borland Pascal implementations in which you benefit enormously from using a makefile. The difference is that FPC, like Delphi etc., handles the tree of dependencies rooted in the program file automatically: each file is (re)compiled when necessary and then the linker is run.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

TRon

  • Hero Member
  • *****
  • Posts: 3463
Re: Compiling a unit
« Reply #11 on: January 21, 2024, 04:09:27 pm »
Thanks for the suggestion, but it's not possible.
Sure it is  :)

Been there done that ...

Quote
Unless there are techniques I don't know about.
Then as suggested by cdbc some reading might be able to shed a light (manuals, references, wiki's, books and writings on the subject usual usually do).

You might try with a read on modular programming.

Quote
Having a finished unit, i.e. compilable, it is not possible to use {$INCLUDE filename} and leave the source code as it is.
Another approach, other tactics.

Quote
There would be conflicts between the different sections (implementation, interface and variable declaration), also possible duplicate names.
You will have to do a selective copy and paste, editing the source code, so you will have to work on it a bit more.
If it were possible to include the units at compile time, all this would be avoided. But apparently that's not possible. My low culture as a programmer (non-professional) doesn't allow me to understand why.
Really read up on modular programming and if you are able to grasp the concept then try building your own compiler.

ccrause explained it perfectly and I also hinted that your idea would not be feasible for at least provided some reasons (but there are many more) why it would be bad to support it.

Basically it boils down to modularity and what is the best/quickest/smartest approach to achieve that goal.

Question for thought: if you are really keen to have everything included in one big pile then, why even bother using units ? Everything fits in the main program file and make things easier as you do not have to rely on any dependency/ies whatsoever.

Gamma.pas
Code: Pascal  [Select][+][-]
  1. program gamma;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Alpha;
  7.  
  8. begin
  9.   Hello_Alpha;
  10. end.
  11.  

alpha.pas
Code: Pascal  [Select][+][-]
  1. unit alpha;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. {$ifndef all_inclusive}
  8. uses
  9.   beta;
  10. {$endif}
  11.  
  12.  
  13.   procedure Hello_Alpha;
  14.  
  15.   {$ifdef all_inclusive}
  16.     {$include beta_h.inc}
  17.   {$endif}
  18.  
  19. implementation
  20.  
  21.   {$ifdef all_inclusive}
  22.     {$include beta_i.inc}
  23.   {$endif}
  24.  
  25. procedure Hello_Alpha;
  26. begin
  27.   writeln('hello Alpha');
  28.   Hello_Beta;
  29. end;
  30.  
  31. end.
  32.  

beta_h.inc
Code: Pascal  [Select][+][-]
  1.   procedure Hello_Beta;
  2.  

beta_i.inc
Code: Pascal  [Select][+][-]
  1. procedure Hello_Beta;
  2. begin
  3.   writeln('hello Beta');
  4. end;
  5.  

beta.pas
Code: Pascal  [Select][+][-]
  1. unit beta;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7.   {$include beta_h.inc}
  8.  
  9. implementation
  10.  
  11.   {$include beta_i.inc}
  12.  
  13. end.
  14.  

That is perfectly do-able without changing any code or shuffle things around. It is always a good idea to think about a approach before writing down even a single line of code.

Don't forget to compile with the define all_inclusive to have beta routines included into alpha unit.
« Last Edit: January 21, 2024, 04:11:04 pm by TRon »
This tagline is powered by AI

Riccardo Ferrari

  • New member
  • *
  • Posts: 8
Re: Compiling a unit
« Reply #12 on: January 22, 2024, 02:19:53 am »
Thanks to all of you.
I have given up on the idea.
I understand it can't be done.
I put all the units in, not just the one that contains them all.
Maybe when I study I'll understand why. For now, I understand that it can't be done.

 

TinyPortal © 2005-2018