Hacker News new | past | comments | ask | show | jobs | submit login
Cosmopolitan Third Edition (justine.lol)
1205 points by jart 11 months ago | hide | past | favorite | 240 comments



There's so much cool stuff in this post.

https://github.com/jart/cosmopolitan/releases/download/3.0.1... is 213MB file which contains "fat binaries" (single binaries that execute on a bewildering array of hardware platforms and operating systems) for dozens of programs, including zip, curl, git, wget, python, ctags and even my own Datasette Python application!

It's absolutely wild that this works.

I just tried it out (on macOS). I downloaded and extracted that zip and did this:

    cd ~/Downloads/cosmos-3.0.1/bin
    ./python -c 'print(4 + 5)'
It refused the first time because of macOS security settings. I had to open the security panel and click "allow"... and then it worked!

Likewise, this worked:

    ./datasette -m datasette -p 8000
That started a https://datasette.io/ server running on port 8000.

Git works too:

    ./git clone https://github.com/simonw/sqlite-utils
That git binary is 6.3MB, and I believe that same exact file can be copied to a Linux or Windows machine and will work the same way.


Here's a bit of a clue to how it works:

    ./python 
    Python 3.11.4 (heads/pypack1:65ac8ac, Oct 16 2023, 02:35:05) [GCC 11.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sqlite3
    >>> sqlite3
    <module 'sqlite3' from '/zip/Lib/sqlite3/__init__.pyc'>
    >>> import pathlib
    >>> list(pathlib.Path("/zip").glob("*"))
    [PosixPath('/zip/.symtab.amd64'), PosixPath('/zip/.symtab.arm64'), PosixPath('/zip/usr'), PosixPath('/zip/.cosmo'), PosixPath('/zip/Lib'), PosixPath('/zip/build')]

From Python's point of view there a "/zip/" folder with stuff in it, presumably stuff that's hidden inside the fat binary.


Yup, this is basically it. If you check out the "Actually Portable Executable" blogpost by the same author [1] and go to the "PKZIP Executables Make Pretty Good Containers" section there's a note on the approach.

1: https://justine.lol/ape.html


absolutely impressive


The "/zip/" folder refers to the ZIP store inside the actually portable executable -- you can run `unzip -vl ./python` to see what's inside.

Also, to add new pure-python packages, you just need to unzip them into a local folder "./Lib", and add that folder to the APE.


It’s so nice seeing portability over binary size winning all around these days. Such a breath of fresh air. There might be legit cases but for some reason so many people are still hang up on ´but binary size’ for no logical reason whatsoever.


I think a lot of the "logical reason" is driven by more the ephemeral, sandboxed, execution tools. e.g. a `docker run` or `serverless` architectures, where full root filesystems are populated on demand. Less executable data size there can go a long way in reducing latency/price.


> Less executable data size there can go a long way in reducing latency/price.

According to the article, Cosmo's fat binary dash was 30% larger but ran faster and used less real memory than Alpine's x86-linux-only version.

However there is still probably a 30% overhead for storage and copying.


> It’s so nice seeing portability over binary size winning all around these days.

It does? I would rather argue that portability between desktop OS matters today less than twenty years ago as the niches are carved out, WSL 2 becomes actually usable and the desktop metaphor as a whole declines.


Binary size was a lot more of a problem before customers had to buy 8-16 GB of RAM to run a web browser.


sudo xattr -rd com.apple.quarantine /path/to/binary/or/app

should also allow anything to run without opening settings


Now imagine nuitka and gcc bundled as a standalone cross plateform binary so you can basically compile a cross plaform python exe from any script.


Am I doing something wrong? I tried this on MacOS 12.6.9 and every binary I've tried so far gives a similar "zsh: exec format error":

    $ unzip cosmos-3.0.1.zip
    $ cd bin
    $ ./python -c 'print(2+3)'
    zsh: exec format error: ./python


You need to upgrade to zsh 5.9, or backport the patch I sent them two years ago: https://github.com/zsh-users/zsh/commit/326d9c203b3980c0f841... If you can't upgrade zsh, then the workaround is to say `sh -c ./ape-program` or `bash -c ./ape-program` instead of `./ape-program`.


Awesome, the workaround worked for me. Thanks for the quick reply (and your amazing work on cosmopolitan and the rest)!


Kind of a shame qemu isn't in there. That would be all sorts of fun.


I wonder if llm would work?



Base https://llm.datasette.io/ should work just fine, but it's basically a thin Python wrapper around the OpenAI Python library which then makes HTTP requests to their API.

The bigger challenge would be LLM with plugins. Those add all sorts of extra dependencies to help LLM run models directly - PyTorch, Transformers, llama-cpp-python etc.

I'd be surprised to see "llm install llm-gpt4all" work for example, since that pulls in compiled Python wheels and I'm not sure it would know which architecture to use.

pip install DOES work:

    $ ./python -m pip install httpx
    Defaulting to user installation because normal site-packages is not writeable
    Collecting httpx
      Downloading httpx-0.25.0-py3-none-any.whl (75 kB)
        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 75.7/75.7 kB 2.7 MB/s eta 0:00:00
    ...
    Successfully installed anyio-4.0.0 h11-0.14.0 httpcore-0.18.0 httpx-0.25.0 sniffio-1.3.0

    $ ./python                     
    Python 3.11.4 (heads/pypack1:65ac8ac, Oct 16 2023, 02:35:05) [GCC 11.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import httpx
    >>> httpx
    <module 'httpx' from '/Users/simon/.local/lib/python3.11/site-packages/httpx/__init__.py'>

    $ ls ~/.local/lib/python3.11/site-packages
    anyio
    anyio-4.0.0.dist-info
    h11
    h11-0.14.0.dist-info
    httpcore
    httpcore-0.18.0.dist-info
    httpx
    httpx-0.25.0.dist-info
    sniffio
    sniffio-1.3.0.dist-info
That ~/.local/lib/python3.11/ directory didn't exist until I ran the ./python -m pip install command.

Unfortunately "./python -m pip install llm" didn't quite work, I got this:

    ./python -m pip install llm                   
    Defaulting to user installation because normal site-packages is not writeable
    Collecting llm
      Downloading llm-0.11.1-py3-none-any.whl (36 kB)
    Requirement already satisfied: click in /zip/Lib/site-packages (from llm) (8.1.6)
    Collecting openai (from llm)
      Downloading openai-0.28.1-py3-none-any.whl (76 kB)
        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 77.0/77.0 kB 31.0 MB/s eta 0:00:00
    Collecting click-default-group>=1.2.3 (from llm)
      Downloading click_default_group-1.2.4-py2.py3-none-any.whl (4.1 kB)
    Collecting sqlite-utils>=3.35.0 (from llm)
      Downloading sqlite_utils-3.35.1-py3-none-any.whl (67 kB)
        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 67.2/67.2 kB 4.9 MB/s eta 0:00:00
    Collecting sqlite-migrate>=0.1a2 (from llm)
      Downloading sqlite_migrate-0.1b0-py3-none-any.whl (10.0 kB)
    Requirement already satisfied: pydantic>=1.10.2 in /zip/Lib/site-packages (from llm) (1.10.12)
    Requirement already satisfied: PyYAML in /zip/Lib/site-packages (from llm) (6.0)
    Collecting pluggy (from llm)
      Downloading pluggy-1.3.0-py3-none-any.whl (18 kB)
    Collecting python-ulid (from llm)
      Downloading python_ulid-2.2.0-py3-none-any.whl (9.4 kB)
    Requirement already satisfied: setuptools in /zip/Lib/site-packages (from llm) (68.0.0)
    Requirement already satisfied: pip in /zip/Lib/site-packages (from llm) (23.1.2)
    Requirement already satisfied: typing-extensions>=4.2.0 in /zip/Lib/site-packages (from pydantic>=1.10.2->llm) (4.7.1)
    Collecting sqlite-fts4 (from sqlite-utils>=3.35.0->llm)
      Downloading sqlite_fts4-1.0.3-py3-none-any.whl (10.0 kB)
    Collecting tabulate (from sqlite-utils>=3.35.0->llm)
      Downloading tabulate-0.9.0-py3-none-any.whl (35 kB)
    Requirement already satisfied: python-dateutil in /zip/Lib/site-packages (from sqlite-utils>=3.35.0->llm) (2.8.2)
    Requirement already satisfied: requests>=2.20 in /zip/Lib/site-packages (from openai->llm) (2.31.0)
    Collecting tqdm (from openai->llm)
      Downloading tqdm-4.66.1-py3-none-any.whl (78 kB)
        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 78.3/78.3 kB 41.9 MB/s eta 0:00:00
    Collecting aiohttp (from openai->llm)
      Downloading aiohttp-3.8.6-cp311-cp311-macosx_11_0_arm64.whl (343 kB)
        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 343.5/343.5 kB 3.5 MB/s eta 0:00:00
    Requirement already satisfied: charset-normalizer<4,>=2 in /zip/Lib/site-packages (from requests>=2.20->openai->llm) (3.2.0)
    Requirement already satisfied: idna<4,>=2.5 in /zip/Lib/site-packages (from requests>=2.20->openai->llm) (3.4)
    Requirement already satisfied: urllib3<3,>=1.21.1 in /zip/Lib/site-packages (from requests>=2.20->openai->llm) (2.0.4)
    Requirement already satisfied: certifi>=2017.4.17 in /zip/Lib/site-packages (from requests>=2.20->openai->llm) (2023.7.22)
    Collecting attrs>=17.3.0 (from aiohttp->openai->llm)
      Downloading attrs-23.1.0-py3-none-any.whl (61 kB)
        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.2/61.2 kB 41.9 MB/s eta 0:00:00
    Collecting multidict<7.0,>=4.5 (from aiohttp->openai->llm)
      Downloading multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl (29 kB)
    Collecting async-timeout<5.0,>=4.0.0a3 (from aiohttp->openai->llm)
      Downloading async_timeout-4.0.3-py3-none-any.whl (5.7 kB)
    Collecting yarl<2.0,>=1.0 (from aiohttp->openai->llm)
      Downloading yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl (61 kB)
        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.3/61.3 kB 427.1 kB/s eta 0:00:00
    Collecting frozenlist>=1.1.1 (from aiohttp->openai->llm)
      Downloading frozenlist-1.4.0-cp311-cp311-macosx_11_0_arm64.whl (46 kB)
        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 46.7/46.7 kB 14.8 MB/s eta 0:00:00
    Collecting aiosignal>=1.1.2 (from aiohttp->openai->llm)
      Downloading aiosignal-1.3.1-py3-none-any.whl (7.6 kB)
    Requirement already satisfied: six>=1.5 in /zip/Lib/site-packages (from python-dateutil->sqlite-utils>=3.35.0->llm) (1.16.0)
    Installing collected packages: sqlite-fts4, tqdm, tabulate, python-ulid, pluggy, multidict, frozenlist, click-default-group, attrs, async-timeout, yarl, sqlite-utils, aiosignal, sqlite-migrate, aiohttp, openai, llm
    ERROR: Could not install packages due to an OSError: [Errno 2] ENOENT/2/No such file or directory: '/Users/simon/.local/bin/sqlite-utils'


Yes, so pip works because the Python APE has OpenSSL built-in.

pip install requires modifying the APE, so I end up installing pure-Python libraries as follows:

    mkdir Lib
    ./python -m pip download httpx
    unzip ./*.whl -d ./Lib
    mv python python.com # in case the next step doesn't work
    zip -r ./python.com Lib
    mv python.com python
Installing CPython extensions like this is an unsolved problem, but I think there might be some interesting workarounds possible.


> The end result is that if you switch your Linux build process to use cosmocc instead of cc then the programs you build, e.g. Bash and Emacs, will just work on the command prompts of totally different platforms like Windows and MacOS, and when you run your programs there, it'll feel like you're on Linux. However portability isn't the only selling point. Cosmo Libc will make your software faster and use less memory too. For example, when I build Emacs using the cosmocc toolchain, Emacs thinks it's building for Linux. Then, when I run it on Windows:

> It actually goes 2x faster than the native WIN32 port that the Emacs authors wrote on their own. Cosmo Emacs loads my dotfiles in 1.2 seconds whereas GNU Emacs on Windows loads them in 2.3 seconds.

Impressive stuff.


This is all super impressive especially for such a small team.

But we should keep in mind that this project is what POSIX should have been, this is a big patch to make things right, as they should have been more than 20 years ago.

It seems magical because of the failure of numerous other teams and people who never managed to tackle the portability issue with the right mindset and skills.


I think this could be said about pretty much any good invention. The physical world doesn't change much, so the only barrier to invention is human. And I suspect most inventions have someone imagining it long before some other person actually builds it.


I disagree.

Most new development in tech, including software, have some dependencies on something that was not available before.


If that is so, how was is possible to develop the dependency? By definition it was not available before, so it must be a new development. So by that reasoning it is impossible to ever see something new.

Since you write "Most" there seem to be fewer 'new developments' which do not follow this pattern. So all you really say, is that rare new developments, which do not depend some other innovation, enable many followup innovations.

After all, your argument is not in conflict with the previous argument. You say, that new developments (aka implementations) have dependencies that have to be available before they can be made a reality, while the previous post just said, that long before something can be implemented, someone had imagined/dreamt about it already.


Is it the job of linux OS people to provide multi-platform executable compatibility with every other OS? That seems like a stretch considering that no OS has ever done that.


You have it backwards on two counts. First count is the point of POSIX is any OS vendor doesn’t need to worry about any other OS compatibility. Just implement POSIX interfaces. Second count is that is OP’s exact point: it never has been done before, because too many OS vendors give POSIX very little thought. This helps realize the original vision of POSIX.


> First count is the point of POSIX is any OS vendor doesn’t need to worry about any other OS compatibility. Just implement POSIX interfaces.

I must be missing something. How are you getting from "just implement POSIX interfaces" to "compile once run everywhere"?

Wouldn't the former just promise that you could compile the same source on any POSIX-compliant OSs and get a binary that runs on that OS, on that architecture?


It's because cosmos implements POSIX in a portable way


POSIX was never about binary portability.


The binary portability is, in practice, not the most difficult feature, as long as the CPU arch is the same. It is also kind of a hack and IMO a nice-to-have feature but not as vital as true portability.

POSIX was not limited to the Unix world, the goal was for it to be implemented by all OS vendors, and it was partially done.


Doesn't matter. POSIX is "write once, compile everywhere," while this is "compile once, run everywhere." It could be that POSIX is easier to write than for Cosmo bins, shifting the balance between them! I see them as just different endpoints of development.


Well said. In reality, it has been more about supporting common system level APIs (think read, write, fork, etc).


Ah, yes, let's just keep on going without trying to make things better for anyone instead. That's sure to make things better!

Improvement doesn't come from passiveness. Someone, somewhere, will have to start first.


That was the most interesting part of the article for me. I don't understand how it can be faster, given that there's syscall translation going on. Is this more of a commentary on the quality of the `libc` available on Windows? Or on the quality of the GNU Emacs Windows port?


IIUC there is no syscall translation, it's more like there are separate libc implementations and the correct one gets selected at program start based on the OS.


So like in-process WINE?


Yes, this seems fairly accurate. In fact I think Wine supports this mode where you link Wine into a "windows program" at build time to produce a "native" Linux executable. So basically the difference is that you target a POSIX API rather than Win32 and the backend implementation is selected at runtime rather than build time. But both projects have the same idea that they will implement a particular API on multiple platforms.


Could be like the improvements seen when running applications using DXVK. My understanding is that sometimes these translation layers can use newer and more efficient methods than the path that a native implement for the time would use. I'm not a subject matter expert though, and could be completely off base.


Every time I see an update from Justine I get so excited. It's like watching the future of computing unfold in real time. It makes me wish we could send them back in time - all of the pieces to make this work have been in place for a long long time but nobody connected all the dots. The funniest part of this post are the instructions to integrate it with autoconf. All of that autotools nonsense wouldn't have had to exist if this had been around!


This is great and all but it’s fundamentally a toy. There are a number of tradeoffs involved here, all so that the same binary runs on multiple operating systems, which isn’t actually very useful. If your program isn’t vaguely portable to begin with, it still won’t work.


> all so that the same binary runs on multiple operating systems, which isn’t actually very useful.

I like to mention my use case when this comes up: my log file viewer (https://lnav.org) uploads an agent to remote hosts in order to tail log files on that host[1]. While lnav itself is not built using cosmo, the agent is. So, it works on multiple OSs without having to compile and include multiple versions of the agent.

[1] - https://lnav.org/2021/05/03/tailing-remote-files.html


Man oh man, how come I didn't find this tool 6 months ago? I think you need more topics/tags on the github repo :-D

Extremely cool, I will definitely check out lnav when I get a chance. I've been battling with the big players for a few months now and their systems are just so overengineered and complex for my needs that it's silly.

I just need tail -f for 10-ish servers and desktops.

I haven't even read the project readme, but I presume lnav is exactly what I wanted. Excellent!


I just wrote a similar thing. A simple CLI that posts alerts and heartbeats to Alerta. I used Go mainly for the same reason. (But I also couldn't write it in C or C++ :D)


Can you elaborate? I’m not sure I follow your argument. A requirement to write portable C doesn’t seem so insurmountable to render the project a mere toy.

The suite of useful tools included in the post seems like a good counter example to the claim that this is inherently not useful for anything serious.

Fat multi-arch binaries are a thing on other platforms like darwin, where they are used extremely widely. What makes this approach so different?


Multi-arch seems completely different than multi-platform. The former is obviously useful, the user isn't necessarily going to understand why a program which ran on their MacBook isn't runnable on their older iMac because it's ARM only. The two programs can also still use highly specific OS integrations, GPU acceleration APIs, and make assumptions about being a macOS system. The stretch to multi-platform comes at a much higher cost in limitations for a much more dubious level of gain, as badass as it is from a technical perspective. When I say "cost" e.g. on Windows I have to rename the executable to end in .exe be able to launch it, when I do simple text based programs like nano do run... but they are completely unusable. Bash runs but I can't select, copy, or paste text with the mouse. It's borderline unusable if the app does more than behind the scenes processing only.

With that in mind, "plugins" to cross platform applications instead of standalone apps could be an interesting use case though. That's something which has typically went towards per platform, interpreted/jited, or VM'd solutions - all of which have their downsides for a typical user, don't really care about the rest of the system as much, and don't need to be anything but "behind the scenes processing" in most cases.


ISO C and POSIX don't provide support for anything beyond CLI applications and daemons.

Sure if one wants to live in the world of UNIX before X Windows, I guess it is ok.


This is true, but given that many applications are built using web tech now, this stack is sufficient to fire up a server and make an app available on localhost. I can see a lot of use cases for that, and it's something that wasn't there in UNIX before X Windows. I'd use this for my personal projects that provide a web interface, since I can build once and sync (using Syncthing) the actual binaries between my Android tablet, my Macbook, and my Intel laptop. Niche use case, but very neat!


Except modern HTTP and the whole security stack isn't part of those APIs either.


I don't understand what's useful here either. It's not inherently useful to have my `ls` on Mac be the same one as chromeOS, I'm happy with whatever is on either.

If this means I can FFI link against one ONNX library instead of one for linux64, Linux ARM, macOS arm, macOS Intel, android, iOS, win x64, win ARM, I'm all for it though.


Not sure what you mean by that, but a lot of great things start as toys.

That even explains part of their success: nobody pays attention to toys, and once they become ubiquitous it's too late to fight them.


Definitely exciting. Portability of binaries is such a problem these days with all the angst around ABI compatibility in the Linux kernel and the push for containerization (e.g. lots of distros going towards Snap/AppImage). Justine's work seems like it's working towards a research idea from Alan Kay about developing a kind of "Model T" library that provides a solid core for all computing [0].

I'm also kind of jealous. Like most of us I work on big systems with millions of lines of spaghetti code. I think that building very small, reliable tools like Justine's would be much more impactful work.

[0] https://web.archive.org/web/20070625105727/http://www.intel-...


exactly!


I swear this is the coolest project ever!!! I am using cosmo for our stuff too. jart & the team is super dedicated and responsive.

Kinda feels like they are super intelligent alien beings from another planet trying to save us from software bloat and fragmentation.

> POSIX even changed their rules about binary in shell scripts specifically to let us do it.

I don't know what to say.


This is a neat trick and clever technical work, but is it useful in practical terms?

Like, wouldn't you just download the binary that's been compiled specifically for the platform and architecture that you're using? Rather than relying on a potentially quite fragile method of cross-platform execution.

In a way it kind of reminds me of Urbit. Very clever, very cool, but also very niche and more of a hobbyist showcase project than anything else. Not that there's anything wrong with that of course.


For the consumer it's a simple switch(arch) statement to download the right binary.

But for the developer, it means setting up 9 different build pipelines and artifacts (and realistically, most won't bother with BSD builds and a lot still don't bother with arm64 builds).

It's not necessarily a huge hurdle or an unbearable expense with modern CI services, but it's still a massive deal that this project can make it all unnecessary for every single C/C++ developer out there. If this were a paid product, literally millions of companies would be happy to pay a small fee to save on CI costs, time and maintenance.


Does this really change if Cosmopolitan e.g. outputs 9 different artifacts instead of 1 artifact merging all 9? The advantage you're describing seems to lie mostly in "a C/C++ build system which can actually cross compile without pulling your hair out" not "a C/C++ build system which produces a binary I can take from BSD to Windows and execute unmodified".


Building a system capable of the latter is what enables the former.

EDIT: not sure what is controversial about this statement. I'm not saying it's the only solution, but it does qualify.


It's because the former is much easier/better if you don't also do the latter. The harder thing gives you the easier thing as a side effect, yes, but you could just do the easier thing directly and not do the harder thing at all. Zig's "zig cc" command is an example of a system that gives you the former without doing the latter. If you ONLY care about simplifying your CI for cross-compilation builds, take a look at Zig as your C/C++ compiler frontend.


You'll still need nine test pipelines.


Write once, run anywhere has been a slogan for coming up on thirty years. Except all implementations of it have acceded to reality in one or more important aspects, such as needing to install Java separately. And it's not just platform-specific compilation, it's everything that could support platform-specific compilation (if you've never tried to cross-compile from Linux to MSVC, you should), and also all sorts of platform-specific code (like console functions vs terminal sequences, or even stuff as banal as $HOME vs $USERPROFILE). Cosmopolitan still isn't perfect, because it doesn't emulate all of Linux, so you still need kernel32.dll here and there. But it is still the best of any attempts.


I agree. You sound like you're speaking from experience. If so, I'd love to hear what sort of stuff you're building with Cosmo, if you're able to share! Feel free to reach out anytime (privately or discord) and let me know what the project can be doing to better serve your needs.


It’s a very cool toy and fun personal project, but it’s not much more even though the author really wants it to be. Your code has to be vaguely portable anyway for this to work. So why would you pay the tradeoffs for a binary that runs in multiple operating systems, which is not that useful.


I can only hope my own projects reach 10% the coolness of this "toy" one day.


It's not a personal attack


It doesn't have to be personal to be condescending and/or dismissive.


I noticed a similar comment from you in the same thread. If you don't write portable software, it doesn't mean the world isn't writing portable software in C, C++, Rust, etc. To list a very few ones:

Blender, GIMP, Emacs, Vim, Pidgin, Evince, Firefox, gEdit, Inkscape, Krita, FFmpeg, Python, Perl, ... I could go on and on.


That "portable" software is full of conditional compilation flags and wrappers to OS specific APIs.


You can write portable software… and then compile it for each platform to get the best performance and functionality.


> You can write portable software… and then compile it for each platform to get the best performance and functionality.

Perhaps not what you intended, but I believe this is that exactly what Cosmopolitan is doing: - They are writing portable software in that it can run on various architectures and operating systems - They compile it for each platform, even if the output is a single binary - For the best performance and functionality, they mention several examples of how Cosmopolitan outperforms the native alternatives

I'm sure there are plenty of rebuttals ("Emacs on Windows is a port", "Cygwin isn't portable", "they could make the native version of $WHATEVER more performant", "Cosmopolitan isn't always faster", etc.), all of which are well and good, but would be missing the bigger picture, which is that there are reasons for both approaches (among others!) to exist, an idea that far transcends software.


That whole comment could equally apply to webassembly, and people seem pretty excited about that.


Cool. Somebody still needs to teach sscanf how to parse floats though. https://github.com/jart/cosmopolitan/issues/456

The code to do it would probably go in here: https://github.com/jart/cosmopolitan/blob/master/libc/stdio/...

I mean, I know why it's not done (parsing floats correctly is a lot harder than it would at first seem to be) and I'm not complaining, more like hinting to some of the fine people that haunt this website who might find such a task interesting.


Is anyone working on this? I'll try it out. I've been reading all I can about floats the past few days in order to add support for them in my language. Perfect opportunity.


I'm so happy to hear you're interested in this problem. There's two packages in the Cosmo repo you could depend on for doing this: third_party/double-conversion/ and third_party/gdtoa/. Both libraries are pretty good, but I think double-conversion is the more impressive of the two. It'd be great to see scanf() parse floats with double-conversion if it's possible. One last thing, if any of the non-standardized features of our scanf() implementation get in your way, then I'm not super attached to them and they can be deleted.


Pull request sent.

https://github.com/jart/cosmopolitan/pull/924

Oops, I only now realized there's a test suite. I'll be adding tests too... After I get some sleep.


I see. I'll try those libraries out. Was about to try writing my own algorithm despite not having a math background. The libraries will definitely be easier. Cosmopolitan can actually link against those despite being the libc?

I'm building my copy of cosmopolitan right now. If I succeed, I'll send you a pull request on GitHub.


> However portability isn't the only selling point. Cosmo Libc will make your software faster and use less memory too.

With that in mind, is there a "slim binary" mode that lets me only export the code to run the binaries on my system, so that I can reap these benefits for personal use without added "bloat" for a feature that I won't need? (where "bloat" is contextual, with the current context being "not actually planning to make use of portability")


Author here. We've got you covered. Search for `MODE=tinylinux` in the https://github.com/jart/cosmopolitan#getting-started section of the README. If you use that build mode, then hello world for x86 linux is only 8kb in size. It's very similar to what you'd expect from Musl Libc. All the Windows / BSD / Mac / BIOS stuff gets removed from the compilation.

That predefined mode is actually a friendly wrapper around a more generalized platform support system Cosmopolitan offers, which is called `-DSUPPORT_VECTOR` where you can define a bitset of specifically what platforms you want to be supported. Then dead code elimination takes care of the rest. The same concept also generally applies to microarchitecture support, where you can have as much or as little runtime dispatching as you want.


Would you consider this a competitive replacement of Busybox? Curious if you've compared, since they also take liberty in cutting out uncommon functionality.


I think you can subset supported systems, like you could only compile for x86_64 ELF systems (aka Linux and *BSD) and have the shim be much smaller; presumably a subset of one is also acceptable. I don’t know how (or if) you can do this with the new build environment, though.


HN doesn't allow non-ASCII in usernames?


I can't use wget from homebrew anymore on my computer because of some weird shared library crap but I can download this universal binary and it just works. Whaaaaat!?!

So so so awesome.


> POSIX even changed their rules about binary in shell scripts specifically to let us do it.

What does this refer to?

The latest POSIX standard was released 2007. [1]

1: https://standards.ieee.org/ieee/1003.1/7101/


Author here. See https://austingroupbugs.net/view.php?id=1250 and https://austingroupbugs.net/view.php?id=1226 with a major shoutout to Jilles Tjoelker from the FreeBSD who helped make it possible back then!


POSIX / SUS / the Open Group Base Specifications have issues (pun not intended, but I’ll take it), and then those issues have editions. The last one of those is from 2018[1], being a revision of (indeed) the 2008 issue. (I remember Landley being more than a little acidic about this versioning scheme.)

I still have no idea what the quote is referring to, though, and given Justine’s slightly (deliberately?) unhinged manner of writing, I’d give even odds the change is in fact from 2001 or something like that.

[1] https://pubs.opengroup.org/onlinepubs/9699919799.2018edition...


The references to POSIX "approval"/"changes" in Cosmopolitan docs are usually talking about bugs like this: https://austingroupbugs.net/view.php?id=1250

I'm not sure whether the proposed changes have actually made it into a published edition of the specification.


This looks to be the one, thank you! Doesn’t look to have gotten into the current version [the sh(1) page in the version I linked still refers to text files]. (The bug is also tagged tc3-2008, when the last corrigendum released is TC2, and the change was marked applied in 2019. So it makes sense it hasn’t found its way into a release yet.)


Don't think this is the bug they refer to, but it's one affecting sh input rules. There are others.

https://austingroupbugs.net/view.php?id=1250


Usually when I see yet another variation on this theme my first response is 'oh not, not again', but this time it is more like 'wow, that's really cool' and I hope that it will be further established and that it will see much adoption.

Of course to get fewer distribution formats you had to make one more distribution format but in this one case it might actually work.


It says arm64 linux support, I will have to try this on a raspberry pi. It’s kind of amazing and magical that this person pulled it off. We need a MacArther genius award for software. And this should be the first award.


What's almost as impressive as the project itself is the author's responsiveness here. Specifically, they have already built a solution for almost everyone's "but what about my niche use case" reply.

Seems to be a really well thought-out project.


Super fast. Love of the craft! Never had an experience where wizard type of coders of projects would respond and fix so fast, even before you finish testing of the previous stuff :)


I'm using Pyinstaller to ship a zero-dependency Python app. It would be amazing if Cosmopolitan could make it portable too. Is anyone working on Pyinstaller+Cosmopolitan integration? I guess a key issue there would be that many Python dependencies ship C extensions which are typically distributed as prebuilt platform-specific binary "wheel" packages via pip. I guess pip would need to start hosting a Cosmopolitan flavor of wheel package in addition to the native ones?


What I would prefer to see happen in the Python community is for Python packages to embed APE binaries and launch them as subprocesses (ideally using posix_spawn) because then you can mostly just ship pure Python with a few APE programs for your native needs, and nothing about the Python packaging ecosystem needs to change.

That was my dream when I worked on the TensorFlow team. One of the questions I asked myself is, if a MatMul kernel takes milliseconds to perform an op, and it takes microseconds to launch a subprocess, then why do I need to dynamically link a 50mb TensorFlow DSO when I can just whip up a simple C program to perform the very small amount of native math, system calls, and data crunching that I need for TensorBoard?

Well, now with Cosmopolitan, it's finally possible. Just whip up the ~100 or so lines of C/C++ code that's impossible to do with Python into a small fat static APE binary, and vendor that program like any other .txt or .dat file asset. Then launch it when you need to, while never caring or needing to worry about shipping multiple .whl files or setting up Jenkins build farms for BSDs, Windows, etc. Life stays easy.


> and it takes microseconds to launch a subprocess

On my laptop (ASUS GA503QM, 5800HS), running /usr/bin/true to completion takes around 400μs, demonstrated by these three different approaches to spawning a thousand processes:

  $ python -m timeit -n 1000 --setup 'import subprocess' 'subprocess.run(["/usr/bin/true"])'
  1000 loops, best of 5: 441 usec per loop

  $ rustc -o x - <<<'fn main() {
      for _ in 0..1000 {
          let _ = std::process::Command::new("/usr/bin/true").status();
      }
  }' && time ./x
  ./x  0.33s user 0.07s system 99% cpu 0.402 total

  $ time (i=0; while [ $i -lt 1000 ]; do i=$(($i + 1)); /usr/bin/true; done)
  [elided]  0.66s user 0.43s system 100% cpu 1.088 total
Historically spawning processes was vastly slower on Windows; I’m not certain of the current state though I think it improved a few years ago, but I believe it’s still considerably more than one millisecond; 10–20ms is the vague number that’s lodged in my memory, but not supported, and I can’t test it now. (I invite anyone running Windows to provide figures. You may well already have a true.exe somewhere, or there’s https://github.com/mlocati/true-for-windows, or just write your own stub executable.)

If you’re going to be using such calls often, spawning just one persistent process and using IPC for I/O is likely to be much faster.


> Historically spawning processes was vastly slower on Windows

Indeed.

> I’m not certain of the current state though I think it improved a few years ago

It did? I feel like it gets slower and slower every time.

> I believe it’s still considerably more than one millisecond; 10–20ms is the vague number that’s lodged in my memory, but not supported, and I can’t test it now. (I invite anyone running Windows to provide figures.)

Yep. On the Windows 10 machine I have it's around 4ms, though that's antivirus and other similar sources of slowness disabled. You could probably get it closer to 2-3ms on a faster machine, but that's the ballpark.


I'm not sure I understand fully. Are you saying that instead of e.g. writing a neural net in Python using PyTorch (which loads several native extensions into the Python interpreter) I should write the whole neural net in C using a C neural net library, and ship it as an executable that my Python code can launch as a subprocess whenever it wants to run a forward or backward pass? Or are you saying that I can use PyTorch in Python but instead of loading a native extension into the Python process it should ship an executable that it launches every time it wants to run a compute kernel? Or something else?


Here's what I'm saying. Let's say you are a Python package author. You ship your app or library on PyPi to a lot of users. You have a problem that can be solved in 100 lines of C++, but it can't be solved using Python code. Python would just go too slow. That's a problem, because in order to introduce a single line of native code into your Python package, it would require assuming numerous burdens relating to compilation and distribution. Native code is hard. Native code being hard is the whole reason we use high-level languages like Python. It's hard because you'd have to setup a devops process to build and test your C code on all these different operating systems. So what I'm proposing that you consider instead, is compile the ~100 lines of C/C++ code you want as a ~100kb fat APE binary, on your one dev system of choice, using Cosmo. Then embed that APE executable inside your pure Python package, launch it as a subprocess, and never have to worry about devops and distribution toil.


I like that idea for a lot of applications (I also like the python "multiprocessing" library, other languages could learn a thing or two from it, and it really takes the sting out of the GIL). But I don't see it working well for something like numpy or PyTorch which are sharing arbitrary memory between Python and native and calling back and forth at a very high frequency.

PyTorch and the neural net implementations built on it are the whole reason I'm using Python at all. If the answer was "build the native extensions you need for PyTorch/etc into the Python binary" that would be fine too, I have no love for dynamic library loading. But I don't see the PyTorch team going out of their way to change anything about their build process or runtime to work with Cosmopolitan, as much as I wish they would, so my guess is I won't be able to use Cosmopolitan Python for the foreseeable future.


There is no support for dynamic libraries in Cosmopolitan right now, so the libraries would either need to be compiled in (statically) or included in the archive as Python-only libraries. With the later ones, it should be a matter of adding them to the zip archive within the cosmo python executable, which should make them available to your scripts. See the discussion elsewhere in this thread (https://news.ycombinator.com/item?id=38102629) for some additional details.


What packages do you use in your app? If you're not using too many C extensions, it may be possible to build your app with Cosmopolitan.


Lots of C extensions. Has anyone gotten PyTorch working with Cosmopolitan? With CUDA?


I'm amazed by this. Platform-independence _with the same binary_ is such a neat solution that would really have helped me at a prior job.

Some corporate IT shops manage user machines with tooling that can't deploy software specific to machine os/version/hardware/etc. This often caused problems with 32-bit vs 64-bit windows machines or differing windows versions (XP/Vista/....). We also couldn't easily make linux or osx executables available for the end-users due to corporate IT policies.


As awesome as these are, they're not really portable executables if you can't set their setuid bits and expect them to run as root like with normal executables, right?


There's a program that's part of cosmos called `assimilate` which can turn any APE binary into a platform-specific binary.

    jart@nightmare:~$ /opt/cosmos/bin/assimilate --help
    assimilate: illegal option -- -
    actually portable executable assimilate v1.6
    copyright 2023 justine alexandra roberts tunney
    usage: assimilate [-xapembfchv] [-o PATH] FILE...
    -h          show help
    -v          show version
    -f          ignore soft errors
    -b          don't remove freebsd from elf os/abi
    -c          clobber input path w/o making backup
    -e          convert to elf regardless of host os
    -m          convert to macho regardless of host os
    -x          convert to amd64 regardless of host cpu
    -a          convert to arm64 regardless of host cpu
    -p          convert to ppc64 regardless of host cpu
    -o PATH     write modified binary to different file
If you aren't using binfmt_misc then you can also pass the `--assimilate` flag to your APE binary, to turn it into a native executable, without having to use the tool. It's baked into the shell script. Just use the `less` command on any APE file and read the shell script.

Once assimilated, you're free to turn it into a setuid binary.

We also have patches in flight for the Linux Kernel as well as BSDs, to make APE native. https://justine.lol/ape.patch


Oh wow, that's very nice! Thanks for sharing!


Wow, that’s some combination of awesome and horrifying.

Is there an actual written spec somewhere describing how this works? What happens if the APE embeds an ELF header and something else? Or multiple ELF headers?


See the comments in https://justine.lol/ape.patch and at the bottom of https://github.com/jart/cosmopolitan/blob/3.0/tool/build/ape... and also https://github.com/jart/cosmopolitan/blob/3.0/ape/loader.c has good information too. I'm planning to roll it all into a formal looking specification pdf sometime very soon. Feedback is welcome. As for your question, ELF headers are defined in the APE shell script as printf 'octal' statements. The loader parses those out in order and looks to see if the e_machine matches the host architecture, and if so, uses that one.


I did read the comments.

ISTM if this thing goes in the Linux kernel (and maybe a BSD kernel and maybe a Windows kernel, yeah right), it should at least be written down cleanly. It doesn’t necessarily need to be a PDF. (Linux can load ELF files. ELF has a spec or five that are only mostly horrible, and I’m not actually aware of a unified ELF spec that covers everything, but this isn’t really a showstopper.)

Off the top of my head, it seems like it would be nice for whatever bit of the shell-compatible header encodes an ELF header to also indicate that it’s ELF (as opposed to something else) and maybe even that it’s Linux-flavored ELF. Maybe like:

#ELF-Linux-LE print…

#ELF-BSD-LE print…

#ELF-U-boot-BE print…

This isn’t intended to be a real proposal. Little- and big-endian in the same binary would be even more amusing than the average APE binary, and I don’t remember off the top of my head exactly which properties of the target can be unambiguously determined from the binary encoding of the ELF header.

(And obviously there would be some shell-flavored conditions in the middle.)


Will it allow native like bash script support on Windows? I use windows as my main OS and use cmder for CLI things but really miss proper bash script support.

Other than bash itself, does it mean it can be used to make whole set of GNU tools cross platform?


Absolutely. cosmos-3.0.1.zip contains bash, GNU coreutils, Emacs, and a whole lot more. All of which run great on the Windows console. On our github release page, there's also a cosmocc zip of a GNU/Linux style GCC compiler. Cosmo provides a refreshing way to build Windows software, because we use the System V ABI (i.e. long is actually 64-bit) when we build Windows software. So there's a much more consistent cross platform development experience.


Tried running bash by renaming it to bash.exe using both CMD and Powershell and both return "Access denied.

Even though Windows 10 already has Terminal and I was getting

     [error 2147942405 (0x80070005) when launching `C:\bin\bash -l']
I downloaded Terminal Preview which still throws the same error. Is Terminal or Terminal Preview the only way to run bash? There might be a way to configure cmder to use bash in a similar way you suggested for Terminal. Don't know how yet.


Try whitelisting the folder with Windows Defender. Sometimes when I get EACCES style errors on Windows mysteriously, it's because I need to recalibrate the security on the folder. Here's an example of something I ran once which fixed it.

    PS C:\WINDOWS\system32> $ACL = Get-ACL -Path C:\Users\jtunn
    PS C:\WINDOWS\system32> $ACL | Set-ACL -Path C:\bin
I also just uploaded cosmos-3.0.1.zip to Microsoft Security Intelligence to make sure they get whitelisted with their cloud security.



I linked bash to bash.exe and was able to start it however everything from /bin was failing with:

  The application was unable to start correctly (0xc0000142).
Turns out it doesn't work when I start bash by double click bash.exe but it works if I start it from cmd.exe.


Yes and yes.


Very cool! What would the "gui-version" of this look like? Would you write it once with linux bindings and the executable would succesfully create a window in every operating system?


I think it'd be pretty sweet to have a basically an APE approach to having a blank GPU framebuffer canvas, and let high level libraries do the rest. Other folks on my team have been floating the idea of getting X to build as an APE binary. Who knows what the future holds? We don't have any resources devoted however to the problem at the moment.


Maybe could APE the web GPU implementations: Google's "dawn" or Mozilla's "wpgu".


This seems like a good place to start: https://eliemichel.github.io/LearnWebGPU/

I think it'd have to be built into the libc...?


Oh man, something like that would be wonderful for indie games. Targeting multiple platforms is a lot of work for a hobbyist game developer, especially if you're not using a full-on engine like Unity or Godot.


Cosmopolitan is cool and I have some uses in mind for it that I wish to get to.

But what I don't understand is the use case for an exe which supports both running as an user app on normal operating systems and from the BIOS. For which application specifically does it makes sense to run it in both these very different contexts?


Look at it the other way round, from someone who wants to put something in the BIOS. It's going to be much more convenient to be able to test as much of that as possible without leaving user mode and actually having to run it by restarting a (potentially virtual) machine.

But also: sbcl. You just know someone's going to do lisp-from-boot with this, if they haven't already.



Emacs could become an actual operating system!


Congratulations on your release and sponsorships!

> In the Cosmos, every program is statically linked and contains a PKZIP central directory where its /usr/share dependencies are embedded.

Sounds really neat, even the data and configuration files are linked into the executable. Can't wait to see what else you'll come up with.


The author might be interested to know that this page might be displaying in an undesired way on iPhone mini screens:

https://i.ibb.co/v4s0Xpj/IMG-1221.png


Eek. If anyone has a quick CSS fix for mobile I'll happily add it. I'm talking to some of my people too. Thanks for bringing it to my attention.


I'm amused by the fact that even authors of the most technically brilliant projects in recent memory also struggle with CSS, just like us mere mortals. :)

Love your work! <3


This is the only concession to mobile that I have on my website, and it seems to do okay:

    <meta name="viewport" content="width=device-width, initial-scale=1">


This behavior really should have been the default in mobile browsers. It's not like emulating a desktop viewport actually makes giant tables usable on a tiny mobile screen so it would have been better to prefer not breaking pages that can reflow for a mostly useless hack.


I don't know, I think pinch-to-zoom + pan is a pretty decent way of dealing with pages that have more complex layouts than basic document, but were designed using e.g. tables for layout. Given that most non-trivial pages would have been laid out that way back when mobile browsers were first coming out, it seems like a reasonable tradeoff to me.

That is to say, it's definitely a hack but I wouldn't call it useless, at least originally. These days it's a lot less useful since the number of pages that do benefit from this treatment has decreased dramatically. But at this point the die has been cast.


How about dynamic linking? Yeah, ok, that's hard. You might have to write an RTLD to link into the executable to find and load cosmo DLLs. Maybe not that hard... You could borrow BSD ld.so.1 code, I suppose.

Ah, that brings me to something else that someone like jart might want to take on:

# bringing static linking for C into the 21st century

What's wrong with static linking in C? Well, it's still stuck with 1970s semantics, while dynamic linking has much nicer semantics. Specifically:

  - static linking flattens the dependency
    tree, which causes

  - symbol collision issues

  - also, there's no RPATH equiv. for static
    linking
My thinking is to:

  - write dependency metadata (-lfoo, rpath,
    -L/...) into a "hidden" .o that has just
    this metadata encoded in it

  - make the static linker look for that
    metadata in dependencies and resolve
    conflicts the same way as in dynamic
    linking

  - for each link-edit, including the final
    link-edit of the executable, require
    only that direct -lfoo dependencies be
    listed
Well, anyways, it's a lot to ask :(


Not disagreeing with your overall point, but symbol collision is still very much an issue with dynamic linking on Linux right?

AFAIK, the gnu dynamic linker doesn't do any namespacing (as opposed to Solaris').


Linux has versioned symbols, and Solaris/Illumos has direct binding. The two schemes achieve roughly the same result: that the bindings made at link-edit time are the bindings you get a run-time.

In the versioned symbols case this is done via decorating symbols in the dependent with the SONAME and version of the dependency that is expected to provide them. In direct binding this is done by decorating symbols in the dependent with just the SONAME of the dependency that is expected to provide them.

The versioned symbol technique allows a shared object to provide multiple versions of a symbol with the same name, which can be useful for some things, but direct binding is just much easier to use than versioned symbols: just add `-B direct` to the link-edits and you're done.

Even in the absence of symbol versioning and direct binding, the fact that each object records its dependencies means that symbol conflicts will be only among those dependencies, and this can be discovered at link-edit time.

LD_PRELOAD interposers, on the other hand, can cause symbol conflicts in spite of all the foregoing. For this you can use `-B protected` or similar, but you may not want to.



Linux and Windows have very different dynamic linking strategies. (I think Windows does it better…)


> (I think Windows does it better…)

Tell us more?


Imagine you have a .cpp file with a global variable. Now imagine this cpp file is compiled into two different shared/dynamic libraries. And that both are loaded by some exe.

On Linux you’ll have one global variable. On Windows each DLL will have its own copy.

Which is better? It depends. Personally I think it’s much better for each shared/dynamic library to be a black box with a clearly defined API boundary. Thus I think the Windows approach is better.

The root evil here is that C++ is underdefined and what should really really really be a language level rule is actually left up to the platform.

I also think globals are evil and should almost never be used. But that’s a separate topic.


You missed the above commentary. If you use versioned symbols then the right thing will happen on Linux too: each shared object will have its own copy.

> The root evil here is that C++ is underdefined and what should really really really be a language level rule is actually left up to the platform.

Well, the issue is that C++ shares linking semantics with C, and C's linking semantics are not that well specified, because there's static linking -broken- and ELF -which has evolved to fix the problem you mention-.


I read the commentary.

Linux has eleventy billion config settings. If you very carefully set them, maintain them, and make regular blood moon sacrifices you can induce the desired behavior.

I think the Windows model is better. I think Linux generally handles shared libraries poorly.

You probably love Linux and think its preferences are great. That’s fine.


This is not a system configuration setting.

This is a matter of linker-editor defaults. Those defaults tend to be bad for backwards compatibility reasons. Yes, if you build software on Linux (or the BSDs, or Solaris, or Illumos distros) you have to know about this, or use frameworks that do.


The thing about defaults is that anyone can change them. It’s easy!

Also Google pays $26,000,000,000 a year to make sure Google is the default search engine. Because defaults are so easy to change that nobody changes them.

The Linux software community expects libraries to be written a certain way. It is a de facto platform configuration setting. Even if there are, per Linux tradition, a few flags.


Trying to run Cosmos apps from the Windows Terminal opens a pop-up saying "Select an app to open '<app>'". How can I execute them?

I ended up finding a solution:

> If you want to run them on Windows, then you simply need to rename the file so that it has the .com suffix. Better yet, consider making that a symlink (a.k.a. reparse point).


What I like to do is configure Windows Terminal Preview so it launches `C:\bin\bash -l` as my command prompt. Once you're inside bash, it doesn't care about the .com or .exe suffix being there. Only CMD.EXE really cares about the suffix. So you have to simply rename the files if you want to run it there.


I'm getting MITM'd by my ISP when trying to view this site and some others. It manifests as an SSL certificate error, and if you ignore the warning, it shows that stupid mcafee thing. Does anyone know how to not get MITM'd by my ISP? I'm already using DNS servers 1.1.1.1, 1.0.0.1.


Have you tried DNS over HTTPS?

If you haven't and you're on Firefox, go to `about:preferences#privacy`, then scroll to the bottom and you should be able to activate it there.


Looked into it a bit more, I don't think DNS is the issue. The request goes to the correct IP address, and then my ISP does the MITM attack based on the IP address. So, instead of getting justine.lol's SSL certificate, I get a certificate instead for *.safezone.mcafee.com. Firefox correctly flags this as a bad SSL cert, and I don't want to accept the bad cert, so I basically just don't have internet access to these websites using my ISP.


Author here. I use MbedTLS to serve justine.lol using Let's Encrypt and TLS v2 with a permissive policy regarding older (but not yet obsolete) crypto formats and protocol versions (because I like supporting old browsers and old operating systems). If there's a weakness in the way I'm doing it, then I want to know about it. It might be possible that your client accepts older weaker SSL varieties and the MiTM is using that somehow as an attack vector. If so, you can try changing your browser settings. It might also be time for me to consider trading away some compatibility by forcing clients to use stronger security. Let me know what you learn! My email is in the blog post.


It's not your fault, it's my shitty ISP. I was able to access the article after discovering a setting to disable it in my modem/router. Thank you for sharing your work!


The Internet Archive can serve as a proxy, in a pinch.


of all things I was able to resolve the issue via this github issue: https://github.com/FiloSottile/age/issues/370#issuecomment-1...


which ISP? that's pretty wild


centurylink. if they had any competitors, I would switch immediately. but it's a monopoly


Experiencing the same thing with the same ISP.


Same for me on centurylink. I've run into this on a number of sites. I don't like it.


I use a SOCKS5 proxy on ramnode.com (from when they had OpenVZ for $15/year, which I think hasn't been available as a new plan for a bit now and I think will be increased or removed as an option at the next biling period; it looks like the lowest cost option is now $42/year). I change SSH to only allow certificate login (and only the particular algorithms I want to use, and listen on ports 80 and 443 to work around some wifi limitations), enable auto OS updates, and stop everything else from listening on the network to keep the chance of something being exploitable to the minimum and it just works. I sparately pass local port 853 to Google's DNS over TLS via the SSH connection (I use ssh -o VisualHostKeys=yes -NMD localhost:2000 -L localhost:853:8.8.8.8:853 and set ALL_PROXY=socks5://127.0.0.1:2000; I've learned that the visual host keys do not help at all with the thing it is supposed to do but I find it an artistic way of saying the connection is up).

I'm not sure how common it is for hosting providers to allow that kind of traffic (I think many do not) and I'm not sure how their privacy policy for that kind of use compares to others but at least they don't try to MITM traffic. Occasionally I get sites that simply block the address range (like Wikipedia for editing last I checked, although viewing works fine) and limitations or oddities will likely be worse at first (Google really wanted to redirect me to their Hong Kong search page for a while when I first stared doing this) but it is rare that I have an issue now. I'm also on CenturyLink (which I chose as still better than Comcast since you can at least use your own device) and I recommend this method (also helpful when using wifi). Another potential downside is that you don't get the local CDN caches, which I'd guess most impacts the online movie services (I don't use them and only have a 12mbps download anyway so it would hardly be the bottleneck). I think routing DNS through SOCKS helps get the closest CDN locations to the proxy (at least using encrypted DNS is a must since CenturyLink messes with that too if you try to use another DNS provider unencrypted).


one of the problems i've always had with emacs on windows is that random commands want to shell out to non-standard programs, so they fail unless you dig around and tweak your system. I hit this immediately in the APE version by trying to download use-package.

  Packages to install: 1 (use-package-2.4.5).  Proceed? (y or 
  n) y
  Operation [ Install 1 ] started
  Contacting host: melpa.org:443
  Opening TLS connection to ‘melpa.org’...
  Opening TLS connection with ‘gnutls-cli --x509cafile nil -p 
  443 melpa.org’...failed
  Opening TLS connection with ‘gnutls-cli --x509cafile nil -p 
  443 melpa.org --protocols ssl3’...failed
  Opening TLS connection to ‘melpa.org’...failed


Christmas came early! Thanks, jart-Claus, it's just what I wanted!


That's some pretty amazing stuff considering how difficult C/C++ portability is.


Hmm could this go one level higher? Could cosmopolitan be used to create a super portable bare metal unikernel applications?


All APE executables are also unikernels that boot from BIOS. Here's a demo video of the APE executable for SectorLISP (ANSI C version) running in the Blink emulator (which I wrote originally just to test this): https://storage.googleapis.com/justine/sectorlisp2/sectorlis... When you compile an APE program with cosmocc, the first 512 bytes are a master boot record where we embed a BIOS bootloader in the PE DOS stub section of the executable. APE is then able to tell when the BIOS is what loaded it, switch to 32-bit mode, set up the page tables, enter 64-bit long mode, and then call _start() and main().

I personally haven't been focusing on bare metal support myself the past several months, but we've got a talented member of the team (tkchia) who actively works on maintaining metal and expanding its capabilities. See also the list of supported system calls for bare metal here: https://justine.lol/cosmopolitan/functions.html As you can see, we still have a lot of work to do. But it's really cool to have, and I have high hopes for it someday as a cloud native deployment format. Hypervisors are in many ways the new OSes, so why do we need a traditional OS in-between?


There is so much to unpack in this comment alone, I am absolutely floored. I can't wait to play with this and tell anyone who will listen to play along too.


I wonder if those people using emacs as an OS by discount booting into it can now finally get their wish of directly booting into emacs lol.


What is the most complicates program in cosmos distro that can boot on bare metal?


What would be the best/lightest GUI-via-the-browser framework to employ with a program compiled as a Cosmopolitan fat binary?

(say, Qt WebAssembly? ...something else?)

Or is there a even better route to run-anywhere Cosmopolitan apps with a GUI?


Perhaps, by the same authors, redbean, which "embeds Lua, SQLite, and MbedTLS into a fork() driven application server" ... " a great fit for when you want to build an app that's vertically integrated into a single tiny file that runs on nearly all PCs and servers". It looks like as of now, greenbean exists as well.


I second this. I'm a Java dev and so have been porting Spring Petclinic to redbean using fullmoon which is a Lua framework built on top of redbean by Paul Kulchenko (who also is the author of ZeroBrane studio - a nice lightweight Lua ide which I have been using).

https://github.com/pkulchenko/fullmoon

So far it's been a lovely experience and Paul is super responsive. Redbean is massively faster at startup so I can build/bounce to do hot reload in real time basically where the spring app takes about 6 seconds to start up.


Generally speaking (I've not tested this kind of setup with the cosmopolitan libc) what I've done in the past with C is use something like libmicrohttpd along with some web assets linked into the executable (`xxd -i` can help you with the assets). That gives you a single (small) binary where you can use HTML/CSS/JS for the main GUI and logic.

You can then integrate additional libraries as you please, such as sqlite3 to give yourself fast, local database access over an endpoint on the embedded HTTP/S/2 (or websocket) server.


I wish Wt were more open: https://www.webtoolkit.eu/wt

Qt was doing their own thing for a while but scrubbed it, I think...

Something something Flutter Web?


This could work with Rust? I have a great use case for it and could slash half of my CI if is true!


https://github.com/ahgamut/rust-ape-example

My above repo contains example with the Rust standard library that build as fat executables with Cosmopolitan Libc.

I also got ripgrep to build https://github.com/ahgamut/ripgrep/tree/cosmopolitan, but it wasn't part of the cosmocc binaries because some crates that are part of the build require `#!feature(rustc_private)]` to be added to their source code. Same goes for bat and fd.

To summarize, Rust CLI tools can be built with Cosmopolitan Libc, but to build them like we can build gcc/emacs/git right now, we will need some support and Rust expertise.


Last time I looked into Rust-on-Cosmopolitan, I couldn't make it work as Cosmopolitan determined syscall numbers, signal numbers, and such at runtime, but Rust standard library assumes compile-time constants (basically the same issue that C switch-case has). How did you get around that? Have you tested these binaries on non-Linux platforms?


We have about ~700 test executables and two programs called runit/runitd which remote execute them across our entire test fleet each time we run `make test`. Currently, the fleet consists of `freebsd rhel7 xnu win10 openbsd netbsd pi silicon`. We used to have rhel5 and win7 in there too, but I've been slacking off the past few months. You can watch a video of how running all the test executables on all the systems only takes about fifteen seconds. https://justine.lol/sizetricks/#why


To clarify, are any of those ~700 executables written in Rust?


The trick could definitely work with rust since fundamentally it's "just" a hack on how the various scripts work on different systems. Actually getting the rust compiler to produce cosmopolitan binaries would likely be a heavy lift though.

Also it says it supports WASM (wasi?) so some applications might work out of the box with that.


I'm so excited about this I can hardly think straight...

I think the next thing I want is WebGPU...

No, wait, I want Tailscale to be built into applications...

Or the smallest possible Linux that can run this... as a Live USB...?

And I want z-machine interpreters ported to this...

And the Protocol Buffers Compiler...

And I want to run Turbo Pascal 3.0 on this somehow...

Ooh, how about Qemu ported to this?

And and and...

I feel like a kid trying to pick a puppy to adopt!


How would one go about compiling Ruby to make a cross platform binary?

I have seen the Ruby build process and it also links to libraries like OpenSSL.

Reference: https://docs.ruby-lang.org/en/master/contributing/building_r...


If I was a billionaire, I'd just give a shitload of money to Justine, Andrew Kelley and Andreas Kling (from the Serenity/LadyBird projects) and put them in a (virtual) room together and let them do their thing.

You'd get a new browser running on any hardware/OS written in Zig that would just blow out the competition.

Oh and let's throw in Fabrice Bellard in there too just for the kicks.


...I kind of want Patreon collections...?

Like, you could make a Patreon Collection out of those people's Patreons / Buy Me A Coffee / Bitcoin wallet...

And someone else could make a Collection out of a slightly different subset of people...

And I could take your Collection and purposefully exclude one person from it, and publish it as a new Collection...

...and then we could all argue about which Collection to support on Patreon...

Oh, and Justine could say, "Well, sure, but 50% of the support I get should actually go to this other Collection..."

And then there's a Cycle in the Graph and the universe explodes...


> the Cosmopolitan monorepo has two million lines of code

Anyone knows roughly how it is broken down? Because that seems massive for a small team. Or is it counting the LOCs of softwares it has wrapped up/fork of libc?


A lot of it is actually vendored code under third_party/ e.g. Python 2.6, libcxx, compiler_rt, zlib, etc. I don't like to write anything myself if I don't have to. Here's a synopsis of how many lines of code are contained in the subset of packages that me and my team (mostly) wrote ourselves.

    $ for x in ape examples libc/* tool/* net/* test/*/*; do echo $x $(wc -l $x/*.{c,cc,S,h,sh,mk,inc} $x/*/*.{c,cc,S,h,sh,inc} $x/*/*/*.{c,S,h,sh} $x/*.S | tail -n1 | awk1); done 2>/dev/null | sort -nrk2 | head -n25
    libc/calls 38690
    libc/tinymath 33400 (mostly copied from fdlibm/arm/musl/freebsd/openbsd actually)
    libc/intrin 28243 (a good chunk of this is from arm and llvm)
    libc/nt 26738 (it's just win32 interface boilerplate)
    libc/stdio 21829
    examples 19740 (a big chunk of that is actually dash)
    libc/sysv 18305
    tool/build 17811
    test/libc/xed 17581 (mostly generated actually)
    libc/nexgen32e 16695
    tool/net 15058
    libc/str 12150
    tool/viz 11511
    libc/runtime 10823
    test/libc/calls 9460
    ape 7507
    libc/sock 7436
    tool/plinko 7075
    libc/proc 6956
    net/http 6901
    libc/thread 6757
    libc/vga 5518
    test/libc/stdio 5057
    libc/log 4759
    libc/time 4749
    test/libc/tinymath 4555
    libc/testlib 4217
That comes out to 429,866 lines. Every file has a copyright header saying where it came from. So a lot of those lines are just copyright notices repeated over and over again. It also means if anyone is bored, there's an opportunity to do some deeper analysis.


I don't feel like programming anymore


Can I recompile Ruby with this and make the ruby runtime portable?


Try it out! We got Lua/LuaJIT, Python, PHP, and Rust building (the latter two are not fully automatic yet), so Ruby might be possible even now.


While I have no experience building ruby, if standard ruby gives you trouble - might be worth to try mruby - it is likely easier to build and debug the build process.


Counterintuitively, having messed around with building mruby for a project a few months ago, I found it harder to deal with. It's a lot more hardcore, with vastly fewer resources and more sharp edges, and is orders of magnitude less popular, so you find yourself hitting basic problems you would think would have been solved years ago.

I'd stay away from it unless you have a very pressing need.


What kind of sorcery is this???

Just kidding, I’ve played around with some of the stuff @jart and other contributors have created and it’s mind blowing. Well done and keep up the good work.


Is specific effort being put in to dodge antiviruses? I've been unable to use redbean at work due to Crowdstrike deciding it's malware.


Author here. I invented a novel polyglot executable format that makes developers lives easier, and we're helping the AV industry feel comfortable with that through openness and transparency. Every time I ship a release, I make an effort to upload all the executables to Microsoft Security Intelligence to give them a heads up and let them know that I wrote them (since there's currently no vendor neutral solution for code signing). If you build APE binaries, then you should do that too: https://www.microsoft.com/en-us/wdsi/filesubmission?persona=... Every time I submit the form, Microsoft whitelists them with zero hassle. They even let you upload a single zip file containing hundreds of executables, and they'll take care of them all. It's great. Doing that ensures Windows Defender won't cause issues. The good news is most other AVs are plugged into the same database as Defender (even Google Search bases their analysis on Microsoft's security intelligence) so that form actually gets you off the radar of a lot of AVs. As for CrowdStrike, if you have contacts there, then I'd be happy to share with them information about what our team is building and shipping, as well as documentation on the APE file format, in addition to free consultation from me for any help they need supporting it on their end. My email is in the blog post.


Which options do you choose on that page before uploading?


- Product: Windows 10 Defender

- Company Name: Justine Tunney

- Incorrectly detected as malware/malicious

- Detection Name: Trojan:Win32/Wacatac.B!ml

- Additional Information (example): I'm the author of Redbean, an open source web server https://redbean.dev It uses a polyglot executable format called APE which I designed. My project has received positive coverage in the media: https://www.theregister.com/2022/06/20/redbean_2_a_singlefil... Sadly we're having trouble with AVs. Could you unflag my release binaries? Thanks!


Thank you


Administrators can create exclusions in Crowdstrike. Given the question I'm assuming you don't have admin rights and you should definitely not try to avoid company policy, that is a fantastic way to get canned


The article says it has support for arm64 Macs, but I get this weird error on Sonoma:

```

~/cosmos $ uname -sm

Darwin arm64

~/cosmos $ ./bin/python

ape error: ./bin/python: prog mmap failed w/ errno 1

~/cosmos $ ./bin/ls

ape error: ./bin/ls: prog mmap failed w/ errno 1

~/cosmos $ sudo xattr -rd com.apple.quarantine bin/*

Password:

~/cosmos $ ./bin/ls

ape error: ./bin/ls: prog mmap failed w/ errno 1

```

Has anyone had any luck getting it to run on Macs?


It is ok on M2 with macOS 13.6.1 (Ventura). Maybe there is something specific to Sonoma ?

    $ ./uname -sm
    Darwin arm64
    ludo@mba in ~/Downloads/cosmos-3.0.1/bin
    $ ./python
    Python 3.11.4 (heads/pypack1:65ac8ac, Oct 16 2023, 02:35:05) [GCC 11.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>>


Fantastic work. For a long time I've been dreaming about things that trancend OSs, this is some very impressive portability.


This is a dizzying amount of awesome information and im not sure what to make of it. I've been in enough rabbit holes lately. Where are the Golang examples I can go reference? Id be interested in testing this out for my Go experiments.


I might be stupid-- but what is this again? Nor clear from the description...


If you click through to the Github homepage of the project, this is the description:

Cosmopolitan Libc makes C a build-once run-anywhere language, like Java, except it doesn't need an interpreter or virtual machine. Instead, it reconfigures stock GCC and Clang to output a POSIX-approved polyglot format that runs natively on Linux + Mac + Windows + FreeBSD + OpenBSD + NetBSD + BIOS with the best possible performance and the tiniest footprint imaginable.


Using Cloudflare DNS, I can never load jart's homepage. Does the .lol domain get blocked? Is there anyway to see "naughty" domains which might be getting intercepted?


Run your own DNS server. It's really easy and a worthwhile upgrade for your home network.

https://nlnetlabs.nl/projects/unbound/about/


cloudflare and dns over https via cloudflared works for me...


Awesome, congratulations!, I am jealous that I cannot start my own thing yet :( I have been wanting to integrate this with one of my projects. :(


I need cosmo katas...

I also want a place where I can contribute to bounties (money) to implementing different things in or on cosmo...


I'm just relieved to see a "cross platform" anything that doesn't involve wrapping things in Chrome.


Impressive! Tried on my M1 Mac but no immediate success though.

  bin ./bash
zsh: exec format error: ./bash


You need to upgrade to zsh 5.9, or backport the patch I sent them two years ago: https://github.com/zsh-users/zsh/commit/326d9c203b3980c0f841... If you can't upgrade zsh, then the workaround is to say `sh -c ./ape-program` or `bash -c ./ape-program` instead of `./ape-program`.


> ARM64: Linux, MacOS, Windows (non-native)

Why non-native?


The Windows platform doesn't run the APE shell script which checks $(uname -m). I don't know yet if it's possible to have a fat portable executable. I would hope that it's possible. I may be mistaken but I vaguely seem to recall reading about portable executables that existed a long time ago that had multiple optional headers for both Windows and OS/2. It would be nice if Microsoft did, or could, make that possible today, so we can have arm64+amd64 pe binaries. Until then, we need to rely on Microsoft's excellent x86-64 emulation support.


Mind blowing, excited to play with Cosmo 3.


Any progress on compatibility with the Zig language?

- Nevertheless, well done!


Amazing work. So many useful projects.

Another Fabrice Bellard.


What happened to bare metal support?

Nevertheless - well done!


Really cool!


Its not immediately clear what this is. The quick description is completely off on another part of the website on another webpage. TLDR: "Cosmopolitan" makes C a build-once run-anywhere language. So here's your very easy tip of the day: Describe what your thing does on the very same webpage you announce it. Very easy to do, but not done nearly enough.


I kind of felt that way, as it starts with the assumption you know what it is.

The first sub-title headline tells you, but it isn't clear to someone new if this is "one of the features of something" or "the thing."

> Build Once Anywhere, Run Anywhere C/C++

I clicked to the home page and then to here: https://justine.lol/cosmopolitan/

Then I understood!

> Cosmopolitan Libc makes C a build-once run-anywhere language, like Java, except it doesn't need an interpreter or virtual machine.

While anyone familiar probably finds these comments "stupid", just some helpful advice to the author - if it matters to you, there are people discovering this for the first time who might not realize what "it" is until you tell them!


>it starts with the assumption you know what it is.

That's the gripe! It's all context! Here it is with SUNSHINE 3.0.1:

     After nearly one year of development, I'm pleased to announce our version 3.0.1 release of Sunshine. The project is an entirely new day. For starters, Apple sponsored our work as part of their FLOWER program. Google also awarded me an open source peer bonus for my work on Sunshine, which is a rare honor, and it's nice to see our project listed up there among the greats, e.g. OPEN, QUIT, etc. In terms of this release, we're living up to the great expectations you've all held for this project in a number of ways. The first is we invented a new widget that lets you grow large dirt which...


An announcement on someone's project web site is not targeted at the random folks on Hacker News, or even random folks in general. They know their audience, and folks showing up from random places should do at least a little bit of work to figure out the context and surrounding pages.

If you've never read their blog or announcements before, I don't know why you would expect them to cater to you.

HN's headline policy makes it especially hard here, because the submitter can't provide context.


>I don't know why you would expect them to cater to you.

Its odd to think someone should not expect new user interest when they've made a new thing. Announcements are for new users and old users alike.


As far as I understood, it's 2 things:

- a compiler outputting a portable executable

- POSIX shims for multiple platforms that get statically linked to resulting binary

I'm not sure why it compares itself to Java, the closest thing would be Cygwin/MinGW.


Probably due to JVM letting you compile once and run your Java application on any subsequent JVM, regardless of OS, or something.


Wow!!


how many cl100k_base tokens is this in terms of LOC


Can we just put @jart in charge of computers now, please?


Docker actually solved this quite a while ago with tags and downloads of the correct architecture container. But this is interesting even though it won't scale well.


> Even though it won't scale well.

Why not?


Because each fork on either end will grow the hairball by a factor of x where x is the other end of the hairball. What a mess.


what do you mean by a fork?


You cant compare these. And if you would then Docker would be Mcafee alike.


Maybe my imagination isn't good enough or maybe I've spent too much time on web apps, but as a developer, why would I use this over just making a web app if my goal is cross compatibility?

Users don't install software anymore, outside of mobile. Most things are now doable through the browser. The browser isn't perfect, but from a user perspective, it's a much better app delivery service than anything that's existed before

The only things I find myself installing recently are text editors, programming languages/command line tools, and games. What else? WSL is pretty good so I can even run a lot of Linux things from within Windows now

If I need something that needs raw power that's too much for a browser, like a database server or running an LLM model, I'm just gonna use Linux - why do I need cross compatibility?


Programs are tools, not services.

Web apps require servers, servers that need to be patched, updated, certificates, DDOS protection, and a number of other things. The apps themselves need management, and maintenance. So a "web app" is a service, no matter how you slice it.

An installed program can work for decades. My personal Wiki (WikidPad) that I run every day, is from an installer compiled in 2015. It just works. I tried to run it under Linux, where it was installed from source, and it won't work. The folks at WxWindows made a major breaking change, so none of the GUI forms/dialogs work, it just seems to work, until you need to change a setting, then it dies.

In theory, you could now create an installer that would work for the next 20 years without issue across operating systems.


> Users don't install software anymore, outside of mobile.

That’s a pretty strong statement without any evidence to back it up. It sounds like the kind of statement I hear often from people who spend all of their time in the web-dev echo chambers. Lots of us install software and don’t spend much time in browsers beyond browsing the web and the handful of Electron apps that we have no choice but to use.


Much software remains outside the browser, yes. Especially games and professional tools.

But it’s not hyperbole to say the browser has become the dominant software delivery platform outside of mobile. Email, CRMs, CMSs, electronic dictionaries, word processors, online chat, filing tax returns are just a few examples of things that used to require installing native apps and now are largely browser-based.


Thank you. My thoughts exactly.


1. Cosmopolitan is great for building terminal apps like HTTP servers, but can't do GUIs.

2. Browsers are great at GUI apps, but depend on HTTP servers and emulate terminals poorly.

So I view the two as being complementary. I imagine it's one of the reasons why Mozilla supported the project. Both platforms solve the portability problem, except for fundamentally different areas. Put them together and you get something greater than the sum of your parts.


Thanks for the explanation!


Because the world is not entirely a web browser.


could be useful for malware developers to be fair, no?


well, couldn't all advancements in this kind of technology be useful to malicious people?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: