Hi people,
Is it possible to keep certain classes implementation in a shared library and export it out directly by some native object pascal ways?
A related question: wouldn't it make sense to have an option to make interface and implementation sections separate (kind of modula-2 or something)? I guess this works like that internally in fpc, since resulting .ppu and .o are separate files.
Mailing lists / fpc-pascal / 2002-07
shared libraries interface
27 messages · 6 people · –
- FFlorian Klaempfl 7
- JJonas Maebe 6
- NNikolai Zhubr 5
- MMichael Van Canneyt 4
- FFull_Name 3
- MMarco van de Voort 2
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
Nikolai Zhubr wroteIs it possible to keep certain classes implementation in a shared library and export it out directly by some native object pascal ways?
No, that is not possible at this time.
A related question: wouldn't it make sense to have an option to make interface and implementation sections separate (kind of modula-2 or something)? I guess this works like that internally in fpc, since resulting .ppu and .o are separate files.
This was discussed recently (not on a public list though) and we decided we'd probably implement this the way Virtual Pascal already supports it (so that not yet another syntax has to be invented). No-one started working on this yet though.
Jonas
Hi
Wednesday, 31 July, 2002, 16:38:48, Jonas Maebe wrote: [...]
Show quoted text 9 lines
Great!
Could you give some refs so that I could find out how this will probably look like?
Nikolai Zhubr wrote 8 lines
Here's a mail from someone that explains it:
***
Show quoted text 7 lines
.
.
If we do it (and I think it's a good idea, in fact), I'd suggest to do it in VP compatible way. Quoting from VP documentation about $PureInt compiler directive (note - VP supports & as yet another prefix for compiler directives in addition to $):
******
&PureInt (Switch: Default=&PureInt- Type=Global)
Forces a unit to be a pure interface unit. To supply a unit's object code without source code and be sure that it works even if the format of the .VPI files changes, a pure interface unit for should be created. To do this, it must contain {&PureInt+} directive at the start of the unit and the entire interface part of the unit. The implementation part of the unit should be removed, except for the uses clause (if applicable). If the unit has an initialisation part, the initial begin should be included as well:
implementation
uses
Dos,Crt;
begin
end.If no initialisation part is present, the begin should be left out:
implementation
uses
Dos,Crt;
end.The {&PureInt+} directive forces the compiler to ignore undefined forward references to procedures, functions and methods and assume that they are implemented in the original version of the unit, in the form of a .OBJ or .LIB file. No object file or library is generated for a pure interface unit, meaning that a newer version of the compiler can be used to create an appropriate .VPI file for it and still use the object file or library produced from the original unit by the old version of the compiler. In the default {&PureInt-} state, a unit is assumed to implement the interface part as usual. Note: Those parts of the Virtual Pascal Run-Time Library that are derived from source code copyrighted by Borland Int are supplied as Pure Interface units; the full source code is supplied as upgrade patches that requires the original source code to be available.
*******
Not that it would really matter, but why to invent something incompatible?
Tomas
***
Hi
Thursday, 01 August, 2002, 22:54:23, Jonas Maebe wrote: [...]
> Great! > Could you give some refs so that I could find out how this will > probably look like?
[...]
The {&PureInt+} directive forces the compiler to ignore undefined forward references to procedures, functions and methods and assume that they are implemented in the original version of the unit, in the form of a .OBJ or .LIB file. No object file or library is generated
Ok. Then would it make much difference to resolve them to a shared library instead of a static one (Optionally)?
Quoting Nikolai Zhubr :
Ok. Then would it make much difference to resolve them to a shared library instead of a static one (Optionally)?
For clases, this would be nice (somthing like packages in Delphi??) For Procedures and Functions, can't you just add "external 'MyLib';" to the end of the items? IIRC FPC will even allow variables to be exported, something that Borland compilers don't do.
One other point.. surely the interface is there just for the convenience of the developer - like a C header file. The bad thing about C header files is that they're *required*. It would be nice to allow the pure interface to still be optional. The compiler could simply ignore it, after all you *can't* change it in any way because the object file is fixed. it's dangerous imho to give developers the ability to use a pure interface and an object file, but still allow them to add/remove symbols from the interface. Surely the point of dcu/tpu's is that they are uneditable.. the pure interface would simply make it easier to see what the unit exported in its interface.
Matt
Full_Name wroteOne other point.. surely the interface is there just for the convenience of the developer - like a C header file.
No, it's mainly to guarantee portability between different compiler versions. The problem is that the ppu files are compiler versino dependent, so if you want to distribute a unit without the source, you have to re-distribute it every time a new compiler version is released (if the ppu format has changed at least), which is not very nice. With the interface-only units, you distribute an object file and an interface and people can use the unit, no matter which versio of the compiler they use (in theory at least :)
Jonas
Jonas Maebe wrote 15 lines
I don't see the use of such a construct:
A. If the internal naming conventions of the compiler change, chances are that the object file is useless anyway. B. If the internal alignment rules for constants, sets, records and I don't know what change, then you're stuck as well. Since with a new compiler version, you are not guaranteed that these things have not changed, this rather defeats the purpose of the unit as you will be forced to redistribute anyway.
So I see no real use for a 'interface-only' unit.
What is more, you can easily make o an 'interface-only unit' now. The easy way is to have all functions in a separate object file and create a unit that just contains the needed definitions.
This is already possible as follows:
-----------------------------------------------------------------------
unit something;
interface
{$l realsomething.o} // Contains actual implementation.
Procedure Dosomething; External name 'DoSomething';
Implementation
end.
-----------------------------------------------------------------------The object file can be created compiling the following:
-----------------------------------------------------------------------
unit realsomething;
interface
Procedure Dosomething; [alias: 'DoSomething'];
Implementation
Procedure DoSomething;
begin
DoSomething
end;
end.
-----------------------------------------------------------------------The something.pp unit can be distributed, together with the realsomething.o file. No compiler support needed.
But this will still suffer from the same problem (B) as the 'interface-only' unit.
Michael.
No, it's mainly to guarantee portability between different compiler versions. The problem…
Quoting Jonas Maebe :
Show quoted text 9 lines
But the interface is still to be thought of as 'read only' ? Otherwise, it would be possible to alter the interface... not good for maintenance.
eg. consider the following...
unit whatever;
{$pureint+}
interface
uses x, y, z;
type
TSomeEnumType = (set1, set2, set3, set4);
type
TMyClass = class
{...}
function SomeFunction(x: TSomeEnumType): string;
function SomeFunction2: TSomeEnumType;
procedure SomeProcedure(x: TSomeEnumType);
property X: TSomeEnumType read getX write setX;
{...}
end;
end.What would happen if I compiler this, gave it to people, and someone changed TSomeEnumType? For example to the following:
TSomeEnumType = (setNone, set1, set2, set3, set4, set5, set6);If I had written code internally well, hopefully not too much would break, but I still think this is dangerous. This is one reason why the DCU/TPU concept arrived in the first place.
Matt
No, it's mainly to guarantee portability between different compiler versions. The problem…
you wrote 8 lines
This isn't 100 per cent correct ;) The binary format of 1.0.4 ppus and 1.0.4 ppus is the same. The point is that the system unit interface changed slightly, thus the ppu for the system unit of 1.0.4 and 1.0.6 is different, i.e. the indizies for the types, vars, procedures in the system unit changed from 1.0.4 to 1.0.6
Show quoted text 14 lines
I don't see the use of such a construct: A. If the internal naming conventions of the…
you wrote 23 lines
If the system unit gets a new type/var/proc/...or even if you reorder the source code of the system unit the indizies for some system unit ppu entries change => ppus compiled with older systems unit doesn't work anymore though neiter A. nor B. apply :)
Show quoted text 8 lines
But it doesn't work flawless with objects and classes etc. I think and you've to maintain to sets of interfaces or you've to use lot of ifdefs...
Quoting Jonas Maebe : But the interface is still to be thought of as 'read only' ?…
Full_Name wrote> No, it's mainly to guarantee portability between different compiler > versions. But the interface is still to be thought of as 'read only' ?
It's a simple text file, so you can't prevent someone from changing it.
Otherwise, it would be possible to alter the interface... not good for maintenance.
I don't see how you could prevent that.
[snip]
If I had written code internally well, hopefully not too much would break, but I still think this is dangerous. This is one reason why the DCU/TPU concept arrived in the first place.
We have ppu's which serve a similar purpose. The problem is that they aren't always portable across different compiler versions, hence the pure interface units (which can then be compiled to ppu files by the people that want to use the unit, without needing access to the implementation). Of course, the solution that Michael proposed in his mail also works...
Jonas
Quoting Jonas Maebe : But the interface is still to be thought of as 'read only' ?…
you wrote 49 lines
Of course, but see my other mail which decribes the problems with the indizies and this problem comes from the binary DCU/TPU concept. While the pureint concept would allow to recompile the interface and everything would be fine.
I don't see the use of such a construct: A. If the internal naming conventions of the…
Hi
Michael Van Canneyt wrote 9 lines
Ok. First, traditional "wrapper" units like your example get not that good-looking if there are 1000 or more externals to declare, and in case that full pascal source is available, <U> which i'm only talking about </U>, it is just kind of source code duplication, it looks not elegant, it is an additional source of typos and bugs, and it does not seem to really provide *something* that would be essentially missing from the project otherwise (In the case of *pure* pascal project with full source available)
But actually I was thinking about some different point when I asked. That is, about how to put some classes implementation into a library (preferrably shared one). The example below won't help much here :(.
BTW, now I've got an impression that VP's approach is only good for hiding sources. Well, it wasn't designed for anything else.
If the system unit gets a new type/var/proc/...or even if you reorder the source code of…
Florian Klaempfl wrote 31 lines
So you're only my case stronger =-)
Show quoted text 13 lines
But the same is true for interface-only units, so you're in trouble in any case...
My conclusion is that interface-only units are useless, and not worth the effort.
Michael.
you wrote 12 lines
No, with pureintf it would work without any problems ...
Show quoted text 15 lines
No they aren't :). Consider a large library which is closed source (most of us don't like it, but they exist.) Even if we added only one entry to the system, this packages isn't usable anymore with 1.0.6 if it was compiled with 1.0.6. With the pureintf stuff it would be still usable because neither A. nor B. did happen between 1.0.4 and 1.0.6 :)
Hi Ok. First, traditional "wrapper" units like your example get not that good-looking if…
Nikolai Zhubr wrote 22 lines
I didn't claim all that, of course
I just don't see the point of the interface-only unit.
Show quoted text 5 lines
in my opinion, there is no good way to do that.
Only interfaces or packages � la Delphi will allow you to do this.
BTW, now I've got an impression that VP's approach is only good for hiding sources. Well, it wasn't designed for anything else.
But you don't need interface-only units for that ? Simply don't distribute the sources.
Strip the interface part and distribute it together with the .ppu. You must do that anyhow for almost each compiler version. (hopefully I demonstrated that convincingly enough) , so...
Michael.
you wroteYou must do that anyhow for almost each compiler version.
No, it isn't necessary.
(hopefully I demonstrated that convincingly enough)
No, you didn't :) with 1.0.4 and 1.0.6 the pureintf stuff would have worked perfectly.
Florian Klaempfl wroteAt 15:24 02.08.2002 +0200, you wrote: >You must do that anyhow for almost each compiler version. No, it isn't necessary.
You don't know that in advance.
Show quoted text 5 lines
That is pure coincidence. With all other released versions it would not have worked. And there is no guarantee for the future. 1.2/2.0 will definitely mess things up, so, why bother ?
Michael.
you wrote 8 lines
I think it will work for all future 1.0.x versions.
Show quoted text 9 lines
That's true of course, but with 1.0.8 it will still work I think.
I didn't claim all that, of course I just don't see the point of the interface-only unit.…
Show quoted text 9 lines
The vendor of that unit must then recompile for each release, and if e.g. a customer has to use some snapshot (e.g. for a bug), he has to recompile it with that also.
You don't know that in advance. That is pure coincidence. With all other released…
Michael Van Canneyt wrote 7 lines
Because with 1.2.x/2.0.x it will most likely work again.
Jonas
Of course, but see my other mail which decribes the problems with the indizies and this…
Quoting Florian Klaempfl :
Of course, but see my other mail which decribes the problems with the indizies and this problem comes from the binary DCU/TPU concept.
Surely the pureint is just a workaround. A hacky a better solution could be found by looking at the way other compilers do things, I'm no expert so I can't say. I don't feel happy with this idea as a solution. It just 'papers over the cracks' imo. The concept of the compiled unit is at fault. You're basically using a concept introduced to Turbo Pascal circa V2 (iirc) in the early part of the 1980's. Maybe Modula or some later language based on Pascal has a better idea? Having struggles with Delphis woefully inadiquate component streaming mechanism all afternoon, I would like to see something like the package concept in java, and the dynamic class loading. (just try getting Delphi to open a DFM without having to explicitly registed all of the components on the form - even if you don't know what they will be beforehand.)
While the pureint concept would allow to recompile the interface and everything would be fine.
Unless there is some way of verifying that the interface in untampered with (a third file? a checksum?) and the compiler either will not compile the source or at the very least issue a compiler warning, I'll not be using the feature personally. There are some many better ways of doing this I think (another idea, ADA uses 'specification/header' and 'body' to split the code.) Moving away from the concept of a 'Unit' would make the usage clearer/cleaner and less prone to problems with understanding.
Matt
Full_Name wrote 5 lines
ADA always uses two files: one for the interface, one for the implementation. I doubt you can recompile the interface without recompiling the implementation as well.
Jonas
Show quoted text 11 lines
Idem for Modula-2, though my compiler had a directive for a kind of interface-only module, like Florian proposed.
Otherwise, if the date of the interface file in the compiled module is older than the one that is found, the compiler will ask for the implementation, just like FPC.
Quoting Florian Klaempfl : Surely the pureint is just a workaround. A hacky a better…
Hi
Full_Name wrotejust 'papers over the cracks' imo. The concept of the compiled unit is at fault. You're basically using a concept introduced to Turbo Pascal circa V2 (iirc) in the early part of the 1980's. Maybe Modula or some later language
Well, yes, nobody had to bother about .so's or .dlls in 1980's perhaps :)
Unless there is some way of verifying that the interface in untampered with (a third file? a checksum?) and the compiler either will not compile the source or at the very least issue a compiler warning, I'll not be using the feature personally. There are some many better ways of doing this I think (another
Hmm. Are there any checksums currently used to ensure that some unit needs to be recompiled? I guess no, just date/time. And, if definition and implementation were kept in separate files, the same logic could be applied: implementation should be recompiled along with other dependants whenever definition has changed (has more recent date/time). This won't help in distributing closed-source units though, but I personally don't care about that.
idea, ADA uses 'specification/header' and 'body' to split the code.) Moving away from the concept of a 'Unit' would make the usage clearer/cleaner and less prone to problems with understanding.
I'm just looking into an ADA book - apparently yes, spec/body can be separate there (No big surprise). IIRC modula-2 is even more clear in this respect, and it is much closer to pascal :)) Perhaps it's worth considering.
you wroteHmm. Are there any checksums currently used to ensure that some unit needs to be recompiled? I guess no,
Yes, of course. A CRC checksum is build.
