blob: 462649cd17e7bfd799a6f6fe50d3f3beb966b8f8 [file] [log] [blame]
<html><head>
<meta HTTP-EQUIV="content-type" CONTENT="text/html; charset=UTF-8">
</head>
<body>
<h1>Compiler and Other Technical Issues in the Mac OS X 10.0.x Platform</h1>
<br>
<p> 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:</p>
<blockquote>
<pre>#ifdef MACOSX
...
#endif</pre>
<pre>#if defined(__GNUC__) && defined(__APPLE__)
...
#endif<b></b></pre>
</blockquote>
<b>
<h2>Static data members in template classes</h2>
</b>
<p></p>
<p>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:
<pre>
template &lt;abc>
class ImplHelper: public ImplHelperBase&lt;abc>
{
static ClassData s_aCD;
...
}
</pre>
<p>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: </p>
<ul>
<li>cppuhelpercppuhelperstaticdatamembers.h
<li>cppuhelpercppuhelperstaticdatamembers.hxx
<li>cppuhelpercppuhelperstaticdatamembers.cxx
</ul>
<p>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.</p>
<p> As of the OO638C release tag, only the following template classes are
supported by this mechanism:
<ul>
<li>vos::ODynamicLoader
<li>cppu::*ImplHelper[0-9]*
<li>com::sun::star::uno::Sequence
<li>comphelper::OPropertyArrayUsageHelper
<li>comphelper::OIdPropertyArrayUsageHelper
</ul>
Should any new static data members be found in template classes, you will need
to implement support for these new static data members in the following script:
<ul>
<li>$SRC_ROOT/solenv/unxmacxp/bin/init-static-template-data
</ul>
<br>
<h2>Static automatic variables in inline functions</h2>
<p>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: </p>
<pre>
{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.
</pre>
<p>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.</p>
<p>For examples of how to implement the first option, take a look at any of the
*.hpp files that are generated by the build.</p>
<p>
<b>
<h2>Static automatic variables in C++ class destructors</h2>
</b>
<p></p>
<p>In certain situations, when the following 2 conditions exist:
<ul>
<li>A C++ class destructor contains a static automatic variable or calls a method
or function that contains a static automatic variable
<li>The static variable is a C++ class
</ul>
The virtual methods of the static variable will be treated as non-virtual. As
a result, the incorrect code may be called. This can be illustrated by the following
sample code.
<p></p>
<pre>
#include &lt;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;
}
</pre>
<p>When this sample program is executed, the program generates the following output:</p>
<pre>
In MyConcreteClass
pure virtual method called
Abort
</pre>
<p>instead of the expected output:
<pre>
In MyConcreteClass
In MyConcreteClass
</pre>
<p>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.</p>
<p>In the above example, we would change the following lines:
<pre>
MyAbstractClass MyWrapperClass::getClass()
{
static MyConcreteClass rClass;
return rClass;
}
</pre>
to:
<pre>
static MyConcreteClass rClass;
MyAbstractClass MyWrapperClass::getClass()
{
return rClass;
}
</pre>
<br><br>
<b>
<h2>Optimization bugs when exceptions are turned on</h2>
</b>
<p></p>
<p>When -fexceptions and optimization flags (e.g. -O or -O<i>n</i>) 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). </p>
<p>As of the OO638C release tag, the standard build recipes will automatically
turn off optimization whenever exceptions are turned on. </p>
<br>
<h2>Duplicate symbol bug in the dynamic library loader</h2>
<p>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: </p>
<ul>
<li>component_writeInfo()
<li>component_getFactory()
<li>component_getFactory()
<li>component_getDescriptionFunc()
<li>component_getDescriptionFunc()
<li>uno_initEnvironment()
<li>uno_ext_getMapping()
</ul>
<p>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. </p>
<p>For this solution to work, developers must implement the following after porting
a module: </p>
<ol>
<li>Determine if any of the above standard functions exist in any of the shared
libraries built in the module. Note that the functions may already contain
an incorrect "lib(some text)" prefix. These functions need to be included
in the next step.
<li>For each standard function that does exist in the shared libraries build
in the module, determine which source file implements the function.
<li>In the makefile.mk file in each of the directories that contains a source
file that implements one or more of the standard functions, add the following
macro definition:
<pre>
.IF "$(OS)"=="MACOSX"
SYMBOLPREFIX=(library name)
.ENDIF
</pre>
In 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".
<li>Perform a clean build of the module using "dmake -u" to verify that standard
functions have been correctly renamed.
</ol>
<p>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: </p>
<ul>
<li>$SRC_ROOT/solenv/inc/unxmacxp.mk
</ul>
<p>
<b>
<h2>Bugs in tempnam() and mktemp() system functions</h2>
</b>
<p></p>
<p>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. </p>
<p>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.</p>
<p>
<b>
<h2>Special packaging requirements for shared libraries</h2>
</b>
<p></p>
<p>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. </p>
<p>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". </p>
<p>Lastly, the Java call System.loadLibrary expects ".jnilib" as the suffix for
shared libraries. </p>
<p>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. </p>
</body>
</html>