Several compiler and operating system issues were encountered during the portingof the Abstraction and Infrastructure Layers of OpenOffice.org. They are described below for your reference. They pertain to Mac OS X 10.0.x and Mac OS X 10.0.x Developer Tools 10.0.x. The solutions discussed in this document are current as of the OO638C release tag and are specifically coded for the Mac OS X 10.0.x platform only. Hence, when implementing the solutions discussed in this document, you need to enclose any corrective code within the following preprocessor statements:
#ifdef MACOSX ... #endif#if defined(__GNUC__) && defined(__APPLE__) ... #endif
As the Mac OS X 10.0.x C++ compiler behaves somewhat differently from GCC compilers for other platforms, the static datat members in template classes, if not explicitly initialized, will cause undefined symbols at link time. For example:
template <abc> class ImplHelper: public ImplHelperBase<abc> { static ClassData s_aCD; ... }
Each instantiation of s_aCD needs to be explicitly initialized once and only once somewhere. Note that it can only be instantiated once or you will get duplicate symbol errors that will crash an executable at runtime. So a mechanism (solenv/unxmacxp/bin/init-static-template-data) was created to automatically detect and collect these static members into a set of files and initialized them. One set of files is created for each source directory. For example, the following files are created for the source directory in the cppuhelper module:
Then, immediately before an executable or shared library is linked, the standard build recipes merge the above files with the same files from all of the other source directories that have been built to create an aggregate list of static data members that require initialization. These merged files are then compiled and linked into a shared library called libstaticmxp.dylib. Since all executables and shared libraries generated by the Mac OS X 10.0.x build are linked to the library, all executables are guaranteed to have each required static data member initialized once and only once.
As of the OO638C release tag, only the following template classes are supported by this mechanism:
Each time an inline function is inlined, a static automatic variable's definition is generated once. So we usually end up having multiple copies of these variable definitions. The compiler may or may not generate a warning about this. However, the assembler will generate error messages like the following:
{standard input}:unknown:Can't emit reloc {- symbol "L37$pb"} @ file address 36. {standard input}:unknown:Can't emit reloc {- symbol "L37$pb"} @ file address 32.
To solve this problem, you must either move the static automatic variable in an inline function to outside of the function (i.e. make it a file scope variable) or reimplement the inline function so that a static automatic variable is no longer used.
For examples of how to implement the first option, take a look at any of the *.hpp files that are generated by the build.
Static automatic variables in C++ class destructors
In certain situations, when the following 2 conditions exist:
#include <stdio.h> // Create a class with a pure virtual method class MyAbstractClass { public: virtual void print() = 0; protected: MyAbstractClass() { } virtual ~MyAbstractClass() { } }; // Create a subclass of the class with a pure virtual method class MyConcreteClass : public MyAbstractClass { public: MyConcreteClass() { } virtual ~MyConcreteClass() { } virtual void print() { printf( "In MyConcreteClass\n" ); } }; // Create a class that invokes the subclasses method in it's destructor class MyWrapperClass { public: MyWrapperClass() { } ~MyWrapperClass(); static MyAbstractClass getClass(); }; MyAbstractClass MyWrapperClass::getClass() { static MyConcreteClass rClass; return rClass; } MyWrapperClass::~MyWrapperClass() { MyAbstractClass& aClass = getClass(); aClass.print(); } // Create problem where the MyWrapperClass' destructor accidentally invokes // the base class' print method instead of the subclass' print method. MyWrapperClass aClass; int main( int argc, char **argv ) { MyWrapperClass bClass; }
When this sample program is executed, the program generates the following output:
In MyConcreteClass pure virtual method called Abort
instead of the expected output:
In MyConcreteClass In MyConcreteClass
To solve this problem, you must either move the static automatic variable in an inline function to outside of the function (i.e. make it a file scope variable) or reimplement the inline function so that a static automatic variable is no longer used.
In the above example, we would change the following lines:
MyAbstractClass MyWrapperClass::getClass() { static MyConcreteClass rClass; return rClass; }to:
static MyConcreteClass rClass; MyAbstractClass MyWrapperClass::getClass() { return rClass; }
When -fexceptions and optimization flags (e.g. -O or -On) are both turned on while compiling a source file, the runtime code execution can be very unpredictable. The exact cause of this compiler bug is unknown. The solution is to turn off optimization whenever the -fexception flag is set (i.e. when either the ENABLE_EXCEPTIONS or EXCEPTIONSFILES macros are set in a makefile.mk file).
As of the OO638C release tag, the standard build recipes will automatically turn off optimization whenever exceptions are turned on.
When loading two different modules/functions with the same symbol name from two different libraries, the Mac OS X 10.0.x dynamic loader resolves to the symbol of the library first loaded even though we wanted two different versions from the two different libraries. In addition, there is no way to unload a library once it is loaded, so we can not unload the first and then load the second. This bug renders OpenOffice.org's UNO plugin technology unusable since the UNO plugin technology needs each UNO shared library to implement the following standard functions:
The solution is to prepend "lib(library name)" onto each of these standard functions so that each UNO shared library's standard functions are uniquely name. Then, at runtime, the library loading functions implemented in the sal/osl/unx/module.c source file will automatically prepend the library name to the requested function before retrieving a pointer to the function from the library.
For this solution to work, developers must implement the following after porting a module:
.IF "$(OS)"=="MACOSX" SYMBOLPREFIX=(library name) .ENDIFIn the above macro definition, substitute "(library name)" with portion of the shared library name after stripping off the leading "lib" and trailing ".dylib". For example, if the shared library name is libi18n625mxp.dylib, "(library name)" should be replaced with "i18n625mxp".
The SYMBOLPREFIX macro is used by the build to create "-D" options for the compiler. These defines are used to rename the standard functions. For a list of these "-D" options that the SYMBOLPREFIX macro affects, take a look at the following file:
Bugs in tempnam() and mktemp() system functions
In Mac OS X 10.0.x, multiple invocations of either the tempnam() or mktemp() system functions will return the same filename. On other platforms, these functions generate a unique filename with each invocation. This Mac OS X 10.0.x bug will cause unpredictable results at runtime.
The solution is to use the tmpnam() function instead of the tempnam() function and to use the mkstemp() function instead of the mktemp() function. Both tmpnam() and mkstemp() return a unique filename with each invocation. Note that since the default behavior for both tmpnam() and mkstemp() is to create their files in the /var/tmp directory, you need to make sure that the /var/tmp directory is readable and writable by all users. The Mac OS X 10.0.x installation program, /var/tmp is set to be readable and writable only by root.
Special packaging requirements for shared libraries
Most Unix platforms use ".so" as the suffix for shared libraries. However, the Mac OS X 10.0.x linker expects ".dylib" as the suffix for shared libraries.
In addition, the library loading functions in the CoreFoundation framework expect that a shared library be "bundled" within the a libname.dylib.framework directory. For example, "libmyshared.dylib" needs to be put into a directory named "libmyshared.dylib.framework".
Lastly, the Java call System.loadLibrary expects ".jnilib" as the suffix for shared libraries.
As of the OO638C release tag, the standard build recipes will automatically create the matching lib*.dylib.framework/lib*.dylib and lib*.jnilib files for each lib*.dylib file that is linked. However, developers need to be aware that the source code may use ".so" in the shared library name. In such cases, developers should modify the code to use ".dylib.framework" in the shared library name for Mac OS X 10.0.x.