Topic: n1496
Author: s_googlegroups@nedprod.com (Niall Douglas)
Date: Fri, 28 May 2004 02:02:03 +0000 (UTC) Raw View
On Thu, 27 May 2004 17:17:54 +0000 (UTC), llewelly
<llewelly.at@xmission.dot.com> wrote:
> s_googlegroups@nedprod.com (Niall Douglas) writes:
> [snip]
>> Note that for every symbol which is available outside its DSO, a
>> particularly expensive form of relocation must also be performed at
>> load time which on all implementations I know of is quadratic to
>> symbol number. See Ulrich Drepper's "How to write shared libraries".
> [snip]
>
> This is actually an argument for having symbols not visible by
> default.
An *implementational* argument for having symbols not visible by default.
With a C++ hat on, one would say that it's the compiler & linker's problem
to most efficiently turn my C++ into the best binary possible. However
with an implementational hat on, one quickly realises that's far from
trivial without additional annotation in the source.
The original poster felt that the compiler & linker could do just fine
with symbols default public. I was illustrating that default public comes
with unacceptable costs and even with improved compiler technology it's
not going to change any time soon.
>> No you're wrong here. A static symbol is indeed hidden in that it
>> cannot be directly referenced outside its compiland. This is not true
>> for the contents of unnamed namespaces - they merely add extra
>> mangling to the symbol which actually makes the problem worse (longer
>> load & linking times and more code bloat).
>
> This is true for current implementations, but does it *need* to be
> true?
>
> Why might an implementation need to make a symbol inside a unnamed
> namespace visible at dynamic link-time?
Off the top of my head, if a type with a vtable were defined within the
unnamed namespace and then a pointer to it typeid()'d in some other
compiland the compiler would need the typeinfo to be available.
Therefore it probably needs to be true - it's certainly /easier/ if it's
true. Certainly it's true everywhere I've seen so far. If a linker were
more clever, it could speculatively hide symbols which weren't used but
that breaks if you use shared libraries where it must export everything
just in case.
Again, an argument for extra annotation of the source. Only the programmer
can really say if a symbol will be used externally or not.
Cheers,
Niall
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: f5xz2bk02@sneakemail.com (Davide Bolcioni)
Date: Fri, 28 May 2004 02:05:20 +0000 (UTC) Raw View
Niall Douglas wrote:
> On Wed, 26 May 2004 02:46:35 +0000 (UTC), Davide Bolcioni
> <6805b3x001@sneakemail.com> wrote:
>> in other words, "gcc -c" might
>> produce an "unfinished" object file where this choice of access is
>> deferred, to be resolved when "gcc" is invoked for the final link step
>> just before handling .o files to the linker (nobody said you have to
>> give the linker exactly the same .o files you started with). Since the
>> decisions in this step are C++ specific, it is the compiler's job,
>> not the linker's.
>
> Not exactly. How ELF does shared libraries means that the app can load a
> shared library and symbols from that can overwrite symbols currently
> defined eg; printf() calls one implementation before and then calls a
> different one thereafter.
This seems to me a violation of the One Definition Rule of C++, so I
should think that: a) the compiler should not produce code causing such
to occur; b) if the programmer causes this to occur within the Makefile,
he had better know what he's doing; c) overwriting symbols is however
useful at times.
> This requires the compiler to always have at
> least the equivalent overhead of a virtual function call. Even with WPO
> you can't elide this - to do so breaks things unless you assume no new
> libraries will be loaded.
Supporting (c) indeed seems to require double indirection; however, I
recollect investigations from KDE people about C++ dynamic linking in
Linux showing that relocations, not indirection, were the main source
of overhead and suggesting prelinking as a solution.
If a member function is already virtual, this is a non issue unless the
implementation doubly indirects (I have not investigated this); if not,
then we have a performance problem if the function is not inline, yet
small enough that the overhead of the virtual call is significant, and
called often. I have seen it happen, although not in recent years, but
not very often (mostly constructors).
> Note that for every symbol which is available outside its DSO, a
> particularly expensive form of relocation must also be performed at load
> time which on all implementations I know of is quadratic to symbol
> number. See Ulrich Drepper's "How to write shared libraries".
Will do.
>> In other words, C/C++ programmers already take a visibility decision in
>> the code, using the language-provided means which the underlying
>> implementation is required to support.
>
> This is not true for the
> contents of unnamed namespaces - they merely add extra mangling to the
> symbol which actually makes the problem worse (longer load & linking
> times and more code bloat). Why don't unnamed namespaces hide their
> contents? Because "export" causes searching of unnamed namespaces
> outside its compiland!
I have not investigated the ramifications of "export" enough to comment
on this; more to come in the future.
>>> I also feel that whether something is visible outside its DSO/DLL is
>>> part of its API spec and thus interface contract. If you disagree
>>> with this, consider how public/protected/private relate to class
>>> design and note that similar logic applies to both.
>>
>> It seems to me that you are unwilling to abstract from the concrete
>> implementation; if what you're after is a further layer of
>> modularization, you might want to research "module" concepts such as
>> those found in Modula languages or the "package" concept of Java.
If I write that a member function is private, I mean exactly that; it
cannot be called from outside the class. The mangled symbol for its
implementation should not require double indirection to reach, once
WPO coalesces invocations from separate .o files; if the programmer
puts some implementations in a .so and some in another, double
indirection would be required and a comment in the standard should
warn of the associated performance cost. Most programmers would
not do that.
The above, however, still allows the programmer to overwrite symbols
through linker directives, or even by making the "mistake" of putting
the implementations he wants to override in a separate .so, causing
the compiler to use double indirection and all that.
If I write that said member function is protected, I am making an
entirely different statement: any member function of a derived class
can invoke it. The set of callers is open-ended and might include
plugins accessed with dlopen(); if the symbol is not visible, a
plugin could be written which is legal C++, compiles, but fails at
dlopen() time (this can happen today with some doctoring of the ELF
binary, unless I'm mistaken, but is clearly a bug).
The C++ language, by itself, does not allow you to directly restrict
the set of classes derived from a base class, although posting the
problem on comp.lang.c++.moderated might turn out a clever workaround;
if such a feature were necessary and introduced, I would certainly want
the error to occur at compile time, rather at the customer's site, and
be "your derived class is not on the list of classes allowed to derive",
not "symbol not found".
If I write public I mean public - anybody can call a public function
from anywhere, which is essentially analogous to the protected case
from the point of view of linking.
> I view DLLs/DSOs as as fundamental mechanism of compartmentalising code
> as classes.
This is my point: they are the mechanism, the implementation, while the
C++ language is the interface. The implementation must keep the promises
made in the interface, which the ELF linker does at the price of
substantial contortions; you're suggesting that the interface, the C++
language, be modified to allow faster linking; I'm objecting that your
suggested change to the interface makes for a poor interface (actually
this is an objection to n1496, as said previously, which introduces
"piecemeal modularization" irrespective of the default chosen).
>> a syntactic construct to address it on a symbol by symbol
>> basis is inappropriate.
My key objection is to "on a symbol by symbol basis", which is a critique
of n1496; the choice of "default hidden" would exacerbate the problem.
> Also I like how right now things can be subdivided
> one way at the source level (via namespaces) but a totally different way
> at binary level - to me, this ADDS value through intuitiveness.
I both agree and disagree; I agree that some latitude in the organization
of code at binary level is highly desiderable, but only as long as this
does not break the contract established by the C++ language.
> If you could show me more proposed syntax, I could say a lot more. While
> I'm initially negative, I could be very easily swayed as TBH I don't
> have enough experience of what you propose would mean.
Let's assume that the intent is to get rid of double indirection; it
seems to me that to achieve this you have to know, at WPO time, that
all references to a symbol in the program will use the definition from
the program itself; indirection will still be needed for accessing said
definition from shared objects and for accessing symbols referenced but
not defined in the program. You want to say "this definition cannot be
overridden" for proteced/public member functions, and for namespace
scope symbols.
One syntax to achieve this might be inspired from Java:
#include "sample_class.h" // Declaration.
package main_program; // Not a scoping construct.
class sample_class { ... } // Definition.
void f(const sample_class& arg) { ... } // Definition.
The implementation would label the symbols as belonging to a package
named "main_program" - this is the reason for having
package main_program;
rather than
package main_program { ... }
which might suggest that you can have multiple packages in the
same source file (on second thought, this might not be such a
bad idea). The package where main() appears would become the
executable program after linking; other packages would become
shared objects (actually shared objects candidates).
Symbols defined in a package are not available outside the
defining package unless explicitly imported
#include "sample_class.h" // Declaration.
package shared_object;
import class sample_class from main_program;
and
#include "sample_class.h" // Declaration.
package plugin;
import class sample_class from main_program;
import void f(const sample_class& arg) from main_program;
Please note that I say "not available" as I do not wish to suggest
further complications of C++ visibility rules; a symbol which is not
visible cannot be imported.
Importing a symbol states the intent to reference the existing
definition and allows the compiler to report a conflicting definition
as an error straight away. Importing a symbol which is already defined
is likewise immediately reported as an error.
Allowing multiple definitions of the same symbol in separate packages
would cause a violation of the ODR rule, but only if said packages
are ever collected together as a C++ program.
When the definition of a symbol is encountered but the symbol is not
imported, the compiler is allowed to assume that this is the definition
referenced throughout the package, an assumption it can exploit at WPO
time; a jump table would still be necessary, since other shared objects
might reference the definition.
When prelinking, conflicting definitions of the same symbol would be
detected and would cause a violation of the ODR; the same would happen
if a plugin attempted to redefine a defined symbol upon dlopen().
All things considered, the above seems a little too much for saving one
indirection from nonvirtual functions; maybe the module/package concept
can bring other benefits from C++, however.
Cheers,
Davide Bolcioni
--
Paranoia is a survival asset.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: s_googlegroups@nedprod.com (Niall Douglas)
Date: Sat, 29 May 2004 15:49:01 +0000 (UTC) Raw View
On Fri, 28 May 2004 02:05:20 +0000 (UTC), Davide Bolcioni
<f5xz2bk02@sneakemail.com> wrote:
> Supporting (c) indeed seems to require double indirection; however, I
> recollect investigations from KDE people about C++ dynamic linking in
> Linux showing that relocations, not indirection, were the main source
> of overhead and suggesting prelinking as a solution.
Absolutely. If however every symbol access requires an address fetch in
order to determine where to fetch the data, you create very nasty pipeline
stalls on modern processors as that singularly defeats any prediction unit
in the CPU.
> If I write that a member function is private, I mean exactly that; it
> cannot be called from outside the class. The mangled symbol for its
> implementation should not require double indirection to reach, once
> WPO coalesces invocations from separate .o files; if the programmer
> puts some implementations in a .so and some in another, double
> indirection would be required and a comment in the standard should
> warn of the associated performance cost. Most programmers would
> not do that.
Thing is, it must remain publicly visible in case a friend class wants it.
And bear in mind that the linker rarely knows anything about C++ at all,
it just blindly assembles object files.
> The above, however, still allows the programmer to overwrite symbols
> through linker directives, or even by making the "mistake" of putting
> the implementations he wants to override in a separate .so, causing
> the compiler to use double indirection and all that.
Y'see, I would argue that the costs of being able to override symbols like
this aren't worth it given the amount of code that will ever use such a
feature. Far better such code does it explicitly so everyone else can run
much faster.
> If I write public I mean public - anybody can call a public function
> from anywhere, which is essentially analogous to the protected case
> from the point of view of linking.
What if it's public to classes within your DSO but not to anything outside?
>>> a syntactic construct to address it on a symbol by symbol
>>> basis is inappropriate.
>
> My key objection is to "on a symbol by symbol basis", which is a critique
> of n1496; the choice of "default hidden" would exacerbate the problem.
My concern is that what you seem to want would need a much more
intelligent linker. Linkers work in terms of symbols and thus why one
specifies visibility on a per-symbol basis. I'm not sure moving that way
is the right one.
>> Also I like how right now things can be subdivided one way at the
>> source level (via namespaces) but a totally different way at binary
>> level - to me, this ADDS value through intuitiveness.
>
> I both agree and disagree; I agree that some latitude in the organization
> of code at binary level is highly desiderable, but only as long as this
> does not break the contract established by the C++ language.
Bear in mind that C++ isn't the only linkable language - many languages
output ELF object formats some of which can even be directly linked with
C++ (though mostly it's just C). What you propose would suggest breaking
with such a capacity.
> Allowing multiple definitions of the same symbol in separate packages
> would cause a violation of the ODR rule, but only if said packages
> are ever collected together as a C++ program.
How do you handle a program loading an unknown library (package) at run
time?
> All things considered, the above seems a little too much for saving one
> indirection from nonvirtual functions; maybe the module/package concept
> can bring other benefits from C++, however.
Of course, one could simply mandate the Win32 method of doing shared
libraries and all these problems on ELF go away. ELF itself as a format
can handle it easily - it's just the semantics of working with shared
libraries need to change (in a non-breaking fashion with how it's
currently done).
Cheers,
Niall
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (llewelly)
Date: Thu, 27 May 2004 17:17:54 +0000 (UTC) Raw View
s_googlegroups@nedprod.com (Niall Douglas) writes:
[snip]
> Note that for every symbol which is available outside its DSO, a
> particularly expensive form of relocation must also be performed at
> load time which on all implementations I know of is quadratic to
> symbol number. See Ulrich Drepper's "How to write shared libraries".
[snip]
This is actually an argument for having symbols not visible by
default.
>
>>> This is partially where the speed & size differential between MSVC
>>> & GCC compiled binaries comes from. The trouble with "default
>>> shared" is that it encourages laziness - most programmers will do
>>> the minimum to get a working application and then stop. If it's
>>> "default private" then programmers must add the extra annotation to
>>> even reach a working binary - which is good, because code quality
>>> improves substantially.
>>
>> In C, to hide a symbol you make it static. In C++ we have the unnamed
>> namespace and access specifiers for classes; this might or might not
>> be enough to provide the information you need for faster binaries, so
>> it might prove helpful to address this in the standard along the lines
>> of "if you do such and such, the translator might be forced to assume
>> that and produce underperforming code".
>>
>> In other words, C/C++ programmers already take a visibility decision in
>> the code, using the language-provided means which the underlying
>> implementation is required to support.
>
> No you're wrong here. A static symbol is indeed hidden in that it
> cannot be directly referenced outside its compiland. This is not true
> for the contents of unnamed namespaces - they merely add extra
> mangling to the symbol which actually makes the problem worse (longer
> load & linking times and more code bloat).
This is true for current implementations, but does it *need* to be
true?
Why might an implementation need to make a symbol inside a unnamed
namespace visible at dynamic link-time?
> Why don't unnamed
> namespaces hide their contents? Because "export" causes searching of
> unnamed namespaces outside its compiland!
[snip]
A typical unix runtime linker has niether the smarts nor the
information availible to do the name lookup needed by exported
templates. Further, some experts have claimed it will probably
never be beneficial to instantiate exported templates at program
load time anyway.
So I think this is a bogus argument.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Thu, 20 May 2004 18:44:54 +0000 (UTC) Raw View
Niall Douglas wrote:
>
> You can get away with not specifying dllimport for functions on Win32 but
> you *must* specify it for variables.
No. The compiler has to know to generate an indirect reference. That
doesn't depend on specifying dllimport, but simply on knowing that the
variable is imported. The marker that indicates that it's exported is
sufficient: the compiler can generate indirect references whenver it
accesses exported data (although this would mean that accesses from the
same linkage unit would be indirect as well).
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: 6805b3x001@sneakemail.com (Davide Bolcioni)
Date: Sun, 23 May 2004 00:18:04 +0000 (UTC) Raw View
Niall Douglas wrote:
>> I'm unhappy with the first model because it seems to break all
>> existing unix code that makes use of shared libraries.
> One could take the view that Unix has it wrong and it needs to change
> for its own good. Irrespective of what the standard says, the
> implementors on Unix will devise some transitory/interoperability
> strategy.
From the point of view of a programmer doing mostly maintenance work of
existing code bases, I would say that Unix had it right from the
beginning and Windows requires the programmer to pepper the code with
too much detail for his own good: the notion that shared libraries are
not something which should concern the language, only the linker, made
my job exceedingly easier. If you want metaphors, think relational
versus handcrafted database, with the linker doing the joins.
> BTW in N1496 appendix item 4 I can confirm that the Unix mechanism
> cannot be implemented on Windows.
Given the time scale expected of C++0x, maybe the right question is
whether it is implementable for .NET ?
> The PE binary hardcodes what symbols
> it looks for from each library by name as of course under PE you can use
> ordinal rather than mangled symbol resolution. The advantage of the PE
> system is a substantially reduced search tree and thus improved load &
> link times but it does mean you can't arbitrarily muck around with DLL
> contents without a relink (not hard as ELF dynamic loaders ARE the
> full-strength standard linker).
This should be of interest only to people implementing a linker, in my
opinion.
>> I'm unhappy with the second model becuase it changes the default on
>> windows; it seems to cause every declaration to undergo a silent
>> change in meaning.
From the point of view of maintenance ... I would personally dislike that
intensely :-).
> N1496 also doesn't cover the need to use dllimport with PE for
> variables. You can get away with not specifying dllimport for functions
> on Win32 but you *must* specify it for variables.
Which is an implementation detail which I expect the linker to handle,
although the PE linker doesn't.
> I think the first model should be mandated. Unix shared libraries
> emulate static linking except that the linking is continuous in that it
> can be more-done or be undone according to manual loading and unloading
> of libraries.
Unix shared libraries implement visibility as defined in the C or C++
language, without introducing another layer of detail for the programmer
to handle (and possibly get wrong). Programmers wishing for the
additional complexity might have the option to specify it, but the
default should be implementation-defined (in the makefile) linking.
In other words: we don't tell the programmer how the program will be
cobbled together, he had better make sure it works anyway. Guidelines as
to which tricks not to pull in order to not have things break
unexpectedly would be really welcome and in my humble opinion belong in
a language standard: FORTRAN got much mileage from its rules for common
variable access, for example.
> In other words, what I'm saying is that a MSVC style shared library
> system can coexist with the Unix shared library system whereas the
> opposite is most certainly not true. Therefore be brave and go with
> system number 1.
On the contrary, I suggest leaving the language as it stands; just
acknowledge that shared libraries are a reality of current
implementations and might impose a series of restrictions which should
be observed by the programmer.
Best Regards,
Davide Bolcioni
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (llewelly)
Date: Mon, 17 May 2004 21:09:47 +0000 (UTC) Raw View
I'm unhappy with the bit in in n1496 about syntax. Specifically:
# There are three possible approaches to specifying which names in
# a translation unit refer to entities with shared linkage. First,
# names with external linkage can be non-shared by default, and the
# programmer would have to explicitly identify names that are to
# have shared linkage. This is the model that Windows programmers
# are familiar with. Second, names with external linkage can be
# shared by default, and the programmer would have to explicitly
# identify names that are not to have shared linkage. This is
# similar to the model that UNIX programmers are familiar
# with. Third, it can be implementation-defined which of the two
# preceeding models applies. This minimizes the required changes to
# existing code.
I'm unhappy with the first model because it seems to break all
existing unix code that makes use of shared libraries.
I'm unhappy with the second model becuase it changes the default on
windows; it seems to cause every declaration to undergo a silent
change in meaning.
I don't think either of the first two models should be accepted.
I think I want all of:
(a) A syntax for declaring a name to have shared linkage.
(b) A syntax for declaring a name to have non-shared linkage.
(c) If a name's declaration does not explicitly specify shared
or non-shared linkage, whether that name's linkage is shared
or non-shared shall be implementation-defined.
The first time I read the third alternative, it seemed to mean
this. On re-reading it, I'm unsure. Specifically, if an
implementation supports shared libraries, I want both (a) and
(b), regardless of the implementation-defined meaning of (c).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Tue, 18 May 2004 01:14:25 +0000 (UTC) Raw View
llewelly wrote:
>
> I'm unhappy with the bit in in n1496 about syntax. Specifically:
>
> # There are three possible approaches to specifying which names in
> # a translation unit refer to entities with shared linkage. First,
> # names with external linkage can be non-shared by default, and the
> # programmer would have to explicitly identify names that are to
> # have shared linkage. This is the model that Windows programmers
> # are familiar with. Second, names with external linkage can be
> # shared by default, and the programmer would have to explicitly
> # identify names that are not to have shared linkage. This is
> # similar to the model that UNIX programmers are familiar
> # with. Third, it can be implementation-defined which of the two
> # preceeding models applies. This minimizes the required changes to
> # existing code.
>
> I'm unhappy with the first model because it seems to break all
> existing unix code that makes use of shared libraries.
It doesn't break anything. It means that such code wouldn't be portable.
It's not portable today, so that's no change.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (llewelly)
Date: Wed, 19 May 2004 10:10:09 +0000 (UTC) Raw View
petebecker@acm.org (Pete Becker) writes:
> llewelly wrote:
>>
>> I'm unhappy with the bit in in n1496 about syntax. Specifically:
>>
>> # There are three possible approaches to specifying which names in
>> # a translation unit refer to entities with shared linkage. First,
>> # names with external linkage can be non-shared by default, and the
>> # programmer would have to explicitly identify names that are to
>> # have shared linkage. This is the model that Windows programmers
>> # are familiar with. Second, names with external linkage can be
>> # shared by default, and the programmer would have to explicitly
>> # identify names that are not to have shared linkage. This is
>> # similar to the model that UNIX programmers are familiar
>> # with. Third, it can be implementation-defined which of the two
>> # preceeding models applies. This minimizes the required changes to
>> # existing code.
>>
>> I'm unhappy with the first model because it seems to break all
>> existing unix code that makes use of shared libraries.
>
> It doesn't break anything. It means that such code wouldn't be portable.
> It's not portable today, so that's no change.
I am sorry, but these two statements make no sense to me. Could you
please rephrase?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: petebecker@acm.org (Pete Becker)
Date: Thu, 20 May 2004 02:51:09 +0000 (UTC) Raw View
llewelly wrote:
>
> petebecker@acm.org (Pete Becker) writes:
>
> > llewelly wrote:
> >>
> >> I'm unhappy with the bit in in n1496 about syntax. Specifically:
> >>
> >> # There are three possible approaches to specifying which names in
> >> # a translation unit refer to entities with shared linkage. First,
> >> # names with external linkage can be non-shared by default, and the
> >> # programmer would have to explicitly identify names that are to
> >> # have shared linkage. This is the model that Windows programmers
> >> # are familiar with. Second, names with external linkage can be
> >> # shared by default, and the programmer would have to explicitly
> >> # identify names that are not to have shared linkage. This is
> >> # similar to the model that UNIX programmers are familiar
> >> # with. Third, it can be implementation-defined which of the two
> >> # preceeding models applies. This minimizes the required changes to
> >> # existing code.
> >>
> >> I'm unhappy with the first model because it seems to break all
> >> existing unix code that makes use of shared libraries.
> >
> > It doesn't break anything. It means that such code wouldn't be portable.
> > It's not portable today, so that's no change.
>
> I am sorry, but these two statements make no sense to me. Could you
> please rephrase?
>
Sure. Today, Unix code that makes use of shared libraries isn't marked
up with import/export specifiers. If the standard adds some way of
saying that various functions will live in a shared library, then code
that's marked up in that way will (eventually) be portable, say between
Unix and Windows. Unix code that isn't marked up won't take advantage of
this added syntax, so it won't be portable to Windows. However, Unix
compilers will certainly still support the current style (through a
command line option), and the code will still work in all the places
where it works now.
For a less abstract example, quite a few programmers still use classic
iostreams through the header <iostream.h>, even though the standard
provides something similar but different through <iostream>.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: s_googlegroups@nedprod.com (Niall Douglas)
Date: Thu, 20 May 2004 02:52:54 +0000 (UTC) Raw View
On Mon, 17 May 2004 21:09:47 +0000 (UTC), llewelly
<llewelly.at@xmission.dot.com> wrote:
> # There are three possible approaches to specifying which names in
> # a translation unit refer to entities with shared linkage. First,
> # names with external linkage can be non-shared by default, and the
> # programmer would have to explicitly identify names that are to
> # have shared linkage. This is the model that Windows programmers
> # are familiar with. Second, names with external linkage can be
> # shared by default, and the programmer would have to explicitly
> # identify names that are not to have shared linkage. This is
> # similar to the model that UNIX programmers are familiar
> # with. Third, it can be implementation-defined which of the two
> # preceeding models applies. This minimizes the required changes to
> # existing code.
>
> I'm unhappy with the first model because it seems to break all
> existing unix code that makes use of shared libraries.
One could take the view that Unix has it wrong and it needs to change for
its own good. Irrespective of what the standard says, the implementors on
Unix will devise some transitory/interoperability strategy. It would also
hardly be the first time that existing implementations did something which
was later ruled out by the standard (I'm thinking unqualified name lookups
within templates particularly).
BTW in N1496 appendix item 4 I can confirm that the Unix mechanism cannot
be implemented on Windows. The PE binary hardcodes what symbols it looks
for from each library by name as of course under PE you can use ordinal
rather than mangled symbol resolution. The advantage of the PE system is a
substantially reduced search tree and thus improved load & link times but
it does mean you can't arbitrarily muck around with DLL contents without a
relink (not hard as ELF dynamic loaders ARE the full-strength standard
linker).
> I'm unhappy with the second model becuase it changes the default on
> windows; it seems to cause every declaration to undergo a silent
> change in meaning.
N1496 also doesn't cover the need to use dllimport with PE for variables.
You can get away with not specifying dllimport for functions on Win32 but
you *must* specify it for variables.
> I don't think either of the first two models should be accepted.
I think the first model should be mandated. Unix shared libraries emulate
static linking except that the linking is continuous in that it can be
more-done or be undone according to manual loading and unloading of
libraries. Certainly from a programmer's point of view, you are supposed
to do nothing special to use shared libraries - just tweak your build
system slightly with no source changes. However the reality is more
complex than that.
Because Unix shared libraries seek to provide this legacy appearance, they
diverge much less from not only the standard but also the spirit of static
linking. Therefore one could view that system as "enhanced static linking"
and therefore not something which needs to be borne in mind when updating
the ISO C++ standard.
In other words, what I'm saying is that a MSVC style shared library system
can coexist with the Unix shared library system whereas the opposite is
most certainly not true. Therefore be brave and go with system number 1.
Cheers,
Niall
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]