| <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 <abc> |
| class ImplHelper: public ImplHelperBase<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 <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> |
| |