Skip to content

Instantly share code, notes, and snippets.

@NHOrus
Last active March 26, 2026 20:23
Show Gist options
  • Select an option

  • Save NHOrus/74bf95d80df868cb9d0519d92e35c7e2 to your computer and use it in GitHub Desktop.

Select an option

Save NHOrus/74bf95d80df868cb9d0519d92e35c7e2 to your computer and use it in GitHub Desktop.

Welcome

Hello! I'm NHO, aka NHOrus and I voluntarily participate in Gentoo's Modern C Porting efforts for fun. This necessery effort is semi-endless mire of ancient code, false positives, headaches and betterment of my distro. It can be both incredibly rewarded and incredibly frustrating (ncurses/gpm circular dependency, for one, is unfixable problem we appear to be stuck with forever). I do it because I want to help my distro, I find successes incredibly rewarding, and it helps with my programming and social skills, for I hate to speak to new people.

But what it is?

C, the antedevulian language of operating systems, has four dialects of interest: K&R C, C89, C99/C11/C17 and C231. This simplifcation smushes three standards into one, but everything that compiles under C99 will compile under C17. This limits near-endless amount of code rewrite, creation of new upstreams for dead packages and generally excessive, wasted effort to two reasonable, distinct cases: If possible, update code until it works correctly under C23, if not possible, bring it to C17. In my experience, porting problems could have following notable categories:

  1. Full K&R C. This needs function definition rewrites: often more pain that ought to be tolerated, but in other regards packages are ok code. Ebuild is pinned to -std=gnu17
  2. Function Polymorphism: Abuse of function pointers defined as having empty argument list, int f(); as arguments or struct members. Used most often in scripting languages; can't be brought to C23 without significant rewrite by experienced people. Ebuild is pinned to -std=gnu17
  3. Struct Polymorphism: usually encountered in old code interacting with X11, situations like struct retcore { struct core;}; struct extraret {struct core; struct trailer;}; where second one could be safely substituted for first one. Safe bet for C23 porting.
  4. Someone else solved this problem! We have Debian, we have Fedora. They also struggle with Modern C Porting, and taking correctly attributed solutions from them means less duplication of effort and more compatibility! In best case, someone have already solved this problem in our repository and all that remains is for old ebuild to be removed.
  5. Other mess: Multiple various problems that need individual solving. I hope that you love puzzles.

How do we get them?

Bug reports in bugzilla. Sometimes, forum topics. Sometimes, running into a problem on your own PC because it's a dependency of thing you want to install. Main sources of bugs are C99 porting and C23 porting topics on Bugzilla. They are produced by various unfortunate souls or tinderboxes and collated by bug wranglers.
It happens, and it needs to be dealt with.

And how do you fix them, exactly?

Let's get through some examples of porting process: I go to bug topic, open a previously-untouched bug and look at it. Triage time. Is it gkrellm? Into a backlog it goes. Is it Gnome? Is it on architecture I don't have access to? Not touching it.
Is this ebuild in tree, still? Are there any comments with information about fixes? Is upstream alive? Does it have a fix or existing bug report? Does it accept bug reports? Sorry, sourceforge, I'm not reporting things on you because I can't register.
Are there other bugs opened for this package so they could be fixed in one go? Also very important step.

In general, we prefer to pass fixes upstream if possible, so this bug triage is important.
Let's go through examples!

dev-scheme/elk-3.99.8-r1 [libtool] [gcc-15] list.c: error: passing argument 2 of XawListChange from incompatible pointer type [-Wincompatible-pointer-types]

A C99 bug in embeddable scheme interpreter. Let's look at ebuilds in gentoo repository. There's elk-3.99.8-r2. And there's commit that fixes the problem in the ticket. That we have here is a duplicate that exists because old version was not dropped. Easy fix, especially when -r1 is EAPI=7.

cd ~/workshop/gentoo/dev-scheme/elk
git switch -c elk-942412
git rm elk-3.99.8-r1.ebuild 
pkgdev commit -c 942412

Ready for PR. But first, let's verify that this thing is correct and works with GCC-16

sudo ebuild ./elk-3.99.8-r2.ebuild compile
Please touch the FIDO authenticator.
Appending /home/nho/workshop/gentoo to PORTDIR_OVERLAY...
 * elk-3.99.8.tar.bz2 BLAKE2B SHA512 size ;-) ...                                                                                                                                                                                   [ ok ]
>>> Unpacking source...
>>> Unpacking 'elk-3.99.8.tar.bz2' to /var/tmp/portage/dev-scheme/elk-3.99.8-r2/work
>>> Source unpacked in /var/tmp/portage/dev-scheme/elk-3.99.8-r2/work
>>> Preparing source in /var/tmp/portage/dev-scheme/elk-3.99.8-r2/work/elk-3.99.8 ...

...
env.c: In function 'Define_Procedure':
env.c:161:11: error: too many arguments to function 'General_Define'; expected 0, have 2
  161 |     ret = General_Define (body, sym);
      |           ^~~~~~~~~~~~~~  ~~~~
env.c:45:8: note: declared here
   45 | Object General_Define();
      |        ^~~~~~~~~~~~~~
env.c: At top level:
env.c:166:8: error: conflicting types for 'General_Define'; have 'Object(Object,  Object)'
  166 | Object General_Define (Object argl, Object sym) {
      |        ^~~~~~~~~~~~~~
env.c:45:8: note: previous declaration of 'General_Define' with type 'Object(void)'
   45 | Object General_Define();
      |        ^~~~~~~~~~~~~~

Oh, we need to port to C23 now. As there's a single error in multi-jobs system, this looks like a simple fix. To do that, I go into a different terminal, escalate to sudo and start editing code in place to make a patch:

cd /var/tmp/portage/dev-scheme/elk-3.99.8-r2/work/
cp -r elk-3.99.8{,.orig}
nano elk-3.99.8/src/env.c

After the build in different terminal, we see that no, this package doesn't respect multi-job build well, because # parallel build is broken; emake -j1 and there are more errors, hiding. I'm also now annoyed enough to try fix parallel build. Fixes proceed apace, with function declarations having their signatures filled, until I hit src/math.c

Object General_Function (Object x, Object y, double (*fun)()) {
    double d, ret;

    d = Get_Double (x);
    errno = 0;
    if (Nullp (y))
        ret = (*fun) (d);
    else
        ret = (*fun) (d, Get_Double (y));
    if (errno == ERANGE || errno == EDOM)
        Range_Error (x);
    return Make_Flonum (ret);
}

That's category 2, I can't do anything sane here because double (*fun)()) in argument list sometimes has one and sometimes two arguments. -std=gnu17 it is. Then I want to run tests, just in case. Apparently, # tests are run automatically during make and fail with default src_test. This is a lie, tests aren't run automatically and so I remove whole src_test() from the ebuild, to let default test run, and will note it in commit message. Finally, I look at Makefile.am ordering with details that are unimportant, but allow me to enable parallel build with two simple patches. Run build a few times. Commit. Push.

git add files/elk-3.99.8-makefile-ordering.patch elk-3.99.8-r3.ebuild
pkgdev commit -b 942412 -e
git fetch
pkgdev push codeberg HEAD:refs/for/master -o topic="elk-942412"
Enumerating objects: 15, done.
Counting objects: 100% (15/15), done.
Delta compression using up to 20 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 2.46 KiB | 2.46 MiB/s, done.
Total 11 (delta 7), reused 0 (delta 0), pack-reused 0 (from 0)
remote: 
remote: Visit the existing pull request:
remote:   https://codeberg.org/gentoo/gentoo/pulls/422
remote: 
To ssh://codeberg.org/gentoo/gentoo
 * [new reference]               HEAD -> refs/pull/422/head

Time to look at the open bugs and check if it's all. Should have started with this, but didn't, because expected this to be a simple fix. More open bugs. There's a C23 bug, a bug with musl and bug with ordering libraries during the install. I can't replicate second one, first one is fixed with this patch and musl one is not very hard to diagnose with musl container and playbook:

cd ~/workshop/gap
ansible-playbook install-package.yml -e package=dev-scheme/elk
PLAY RECAP ******************************************************************************************************************
127.0.0.1                  : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
gentoo-glibc-gcc-systemd   : ok=7    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
gentoo-glibc-llvm-systemd  : ok=4    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
gentoo-musl-gcc-openrc     : ok=4    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
gentoo-musl-llvm-openrc    : ok=4    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

More problems than expected. There's fpurge() problem that's declared but not implemented in musl, copy solution from zsh fix. Fixes musl-glibc build. In LLVM container garbage collector test now segfaults. Failing test has a comment that it may randomly fail. gdb tells me that it's either 32/64 or signed/unsigned confusion. Condition tests to run with gcc only. Now it is done and amended commit goes to Codeberg.

gnustep-apps/gshisen-1.3.0-r2 - board.m: error: incompatible function pointer types

An old puzzle video game. Step zero: Check for other open bugs. There's none. Step one: Let's look at repology for solutions. We have Debian package! With patch.
Trying to build. Oh no, it needs ObjectiveC compiler. Should have known that from the category. Now I'm worried. And also rebuilding gcc.

I was expecting build failure, instead I got succesfull emerge, with incompatible pointer types being a warning. Well, OK.
Wget, annotate patch, ebump and modify ebuild, verify build, failure.

Patch fails due to different line endings. edos2linux is the solution. Verify. Commit. PR.

dev-util/treecc-0.3.10-r3 fails test - FAIL: run_tests

This is a metacompiler for gnu's .NET replacement. And the error may be caused by changes in types in yacc template. My first instinct is to regenerate test outputs. After looking at patches and previous commits, I can see that it's caused by porting to C23 and it indeed caused by changes in yacc template.

Beyond my competence level. Ask a question in the bug, leave it be.

Footnotes

  1. Full history, differences and variations of C are well-noted in other places, repeating it here serves no purpose and is beyond my competence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment