
    A short guide to compiling, linking, running and debugging issues
    in the viewer and its packaged libraries.

Introduction

    A recent pass through some third-party libraries resulted in the
    collection of a lot of information about how things should and
    shouldn't be built in the viewer.  Some of that is presented below
    with hints and rules about doing things well.  What's presented is
    a guideline only.  Not all suggestions are hard rules and you'll
    find exceptions all over.  Some exceptions arise from solid
    reasoning, others may be legacy that hasn't been re-examined.

    Use good engineering judgement when applying this information.

Compilation

  Windows Targets

    Significant compilation flags and defines follow:

    ----------------------------------------------------------------------------
    Option                Release          RelWithDebInfo          Debug
    ----------------------------------------------------------------------------
    wchar_t             /Zc:wchar_t-             "                   "
    RTL type               /MD                  /MD                 /MDd
    FLoating Point       /fp:fast                "                   "
    Debug Info        /Zi (app/dll), /Z7 (lib)   "                   "
    Optimizer           /O2 /Ob2 /GR       /Od /Ob0 /GR           /Od /GR
    Incr. Link      /INCREMENTAL:NO        /INCREMENTAL       /INCREMENTAL:NO
    Debug                /DEBUG               /DEBUG              /DEBUG
                         /OPT:REF
    Ignore Libs          LIBCMT               LIBCMT      LIBCMT;LIBCMTD;MSVCRT
    Alignment           Default                  "                   "

    Defines        WIN32                         "                   "
                   _WINDOWS                      "                   "
                   LL_RELEASE=1          LL_RELEASE=1               n/a
                   LL_RELEASE_FOR_DOWNLOAD=1    n/a                 n/a
                   NDEBUG                NDEBUG               _DEBUG
                           n/a                  n/a           LL_DEBUG=1
                           n/a           LL_RELEASE_WITH_\          n/a
                                         DEBUG_INFO=1
                           n/a                  n/a           _SCL_SECURE_NO_WARNINGS=1
                   _SECURE_STL=0         _SECURE_STL=0        _SECURE_STL=0
                   _HAS_ITERATOR_DEBUGGING=0    n/a                 n/a
                   LL_WINDOWS=1                  "                   "
                   UNICODE                       "                   "
                   _UNICODE                      "                   "
                   WINVER=0x0600                 "                   "
                   _WIN32_WINNT=0x0600           "                   "
                   LL_OS_DRAGDROP_ENABLED=1      "                   "
                   LIB_NDOF=1                    "                   "

    ----------------------------------------------------------------------------
    Notes:

    1.  /Zc:wchar_t-.  Not certain where this comes from.  It may be
    due to a default set of compilation flags in Qt 4.X that then
    propagates outward.  In Qt 5.X, this setting is flipped back to
    default (wchar_t is a built-in).  Other options for dealing with
    this include:

    http://msdn.microsoft.com/en-us/library/dh8che7s%28v=vs.110%29.aspx

    Recommend trying to stay with /Zc:wchar_t (the default) when
    adding libraries.  If incompatible, you'll typically get some
    missing ostream '<<' operators or something similar in the stream
    headers.

    2.  /Z7 (VC 7.0 compatibility symbols) gives us debug information
    in the static libraries we build.  Otherwise builds generate
    vc100.pdb files all over the place which generally aren't useful.
    DLL's and .EXEs are to get /Zi or /ZI with separate .PDB files.
    These .PDB files can then be packaged up in symbol tarballs for
    the crash dump analyzer or used in debugging.  There are issues here
    for VS 2013 (see below).


  Mac Targets

    Fairly straightforward, optimization level is easily changed (may
    be little or negative gain for -O3 and RelWithDebInfo should be
    kicked up to 1 or 2.  Boost debug symbols to dwarf-2 with a goal
    of dwarf-2 in separate dSYM file when building .dylibs and
    executables.

    ----------------------------------------------------------------------------
    Option                Release          RelWithDebInfo          Debug
    ----------------------------------------------------------------------------
    Strip Debug Symbols     On                   "                   "
    During Copy

    Generate Debug Syms     On                   "                   "

    Level Debug Syms    -gdwarf-2                "                   "

    Optimization           -O3                  -O0                 -O0

    PIC                -fPIC -DPIC               "                   "

    Defines        LL_RELEASE=1          LL_RELEASE=1               n/a
                   LL_RELEASE_FOR_DOWNLOAD=1    n/a                 n/a
                   NDEBUG                NDEBUG               _DEBUG
                           n/a                  n/a           LL_DEBUG=1
                           n/a           LL_RELEASE_WITH_\          n/a
                                         DEBUG_INFO=1
                   LL_DARWIN=1                   "                   "
                   LL_OS_DRAGDROP_ENABLED=1      "                   "
                   LIB_NDOF=1                    "                   "

    ----------------------------------------------------------------------------
    Notes:

    1.  We're also building dylibs in a somewhat unusual way.  They're
    currently being generated with a link path of
    '@executable_path/../Resources/<library>'.  If we were to follow
    the recommendations in dyld's man page, we’d instead reference
	'@loader_path/<library>', use -rpath on the executable link
    (pointing to the 'Resources' subdir of the main executable), and
    be able to avoid some symlinking in the .app tree.

    2.  Use the -headerpad_max_install_names link option on all .dylibs.


  Linux Targets

    Not much variety here.

    ----------------------------------------------------------------------------
    Option                Release          RelWithDebInfo          Debug
    ----------------------------------------------------------------------------
    Debug Level     -g (-g0/1 better?)          -g                  -g
    During Copy

    Optimization            -O2                 -O0                 -O0

    PIC                    -fPIC                 "                   "
    ----------------------------------------------------------------------------
    Notes:


Linking

    The library update work has generally moved in the direction of
    preferring static libraries over dynamic (Qt4 being the notable
    exception).  It also mostly eliminated the extremely bad practice
    of having multiple versions of a library built into an image.

    How bad was it?  Very.  Appalling.  A nightmare.  On Windows, at
    least four versions of zlib (1.2.3, 1.2.5, 1.2.6, unknown), three
    versions of Boost (1.45, 1.48, 1.52), two versions of OpenSSL
    (0.9.8q, 1.0.0g) and three different builds of libexpat
    2.0.5/1.5.2 were used.  Mac was worse with five builds or versions
    of zlib, two of PCRE, two of c-ares, and three of OpenSSL.  Linux
    topped that by adding two builds of libpng.

    DO NOT ALLOW THIS TO HAPPEN AGAIN.  It isn't enough to update a
    library and then stuff a new triplet of S3 URLs into the viewer's
    autobuild.xml.  If you update a library you MUST:

    *  Update the autobuild.xml of ALL consumers of the library.  In
    the case of zlib, that meant updating freetype, libpng, openssl,
    libxml2, fontconfig, curl, Boost, SDL, llqtwebkit, google-mock and
    colladadom.

    *  Confirm by test and observation that the consumers actually use
    your library rather than 'call home to mother' and find
    system-supplied versions of your library.  This may consist of
    watching configuration scripts, probing with ldd/depends/otool,
    pulling text out of binaries with 'strings'.  The previously-
    mentioned libraries all have a README.Linden file that gives
    examples specific to the consumer library.

    *  DO NOT RE-EXPORT LIBRARIES.  Colladadom was the worst offender
    of this rule.  As a shared library, it was re-exporting part, but
    not all, of Boost filesystem and system, some zlib, some PCRE,
    some libxml2 and minizip.  This meant that depending upon link-
    time and run-time symbol resolution, data constructed with one
    version of a library might be processed by a method built in a
    second, incompatible version of the library.  Switching colladadom
    to a static library ended the re-export problem.

    *  Preventing re-export is not sufficient.  Other libraries will
    still be shipped as shared and they can still have Singleton and
    Fragile Base Class issues.  A DLL may be built with a static
    archive of a library that has global data.  That same static
    archive might be linked into the application proper.  An object
    created with a method in the DLL may pass into a method in the
    application where the archive's global data has a second instance
    and no knowledge of the object.  This is a failure due to an
    assumption of Singleton global data which leads to some kind of
    failure.  This is the same effect as when, in Windows, both MSVCRT
    and MSVCRTD get activated in a program.  If you're lucky, some
    asserts fail in that case having to do with file handle global
    data.


Running

    Windows Debug Build.  Seems to have been rendered nearly useless
    by having the LL_CHECK_MEMORY define in llmemory.h calling
    _CrtCheckMemory().  Viewer is almost useful disabling this in
    llvoavatar code alone but not quite.


Futures

  Static Versus Dynamic Libraries

    One solution to the above linking problems is the use of static
    libraries for everything.  Single version, singleton instancing of
    data, etc.  But it's not the 1950's and we're not running our
    applications on bare metal.  Every platform comes with 100s of
    libraries waiting to interfere with operations by breaking the
    single-version and singleton-data assumption.

    Additionally, there are libraries that simply expect to be built
    into shared libraries.  Qt4 is one such.  The version we're using
    now, 4.7.1, is actually trying to disable both Webkit and plugin
    modules because we're building it statically on Mac and Linux.
    It's only because of configuration bugs that we're getting the
    functionality out of it that we want.

    With enough libraries and a single, global namespace, eventually
    there will be collisions and there may not be a warning.  All it
    takes is two programmers who thought that 'FILE * open_file(const
    char *);' was a safe signature to use between compilation units in
    their libraries and glorious debugging sessions are in your
    future.  Having debugged it, you will now become the proud owner
    of a one-off version of one of those libraries that uses a special
    symbol prefix which you will be maintaining forever.

    Lastly, we have some binary blobs that we must use as delivered.
    Executables can be isolated at run-time if necessary.  Shared
    libraries are a different problem.  They may bring their own
    library dependencies that affect link- and run-time symbol
    resolution and they'll impose that on us according to platform
    rules.

    So, what to do?  My natural bias for large software is to use
    shared libraries for everything.  It's a path to single-version
    and singleton data and isolates namespaces and prevents
    interactions.  It also has some field serviceability benefits if
    you need to debug some bizarre problem a user has.

    But there's a local preference for static.  Here, my
    rules-of-thumb are:

    * Static library used by default.

    * Shared library where the library must be built shared.

    * Shared library if that is the only means to enforce the
      single-version and singleton-data requirements.

    * Shared library *on a case-by-case basis* if the library is also
      provided by the platform and some benefit is plausible.  (An
      example of this is freetype/fontconfig on Linux.  The .so
      versions we build with, and incompletely ship, are inferior in
      behavior to the platform libraries.  By being shared libraries,
      the platform-supplied option is available to all Linux users.)

    In all cases, beware of cmake which appears to collapse and move
    library references in links.  This can drastically affect symbol
    resolution when there are multiple sources for a symbol.

  General

    VS 2013.  The /Z7 flag is rumored to be somewhat broken in 2013.
    But it also sounds like there are explicit controls to name .PDB
    files associated with static archives.  That would make this an
    ideal time to switch to /Zi or /ZI everywhere with explicit naming
    and bring all the .PDBs together.

    The embedded browser technology (e.g. Qt4 with Webkit) is the
    800-pound gorilla in the viewer.  When starting any major work,
    decide what changes you need here as those changes will propagate
    outwards forcing many other decisions (cf: /Zc:wchar_t- flag).

    The current package structure (./include, ./lib/release,
    ./lib/debug, etc.) really works against the conventions used by
    configure-like programs.  I wasted a lot of time getting each
    library to work with our structure without having to go back to
    automake/autoconf.  For Linux and Mac (and even for Windows), a
    structure like the following where each grouping is optional would
    probably save some work:

        ./debug/bin
               /include
               /lib
        ./debug/shared/bin
                      /include
                      /lib
        ./debug/static/bin
                      /include
                      /lib
        ./release/bin
                 /include
                 /lib
        ...

    In zlib and openssl and in a few of the libraries that consume
    them, I experimented with packaging both static and shared
    libraries and then having the consumer library move the unwanted
    pieces out of the way to use the library type of choice (see
    restore_dylibs() and restore_sos() functions).  It was a bit fussy
    and simplicity and clarity are the keys to maintaining libraries
    in the future.

    But it did suggest another approach.  The idea is that every build
    pre-stages inputs.  Before anything is built, package pieces are
    copied or symlinked from the 'stage/packages' area to the
    'stage/input' area.  Builds then proceed with a single set of
    -I/-L options for the dependencies.  And products are built and
    installed in a similar output staging structure for the next
    consumer:

        stage/packages/<package>/[above structure]
        stage/input/{bin,include,lib}
        stage/<package>/[above structure]

    Next library project.  I'd recommend working on the related set of
    libexpat, apr, aprutil, xmlrpc-epi.  We know libexpat has some
    updates that should improve stability.  Libapr consumes it and it
    could use some /Z7 flag work to get rid of some 1000's of PDB
    warnings and improve our debug symbols.

    Miscellany to be sorted out:

    * The packaging of libfreetype and libfontconfig on Linux.
    Determine what the right thing is, do it.

    * Maybe do something with ICU4C.  Qt5 will require it and a number
    of our packages can consume it typically replacing iconv or some
    other library.  But it is a huge bolus of static data.  It can be
    trimmed, but still.

    * Revisit openssl.  Package as a shared library?  Replace with
    LibreSSL when available?  Start using platform-supplied crypto?

