[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)