User:Schievel/fixing clang16 errors

From Gentoo Wiki
Jump to:navigation Jump to:search

Tipps an tricks for ancient code to modern C

General workflow

  • If the fix is not trivial I usually unpack the ebuild with
user $CC=clang CXX=clang++ ebuild $name_of_the_program.ebuild clean compile

(NOT as root user)

I use compile here because sometimes the build creates some artifacts. I don't want to include the artifacts in the patch later, so I need them to be created before I initialize a git repo.

  • I go to the S directory, usually
    user $cd /var/tmp/portage/$category/$packagename/work/$packagename
  • I initialize a git repository in the workdir and commit everything in the workdir to one initial commit
    user $git init && git add . && git commit -m "init"
  • Now I start working on the code. I can run (in the directory where the .ebuild is)
    user $CC=clang CXX=clang++ ebuild $name_of_the_program.ebuild compile
    (without clean!) to see what compiler errors still occur and what problems there are. I also start my LSP clangd in that repository which gives me additional hints.
  • when done I run
    user $git diff
    to get my patch. This prints the patch into stdout. Be aware that patches sometimes fail when we copy them out of stdout (from the console) into another file. I haven't figured out what exactly is causing this, I assume it has something to do with line endings and such control characters. (like the CRLF vs. CR hassle with patches written on Windows) However this can be worked around by simply writing the output of git diff to a file, e.g. with
    user $git diff > /path/to/gentoo/development/repo/$category/$packagename/files/$packagename-$version-fix-build-for-clang16.patch
  • Patches should be cleaned up with scrub-patch of app-portage/iwdevtools. Also add a small description on top of the patch that this is for clang16, a link to the bug, if this patch was already sent to upstream and you as the author.

Fixing K&R C declarations

Often errors are caused by old K&R style function definitions. So this:

CODE
int
 REmatch(pattern, start, end)
 char *pattern;
 int start,end;
 {
    ...
 }

needs to be reworked into this:

CODE
int
 REmatch(char *pattern, int start, int end)
 {
    ...
 }

This is not a very hard task, but I becomes exhausting when doing this for a larger project.

dev-util/cproto can automate this. For a given file myCfile cproto will convert (and return the prototypes of all functions it can find) with

user $cproto -a myCfile.c

Or for all the .c-files in a project:

user $find ./ -name "*.c*" | xargs cproto -a

Fixing incompatible function pointer types

The code worked before, so usually those function pointers are not too far apart. An example on invalid function pointer types. Here is an example error for this:

read-rl.c:113:36: error: incompatible function pointer types assigning to 'rl_completion_func_t *' (aka 'char **(*)(const char *, int, int)')
from 'char **(char *, int, int)' [-Werror,-Wincompatible-function-pointer-types]

This is caused by the given code snippet here:

rl_attempted_completion_function = rl_esh_completion;

Now, rl_attempted_completion_function is a rl_completion_func_t defined in the GNU readline utility:

typedef char **rl_completion_func_t (const char *, int, int);

While rl_esh_completion is defined by this:

static char** rl_esh_completion(char* word, int start, int end)

(notice the missing const) Now, as the compiler message already suggested, this is easily solved by casting rl_esh_completion to the right type:

return rl_completion_matches(word, (rl_compentry_func_t *)rl_find_builtin);

Fixing tricky function pointers declarations

An example warning for this would be:

hash.c:162:6: warning: passing arguments to a function without a prototype is deprecated in all versions of C and is not supported in C2x   
[-Wdeprecated-non-prototype]
       func(he->data);
           ^

For this it is usually enough to put the variables into the function declaration. The code where func() is defined is this:

void hash_free(hash_table* tab, 
      void (*func)()) {
int i;
list* iter;

Now let's look up what type he->data is:

hash_entry* he = (hash_entry*)(ls_data(iter));

and

struct hash_entry {
 char* key;
 void* data;
};

So he->data is a void*. So we need to declare a void* parameter as the first (and only) parameter of func():

void hash_free(hash_table* tab, 
      void (*func)(void* data)) {
int i;
list* iter;

Fixing "possible configure breakage" bugs

Bugs like https://bugs.gentoo.org/879787 are often very easy to fix. Just put inherit autotools and eautoreconf in src_prepare() into the ebuild. If the program uses autotools. If it uses some homebrew configure script we have to manually patch the configure. Generally speaking, if it is possible to use eautoreconf to fix a bug, it is preffered over patching a configure script. If we ever need to run eautoreconf in the future, we would have to make a new patch.

See also