| Deutsch English Français Italiano |
|
<vik8tc$3ang9$1@dont-email.me> View for Bookmarking (what is this?) Look up another Usenet article |
Path: ...!weretis.net!feeder9.news.weretis.net!news.quux.org!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: Bart <bc@freeuk.com>
Newsgroups: comp.lang.c
Subject: Re: question about linker
Date: Mon, 2 Dec 2024 12:24:11 +0000
Organization: A noiseless patient Spider
Lines: 153
Message-ID: <vik8tc$3ang9$1@dont-email.me>
References: <vi54e9$3ie0o$1@dont-email.me> <viaqh0$nm7q$1@dont-email.me>
<877c8nt255.fsf@nosuchdomain.example.com> <viasv4$nm7q$2@dont-email.me>
<vibr1l$vvjf$1@dont-email.me> <vic73f$1205f$1@dont-email.me>
<20241129142810.00007920@yahoo.com> <vicfra$13nl4$1@dont-email.me>
<20241129161517.000010b8@yahoo.com> <vicque$15ium$2@dont-email.me>
<vid110$16hte$1@dont-email.me> <87mshhsrr0.fsf@nosuchdomain.example.com>
<vidd2a$18k9j$1@dont-email.me> <8734j9sj0f.fsf@nosuchdomain.example.com>
<vidnp3$1ovvm$2@paganini.bofh.team> <vihpjh$2hgg1$1@dont-email.me>
<vihrh1$2hk5l$1@dont-email.me> <vii0jp$2jkd9$1@dont-email.me>
<viifv8$2opi7$1@dont-email.me> <vik28b$390eg$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Mon, 02 Dec 2024 13:24:12 +0100 (CET)
Injection-Info: dont-email.me; posting-host="8d706a207c8aaed216e2647004c96849";
logging-data="3497481"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18DY9WMf+h+1Cl8QBUBi1Mu"
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:BNVXfh2n9OxJF/2iQAqHCJPrfUU=
Content-Language: en-GB
In-Reply-To: <vik28b$390eg$1@dont-email.me>
Bytes: 7467
On 02/12/2024 10:30, David Brown wrote:
> On 01/12/2024 21:12, Bart wrote:
>> Yes, this is why a module scheme (such as the kind I use) is invaluable.
>>
>
> Agreed. C does not have a real module scheme as such. But it supports
> getting similar effects - you just have to be disciplined in the way you
> write your headers. This has the disadvantage of being less consistent
> than, say, Pascal or Modula 2, especially if the programmer is not
> disciplined. And it has the advantage in flexibility - I have a scheme
> that I like and that works well for the kind of code I work with, but
> other people prefer other schemes. It's easy to fall into the trap of
> "my way is the right way", especially when you make your own language
> and you are the only user, but there is always a balance to be sought
> between consistency and flexibility.
>
>> In the example above, you'd define both F and G in one place. There is
>> no header and there are no separate declarations.
>>
>> If another module wishes to use F, then it imports the whole module
>> that defines F.
>>
>> Some schemes can selectively import individual functions, but to me
>> that's pointless micro-managing.
>>
>
> To me, it is absolutely vital that the importing unit can only see the
> identifiers that were explicitly exported.
Speaking for my scheme, that is exactly what happens.
(First, I should say that my programs - sets of source files that will
comprise one binary - are organised into 'subprograms', each of which is
a chummy collection of modules that effectively import each other. The
following is about one subprogram.)
Only entities marked with 'global' are visble from other modules. But if
module X exports names A, B, C, all will be visible from Y.
Further, exported names D, E, F from X will be visible from X. Imports
can be circular (but subprograms are hierarchical).
What I object to in other schemes are:
* Where each of dozens of modules contains a ragtag list of imports at
the top. These look untidy and need to be endlessly maintained as a
fresh imported function is needed from module not yet listed, or an
import needs to be deleted as references to it are dropped. (This used
to be my scheme too!)
* Where functions are selectively imported from each module. FGS!
Instead of a few dozen imports, now there could be hundreds of lines of
imported function names to maintain. You'd have time for nothing else!
> It is also absolutely vital
> (and this is a critical missing feature for C - and a good reason to
> switch to C++ even if you use no other feature of that language) that
> the imported identifiers be in their own namespace so that they do not
> conflict with identifiers in the importing unit. If the language
> provides a feature for importing the external identifiers directly into
> the current unit's namespace, then it has to allow selective import of
> identifiers - otherwise all concepts of scalability and modularity go
> out the window.
Each of my modules creates a namespace. (Also, each of my subprograms
creates one namespace for all entities exported from the whole library:
that requires 'export' rather than 'global'.
However that namespace is rarely used. If this module imports X which
exports function F, then I can write F() instead of X.F().
I only need to use the namespace if:
* This module imports two modules that both export F so there is an
ambiguity (this is reported)
* This module has its own F so it shadows any imported versions. This is
not reported, but has the issue that, if a local F is freshly created,
it can silently shadow the previously imported F().
>
>> In my scheme, it is not even necessary for individual modules to
>> explicitly import each other: a simple list of modules is provided in
>> one place, and they will automatically import each others' exported
>> entities (which include functions, variables, types, enums, structs,
>> named constants, and macros).
>>
>
> That sounds, frankly, utterly terrible for anyone who worked with other
> people.
You've never used my scheme. One significant advantage is that because
all modules (and subprogram imports) are listed in the lead module
(usually that's all it contains), it is very easy to build a different
configuration using an alternative lead module with a different collection.
Alternatively, different modules can be commented in or out, in one
place. Below is the lead module of my C compiler, what is submitted to
my main compiler. No other modules contain any project info (only pcl.m,
a separate subprogram/library).
The only thing I haven't yet figured out is how the compiler knows the
location of an imported library which may reside elsewhere in the file
system. For now this is hardcoded.
--------------------------------
project =
module cc_cli
# Global Data and Tables
module cc_decls
module cc_tables
# Lexing and Parsing
module cc_lex
module cc_parse
# Generate PCL
module cc_genpcl
module cc_blockpcl
module cc_libpcl
# General
module cc_lib
module cc_support
# Bundled headers
module cc_headers # full set of embedded std headers
# module cc_headersx # dummy module with 0 headers
!Diagnostics
module cc_show
# module cc_showdummy
!IL Backend
$sourcepath "c:/px/"
import pcl # fully loaded backend
# import pclint # interpret only
end
(As is, this builds a 336KB C compiler with multiple options. With all
those alternate modules commented in instead, it builds a 178KB C
interpreter.)