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).
Table of Contents
|
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.
- Sun Studio 12: Using the Predefined __func__ Symbol for Function Name
- GCC Function Names as Strings
- Elaborate autoconf test
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 function cfmakeraw
Solaris 10 does not have `cfmakeraw`, but it can easily be simulated as explained in this post:
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.
- Dovecot mkdir issue
- lighttpd mkdir issue
- mkdir operation on autofs sourcecode Please note that Solaris is not POSIX conformant in this way and should be fixed here in the sourcecode (as pointed out by Jörg Schilling)
- Mailing llist thread about issue
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:
- gmake patch → extract pristine source and apply all current patches.
- hack the source as appropriate, run gmake build and gmake package until you're satisfied with the result. Don't run gmake clean!
- call gmake makepatch; enter a good commit message
- add the 000X-your-good-description-of-the-change.patch file to PATCHFILES
- 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
- Adding Gnulib To A Project
- Using Git to produce patches
Books on Autotools
Additional web resources
- Using Sun Studio for open source apps (archive.org; probably deprecated — needs review)
- Comparing C++ Standard Libraries libCstd and libstlport
- Sun Studio 12: C++ FAQ
- Oracle Solaris Studio 12.3 C++ FAQ
- Oracle Solaris Studio Technical Articles and Whitepapers
- OpenSolaris Porting Code Fixes at Nexenta (archive.org)
- A Practical Guide to Adopting the Solaris 8 OS (July 2000; archive.org; probably deprecated — needs review)
- Porting to the Solaris OS (October 2008)
- Migrating from Linux to Solaris or OpenSolaris (More porting related links there) (archive.org)
- Solaris 2 Porting FAQ (1996; archive.org; probably deprecated — needs review)
- The System Developer's Edge Selected Blog Posts and Articles, (local copy)
- HP-UX to Oracle Solaris Porting Guide (local copy)
- Online (GCC) C++ Symbol Demangler
- The Solaris Operating System on x86 Platforms - Crashdump Analysis Operating System Internals (local copy)