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.)