You're wrong about GTK, Qt, WinUI and Electron though. They default to "do nothing" which eliminates the ability to even know that another instance exists. You have to manually program that.
1,989 karma · joined June 20, 2021
You're wrong about GTK, Qt, WinUI and Electron though. They default to "do nothing" which eliminates the ability to even know that another instance exists. You have to manually program that.
I was visiting a radio test lab in last February for our new product. They use a professional software which was written in WPF. The assistant there was flying with the keyboard shortcuts.
I recommend every self-describing Unix or terminal fan to watch videos of photo or video editors / VFX people on YouTube. They are hella fast.
Mobile has significant paradigm changes that makes using both terminals and traditional GUIs harder anyway though. I do expect the need for completely different cross-platform libraries for mobile UIs.
VSCode SSH extension is one of the most widely developer-used proof against this. Windows' RDP is the other one where many engineers and POS personnel have experince using them. Many electrical and mechanical engineers still use Windows RDP at my work to run simulations. The connection is responsive enough to survive their home-to-office VPN connection. I set up complex chemical simulation software that is accessed by clients of a HPC cluster over 1000s of kms away.
VScode has a really efficient protocol that communicates only that's required, Windows RDP can declaratively send UI component changes as long as one uses Win32 or WPF. It can also reasonably compress the data to even survive dial-up levels of bad data.
We use multi-attendant video conferencing day to day with whiteboarding extensions. If there is will, efficient and amazing remote-GUIs are easy.
It's not Musl's fault that Glibc has an undocumented, badly designed, tightly coupled implementation. It's not Musl's fault when they decide to not follow Glibc's design which they have to reverse engineer and rewrite from scratch. Then Glibc can break it in a future version anyway. They give 0 guarantees and have a track record of breaking things.
Sorry but I feel like you're trying to excuse Glibc out of their terrible design. Glibc didn't ask anybody for standardization. Glibc didn't document their behavior. Musl doesn't need to follow any undocumented behavior. Musl has its own implementation of thread_local variable and it works only for Musl dynamic binaries (which you cannot load with Glibc's ld-linux.so either). You need to tell your compiler to generate code that Musl prefers not Glibc. So effectively we have two ABIs.
There is no standard and any design that tightly couples the system binary loader to the C standard library is just extremely terrible design. Both Musl and Glibc do it. Both of them are terrible. Glibc was first and it set the horrible, binary hostile behavior "have no standards, trust Glibc, and recompile your programs again" as the "standard".
The entire Linux userspace depends on Glibc's terrible design. Due to Hyrum's Law, the exact needs of the complex and emergent behavior can only be surfaced via making a better designed, completely independent system loader and a completely independent libc and then fixing the entire tens of thousands of userspace libraries in the upcoming decades. It is just Sisyphean work to fix Linux userspace.
There is no simple "let libc-X obey the standard S" solution. There is no standard. Linux Standard Base project tried to set a standard. It failed.
I'll won't further discuss this with you. Maybe you have good intentions, maybe you're playing dumb. I'm not sure anymore. If you're the former, I'm not going to deliver every single bit of information. I provided enough resources and you can learn.
What happened to the Unix principle "do one thing and do it well"? Windows solved this quite modularly and it works perfectly well.
Glibc is terribly designed and it is the core component of almost any Linux userspace app today. Let's not try to find excuses for horrible designs.
It isn't that this is 2026 and it was a bug that hasn't been fixed since. The userspace of GNU is designed against what you consider as basic functionality.
It is not just payment. Without being "big enough" and guaranteeing some big volumes of CPU sales, Intel won't give you the specs. AFAIK only ODMs and BIOS makers like AMI has the full low-level CPU bootstrap spec.
This is just the CPU. Now add the other peripherals like HDMI controllers. You'd see the problem now.
csrss.exe handles some of the loading functionality: https://en.wikipedia.org/wiki/Client/Server_Runtime_Subsyste...
When you link with UCRT your specific program just gets a "view" of standard C functions. You can load DLLs that were linked with MSVCRT from a UCRT program. It just works
Windows never had this problem. If you really want it, you can actually skip CRT completely on Windows. Only thing you need is the initialization code that's statically linked anyway: https://nullprogram.com/blog/2023/02/15/ . You can still make Win32 calls with it. CRT is there as a convenience.
And since Linux distros are compiling everything from source anyway, this makes Linux a prime candidate for complete libc and complete ABI replacement. Thanks to stable kernel ABI, we can also use the same kernel even with Docker etc! Musl did it. Why can a completely modularized libc not?
Will it break a lot of programs in the userspace? YES! Hyrum's Law exists.
Will it be rejected by a significant part of user base? YES! They rejected systemd as well.
Will it take one or more decades to have something working? HELL YES! This is Linux we're talking about. Everybody has seen how Wayland played out. However, maybe if Valve has enough motivation to fix Linux binary problem, we maybe can get finally a binary-compatible distro in a decade or half a decade.
Guess what happened with LSB? Some distros like Debian never adopted it. It also broke backwards compatibility at random times. It is now abandoned.
> Or do the MS thing, and ship multiple versions like msvcrt
MS can do that since the CRT is decoupled from the system DLL loader and Windows ABI is designed to isolated loaded DLLs into their own symbol namespaces. So your program can load DLLs that depend on a different CRT version.
Glibc's design tightly couples the system loader with the specific libc. Moreover symbols in ELF files are loaded into a single global namespace. You cannot ship shared libraries that are compiled with a different version of Glibc or Musl libc.
> Then, what is the exact reason a library compiled against glibc must be loaded by a specific ld-linux? I could see that this is true for C++ perhaps, or when you use very special features, but I do not see this for C.
You still have functionality like `dlopen` with C or `pthreads` with C. ld-linux.so is the thing that prepares the stack frame, or the segment pointers (FS_BASE on x86_64).
When you have your main loaded __libc_start_main_impl is called from glibc and if you disassemble it you'll see this line:
call 0x7ffff7c28790 <_dl_audit_preinit@plt>
Guess where _dl_audit_preinit lives?
(gdb) info symbol _dl_audit_preinit _dl_audit_preinit in section .text of /lib64/ld-linux-x86-64.so.2
Moreover glibc has "magic" sections like .init_first. Only ld-linux.so that is compiled from glibc source knows how to handle that. https://elixir.bootlin.com/glibc/glibc-2.44.9000/source/csu/...
> I often compiled programs against one version of glibc and run it against a different version, so I know there is not a tight coupling. So please be specific in explaining in what scenarios this would break.
It didn't break, since glibc hasn't broken backwards compatibility of ld-linux.so and glibc combination lately. Last time they broke it was in 2024 for a really specific subset: https://sourceware.org/pipermail/libc-alpha/2024-December/16...
A breakage hasn't been observed doesn't mean that there is no tight-coupling between ld-linux.so and glibc that is compiled from glibc source.
If you want a really specific scenario:
- Write a very simple C file that contains a global (volatile if you want to stop the compiler optimizations) thread_local variable with C23 syntax
- Compile a simple .so file on a GNU distro targetting glibc ABI with GCC (pass -std=c23)
- start up a Musl distro (e.g. Alpine Docker image), copy that .so file in
- Write a C program that dlopens the GNU .so file
- Try accessing the thread_local variable you defined
- Watch the world burn
When you compile libc, you also get a binary loader ld-linux.so with it. They are not two independent components of a system.
Basically all .so files compiled with glibc require the ld-linux.so that's also generated by that glibc (or a later version, if they didn't break the binary compatibility).
There are a lot of stuff that's executed by ld-linux.so and glibc that are not explicitly documented but they are absolutely necessary for your program to start and correctly initialize things like global variables or signal handling or loading other dynamic libraries. Some of that functionality sits in ld-linux.so and some of that in glibc. They have circular dependencies to each other. glibc expects ld-linux.so to put things in certain order but ld-linux.so also must load glibc first to have access to certain APIs. They are not part of System V ABI. They are not documented.
Musl maybe can implement this but it is simply reverse engineering what glibc did and then playing a game of cat and mouse. There is no independent ABI standard.
The ABI is strongly dependent on explicit libc implementation in current Linux systems. There is no libc independent ABI on Linux.
On Windows you don't need to ship a new binary loader. I can just ship Windows 10 UCRT DLL (which is the new libc of Windows) to Vista and my binaries will work. The binary loader isn't interlinked with the libc.
Until you define a thread local variable (C11) or use atomics (also C11) or define a global with an initial value. Then it happily generates code that depends on "whatever my target glibc + ld-linux.so needs".
Yes glibc has some backwards compat but you cannot load a binary compiled with a newer version of glibc using an older ld-linux.so. That's because the interdependency. Nor you can load binaries that depend on different libc.so files with glibc systems
I cannot comment on macOS, I have never used it. However this is not a problem with Windows. You can ship a newer CRT or you can install it as a system component using Microsoft's MSI. The dependency is one way on Windows. CRT purely depends on Win32. Moreover the loader is completely independent and DLLs are loaded into their own unique scoped namespace unlike Linux that loads them in global symbol namespace. That's why you can mix and match DLLs compiled for different CRT versions.
How libstdc++ initializes global variables absolutely depends on glibc and ld-linux.so. That is part of C++ ABI.
C++ global/static variable initialization depends on the specific version of glibc (they don't usually break compat, but they can and they did in the past) which also provides ld-linux.so that loads those global variable placeholders in the correct manner such that glibc and libstdc++ can initialize them correctly.
This is just one example. Thread local variables and behavior of things like pthreads with signal, fork etc all depend on glibc.
Shared libraries have always been broken in Linux. Unfortunately many things like GPU drivers, graphics libraries and NSS need shared libraries to dynamically load certain runtimes (because you don't want to load all possible GPU drivers in existence to your RAM). So an ecosystem has been developed on top of terrible ABI and architecture GNU/glibc provided.
However modern FW of PC clones don't only contain a bootloader and a "simple" hardware initializer. Modern laptops have tens of sensors, power measuring parts, power controllers, completely remote management (Intel ME / AMD PSP), embedded controller code for fingerprint, embedded controller code for keyboard etc.
Companies ship a new product line every single year. This churn causes nothing but shitty FW to be developed. Moreover the component manufacturers also slightly change things every single year. That's why sleep sucks with PCs. That's why Fn shortcuts don't always work correctly. That's why batteries drain.
Everything is fixed in the 6 months to a year following the launch in PC industry. Then they start to work on the new model and only supply security updates.
Intel / AMD and BIOS vendors simply do not expose their designs to everyone. So you have to go through an ODM to have an Intel chip-based motherboard design. The silicon industry is completely rotten at this point. Framework could simply be too small to get access to secret sauce.
The comparison that's being made is equivalent to implementing quick sort in Python and bubble sort in C++ and then declaring bubble sort is the better alternative.
Anyone with a healthy understading of computer science and programming experience will not make bullshit claims like that.
It is hopeless. There is a reason why systemd-resolved exists and there is a good reason why people say that only way to sanely interact with a Go program is through a network socket.
You need to give up Linux-style thinking first. Windows-native tools like Visual Studio, WiX, MSI etc. make it nice and easy to vendor your own DLLs. They are designed for closed-source and binary-distribution first. And if the libraries are designed for this ecosystem, you just import them in VS.
If you don't want to give up Linux-style dependency management you can use source-based build systems. You can use `conan` as a source package manager to get something closer and then export every single binary dependency `conan install . --deploy=runtime_deploy --output-folder=dist`.