Actually Portable Executables
ahgamut.github.io
ahgamut.github.io
It's like telling someone that SICP is the best way to learn Scheme. Maybe, but lots of people learn differently.
Unfortunately I don't have good suggestions myself, but at least they won't feel bad if K&R isn't their cup of tea.
I tried to refresh my memory from previous threads, and I think the general trend has been to recommend (as seen in sibling comments):
https://modernc.gforge.inria.fr/
https://nostarch.com/Effective_C
I've also seen the older:
https://www.oreilly.com/library/view/21st-century-c/97814493...
Mentioned.
There's also Architecture of Open Source Applications, which can help with starting to read some larger code bases, some of which are in C: http://aosabook.org/en/index.html
And there's a general recommendation to go read the source code of the Redis cache/db.
Finally i came across a mention of this short article on gdb (nb: mention of TUI text ui should probably have been in the top, not a foot note):
https://www.recurse.com/blog/5-learning-c-with-gdb
I feel I'm missing a book that has come up often, but can't think of which one.
I did like zed Shaws learn c the hard way, but I'm afraid it's getting a bit long in the tooth: https://learncodethehardway.org/c/
The first three are just useful for getting the basics. The next two are for starting to learn low level stuff. You don't really understand C until you understand how it relates to lower level code.
I thought 21st Century C was good, i've still kept my copy. I'd happily recommend it.
I like the K&R book too - it feels reeeeeeally old but it's really short.
There's a few others that have helped me in various ways but these are a little older -
Love C by Tim Love (free online, my copy is something i just printed out, it's not that long).
Programming from the Ground Up (x86 assembly) - this is available freely online but i bought the book and that helped me a lot with C even though it's a book with only assembly... (to be fair, it does go through calling conventions).
Finally there's another book i love, Advanced Programming in the Unix Environment by Stevens, i have the 6th edition updated by Rago after Stevens' passing. Fascinating book - but huge.
Besides I was in the same boat as you. I come from the world of JS/Python/Go. I even wrote https://github.com/Himujjal/ekon in pure C recently. The reason I thought C would be good is performance and portability. But I found it to be better to invest time in Rust rather than in C. C is a fantastic language but cross platform dependency management is difficult. Unit Testing is also difficult. There are solutions but not as efficient as Rust's ecosystem.
BTW I wish there could be a Cargo for every language.
Odd...I find that a very strange sentiment.
I thoroughly enjoy C, and have even written a compiler for it, but I don't think it's a well-designed language by any account.
I don't like 21st Century C, it may have changed since then but it has a chapter titled "Object-Oriented Programming in C" which is confusing object with Abstract data type.
struct Object;
void Object_init(struct Object *o);
That's ADT.But the next step, which I think is far more important, is to look at the source code of tools that you actually use in real life. Things like cp, or wc, or head. You've probably used them for years without thinking about it, but they're all written in C. Don't look at the modern GNU versions just yet, since they can be packed full of complex functionality, start with micro implementations like Busybox or Toybox. Then look at some OSes that are known for super clean code like NetBSD or OpenBSD. In those OSes you have the benefit of being able to go back to the version that existed 25+ years ago, so you can read through the diffs to see how they adopted new features and found new ways to address C's biggest flaw/risk - memory exploits.
If you're interested in kernel programming, check the Linux and BSD sources, and lurk on the mailing lists for a while to see how people talk about the code. The review process tends to be a bit more brusque than you might be used to on Github, but it's often detailed and results in code that is of a relatively high quality, or at least a consistent standard. It's a great place to learn.
Why is there a forest of files in Cosmopolitan Libc? I tried looking at it on Github to see how things were done, and there were a lot of .h and .S files, I couldn't actually find the C source, though I'm sure somewhere in there is a .c file.
Doesn't fragmenting the source into thousands of files make compilation far slower than it needs to be?
Also, I wonder if/how functions that aren't called in a program get trimmed away by the linker, and thus don't make the executable larger.
Having lots of objects is a good thing because it helps static linking work better. When the Unix linker loads a symbol from a static archive, it pulls in the whole module that defines that symbol. For example, if you define memcpy() and memset() in the same .c file and then your app only needs one of them, they'll both go towards bloating your binary. Workarounds exist like -ffunction-sections and -Wl,--gc-sections but a C library should make assumptions about the fewest flags feasible.
What's the end result? We're able to build executables that are 12kb in size which run on seven different operating systems. The big codebase is what made tiny binaries possible: https://justine.lol/cosmopolitan/howfat.html
I read your post about actually portable executable format but I wonder if it's something that you found immediately helpful for some project or if you work on it just out of curiosity.
build_directory_link := $(shell readlink $(build_directory))
$(if $(build_directory_link),$(shell mkdir -p $(build_directory_link)))Linux will automatically cache all source files in RAM because of the page table cache. Writes to slow storage devices are eliminated through tmpfs. Amazing really.
Also much lower peak memory usage for lld, which is great if you have multiple concurrent link steps.
For a datapoint it takes me ~2 minutes to build a reasonably fully featured ARM linux kernel with a cold cache on a 5 year old i5. wc counts 1399 CC, 65 AS and 411 LD calls. And of course incremental rebuilds are only a fraction of that.
This allows incremental compilation to work much better than it otherwise would. Your first clean build may be slightly slower, but after that, you only have to recompile the files you change.
I was wondering if we can accompany runtimes written in C (like lua) with some scripts? So we have cross-platform, double-click-to-run scripting?
For us poor souls who can't write reliable C code, that would be a great thing!
I was working on something similar (though much smaller in scope), but had to stop when I realised that `ld-linux.so` has some internal APIs that Glibc uses to setup dlopen()/dlsym(); essentially meaning that it is very hard -if not impossible - to load any shared libraries if one does not link to Glibc.
What I wouldn't give for a liblinux, similar to NTDLL.
https://github.com/jart/cosmopolitan/blob/d7ac16a9ed56ebdc70...
Hey I actually tried to make such a thing.
https://github.com/matheusmoreira/liblinux
It provides access to Linux system calls and process start up code that gets all the arguments, environment and auxiliary values. I have several examples of applications written in 100% freestanding C with zero dependencies other than this library:
https://github.com/matheusmoreira/liblinux/tree/master/examp...
It's a bit too low level but I actually planned to make my own ld-liblinux eventually. It currently works with static and dynamic linking. The ld-linux.so is able to link even though nothing else links against glibc. I didn't test dynamic loading though.
I stopped working on it because I found better solution for system calls on the Linux kernel repository:
https://github.com/torvalds/linux/blob/master/tools/include/...
Do you think liblinux could have a future?
Yeah, I have seen that file. Thought last I checked, it crashes in certain conditions [1]; I didn't really go back to it to fix it.
> I actually planned to make my own ld-liblinux eventually
Can you share this code? If not, could you document how exactly would you have done this? I lost all motivation once I realized that ld-linux and Glibc communicate with private APIs, but I'd love to actually work on it if it was possible to do this.
> Do you think liblinux could have a future?
Absolutely. The problem with Linux currently is that the loader rejects programs at the sign of slightest incompatibility before even trying to execute them, which means that there is nothing that the application code could do to work around said incompatibility. If we were able to get our code running (or, as I like to say it, make %RIP point inside the main function), we could then do whatever hacky-bullshit was required make the software work. All I need is to get our code executing, and from that point on, I'll handle system compatibility.
_start:
xorq %rbp,%rbp /* user code should mark the deepest stack frame
* by setting the frame pointer to zero
*/
movq %rsp,%rdi
call liblinux_start
movq %rax,%rdi
movq $__NR_exit,%rax
syscall
static void *after(void *vector) {
void **pointer = (void **) vector;
while (*pointer++ != 0);
return pointer;
}
int liblinux_start(void *stack_pointer) {
long count;
char *arguments;
char *environment;
struct auxiliary *values;
count = *((long *) stack_pointer);
arguments = ((char **) stack_pointer) + 1;
environment = arguments + count + 1;
values = after(environment);
/* start is the main function */
return start(count, arguments, environment, values);
}
> Can you share this code? If not, could you document how exactly would you have done this?Unfortunately I didn't make it that far. I was planning to study how glibc and musl do it just like how I studied their system call implementations. If I start working on this again I'm gonna look this up. I'll need to learn this linking stuff in order to support the kernel vDSO anyway.
I think your work is outstanding but it looks a bit childish/bizarre with this name, and thus it might prevent some people to trust its reliability.
https://www.youtube.com/watch?v=Xblh12XgQ4o
The first half is relevant.
With that out of the way, am I understanding correctly that the way this works on Linux/Unix is that the modifies itself (by overwriting the EXE file header with an ELF header)? This seems to have the consequence of making that specific file no longer portable. If I'm understanding things correctly, it also looks like the QEMU hack for non-x86_64 architectures will only work once per file, since after the first time running the file it will no longer run as a shell script on Unix so the QEMU invocation will be unreachable.
Have you considered adding workarounds for this?
What would it take to create an analog of SDL- some kind of lowest-common-denominator interface for mouse/keyboard io, audio output, and software-rendered graphics?
Something like SDL could be ported to run on top of Cosmopolitan but we'd need to port all its dependencies too. That would be a massive undertaking. If Cosmopolitan ends up being the next big thing and attracts a large community of contributors then something like that is bound to happen. Right now it's just a scrappy ambitious project being built for fun. So GUIs aren't something we're able to do quite yet. Although we've got TUIs working great! You can have the best most portable console / terminal apps in the world, today.
Think about it this way. How many years did it take Microsoft and Linux before they could offer a polished GUI? That should give you a rough estimate of how long it takes to develop these sorts of things from first-principles.
I missed an opportunity to ask in the previous thread: what would it take to link an app in a different language (say, Rust) with this library? Is it enough to just build an object file, that has libc functions assuming LP64 ABI as unresolved exports?
As someone who has never messed around with Libc-level programming, it was surprisingly straightforward (and exciting!) to compile Lua all the way.
Cosmopolitan is incredible, thank you so much.
Cosmopolitan is going to be a big thing.
http://valleywag.gawker.com/why-does-google-employ-a-pro-sla...
That’s the problem with trolling like that: once you do something cool that’s unrelated and try to move on it’s not clear if you’re genuine about anything any more. The history there will absolutely make larger interests hesitant to associate, contribute or integrate in something like, say, LLVM (regardless of the merit or lack thereof), particularly in today’s less forgiving culture.
Note that I’m not sharing an opinion on the content. It’s a metaobservation about where we are, for better or worse. That’s on page 1 of my Google search for “wow, who’s this amazing coder?”, so my path is the same anyone else would take doing due diligence on getting involved.
Traditional left didn't give a shit on gender, race or whatever bullshit you think you should declare yourself "inferior" because of an excuse. Just work and equality.
I hate both poshy techno-aristocrats (I would kick them out to Somalia or a Mexico narco shithole, to see what they can do without social support or a state backed police), and SWJs with far more points in common with fascism (Fuck that so-called cultural appropiation) than the common worker.
And exactly why should I care about the current maintainer? Except maybe to say "thank you"?
Let's put the question upside down: what have you (or the gawker journalist) brought to me? I mean, besides your outraged opinions (which anyone is entitled to have!)
On one hand, you have a wonderful technical creation by someone asking nothing in return. On the other, you are providing... hatred towards the author? On a 2 hours old account?
I'm sorry if she breaks the kumbaya illusion, but people are not equal. Some can't escape the working class, or the welfare class - not due to any personal failure or limits, but due to societal indoctrination.
Some other people break free, and then bring gifts of the gods to mankind. They are called innovators, entrepreneurs - the name vary. But you know one when you see one. There is nothing is cosmopolitan that was "impossible" to achieve by anyone dedicated, even years before. There's nothing magic- except in the mind of the author, that associated the right pieces together.
> The history there will absolutely make larger interests hesitant to associate, contribute or integrate
If anything, your comment make me less likely to associate with you!
> particularly in today’s less forgiving culture.
I couldn't care less. The less forgiving culture is a problem for those who need to work ("will code for food" as they said during the dotcom crisis) or integrate with the rest of society. Unfortunately, that means most of the people here, especially those working for the FANGs.
But there are some of us who just don't care - except to lament that, when shown the way to escape, most geeks double down on their own mistakes, and remain chained to their FANGs masters.
So please go on attacking the author if that makes you happy, while the rest of us admire the creativity and new things made possible by cosmopolitan (and make money out of that too!)
You may want to notice that the author, Justine Tunney, was also chained to her "FANGs master" Google during the period described.
And now she's free, which creates an even more compelling narrative: true creativity can only shine in freedom, not in chains
I took a look through her twitter, and her current opinions seem to be broadly similar to the ones she expressed in 2014.
1) Actually Portable Executables, a clever way of formatting a program so that all four OSes interpret it a valid program in their own format.
2) Cosmopolitan libc, a library for communicating with the OS that handles each OS's interface, allowing programs to work on all four.
$ wget https://justine.lol/redbean/redbean-2021-02-27.com
$ unzip -vl redbean-2021-02-27.com
Archive: redbean-2021-02-27.com
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
426 Defl:N 215 50% 02-09-2021 09:24 f9cc9464 tool/net/redbean.css
896 Defl:N 509 43% 02-09-2021 09:24 eb74f8a0 tool/net/redbean.html
16958 Defl:N 6093 64% 02-09-2021 09:24 6a76bd39 tool/net/redbean.ico
5073 Stored 5073 0% 02-09-2021 09:24 86c2afe6 tool/net/redbean.png
554 Defl:N 285 49% 02-09-2021 09:24 0aa6870a usr/share/zoneinfo/Beijing
2335 Defl:N 1093 53% 02-09-2021 09:24 6ccd4450 usr/share/zoneinfo/Berlin
2453 Defl:N 1170 52% 02-09-2021 09:24 7fed6d80 usr/share/zoneinfo/Boulder
...
Another ZIP tool that works well with APE is Windows 10 file explorer. But you have to change the extension from .com to .zip temporarily.Meanwhile Cosmopolitan doesn't provide a portable GUI toolkit so it can't replace electron on its own. Maybe if you could package Cosmopolitan + Qt or something like that you could end up with something very interesting though.
Likewise for non-GUI apps, like command-line utilities that are implemented with NodeJS. As prior art, Fabrice Bellard's QuickJS is able to compile JS programs to spit out a native binary that requires no external qjs runtime. If you modified it to output Actual Portable Executable binaries instead, it would be even more portable than the programs installed with `npm install`.
I've done some experiments and progressed to writing tooling that approaches that I-want-ridiculous-portability problem differently. It doesn't use APE, so it still requires a separate interpreter (such as NodeJS) capable of executing the compiled output, but the object files it outputs are such that even if you don't have a copy of NodeJS installed on your system (or the right copy of NodeJS installed), then you can piggy back off the interpreter built in to your browser. You get a similar double-click-to-run experience, but when you do double-click to run, it launches in the browser, and you can go from object file to modifiable source trivially, since the object file and the Git repo from which it is built are automorphisms. The downside, if you consider it one, is that it doesn't work with arbitrary NPM modules. You have to really buy in to the scripting language dialect and the development philosophy to get anything out of it.
It would be interesting the use the QuickJS+APE strategy above so that there is _no_ reliance on an external interpreter, at the cost of marrying yourself to x86 and introducing some small hurdles in the path to modification and also giving up the safety of the browser sandbox, since you're back to running arbitrary executables.
Speaking of deprecating it, it might be one scenario, but developers probably don't just choose Electron because it is platform independent. I mean, there were other frameworks that supported that use-case even before Electron (e.g. QT). However, what is specific to Electron, is that you can use web technologies to build Apps. But that is also nothing you can do with APE.
So as much as I like to see one binary format for many operating systems, I doubt that it will change anything regarding the Electron problem.
There certainly multiple ways of solving it, but in my opinion, Apple and Microsoft must come to a common ground and support some kind of web-view that is built-in to the OS and extended with a platform independent API for the things that normal browsers do not support/allow, like filesystems access.
At some point both supported the Progressive Web App (PWA) movement for a while, but afaik Apple is the one holding it back at the moment. My guess is that they saw their App-Store business at risk. And even if PWAs were a thing, they are still some use-cases they can not cover in the current state (e.g. missing filesystem access).
Also...given that AMD exists and the x86 instruction set is not some magic potion ingredients...
Each individual function is probably on the order of a few dozen machine instructions. Let's say there's 30 such functions that are implemented and 7 OSes to support. 36307 is about 7500 instructions. The average instruction length on x86-64 is 2-3 bytes. So maybe it ends up around 20KB of code space for a program that uses every possible operating system feature that's implemented?
I haven't looked at the implementation. I wonder how it selects between OS implementations. Does it switch on every system call, use a function pointer table, or do some sort of clever in-memory code rewriting?
Then she wrote a standard C library that detects which OS you're using at runtime and branches to the appropriate implementation, allowing the same x86_64 code to run on any supported system.
if (IsWindows())
DoWindowsThing();
else
DoUnixThing();
Traditionally, these system differences are resolved at build time: only the code for the target platform is included. Why would anyone want Windows-specific code in a Linux build? It's dead code... right? The new run-anywhere executable format makes that code useful.You might be right though. The author might be very good at executable hacks but they're a terrible writer. Their explanation explains nothing.
> Here's how it works:
>
> MZqFpD='
> BIOS BOOT SECTOR'
> exec 7<> $(command -v $0)
> printf '\177ELF...LINKER-ENCODED-FREEBSD-HEADER' >&7
> exec "$0" "$@"
> exec qemu-x86_64 "$0" "$@"
> exit 1
> REAL MODE...
> ELF SEGMENTS...
> OPENBSD NOTE...
> NETBSD NOTE...
> MACHO HEADERS...
> CODE AND DATA...
> ZIP DIRECTORY...
Ok well that clears it up. MZqFpD='. Of course!
You might want to ask the thousands of Electron App users how much they care about dead code ;-)
I mean, you are right. But if you offer your users no alternative they might not care enough to choose another product. In addition, some might even value it not having to choose the right binary for their system.
Yes. The true innovation that made all this possible is the novel Actually Portable Executable (APE) format. This means there's no need to choose: Windows will read it as a valid PE file while Linux, the BSDs and Mac will read it as a valid ELF program.
Having code for all operating systems in the executable has always been possible. It's just that before APE there used to be no point. Windows simply isn't able to load and execute an ELF program even if there is Windows code in it.
ELFs would be incompatible even between Linux, Mac and the BSDs since they would almost always depend on very different dynamic libraries. Cosmopolitan fixes this by providing a standard C library with support for everything. I assume incompatibilities can still be introduced by linking against other libraries.
Gonna need to solve that 1/2=g problem before Numpy is happy though!
CC="" luastatic main.lua
# Compile main.luastatic.c with Cosmopolitan Libc
[1] https://github.com/ers35/luastaticOne problem for libraries like SDL is they disable all their per platform code with #ifdefs. To build a static, cross platform version you would have to convert them all those #ifdefs to runtime branching, dynamically load libraries and provide headers files for all platforms.
Because Cosmo could work as a wrapper of windows/mac/linux binary executables and then the cosmo app can decide which one to invoke.
Based on my understanding if program A is to run program B, program B needs to be addressable in the filesystem. So based on my testing, the bundled executables need to be written to disk first and then the main program could run them. This also might work with macos .app folder formats but not sure how to do it on linux to avoid chmod +x issues and how to have 1 binary file on windows.
Any ideas?
> Cosmo could work as a wrapper of windows/mac/linux binary executables and then the cosmo app can decide which one to invoke.
It sounds like you misunderstand the reason for the project and that you're trying to add another layer of indirection to the thing that is already able to achieve the effect that you you seek to accomplish with that layer of indirection. No need for the indirection, just use the thing directly.
If you want to run $APP on platforms X, Y, and Z, then you'd use Cosmopolitan to build the $APP binary as an Actual Portable Executable, and you'd run that executable on any of those platforms.
I am referring to cases where the source is not available or its hard to set up some projects together. Some projects (usually hardware related) require different compilers, compile options, etc. If the project already has the binaries, then for distribution maybe a wrapper could be a good option.
In principle, Rosetta should detect that it's x86, perform the translation, and everything should "just work".
In practice, it's possible that the weird things APE is doing to get cross-platform compatibility will undermine one or more of Rosetta's assumptions.
I don't have an M1 Mac, so I'm not in a position to try it. But someone should!
It is one of the best hack I've ever seen, ever. Although as others have pointed out I wouldn't consider it exactly elegant (IIUC basically shell script to morph it on first run on nix); Nor exactly ground breaking with the fat-binary-like concept, if you don't use platform specific libraries or calls anyway, cross compile works just fine? What's the use case here? I mean for platforms where performance or size overhead of vm-based languages is a problem, you probably don't want it to include extra code for other platforms anyway?
OTOH Blinkenlights looks really nice tho. I've see a dude live hand editing code page 417 with notepad.exe to change a jmp so it doesn't look for a CD with my own eyes ;)
Always admire hackers of this rank. I think Blinkenlights could help me achieve something similar someday if I allocate bandwidth to it, would spend lots of time to play with it.
It is pretty damn impressive, though. I'll give it that.
It's like that cat pushing a watermelon meme. This is a binary that runs on seven operating systems. Your argument is invalid.
Not to detract from the technical breakthrough, but won't this be a major gift to virus writers ?
Exploit attempts for embedded systems (routers, cameras, etc) typically start with attempting to execute code in a portable language such as Shell scripts (which would be the only thing this new project would replace), those scripts try to detect the architecture of the system and then download the appropriate binary (the server hosting the malicious binaries provides many variants for different architectures).
In the end I don't see this solving a real problem when it comes to malware - this problem has already been solved through other means.
This project is going to benefit developers on all platforms, because it supports everyone without bias. Indie developers are going to have more opportunities to be successful writing native apps, since Cosmo helps them reach a broader audience. Before Cosmopolitan only big companies could introduce new projects (e.g. TensorFlow) that effectively solve the portability problem, since the only way to do it before was brute force cash. Lastly, Cosmopolitan is going to relieve language authors of many of the portability burdens they've each needed to carry on their own, which means they're going to have more time to focus on their visions.
If we don't use Actually Portable Executable to accomplish grand acts of public service, then operating systems are just going to block it. For example, UPX is a project that does creative things with executable formats. If you read the XNU source code you'll notice that they have explicit source code for blocking those executables and they call out the project by name.
`objcopy -S -O binary` does two things. One is to strip all the ELF headers and just dump the section contents into an output file. It looks like the input to this command is an executable within an executable, with the BIOS boot sector, ELF segments, Mach-O headers, etc. all embedded as section contents within an outer ELF file; objcopy then removes the outer shell. Clearly a necessary step, but it won't make much difference in binary size. However, the `-S` tells objcopy to strip debug information, which is included in the original since `-g` was passed to `gcc`. This is presumably responsible for almost all of the difference; debug info is notoriously huge. You can get a similar size reduction in a normal compilation by running `strip`.
Edit: But objcopy does not do anything fancy like compress the input. It looks like the pkzip part only contains associated files the binary might need (e.g. "hellojs.com" contains a JavaScript file and time zone files), not the executable code itself.
can we have an actually portable (common) lisp/python interpreter with at least terminal interface?
Can the terminal have something like VT-100 or other basic interface? and
Can we even run javascript to do screen related items ... like https://github.com/d3/d3
https://github.com/jart/cosmopolitan/blob/master/examples/he...
I think it's an interesting research project, but from a practical perspective - there are significantly better (and more mature) ways to achieve cross-platform compatibility that don't involve many of the compile-time and run-time hacks required to get Cosmopolitan to work.
"Actually Portable Executables" are not any more "portable" than a statically compiled .exe running natively on Windows, or using Wine[0] on a Linux, as an example.
That's why I hope Cosmopolitan can have a positive impact. Because interpreters are great but we shouldn't need to rely on them as much as we currently do. The only thing your Actually Portable Executables need is the canonical stock preferred kernel interfaces that have indefinite stability promises backed by the most powerful technology corporations on earth. No one got fired for depending on the IBM's of the world. Your software is going to have a long life with little maintenance and best of all it's going to be fast.
I came across some of the following statements in your website (https://justine.lol/cosmopolitan/index.html):
> "Cosmopolitan makes C a build-once run-anywhere language, similar to Java, except it doesn't require interpreters or virtual machines be installed beforehand"
Glancing at the code so-far, Cosmopolitan is really just an alternative libc implementation. It's important we acknowledge that there's only so much you can do with a libc implementation: it's a paper-thin abstraction layer for a small subset of rudimentary APIs.
It's common for software today to depend on operating system interfaces (which are platform-specific), either directly (via static/dynamic linking with operating system libraries) or indirectly (delegating to a runtime environment such as Java, Python, .NET Core, Mono, Wine, and others). I don't see how Cosmopolitan caters for these scenarios, and I don't see why you would make that comparison in the first place.
> "Cosmo provides the same portability benefits as high-level languages like Go and Rust, but it doesn't invent a new language and you won't need to configure a CI system to build separate binaries for each operating system"
Cosmopolitan doesn't change anything about the C language itself, right? How portable a certain C project is depends entirely on the business logic within the code. Any C code using nothing but libc is pretty much guaranteed to be "portable" (it can be built using almost any combination of hardware, operating systems and compilers) - I'm not sure what Cosmopolitan contributes to the portability story?
> "What Cosmopolitan focuses on is fixing C by decoupling it from platforms"
C is already "decoupled from platforms", so I'm confused by this statement. There are a lot of projects out there that don't use libc at-all, or use their own custom abstractions on-top of platform-specific code (#ifdefs, fancy buildsystems, etc). There's nothing about Cosmopolitan itself that makes it somehow "decoupled from platforms": the decoupling happens by virtue of writing code that relies on the public interfaces exposed by libc, and the ability to swap libc at both compile- and runtimes.
Packaging multiple entry points in the same file is a clever hack but is extremely brittle (for example, archiving/re-archiving can mangle relevant sections which ZIP doesn't care about -- this will break your binary), ELF uses a pre-processing step which renders the binary non-portable once it's run, and the cross-platform libc stuff has been done since time eternal.
Not to mention that, as you say, just C is nigh useless these days, anyway. It's kind of funny to see people comparing this to Electron.
> Cosmopolitan makes C a build-once run-anywhere language, similar to Java, except it doesn't require interpreters or virtual machines be installed beforehand. Cosmo provides the same portability benefits as high-level languages like Go and Rust
That is simply not true. Java, Go and Rust can run programs at native speeds on non-x86-64 architectures, e.g. ARM, but Cosmopolitan cannot, not now and not ever because x86-64 is a terrible IR.
These things are not mutually exclusive. Nothing is stopping you from shipping a JVM, Go, or Rust app ontop of Cosmopolitan.
Also the latter claim is not true AFAIK. For example if Cosmopolitan were to support all the architectures Rust supports, at native speeds, it would have to support packaging the compiled code for those different architectures into some kind of super-fat-binary. Currently it only supports x86-64.
I gave up.
You can build very little with the C Standard Library alone, wouldn't you agree? Things like graphics, anything beyond the most rudimentary I/O, etc - are not a part of the C Standard Library.
Obviously Windows could also be supported by recompiling under Cygwin, or MSYS2, but those tools are challenging. Compiling code designed for a UNIX on Windows is a pain in the ass, and sometimes the end result has strange behaviors. Upstream projects tend not to care much about Windows support, so trying to fix it you're on your own.
Nowadays we have WSL so we can just run Linux binaries on Windows as-is, but that's still a fairly heavyweight solution.
Wouldn't it be better to just compile once on UNIX, link to a magical portability library, and now you have a binary that just works everywhere? I think so.
MSYS2 is a dream. You install it, specify your dependencies using Arch's pacman, and go to town. No fiddling with Windows configuration files or paths, it just works. In fact it has been easier to get new devs up and running in that environment than in Linux, where they tended to smear build-time dependencies across the bare metal install. Of course there are solutions for that, but those solutions are more of a pain to set up than MSYS2.
The dream is that a programmer can just write their tool, using standard ISO C, maybe some POSIX, then compile and link it to Cosmopolitan and they're done. No need to set up any special configs or ifdefs. No need for any platform specific distributions. You just compile once and now you have the canonical version.