Porting FAQ

This page contains issues you might to run into when porting software from Linux to Solaris along with some advice on how you can address them. The issues range from OS-specific differences (Solaris 8/9 e.g. doesn't have some libc functions you might find on Linux) to compiler-specific differences (some builds are geared towards gcc and don't expect to be built with another compiler like Sun Studio).

Compilation errors

cannot find include file: <stdint.h>

Solaris only includes stdint.h starting from version 10. For previous versions, use sys/inttypes.h instead. To make it suitable for upstream inclusion, you can shield it for Solaris.

  • Autoconf-enabled application
#ifdef HAVE_STDINT_H
#  include <stdint.h>
#  else
#  ifdef HAVE_INTTYPES_H
#    include <inttypes.h>
#  endif
#endif
  • Bare include
#if defined(__sun) || defined(__sun__)
#include <sys/inttypes.h>
#else
#include <stdint.h>
#endif

See also: How to detect we're on Solaris.

libtool: link: cannot find the library ‘/opt/csw/lib/<name>.la’ or unhandled argument ‘/opt/csw/lib/<name>.la’

Add to the gar Makefile:

STRIP_LIBTOOL = 1

Symbol not found for an inline function.

When linking fails with a "symbol not found" error, and the function is inline1, add to the Makefile:

EXTRA_CFLAGS += -features=no%extinl

Undefined symbol __FUNCTION__

This is gcc'ism resulting in the name of the enclosing function, mostly found in debugging code. The substitute in Sun Studio 12 is __func__ and supplying -features=extensions. In GAR you would do this by

EXTRA_CPPFLAGS = -features=extensions

or
EXTRA_CPPFLAGS = -features=extensions -D__FUNCTION__=__func__

You can use this idiom to generally add support for __func__:

#  if (__STDC_VERSION__ >= 199901L) /* C99 */ || \
    (defined(__SUNPRO_C) && defined(__C99FEATURES__))
#   define __func__ __func__
#  else
#   define __func__ "<unknown>"
#  endif

Below is an elaborate autoconf test to be used in configure.ac.

Undefined symbol INADDR_NONE

Solaris 9 is lacking this definition, whereas Solaris 10 has

/usr/include/netinet/in.h:#define       INADDR_NONE             0xffffffffU

To work around this use

EXTRA_CPPFLAGS += -DINADDR_NONE=0xffffffffU

Undefined symbol AF_LOCAL

Solaris 10 is lacking AF_LOCAL, but AF_UNIX from <sys/socket.h> can be used instead.

Undefined symbol LOCK_EX

Solaris 10 does not have flock, instead the POSIX-conformat `fcntl` should be used as explained in this post:

Undefined symbol __sync_fetch_and_add_4

This can happen on GCC when using optimization. The problem goes away when disabling optimization with

OPT_FLAGS_GCC =

It occurs in GCC 4 starting with -O1. The error can not reproduced by turning on all optimization flags either listed in the g++ manpage for -O1 nor by comparing
 /opt/csw/gcc4/bin/g++ -c -Q -O0 --help=optimizers
 /opt/csw/gcc4/bin/g++ -c -Q -O1 --help=optimizers

Undefined symbol _mcount

This essentially happens when a file is compiled with -p (gather performance data), but is linked without -p. Most of the time this is due to some erranous passing of flags not understand by the Sun compiler like -pedantic which by coincidence starts with a '-p'. The solution is to weed out the wrong flags.

Undefined function warn, warnx, err or errx

This is essentially a wrapper around fprintf and exit. The following addition solves the problem:

#if !defined(HAVE_ERR_H)
#define err(exitcode, format, args...) \
  errx(exitcode, format ": %s", ## args, strerror(errno))
#define errx(exitcode, format, args...) \
  { warnx(format, ## args); exit(exitcode); }
#define warn(format, args...) \
  warnx(format ": %s", ## args, strerror(errno))
#define warnx(format, args...) \
  fprintf(stderr, format "\n", ## args)
#endif

Undefined symbol sunOglCurPrimTablePtr and sunOglCurrentContext

When the symbols are not found during linking like this then there is a flag missing:

Undefined symbol                    first referenced in file
sunOglCurPrimTablePtr               ../../lib/libgltt.so
sunOglCurrentContext                ../../lib/libgltt.so

Without the SUN_OGL_NO_VERTEX_MACROS compilation flag, all calls to glVertex*(), glNormal*(), glColor*(), glIndex*() and glTexCoord*() will be translated into internal, performance-enhanced routines. These function calls will NOT show up when dbx() is used, or when performing SLI-related interposing of OpenGL for Solaris applications. The conditional include is done in /usr/openwin/include/GL/gl.h.

In GAR use EXTRA_CPPFLAGS = -DSUN_OGL_NO_VERTEX_MACROS
See XMMS GAR Makefile as example.

Testsuite is broken

There may be a lot of reasons why tests are failing. That being said it may be the case that the testsuite is linked against the installed version of the library instead of the newly built one due to the usage of LD_OPTIONS. For well-behaving software it may be possible to pass the runtime flags via the usual linker flags avoiding the forced linkage against installed version. In GAR this can be done with

# We don't need it and if defined the test breaks
LD_OPTIONS =
EXTRA_LINKER_FLAGS = $(RUNPATH_LINKER_FLAGS)

Especially software using the full autotool/libtool collection for the testsuite is sensitive to this.

Missing definitions of CMSG_ALIGN, CMSG_SPACE, CMSG_LEN

Add this to the main include file for the project:

#if defined (__sun) || defined (__sun__)
/*
 * CMS_SPACE etc. definitions for Solaris < 10, based on
 *   http://mailman.videolan.org/pipermail/vlc-devel/2006-May/024402.html
 * via
 *   http://wiki.opencsw.org/porting-faq#toc10
 */

# ifndef CMSG_ALIGN
#   ifdef __sun__
#     define CMSG_ALIGN(len) _CMSG_DATA_ALIGN (len)
#   else
      /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */
#     define CMSG_ALIGN(len) (((len) + sizeof (long) - 1) & \
                              ~(sizeof (long) - 1))
#   endif
# endif

# ifndef CMSG_SPACE
#   define CMSG_SPACE(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + \
                            CMSG_ALIGN (len))
# endif

# ifndef CMSG_LEN
#   define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
# endif

#endif /* Solaris */

A similar patch has been e.g. submitted to DBus bug #40235

Missing definitions for setenv and unsetenv

Add this to some C-file:

#ifdef __sun
void setenv(char *n, char *v, int x) {
  char buf[256];
  snprintf(buf,sizeof(buf),"%s=%s",n,v);
  putenv(buf);
}

void unsetenv(char *env_name) {
  extern char **environ;
  char **cc;
  int l;
  l=strlen(env_name);
  for (cc=environ;*cc!=NULL;cc++) {
    if (strncmp(env_name,*cc,l)==0 && ((*cc)[l]=='='||(*cc)[l]=='\0')) break;
  } for (; *cc != NULL; cc++) *cc=cc[1];
}
#endif

Please note that there may be memory leaks introduced as discussed here:

Solaris changed the handling of the environment significantly between Solaris 8 and Solaris 10; and when you want to have a Perl binary that runs equally on Solaris 8 and 10, then there's no other choice than using putenv(), which leaks memory. Only a native compile on Solaris 10, using the new setenv() and unsetenv() functions (not available in Solaris 8) will cure the issue once and for all…2

Missing O_NOFOLLOW

Solaris 9 is missing this flag from the open() syscall. It can be worked around using lstat() to check for symlink. There is a race condition in this approach, which can be minimized by verifying the device and inode numbers.

Missing getopt_long()

Solaris 9 is lacking a getopt_long() implemention. There's a libgnugetopt package in our software stack that you can use instead. The relevant pieces are /opt/csw/include/getopt.h (your build will very likely already pull it in via -I/opt/csw/include in CPPFLAGS) and /opt/csw/lib/libgnugetopt.so (make sure to link against it). Also remember to depend on the libngugetopt package.

In GAR this can be achieved via:

# On Solaris 9 getopt_long isn't part of the OS, thus we pull in CSWlibgnugetopt
PACKAGING_PLATFORMS = solaris9-sparc solaris9-i386 solaris10-sparc solaris10-i386
RUNTIME_DEP_PKGS = $(RUNTIME_DEP_PKGS_$(GAROSREL))
RUNTIME_DEP_PKGS_5.9 = CSWlibgnugetopt

EXTRA_LDFLAGS = $(EXTRA_LDFLAGS_$(GAROSREL))
EXTRA_LDFLAGS_5.9 = -lgnugetopt
# / On Solaris 9 getopt_long isn't part of the OS

IPV6_V6ONLY symbol missing

IPV6_V6ONLY is missing on Solaris 9. Disable IPv6 for Solaris 9 and create a separate build for Solaris 10 with IPv6 enabled.

In GAR (IPv6 is enabled by default)3:

PACKAGING_PLATFORMS = solaris9-sparc solaris9-i386                                        
PACKAGING_PLATFORMS += solaris10-sparc solaris10-i386
CONFIGURE_ARGS_5.9 = --disable-ipv6
CONFIGURE_ARGS += $(CONFIGURE_ARGS_$(GAROSREL))

Missing definitions of sockaddr_in6, sockaddr_storage, …

This is triggered on Solaris 9 when __EXTENSIONS__ is not used. In GAR this can be done by

EXTRA_CPPFLAGS += -D__EXTENSIONS__

Missing definition of LOG_PERROR

Solaris 9 and 10 do not have LOG_PERROR, this small snippet uses LOG_PID instead of LOG_PERROR, alternatively if it or'ed in it can just be omitted:

#ifdef LOG_PERROR
  LOG_PERROR
#else
  LOG_PID
#endif

You could also define LOG_PERROR to 0x00 (a no-op) with:

EXTRA_CPPFLAGS += -DLOG_PERROR=0x00

Missing functions, e.g. mkdirat available via GNUlib

A lot of functions are available as substitutes via GNUlib. Besides the regular use for inclusion via autoconf a separate static library and header files are available in the package CSWgnulib-dev.
The library can be used with

BUILD_DEP_PKGS += CSWgnulib-dev
EXTRA_CPPFLAGS += -I$(includedir)/gnulib
EXTRA_LINKER_FLAGS += -lgnu

or adding the linkage to a specific link operation manually.

Zero-sized struct/union

This is not allowed in strict C99. By using -features=extensions this can be turned into a warning, e.g.

EXTRA_CFLAGS = -features=extensions

Zero-sized / empty arrays

This is not allowed in strict C99. By using -features=zla this can be turned on.

How to detect we're on Solaris

In C preprocessor, how to write code specific to Solaris?

#if defined(__sun) && defined(__SVR4)
(...)
#endif

Checking for __sun is not sufficient to identify Solaris. Compilers for the obsolete BSD-based SunOS also defined __sun (and Solaris Studio still defines __SunOS, even on System V-based Solaris). To identify Solaris specifically, the __sun and __SVR4 macros must be defined. Also note that you need to check for upper-case __SVR4 instead of the lower-case __svr4 that's only defined by GCC and not by Solaris Studio.
Compiler operrating system macros

Please also see How to use compiler predefined macros to detect operating systems

Missing symbol sethostname

Solaris 9 and 10 are missing the prototype for sethostname in unistd.h. The work around is to define the prototype in the required file as extern. Something along the lines of:

#if defined(__sun) || defined(__sun__)
 #if defined(__SunOS_5_9) || defined(__SunOS_5_10)
  extern int sethostname(char *, int);
 #endif
#endif

Undefined symbol nanosleep or sched_yield

Add -lrt to the linker invocation.

EXTRA_LINKER_FLAGS = -lrt

"could not find ParserDetails.ini"

This happens when a XML::SAX Perl module tries to install or read the list of installed parsers. Short workaround: add this lines as postinstall:

perl -MXML::SAX -e "XML::SAX->add_parser(q(XML::SAX::PurePerl))->save_parsers()"

This is described here:

Runtime Problems

"mkdir" return ENOSYS instead of EEXIST on automounted directories

The setting of errno to ENOSYS instead of EEXIST on mkdir(2) sometimes confuses routines to recursively generate directory pathes. Usually the code must be patched to handle EEXIST and ENOSYS the same way.

Manual-page not formatted properly

Some programs have their manpages formatted for GNU nroff which provides the "mdoc" macro set which allows for more macros. The Solaris manual pages must be formatted with only the "an" macro set. The contents can be printed manually with

nroff -man mycmd.1

Manualpages formatted for mdoc can be converted with the mdoc2man.awk utility. This commit may be used as reference to integrate flexible manpages:

General / GAR

Build Environment

It has been observed on occasion that the build environment can play an important factor in creating a working package. If you're encountering problems that are not related to compilation, consider running things with a known-clean environment where only explicitly defined values are propagated to the build process. GAR will do this for all of the major build steps, including configure, build and test. However, there are times when you may have post-build-modulated stages defined in your recipe to force the creation of non-standard parts of a package. It is these things that you should ensure are run cleanly.

To do this, consider running your custom steps with a prefix like:

/usr/bin/env -i $(BUILD_ENV) /opt/csw/bin/gmake ...

There are similarly named ENV variables for CONFIGURE and TEST.

How to quickly create a patch?

GAR has now integrated git support. Use the gmake makepatch command. Basically, your workflow to create a patch is:

  1. gmake patch → extract pristine source and apply all current patches.
  2. hack the source as appropriate, run gmake build and gmake package until you're satisfied with the result. Don't run gmake clean!
  3. call gmake makepatch; enter a good commit message
  4. add the 000X-your-good-description-of-the-change.patch file to PATCHFILES
  5. re-run gmake makesums

What was the old way?

Here's a quick copy&paste example. Make sure you more or less understand what it does.

# Sanity
[ -f Makefile -a -d work ] && echo "Sanity OK" || echo "Are you in the right directory?"

# File you want to patch and the resulting patch name
FILE_TO_PATCH=gck-rpc-module.c
PATCH_NAME=inttypes

# Make a copy of the file so that we can create a patch later on
WS=`gmake -f <( cat Makefile; echo -e '\nfind-ws:\n\t@echo $(WORKSRC_FIRSTMOD)' ) find-ws`
WB=`basename $WS`
FP=`find $WS -name $FILE_TO_PATCH`
[ "${FP}" ] || echo "Couldn't find $FILE_TO_PATCH"
cp $FP $FP.orig

# Here comes your work
vim $FP
gmake build
# Repeat "vim" and "gmake build" until it's done.

# When you're happy with the change:
(cd $WS/.. && gdiff -ru $WB/${FP//${WS}\/}.orig $WB/${FP//${WS}\/}) > files/$PATCH_NAME.patch
echo "# PATCHFILES += $PATCH_NAME.patch" >> Makefile
svn add files/$PATCH_NAME.patch

When you want to rebuild again from scratch, uncomment all the PATCHFILES lines and move them above the "include gar/category.mk" line. Then you can do "gmake clean makesum build". Uncommenting PATCHFILES early will cause trouble because GAR will try to patch files that are already patched.

See also

Books on Autotools

Additional web resources

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License