Hacker News new | past | comments | ask | show | jobs | submit login

Maybe I'm missing something, but what is painful to set up with C toolchains? On almost every *nix, (g)cc, vi(m) and make are enough to be dangerously productive. Sure, you can overcomplicate stuff with modern IDEs and IDE-like tools, but that is out of the realm of the usual C toolchain.



I’ve never seen a real project that doesn’t use make, cmake, or some other glue on top of gcc/clang. Dependency management is absolute hell as well


Are you really putting make and CMake in the same bag? POSIX make and Plan 9 mk are incredibly simple, compared to autotools/CMake; even BSD/GNU make, with all their extensions, are quite simple.

Personally, after having gone through a lot (GNU make, sh script + POSIX make, CMake + conan at work), I think a simple POSIX 2024 make + pkgconf(ig) really is enough for simple programs; and Windows devs can use WSL or whatever.


They themselves might be “simple” but every real usage I’ve seen has been an impenetrable shitshow.


Dependency management in C is the hell that you and your dependency make it, alone. You can try to copy a .a file and a directory of headers into your project, or you can try to make a massive graph of 1000 dependencies that needs a SAT solver to untangle.

Dependencies are hell in JavaScript, Haskell, and Python too, but you don't notice because the computer works through the most common hells automatically... so developers don't hesitate to create hells. In C, they hesitate.


> In C, they hesitate.

Looks at most Linux distros.

Are you sure about that?!


i've started building my C projects with zig, it works quite nicely and has decent support for pulling in C dependencies as well (e.g., https://github.com/allyourcodebase/libxml2)


> dangerously productive

As in SIGSEGV dangerous? C is a language so simple that together with the lack of libraries it'll drag you down to problems you were not going to stumble into in most alternatives.

Sure, eventually you'll get your own scars and learn the hard way lessons that will stick and give you better intuition on how things work, but I don't feel there's need to keep using C these days beyond learning and doing specific low level stuff.


I’ll take a SIGSEGV bug any day over working on memory corruption issues. I have some nasty battle scars in that area.


> what is painful to set up with C toolchains?

This reads remarkably tongue-in-cheek, especially when combined with the "dangerously productive" remark a bit later, but: navigating the maze that is picking a C runtime, a libc implementation, a compiler or potentially compiler frontend and backend, a linker, a build tool, a dependency manager, and then figuring out the linking, figuring out the dependency management, figuring out the building process, tackling version control crap (setting up submodules) if needed, then rinse repeat for every single project ever. And if you're targeting not just *nix, but also platforms people actually use (Windows), then this gets especially nasty.

Not your project? Well then you get the chance of taking a deep dive into a random assortment of these, taking up however much of your time. Or you'll just try building it and squash errors as they come. Such a great and sane toolchain and workflow.

All of this is of course completely excluding the very real factor of even knowing about these things, since being even slightly confused about this stuff is an immediate ticket to hours of research on various internet forums to even get to know what it is that you don't know - provided you don't just get sick of all this crap and move on to some other toolchain instead, or start the rote reproduction of some random dood's shitty guide, with the usual outcomes.


> navigating the maze that is picking a C runtime, a libc implementation, a compiler or potentially compiler frontend and backend, a linker, a build tool, a dependency manager, and then figuring out the linking, figuring out the dependency management, figuring out the building process,

You're misrepresenting this somewhat: all but two of those items listed need you to only "pick" a compiler and (as parent said) use Make.

The dependency manager is a problem yes, but lets not misrepresent everything.


It comes up more when you try stuff multiplatform.

Another thing I didn't touch on is the massive compatibility tables for language features one needs to look out for, in case they plan to make their code work on multiple mainstream compilers, which is arguably the prudent thing to do.

I really don't think that considering the C/C++ build story as complex and frustrating would be misrepresentative.


> I really don't think that considering the C/C++ build story as complex and frustrating would be misrepresentative.

Who was talking about C++? This thread was about C, right?

(It's possible that I didn't read very closely upthread, but I'm almost certain that we were all talking about C).

I actually agree that C++ can be a pain in the rear, especially for multiplatform, and you have to pick all your options, etc.

But C? Not so much. Even on multi-platform.

As GP (or GGP, or GGGP, I forget how far upthread it is) said, with C all you need is a compiler, an editor and Make. That's pretty much still true, even if you're using third party libraries.


The compilers require a bunch of arcane flags to actually do something useful, so you pretty much need some kind of build system or at least a shell script.


I have been a Gentoo Linux aficionado for decades. When you set it up you define a set of CFLAGs and CXXFLAGS etc. Those are your globals, your defaults.

I am also a human. When I deal with another person I have never met before, I have a set of defaults. I override them as required.

gcc (at least) only requires an input and will behave reasonably and generate: a.out.

You might like to pass -O2 for something a bit more complicated. Beyond that then yes you will need to get into details because any engineering discipline is tricksy!


> Beyond that then yes you will need to get into details because any engineering discipline is tricksy!

When you have multiple files in your project or are using external libraries, pretty much any other programming language will know what tt do. Only C requires you to manually name them in the compilation command even though they’re already named in the file you’re compiling.


> compilers require a bunch of arcane flags to actually do something useful

   $ gcc lolno.c && ./a.out
   lol, no
   $


Why is the executable named ./a.out and not ./lolno? Why are warnings disabled by default? What if you need to use <math.h>? And that’s just for a single file.


> Why is the executable named ./a.out and not ./lolno?

  $ ls
  lolno.c
  $ make lolno
  cc     lolno.c   -o lolno
  $ ls
  lolno lolno.c


Now do a project with multiple files.


Sure. Here's viola, a web browser from the early 90s, with a replacement makefile (GNU make) that's a bit more sane:

    CC      = gcc -std=c99 -Wall -Wextra -pedantic
    CFLAGS  = -g
    LDFLAGS = -g
    LDLIBS  = -L/usr/X11R6/lib -lICE -lSM -lXpm -lX11 -lXext -lXmu -lXt -lm

    VIOLA_PATH := $(shell pwd)/resources

    override CFLAGS += -DPOSIX_C_SOURCE=199309L         \
                    -D_POSIX_SOURCE -D_XOPEN_SOURCE     \
                    -D_BSD_SOURCE -D_SVID_SOURCE        \
                    -DDEFAULT_VIOLA_PATH='"$(VIOLA_PATH)"'\
                    -DVIOLA

    %.a:
            $(AR) $(ARFLAGS) $@ $?

    viola/viola: $(patsubst %.c,%.o,$(wildcard viola/*.c)) \
                    libIMG/libIMG.a     \
                    libXPA/src/libxpa.a \
                    libStyle/libStyle.a \
                    libWWW/libWWW.a     \
                    parmcheck.o

    libIMG/libIMG.a     : $(patsubst %.c,%.o,$(wildcard libIMG/*.c))
    libXPA/src/libxpa.a : $(patsubst %.c,%.o,$(wildcard libXPA/src/*.c))
    libStyle/libStyle.a : $(patsubst %.c,%.o,$(wildcard libStyle/*.c))
    libWWW/libWWW.a     : $(patsubst %.c,%.o,$(wildcard libWWW/*.c))

It's 155,000 lines of C code across 361 files. Not shown are the nearly 900 lines that make up the dependencies, but using `makedepend` (which came with my system) makes short work of that. I have a more complicated project that compiles an application written in Lua into a Linux executable. It wasn't hard to write, given that you can always add new rules to `make`, such as converting a `.lua` file to a `.o` file:

    %.o : %.lua
            $(BIN2C) $(B2CFLAGS) -o $*.l.c $<
            $(CC) $(CFLAGS) -c -o $@ $*.l.c
            $(RM) $*.l.c
Okay, that requires a custom tool (`bin2c`) but can other build systems do this? I honestly don't know.


That still doesn't require any flags. Where it starts to get complicated is when you link in system libraries, because they vary between OSes and different versions/distros of the same OS. If you need to support multiple platforms this quickly becomes combinatorially complex, which is where Makefile hell comes from.


Great, now do TLS, a GUI, graphics rendering or database access.


Use stunnel for TLS. A benefit is that if you properly sandbox the daemon behind it, a compromise in the daemon behind TLS does not result in the server key being compromised.

A GUI could be done in SDL+Nuklear, GTK+ or others.

Database access from C is easy, since the databases are written in C and provide C APIs for access.


Can you use those libraries without a bunch of arcane compiler flags? Because that's what the argument was about.


stunnel is not a library and linking to C libraries is easy.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: