User:Schievel/fixing clang16 errors
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) (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.
user $
CC=clang CXX=clang++ ebuild $name_of_the_program.ebuild compile
- when done I run 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
user $
git diff
git diff
to a file, e.g. withuser $
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:
int
REmatch(pattern, start, end)
char *pattern;
int start,end;
{
...
}
needs to be reworked into this:
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.