Musl porting notes
musl is very strict regarding standards-conformance compared to the widely used GNU C Library (glibc). This means that many of the GNU extensions, as well as much of the backwards compatibility provided by glibc is completely absent, and applications that use these will often fail to build. Here are some pointers on getting software to compile with musl.
For those looking to port Gentoo's Musl support to a new architecture then the New Musl Stage Creation article will show how to achieve this to apply for official support in Gentoo as the end result.
Macro errors
Errors like these are usually the easiest, and thankfully the most common issues encountered when porting software to musl. Oftentimes it is possible to just copy the definition from glibc, and then conditionally define it. Sometimes these macros are only aliases in glibc, and if that's the case just replace the macro with the original one. The good way of dealing with this is to remove the usage of these macros, and submitting patches upstream.
MAXNAMLEN not defined here
MAXNAMLEN
is the BSD name for NAME_MAX
. glibc aliases this as NAME_MAX
, but not musl, so applications which tries to use this macro will fail to build.
To fix this:
- Include
<limits.h>
. - Add a conditional "ifdef" for
NAME_MAX
, if it's defined then use it. If not, fall back toMAXNAMLEN
. The reason to fall back toMAXNAMELEN
is to make the BSD users and friends happy.
See also glibc's documentation.
MSG_TRYHARD undeclared
MSG_TRYHARD
is also one of these glibc aliases (_GNU_SOURCE
set). Just use MSG_DONTROUTE
instead.
S_BLKSIZE undeclared
S_BLKSIZE
is an alias for DEV_BSIZE
. Just use DEV_BSIZE
instead.
Undefined references and missing functions
These errors are very similar to the macro errors above, but for functions instead of macros. The most common cause for undefined reference errors is that the program in question uses some GNU extension, or that musl has moved the function into a separate header that needs to be included first.
getopt was not declared in this scope
musl moves this into its own header. To fix, include <getopt.h>
.
undefined reference to getpt
getpt
is specific to glibc, instead use the portable posix_openpt
function, for example.
getpt
does not take an argument, but posix_openpt
does. To get the same behavior, simply pass O_RDWR
Example: "net-misc/vmnet-0.4: vmnet.c:(.text+<snip>): undefined reference to getpt" bug #712470
undefined reference to fts* (ex. fts_read)
These functions are part fts, a set of functions in glibc that are not in musl libc. There is a standalone package for this here: sys-libs/fts-standalone. To fix this, simply add the standalone as a DEPEND for the affected package:
DEPEND="
...
elibc_musl? ( sys-libs/fts-standalone )
...
"
undefined reference to `libintl_dgettext'
See: https://www.gnu.org/software/gettext/FAQ.html#integrating_undefined
Example: "media-libs/fontconfig-2.13.0-r2: undefined reference to `libintl_dgettext' [...] on amd64-fbsd" bug #652674
strtol_l not declared
strtol is a function to convert a string to an integer type. The '_l' counterpart takes an additional locale parameter to be used instead of the global locale. musl only uses "C.UTF-8", so passing a local locale does not make any sense.
Check for strtol_l in the build system and use strtol if it's not available to fix this. Platform macros can also be used, though configure checks are usually prefered.
error: LFS64 interfaces (*64 undeclared here, ex. pread64)
The Gentoo tracker bug for these issues is bug #903611.
The legacy "LFS64" ("large file support") interfaces, which were provided by macros remapping them to their standard names (#define stat64 stat
and similar) have been deprecated and are no longer provided under the _GNU_SOURCE feature profile, only under explicit _LARGEFILE64_SOURCE. The latter will also be removed in a future version. https://musl.libc.org/releases.html
The correct fix is to adjust the code to use standard off_t
types and then to cater for glibc by passing -D_FILE_OFFSET_BITS=64
to avoid regressing glibc systems. In autoconf, this can be done with the AC_SYS_LARGEFILE
macro.
As a temporary workaround, -D_LARGEFILE64_SOURCE
can be appended to CPPFLAGS
by doing
inherit flag-o-matic
...
src_compile() {
# Temporary workaround for musl-1.2.4 (upstream bug #123456, gentoo bug #123456)
# XXX: This will stop working with future musl releases!
append-cppflags "-D_LARGEFILE64_SOURCE"
}
Report usage of these macros upstream.
See also: musl release notes, see 1.2.4
Missing headers
musl is relatively selective of what should go into the core musl libc codebase. The reasoning is obviously different on a case-to-case basis but usually it boils down to:
- GNU extensions.
- Often unused/error-prone functionality.
- Makes more sense as a separate library.
This can often be worked around with *-standalone packages. Be aware that some standalones, like sys-libs/cdefs-standalone, are only there for user convenience. Preferably usage of these should be reported upstream.
error.h: No such file or directory
error.h just provides extra ways to report errors. This is a GNU extension and is not provided by musl. To fix this, either use the perror
function, or combine fprintf(stderr, ...)
with exit(EXIT_FAILURE)
.
error.h includes a global
error_message_count
variable which "counts the number of messages that have been output by error()
and error_at_line()
". This sometimes needs to be accounted for, just check for error_message_count
in the application.sys-libs/error-standalone is available for users' comfort when compiling third-party software, but contributors and developers should fix these errors, and preferably fix this upstream.
Example: "net-libs/iax-0.2.2-r3 : iax.c: fatal error: error.h: No such file or directory " bug #712510
cdefs.h: No such file or directory
cdefs.h is an internal glibc header that should NEVER be used by any application, see musl faq
Developers like to wrongly include sys/cdefs.h to use the _*_DECLS
macros. This is a bug and the correct way to do it is to use:
#ifdef __cplusplus
extern "C" {
#endif
instead of
_BEGIN_DECLS
and
#ifdef __cplusplus
}
#endif
instead of
_END_DECLS
Other build time errors
Other build time errors that do not belong to any of the above sections.
error: assignment of read-only variable '[stdout|stdin|stderr]'
In musl stdout, stdin and stderr are read-only and cannot be set like in glibc.
To fix this, use freopen like this:
freopen("standard-output-file", "w", stdout);
Instead of:
stdout = fopen ("standard-output-file", "w");
See: glibc standard streams.
Example of this: lvm2 fix
This functionality is not implemented in musl mostly due to the "usefulness/security-risk"-ratio beeing far too low. It is however mandated by POSIX and therefore musl defines it as stubs instead of just not including it at all.
Because it's implemented with stubs instead of simply not being there it means that builds will not fail with a simple "{u,w}tmp.h" not found error as expected. Builds can instead complain about things like undefined macros such as WTMPX_FILENAME and _PATH_WTMPX, or not finding a valid path to utx.log. This should almost always be solved by making the functionality optional/conditionally removing it.
Example: AccountsService: "Do not know which filename to watch for wtmp changes"
Runtime issues
musl, compared to other libc's, uses a tiny default stack size. That can cause runtime crashes for applications that allocate a lot of data on the stack. See todo below.
See also
- Libc — a software component that allows userspace applications to interact with operating system services.
- Project:Musl - Gentoo's musl project
External resources
Standalone packages
glibc includes various extra functions which are not part of POSIX, so musl does not include them.
User:blueness has ported and added the common ones to Gentoo:
- sys-libs/fts-standalone (adds fts - functions to traverse directories etc)
- sys-libs/obstack-standalone (obstack in glibc)
- sys-libs/queue-standalone (queue.h)
- sys-libs/rpmatch-standalone (used for 'yes/no' questions)
- sys-libs/argp-standalone (extends getopt)
Porting tasks
- Tracker bug for missing includes/compile errors
- Bugs with possible patches to test and commit
If a patch is discovered in another distro (or if a developer creates one themselves!), please add PATCH to the keywords (if the correct permissions are possessed) and comment with a link to the patch. File a new bug if one does not already exist.
Patches from other distros
As Alpine Linux is musl-only, compared to Gentoo and Void, it tends to make non-portable patches. In worst case scenario this will break glibc, oftentimes by symbol redefinition. If unsure, test on glibc.
These patches are often also poorly documented. Please try to figure out what they do and supply a nice message in the .patch/commit. If unsure, ask for help!
If stuck, it may be worth seeing what other musl-using distros have done to fix the problem.
Be aware that some distros, like Alpine, include compatibility packages by default (for now), so this will not always help.
- sabotage's patches
- dragora's patches
- netbsd's pkgsrc patches
By all means look at Alpine or Void Linux too, but they do not seem to have an easy listing of patches like the above.
- Alpine Linux search (git)
- Void Linux search
- OpenEmbedded
- Buildroot
- Adélie Linux
- Miscellaneous projects using musl
Other resources
- #gentoo-hardened (webchat)
- #musl (webchat)
- musl's FAQ
- musl's POSIX table; useful for seeing 'new' header file names
- musl's compatibility page
- Gentoo's musl overlay