Hacker News new | ask | show | jobs
by amiga386 335 days ago
> Yet, what if the logger’s ctor function is implemented in a different object file?

This is a contrived example akin to "what if I only know the name of the function at runtime and have to dlsym()"?

Have a macro that "enables use of" the logger that the API user must place in global scope, so it can write "extern ctor_name;". Or have library specific additions for LDFLAGS to add --undefined=ctor_name

There are workarounds for this niche case, and it doesn't add up to ".a files were a bad idea", that's just clickbait. You'll appreciate static linkage more on the day after your program survives a dynamic linker exploit

> Every non-static function in the SDK is suddenly a possible cause of naming conflict

Has this person never written a C library before? Step 1: make all globals/functions static unless they're for export. Step 2: give all exported symbols and public header definitions a prefix, like "mylibname_", because linkage has a global namespace. C++ namespaces are just a formalisation of this

2 comments

> This is a contrived example akin to "what if I only know the name of the function at runtime and have to dlsym()"?

Well, you just do what the standard Linux loader does: iterate through the .so's in your library path, loading them one by one and doing dlsym() until it succeeds :)

Okay, the dynamic loader actually only tries the .so's whose names are explicitly mentioned as DT_NEEDED in the .dynamic section but it still is an interesting design choice that the functions being imported are not actually bound to the libraries; you just have a list of shared objects, and a list of functions that those shared objects, in totality, should provide you with.

Also, don’t use automatic module init, make the user call an init function at startup.

And prefix everything in your library with a unique string.

What if you use two libraries A and B that both happen to use library C under the hood? Is the application expected to initialize all dependencies in the right order at the top level? Or is library initialization supposed to be idempotent?

This all works as long as libraries are “flat”, but doesn’t scale very well once libraries are built on top of each other and want to hide implementation details.

The call to init should be idempotent
That can be difficult in a multi-threaded environment with dynamically loaded shared libraries. Or at least it isn’t something that’s generally expected to be guaranteed to work.
C++ "magic statics" handle that use case (but with hidden atomic flag load (& more) costs at each access)
Ideally they would do the explicit init at startup before starting threads
Agree, there should be a prefix. But if 2 of my dependencies didn't use a prefix, why is it my fault when I fail to link against them?

Also, some managers object to a prefix within non-api functions, and frankly I can understand them.