HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
jameysharp
corrode
Haskell2016–2025
jameysharp / corrode

corrode

C to Rust translator

27Distinct people
32Mentions
0Explicit recommenders
2.2KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

C to Rust translator

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 8–Nov 15 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/15/2026, 6:59:22 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year32 dated mentions

Observed mentions: 2016-07-04 23:31:17 UTC to 2025-11-03 17:32:56 UTC.

0510152016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 10 mentions; 2 submissions, 8 comments20162017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 15 mentions; 1 submissions, 14 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments20202021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2025

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC1028
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC15114
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC202
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC101
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC000
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC101
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC101
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC101
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC000
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC101

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
Corrode: Automatic semantics-preserving translation from C to Rust This program reads a C source file and prints an equivalent module in Rust syntax. It's intended for partial automation of migrating legacy code that was implemented in C. This tool does not fully automate the job because its output is only as safe as the input was; you should clean up the output afterward to use Rust features and idioms where appropriate. Quick Start As of now, there are no pre-built binaries available, so you need to build the project yourself, but don't let that scare you away; clone the project, cd into it and follow along :) Windows If you're using Windows, start by running fixGitSymlinksForWindows.bat as admin (this is necessary for Git to create symlinks). Cabal Ensure that you have GHC and the cabal-install tool installed by following the directions on haskell.org. You'll also need to have the happy and alex tools available in order to build corrode: you can install them with the cabal-install tool, as well. Once you have installed the cabal-install tool, you can build corrode by navigating to the corrode directory, installing the happy and alex tools, and then building and installing the corrode package: cabal install happy cabal install alex cabal install This puts the corrode executable in ~/.cabal/bin, so ensure that that location is in your $PATH. Alternate instructions: Stack Alternately, you can use the Haskell Stack tool for Haskell development. If you don't have it, head over to their website and follow the instructions for installing it on your machine. Install the Glasgow Haskell Compiler using stack setup. You can skip this step if you already have a version of GHC installed on your system. You can then build and install corrode by navigating to the corrode directory and running: stack install Stack will build and install corrode to ~/.local/bin. For ease of use, make sure that directory is in your $PATH. To experiment with the project itself, you can build it using stack build then run the executable: stack exec -- corrode -Wall filename.c -I/usr/local/include -lm Usage There are two ways to use Corrode. You can simply generate a .rs file from the C source, or you can do this and compile in one step. Generating Rust source You can now run corrode, giving it any options that gcc would accept. corrode -Wall filename.c -I/usr/local/include -lm It will only use the options that are relevant to the C pre-processor, like -I or -D, but since it accepts and ignores any other options, you can usually get going just by changing gcc to corrode in the gcc invocation you've been using. Unlike a real C compiler, Corrode does not produce an object file or executable! Instead, if you ask it to process filename.c, it generates equivalent Rust source code in filename.rs. If you do want object code, there is a script to help with that. Codegen with compilation You can either invoke rustc on Corrode's output yourself (or import it into a Rust project), or use the scripts/corrode-cc tool in place of gcc to compile and link. In many build systems, such as make, you can simply set CC=corrode-cc without modification. Design principles The overarching goal of Corrode is to preserve the original properties of the source program as much as possible: behavior, ABI compatibility, and maintainability. We expect the output of Corrode to be used to replace the original C, not just as an intermediate step in a compiler toolchain. Corrode aims to produce Rust source code which behaves exactly the same way that the original C source behaved, if the input is free of undefined and implementation-defined behavior. In the presence of undefined behavior, we've tried to pick a behavior that isn't too surprising. For example, if a signed addition might overflow (which is undefined behavior in C), Corrode just translates it to Rust's + operator, which panics on overflow in debug builds. The compiled Rust source in turn will be ABI-compatible with the original C. If you compile Corrode-generated Rust to a .o file, you can link to it exactly as if it were generated from the original C. Every function that Corrode generates with be annotated with the extern "C" modifier. At the same time, Corrode should produce code which is recognizably structured like the original, so that the output is as maintainable as the original. Every statement and every expression should be represented in the output—in the same order, where possible. If a programmer went to the trouble to put something in, we usually want it in the translated output; if it's not necessary, we can let the Rust compiler warn about it. If either behavior or ABI is not preserved, we consider that a bug in Corrode. However, it is not always possible to preserve the structure of the original code, so we do the best that we can. Testing So far, Corrode has primarily been tested by generating random C programs using csmith, fixing Corrode until it can handle all syntax used in that particular program, and verifying that the resulting Rust module compiles without errors. Verifying that the translated output is equivalent to the input is not trivial. One approach I think is worth trying is to use the Galois Software Analysis Workbench to prove that the LLVM bitcode generated from clang on a C source file is equivalent to the LLVM bitcode generated from rustc on a Rust source file from Corrode. SAW uses a symbolic simulator over LLVM bitcode to extract logical formulas representing the behavior of each function, and then uses an SMT solver to prove equivalence between pairs of formulas. Generating large numbers of random C programs using csmith and then proving the translation results equivalent for each one should give pretty good confidence in the implementation. Because the project is still in its early phases, it is not yet possible to translate most real C programs or libraries. But if you have one you particularly want to try out, I'd love to get pull requests implement
Read the full README on GitHub

What Hacker News says

15 sources
I'm the author of https://github.com/dropbox/rust-brotli and I certainly ran into the issues mentioned in the article, and the initial version of my brotli decoder and encoder were each almost 10x slower. I also worked around each and every one of them, and the result is something that performs at 80-90% of the speed of the original on average, and some files compress faster with rust than with the original brotli codec. allocator: I ran into the same situation and abstracted it with a generic allocator: https://github.com/dropbox/rust-alloc-no-stdlib it's an ugly solution, but it works and can allow for significant perf improvements down the line by bundling all same types together benchmarks: I simply made a test that printed the time primitive types: it's easy to write generic functions that do this macro system: I found to be amazing
Read the rest
, but I never used it to compact data types borrow checker: split_at_mut was super helpful...also core::cmp::replace was useful to taking away pieces of a structure and manipulating them, then putting them back Though it wasn't all roses: to try to get SSE vectorization I had to convert this 6 line short string matching function https://github.com/dropbox/rust-brotli/blob/238c9c539b446d7d... into this multi hundred line monster with macros and so forth https://github.com/dropbox/rust-brotli/blob/238c9c539b446d7d... but in the end it was as fast as hand-tuned intrinsics in C I also found myself scared by dependencies, including onto the std library, so I tried to get everything to remain within the core library. This should allow something as low-level as a codec to be used in kernel space or in another place where a custom allocator is needed. I also found that "rewriting in safe rust from C" was made easy by corrode https://github.com/jameysharp/corrode since C and rust can be interface compatible, it's easy to go one file at a time and turn it into working rust, then safe rust.
In Rust: Not So Great For Codec Implementing
Bonsoir, allow me to introduce Servant. http://haskell-servant.readthedocs.io/en/stable/index.html Servant allows you to write a type that describes a server/API, and automatically derives a specification for it. You can then write handlers for the different API endpoints, and it will only compile if every endpoint is correctly handled. That includes content types, status codes, and so on, everything is verified, and things are often derived for you. All (de)serialization to/from JSON is automatic (although you can write your own instances if you want your JSON to look a certain way). For example, from the Servant docs: type API = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage :<|> "marketing" :> ReqBody
Read the rest
'[JSON] ClientInfo :> Post '[JSON] Email This is equivalent to an API that defines these three endpoints: GET /position/:x/:y/ returns a Position object as JSON GET /hello?name=whatever returns a HelloMessage object as JSON POST /marketing given a JSON request that represents a ClientInfo object, returns an Email object as JSON but the spec is code: code that the compiler can check for you! You can then write functions of the following types handlePosition :: Int -> Int -> Handler Position handleHello :: Maybe String -> Handler HelloMessage handleMarketing :: ClientInfo -> Handler Email where "Handler thing" effectively means that you can do something like write to a log or throw an exception while you return the thing. This will typecheck, and you have a server that must do what it says on the "tin", the tin being the API type above. If you add a new API endpoint, and forget to write a Handler for it, you'll get to know. If you change the Position type to work with x, y, and z coordinates but forget to update your handlers, you'll get to know. If you'd like to also allow clients to request HTML instead for some endpoint, just change the '[JSON] to '[JSON,HTML]. The Haskell typesystem will make sure that someone requesting a text/html Content-Type doesn't get hit with a 500 or something. Note the Maybe String there: if you wrote a handler for the /hello endpoint that had the type String -> Handler HelloMessage, Servant would complain: you're expecting a query parameter, which the client doesn't have to provide. This is in stark contrast to, say, the "NoneType has no attribute whatever" problems that one risks having to face with Django: if it compiles, it meets the spec. Of course, static typing won't prevent you from responding to /hello with Lovecraft quotes. -- > I start getting lost in layers of monad transformers Handler is actually a monad transformer, and it's a great first one: it's essentially[0] type Handler a = ExceptT ServantErr (ReaderT Config IO) a if memory serves, which means that a "Handler a" is a computation that can * throw a ServantErr * read values from a Config object * perform IO actions (read files, make other network requests, log things, "fire missiles") when run, returning a value of type a. Anecdotally, monad transformers never clicked for me until I started muddling through actually using them in code like this. After a couple of months, you realise it's not too wrong to say you understand how to use them, and you slowly begin to be able to rely on the type system for support. Libraries like Servant are a great example of how this can really, really help. I stopped to think last week how similar it is to pair-programming with a really intelligent but sometimes obtuse friend who likes pointing out how "this doesn't follow from your assumptions", all the way from > "Wait, but you can't add two books together." to > "What if someone PUTs to /login?" which is what we had above, to > "And what happens if I try to withdraw all my money exactly when the payment I've made to you is getting executed?" (in this case, you discover the wonders of software transactional memory[1]). A better typesystem allows you to let the compiler handle more of the busywork that you'd originally have written tests or comments for. It is sometimes confusing starting out (when one discovers that 3 isn't an Int, but a "Num a => a", for instance), but it gets better. Once you get past the Project Euler/"look ma, infinite lists!" stuff, "real" Haskell does have a tendency to make people underestimate how much they really know, but as I've discovered, taking the plunge reveals that one has progressed much farther than one thinks. Also, #haskell on Freenode is one of the friendliest places I've encountered on the internet[0]. [0]: http://haskell-servant.readthedocs.io/en/stable/tutorial/Ser... [1]: https://www.schoolofhaskell.com/school/advanced-haskell/beau... [2]: Here's a hilarious example (NSFW language warning): https://gist.github.com/quchen/5280339 -- Other stuff: Corrode is a C-to-Rust converter written in literate Haskell (as in, it's like a blog post that you can compile and run, to give a slightly strained analogy). https://github.com/jameysharp/corrode webshit weekly actually "quoted" a previous HN comment of mine about it, in which I was falsely slandered: I'm not a Rust evangelist! I wrote a small "script" to make tmux status bars a while back that was a good example of how fun "scripting"-style thing can be in Haskell. https://github.com/mrkgnao/remux And there's always XMonad!
In What programming languages are used late at night?
For automated tools that can convert a C codebase to Rust, you're looking for is Corrode: https://github.com/jameysharp/corrode Last I heard, Corrode can convert many C syntactic structures into their Rust equivalents, they usually compile and sometimes they even work. Even when the conversion works flawlessly, the resulting Rust does exactly what the original C code did—there's no safety benefit (but you can begin refactoring to clean things up).
In Addendum to “Curl is C”
I didn't run into the Arrays issue. This issue I filed, has a list of all the things I hit: https://github.com/jameysharp/corrode/issues/109 Most of the issues I ran into were not exactly with the corrode tool, but with compiler options, i.e. passing the DARWIN_C_LEVEL flag for macOS (my main dev machine). Actually, the library I hacked on was only built for Linux, I spent a lot of my time converting the C to multi-platform, not because it was necessary, but because I didn't feel like running a VM. What I found is that corrode produces mostly compilable code. I had played around a bit with FFI from C to Rust before, so the task of integrating a Rust library into a C codebase was already familiar to me. I would love to see a guide for doing that in corrode though, like an example project, for others. If I have time I might do that. One rea
Read the rest
lly cool thing, is that the Rust compiler detected some undefined behavior in our C code, which I filed a bug for to our team (it was an uninitialized stack variable, passed as a pointer to a function; in practice it would never actually rely on the undefined behavior since all the fields of the struct were set in that function, but it's still poor form). There are some things which you will need to massage, but I found in general that it wasn't much. I had a problem with null function pointer creation that I need to go back and look at. I think my biggest issue, is that every conversion produces unsafe code in Rust. It's left up to the developer to figure out how to convert it to safe code. I think this is ok, but unsafe is still dark arts for me in Rust (meaning that I don't completely grok the best practices right now). I need to go back and reread the Rustonomicon: https://doc.rust-lang.org/nightly/nomicon/ , as there may be more details there than the last time I checked it out. I would love it if corrode could try and produce more safe blocks of code, but I also understand why it's this way. Anyway, I think it's an awesome tool, works 95% of the time, and you can probably easily come up with some standard techniques for going back to fix up the commonly incorrect cases. I'll reiterate this: integrate the Rust code into your C build right at the beginning (I used Cargo + staticlib), I even made this optional in my setup, so that you can flip between the two implementations easily for testing. I set up a make recipe which converts the C src to Rust with corrode (to capture all the CFLAGS needed), and that will only run as long as the .rs file doesn't exist. I found this to be very powerful for verification. I'd highly recommend corrode at this point, but don't be misled to believe that you won't need to make changes to the produced code. Edit: I should mention that to get all this setup, with all the C library fixes in macOS included and the Makefile integration, it took me 6 hours to get setup, with about 10-15 minutes spent actually making the produced .rs file compile.
In A Guide to Porting C/C++ to Rust
> I just started porting an application using corrode on a C library at work. Can you tell us a bit about your experience with Corrode? The Readme itself states that it's not expected to work on "real" code, and there are open issues like this: https://github.com/jameysharp/corrode/issues/52 titled "Arrays are broken!" in which Corrode's developer wrote half a year ago: "The current hack gets arrays translated correctly in function arguments, but gets them wrong everywhere else." In your experience, does it work better than this makes it seem? (To be somewhat fair, the issue does have detailed discussion, and partial fixes seem to have been merged, but it's still open.)
In A Guide to Porting C/C++ to Rust
Warning: rambling comment. A rambling post deserves a rambling answer, particularly if the rambling is in the wrong direction... http://xkcd.com/386/ > Every morning, I wake up, drink a glass of Soylent and recite the following: “Today, I will solve challenging problems. Tomorrow, I will also solve challenging problems. Every day, I will solve challenging problems, and then the robots will take over, and I will die a fulfilled man, and someone will post my obituary on Hacker News.” That's this guy: https://alexvermeer.com/life-hacking/. Pretty sure he occupies a unique niche in the world though. > I am creating This statement is clearly false, as writing blog posts is in no way related to writing a transpiler. Typically all coding posts are post-mortems. > a JavaScript to Rust transpiler in Haskell, I guess this is a takeoff on the C-to-R
Read the rest
ust translator (https://github.com/jameysharp/corrode)? (and all the compile-to-JS projects such as GWT, emscripten etc.). But those have actual use cases, whereas going from front-end to deep back-end / systems programming seems like a stretch. It's true there are a lot of programming language and toolkit posts / flames on HN, and I admit they're often kind of shallow. But a small discussion is better than none at all, and it occasionally gets someone knowledgeable to contribute. But there's a qualitative difference between lots of people spending a little time on a subject versus a few people spending a lot of time on a subject. The first is often productive in a wisdom-of-the-crowds sort of way, while the second is only worthwhile if it's some kind of meeting or contract negotiation with external resources at stake. If you're exerting large amounts of energy arguing on HN then I would venture to say that you're using it wrong. > will I be able to have conversations with normal human beings again? I take offense at this. There is no reason you would want to talk to "normal human beings"; they are fundamentally disassociated from their internal desires. See https://youtu.be/eJ3RzGoQC4s?t=4107 (Century of the Self, part 2, Anna's project to create normal human beings). There are strong elements of this thinking in recent news surrounding the elections, so it's not surprising you would have been swept in. But the fact is that "normal human beings" are a phantom: http://ijr.com/2015/06/354635-epa-administrator-says-half-am.... Best you can do is segmentation, e.g. http://c.ymcdn.com/sites/dema.site-ym.com/resource/resmgr/Me.... > put an end to the godforsaken monotony day after fucking day > Will I be able to feel? If you cut me, will I bleed? > Please Just End My Suffering > Please save me Sounds like a metal/rock band: https://www.youtube.com/watch?v=5NZsCYOM4j0 https://www.youtube.com/watch?v=2okd9UHLExY https://www.youtube.com/watch?v=XblNnon-XTc https://www.youtube.com/watch?v=BZg-72u-QpI. Maybe that was the point of this post, as some sort of experimental art. > Be on the lookout for a stable release soon. Software doesn't have stable releases: https://blog.codinghorror.com/the-infinite-version/. It has stable channels and (occasionally) pinned versions. But a transpiler is developer-oriented so would never have a stable (product) channel at all. > I see clouds in the sky, and green grass. It has been fifty years and I am sitting in the park with my dog, feeding ducks and watching the local children at play. I haven’t uttered the phrase “type-safety” in years. All the startups are gone. I am free. The Matrix Revolutions ending is better: https://www.youtube.com/watch?v=qTnBVDKuNdI
In I Am Writing a JavaScript to Rust Transpiler, So Please Just End My Suffering
It's a shame, really, but if you could write a decent C to safe Rust transpiler, than Rust probably would not exist. Lifetime inference etc is a hard problem, and if it could be done right now, compilers would just have static checks for all that. There is a C to UNSAFE Rust transpiler, though: https://github.com/jameysharp/corrode.
In Getting Past C

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.