[HN Gopher] Using Zig to Unit Test a C Application
       ___________________________________________________________________
        
       Using Zig to Unit Test a C Application
        
       Author : todsacerdoti
       Score  : 120 points
       Date   : 2023-12-18 15:36 UTC (7 hours ago)
        
 (HTM) web link (mtlynch.io)
 (TXT) w3m dump (mtlynch.io)
        
       | raoulj wrote:
       | I've done this where I use python's ctypes library to write tests
       | for a c codebase. This feels very similar in that it can be
       | tricky to get the type interop correct the first time around.
       | What other strategies/solutions do people like to use for testing
       | their c projects?
        
         | fredyr wrote:
         | I've done a lot of CFFI with Python for this kind of testing in
         | the past. But nowadays I'm also looking at Zig for this.
        
         | physPop wrote:
         | the point of zig is that there is no FFI to get right
        
       | convivialdingo wrote:
       | It would be nice if something in Zig could auto-magically
       | generate the zig to c interop call and type declarations.
       | 
       | I see there's "translate-c" to help migrate C to Zig, and maybe
       | that's enough.
       | 
       | Generally I fall on the side of if a compiler can toss out a type
       | warning, it could certainly give a reasonable solution also.
       | Best-guess with a "// Warning type was guessed" is better than an
       | opaque "RTFM" in most every case.
        
         | throwawaymaths wrote:
         | > It would be nice if something in Zig could auto-magically
         | generate the zig to c interop call and type declarations.
         | 
         | Do you mean building a .h file from zig code?
         | 
         | The other direction is just @cImport.
        
           | wredue wrote:
           | If you watch some of the zig streams, there are some C
           | libraries that are quite complex for importing. It's not
           | always just an @cImport.
           | 
           | I wouldn't so much pin this on zig as much as the complete
           | clusterfuck that is building c libraries.
        
             | throwawaymaths wrote:
             | Oh sure, was just curious what feature gp was looking for.
             | I would love the first one for example
        
       | systems wrote:
       | zig , ocaml, odin
       | 
       | many system languages are making the headlines lately its very
       | hard to pick one to learn
       | 
       | not sure how to deal with this, learn them all, bet on one, what
       | should we do
        
         | leosanchez wrote:
         | ocaml is a systems language ?
        
         | golergka wrote:
         | Is ocaml a system language?
        
           | avbanks wrote:
           | Yes believe it or not ocaml is a systems language.
        
           | systems wrote:
           | yes it can be used to create systems and backend tools
           | - it is used to create an OS https://github.com/mirage
           | - it is used to create a transpiler
           | https://melange.re/v2.2.0/        - it was used to create
           | Rust first compiler
           | 
           | ocaml is surely a systems language
        
             | Rendello wrote:
             | The predominant OCaml shop is Jane Street, they have a good
             | podcast where they talk to those involved in their
             | infrastructure. A lot of the episodes go into the tradeoffs
             | between the GC'd and functional OCaml vs languages like C++
             | and Rust:
             | 
             | https://signalsandthreads.com/
        
             | Buttons840 wrote:
             | There's nothing "system" about a compiler. What language
             | hasn't been used to create a compiler or two? If languages
             | used to create compilers are system languages, then all
             | languages are system languages.
             | 
             | Writing a OS is more "system", and certainly those using
             | the Mirage operating system use OCaml as a system language.
        
             | actionfromafar wrote:
             | So sad IncludeOS https://github.com/includeos/IncludeOS is
             | no longer developed.
        
           | akprasad wrote:
           | It depends on what you mean by "system language." For me,
           | this category mainly includes languages that provide fine-
           | grained control over memory management (C, C++, Zig, Rust,
           | ...), so I personally wouldn't include OCaml.
        
           | thefaux wrote:
           | This question reminds me of is golf a sport or a game?
           | 
           | A colloquial definition of systems language seems close to:
           | "exposes low level details and doesn't have garbage
           | collection." By this definition c, c++, zig and rust are
           | system languages, java and ocaml are not. Go is debatable
           | (and people do debate this).
           | 
           | Personally though, I prefer to think of what types of
           | _systems_ I can build with a language. I can design a
           | framework in a high level language which then transpiles to,
           | say, c. I consider this high level language to be a systems
           | language because it facilitates a system (the framework).
           | Others will disagree but it comes down essentially to a
           | semantic question over what counts as a system language. That
           | debate doesn't seem especially fruitful to me.
        
         | oconnore wrote:
         | I think the two main ones are Rust and Zig. This may be
         | controversial (but it seems very obvious to me) that:
         | 
         | Rust is created in the same spirit that created and evolved
         | C++: create a complex and featureful language that enables
         | compiling your solution from a high level representation in an
         | expressive/safe/performant way.
         | 
         | Zig is created in the same spirit that created and evolved C:
         | create a simple language that allows you to directly and
         | transparently represent and reason about what you want to have
         | happen.
         | 
         | You'll probably think that one of these statements is more
         | biased than the other, and that probably reflects your own
         | preferences :)
        
           | throwawaymaths wrote:
           | I think a stronger statement is that zig is explicitly
           | created to out-C c. Even the high level comptime stuff
           | evolved out of simplification and explicit-ification of some
           | opaque things that c (and especially c++) compilers might do.
        
           | FoodWThrow wrote:
           | There's something to be said about philosophy of simplicity
           | in C. However, C pretty clearly evolved into the opposite
           | direction. This is nearly all due to compiler developers, and
           | the fact that C has to cater to so many different hardware
           | requirements.
           | 
           | Unlike C++, ISO C is nothing more than culmination of
           | features that more than 1 compiler has implemented (and
           | doesn't interrupt the compilation process of a micro-
           | controller firmware that was released literally 40+ years
           | ago). Anything else, is GNU C. And it is so incredibly
           | complex and obtuse at times that clang still can't compile
           | glibc after _years_ of work.
           | 
           | Zig was not created with the same spirit that created and
           | evolved C. Zig was created with the idea of a simple C, one
           | that does not match reality, and frankly leans more on Go
           | rather than C. Zig, Odin, V, nearly all these better-C
           | languages are more inspired by Go itself, than what C
           | actually is. What they want from C is just the performance;
           | that's why they're so focused on manual memory management one
           | way or another.
        
             | throwawaymaths wrote:
             | Zig borrows some ideas from go. Probably defer is the big
             | one, but if you watch "the road to zig 1.0" you will
             | understand that zig is not really a go derivate. Most
             | things in zig are directly addressing issues in c.
             | 
             | If you squint zig's error return fusion looks a bit like
             | go's tuple error return but it actually is more "first-
             | classing certain c conventions" than "adopting a go
             | pattern". Same goes for slices.
        
               | FoodWThrow wrote:
               | Most of C's issues were directly addressed in Go as well.
               | Only, Go did away with manual memory management.
               | 
               | C never had the philosophy of keeping things simple
               | through the years. If it did, we would not have time
               | traveling UBs to begin with. The lauded simplicity and
               | explicitness comes directly from Go, where the philosophy
               | was crystalized and preserved very early on.
               | 
               | You might say it is semantics, to call improving upon C
               | being a derivative of Go (with manual memory management).
               | You would be partially correct, it is semantics, but one
               | that holds up very well if you look at how languages
               | developed over the decades.
        
               | throwawaymaths wrote:
               | > The lauded simplicity and explicitness comes directly
               | from Go
               | 
               | I have two words for you: json marshalling
        
         | brabel wrote:
         | I was in the exact same situation. I know Rust but don't want
         | to use it for everything... had a look at:
         | 
         | Zig - attempts to stay simple, like C, but with warts fixed and
         | with cool compile-time programming. Its biggest strength seems
         | to be not the language itself, but the compiler and build
         | system which can cross-compile seamlessly, including C code.
         | 
         | Nim - a systems-language that looks like Python and tries to be
         | fun to write. Has macros that may remind you of Lisp macros.
         | Compiles to C or JS.
         | 
         | D - older but very cool as well... I was surprised to find out
         | its metaprogramming capabilities are as good as Zig's or Nim,
         | and that is has a lot of cool features not seen in mainstream
         | languages, like contract programming and executable
         | documentation. Much more mature than the previous ones. Also
         | seamlessly compiles and imports C.
         | 
         | Odin - really reminds me of Go. It's used in production to
         | create fluid simulation for Holywood movies apparently. Very
         | minimalistic language but I couldn't see what it brings to the
         | table that the ones above do not. It's kind of similar also to
         | Jai which is also upcoming but focusing on game programming
         | from what I understand... that's still not even publicly
         | available yet.
         | 
         | Which one to choose really depends on your taste, hope my
         | descriptions above help, even if they're pretty rough
         | simplifications.
         | 
         | If you want the most popular language in this area, that's
         | undoubtedly Rust though.
        
         | generichuman wrote:
         | > its very hard to pick one to learn
         | 
         | If you don't already, you learn C, as well as you can. It is
         | not a hard language to learn, but it has a lot of footguns.
         | That's why you learn it along with tools like Valgrind &
         | sanitizers.
         | 
         | Then you look at Rust. That's somewhat harder to learn, but
         | nails some important details you need to think about while
         | writing C. It will make some things obvious that you'd need to
         | learn by shooting yourself in the foot repeatedly in C. You
         | don't need to use Rust once you got what you need out of it
         | education-wise, but a lot of people like and use it.
         | 
         | At this point it is kind of unimportant what other "systems"
         | language you decide to learn, but here's my opinion of some of
         | them: - Personally I like Odin's ergonomics. It is incredibly
         | convenient. You can just jump in and start writing OpenGL code
         | without dealing with wrappers and all that. Included vendor
         | libraries take care of a lot. - I also like the explicitness of
         | Zig. It seems like it'll be the most popular one in the future,
         | most likely not because of the language itself but because of
         | the tooling. By the way the reason I say "not because of the
         | language" is that the maintainers seem uninterested in having
         | some way to constrain generics. The language sorely needs some
         | sort of comptime interface / traits / concepts, anytype-
         | everything is not nice. In 10 years someone will come up with a
         | Boost-like library that implements just that in userspace and
         | it'll be horrible. - Ocaml is garbage collected Rust, or
         | rather, Rust is non-garbage-collected Ocaml. It is underrated.
         | Jane Street people are adding borrow checker to it. Could be
         | more popular in the future. Also, all languages are "systems"
         | languages depending on how you wield them. No need to bikeshed
         | about Ocaml's "system"ness status. - D is pretty cool, I used
         | it professionally before. Very fragmented library ecosystem if
         | you want to do betterC or no-gc though. Be prepared to just use
         | C or C++ libraries, which it can talk to pretty easily. - Nim
         | is a nice language. Does reference counting so it has a low
         | memory footprint compared to other GC'd languages. It compiles
         | to C so technically it is the most portable language in this
         | list. You can easily run it on microprocessors that others
         | won't run on. Try it, you'll very quickly land on "like it" /
         | "don't like it" territory depending on your programming style.
         | - Jai is non-existent right now. Doesn't warrant a discussion
         | until Jon Blow feels it is ready for prime time. But since
         | that's his strategy, expect something high quality. If it
         | sucks, two possibilities: 1) he didn't deliver or 2) your use
         | case was not in consideration. - C3, it exists, it is usable,
         | it is like a halfway between C and D. I didn't spend much time
         | on it yet. - Free Pascal: I didn't use it but just putting it
         | here because this list is getting long & it kind of deserves a
         | shout. Lazarus looks nice. - Go: Use Java or C# instead, they
         | can compile to native now. - C++: It exists, it is used
         | everywhere, it sucks. As opposed to most other languages on
         | this list, it wasn't designed. It kind of picked up random
         | features along the way because they looked good. Don't use it
         | if you can help it. If you have to use it you most likely
         | didn't have a choice in the first place.
        
       | throwawaymaths wrote:
       | This is going to get really good when zlibc is done, you'll be
       | able to for example, override the c stdlib "free" function in the
       | c code and add features, for example (runtime) UAF/DF detection
       | with metadata tracking (like stacktraces of where the memory was
       | created and freed)
        
         | duped wrote:
         | You can already do this with LD_PRELOAD, no?
        
           | throwawaymaths wrote:
           | Could be wrong, but only if libc is expected to be
           | dynamically linked (and anyways you'd still need zlibc)
        
             | staunton wrote:
             | You can just define your own malloc and free in any C
             | program. Am I missing what you're talking about?
        
         | maxmcd wrote:
         | What is zlibc? A libc implementation in zig? Googling did not
         | turn up much.
        
         | dataangel wrote:
         | You can do that in any C program today
        
       | jedisct1 wrote:
       | I also now always use Zig to write tests and benchmarks for C
       | code.
       | 
       | This is for example the case in libaegis:
       | https://github.com/jedisct1/libaegis
       | 
       | Calling C functions from Zig is easy (C headers can be imported
       | directly) and doesn't have any overhead. So I can take advantage
       | of the convenience of Zig, even if the tested code only requires
       | a C compiler.
       | 
       | I also now always add Zig build files as an alternative to
       | make/libtool/automake/cmake/meson/etc. The main advantage is that
       | cross-compilation to many targets is supported out of the box,
       | including to WebAssembly. So I can quickly test if the C code
       | compiles fine before actually trying to run it on an emulator.
        
         | mtlynch wrote:
         | Using it to benchmark C is a cool idea. I hadn't thought of
         | that!
         | 
         | Thanks for sharing!
        
         | acqq wrote:
         | > The main advantage is that cross-compilation to many targets
         | is supported out of the box
         | 
         | For the readers who aren't familiar:
         | 
         | The code for running test and then cross-compiling (on one
         | machine and OS) for different target platforms is:
         | 
         | https://github.com/jedisct1/libaegis/blob/main/.github/workf...
         | 
         | and the only zig file in the repo which drives the build
         | process is:
         | 
         | https://github.com/jedisct1/libaegis/blob/main/build.zig
        
       | giancarlostoro wrote:
       | Curious now if you could use D in the same way? Walter Bright
       | built a faster preprocessor for Facebook (kind of a sidenote and
       | not fully relevant), wouldnt surprise me if D is another good
       | candidate especially given its age.
        
         | brabel wrote:
         | Yes: https://dlang.org/spec/importc.html
         | 
         | The D compiler(s), as Zig, can be used to compile C code... and
         | D code can import C files as if they were D modules (as in Zig,
         | there are some special types to represent C strings and other
         | types that are not exactly the same).
        
       | roland35 wrote:
       | This is interesting! I like how unit tests are easier with Zig.
       | 
       | The approach I am more familiar with is using Google test and C++
       | to test C code. It's pretty easy if you already have a cmake
       | project set up, and most C developers can wrap their heads around
       | GTest.
        
       ___________________________________________________________________
       (page generated 2023-12-18 23:00 UTC)