Changes between Initial Version and Version 1 of Guidelines/Separate


Ignore:
Timestamp:
Feb 14, 2010, 12:05:56 PM (13 years ago)
Author:
Daniel James
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Guidelines/Separate

    v1 v1  
     1= Guidelines for Authors of Boost Libraries Containing Separate Source = #intro
     2
     3These guidelines are designed for the authors of Boost
     4libraries which have separate source that need compiling in
     5order to use the library. Throughout, this guide refers to a
     6fictitious "whatever" library, so replace all occurrences of
     7"whatever" or "WHATEVER" with your own library's name when
     8copying the examples.
     9
     10== Changes Affecting Source Code == #source_changes
     11
     12=== Preventing Compiler ABI Clashes === #abi
     13
     14There are some compilers (mostly Microsoft Windows compilers
     15again!), which feature a range of compiler switches that alter
     16the ABI of C++ classes and functions. By way of example,
     17consider Borland's compiler which has the following
     18options:
     19{{{
     20-b    (on or off - effects enum sizes).
     21-Vx   (on or off - empty members).
     22-Ve   (on or off - empty base classes).
     23-aX   (alignment - 5 options).
     24-pX   (Calling convention - 4 options).
     25-VmX  (member pointer size and layout - 5 options).
     26-VC   (on or off, changes name mangling).
     27-Vl   (on or off, changes struct layout).
     28}}}
     29
     30These options are provided in addition to those affecting
     31which runtime library is used (more on which later); the total
     32number of combinations of options can be obtained by
     33multiplying together the individual options above, so that
     34gives 2*2*2*5*4*5*2*2 = 3200 combinations!
     35
     36The problem is that users often expect to be able to build
     37the Boost libraries and then just link to them and have
     38everything just plain work, no matter what their project
     39settings are. Irrespective of whether this is a reasonable
     40expectation or not, without some means of managing this issue,
     41the user may well find that their program will experience
     42strange and hard to track down crashes at runtime unless the
     43library they link to was built with the same options as their
     44project (changes to the default alignment setting are a prime
     45culprit). One way to manage this is with "prefix and suffix"
     46headers: these headers invoke compiler specific #pragma
     47directives to instruct the compiler that whatever code follows
     48was built (or is to be built) with a specific set of compiler
     49ABI settings.
     50
     51Boost.config provides the macro `BOOST_HAS_ABI_HEADERS` which
     52is set whenever there are prefix and suffix headers available
     53for the compiler in use, typical usage in a header like
     54this:
     55{{{
     56#ifndef BOOST_WHATEVER_HPP
     57#define BOOST_WHATEVER_HPP
     58
     59#include <boost/config.hpp>
     60
     61// this must occur after all of the includes and before any code appears:
     62#ifdef BOOST_HAS_ABI_HEADERS
     63#  include BOOST_ABI_PREFIX
     64#endif
     65//
     66// this header declares one class, and one function by way of examples:
     67//
     68class whatever
     69{
     70   // details.
     71};
     72
     73whatever get_whatever();
     74
     75// the suffix header occurs after all of our code:
     76#ifdef BOOST_HAS_ABI_HEADERS
     77#  include BOOST_ABI_SUFFIX
     78#endif
     79
     80#endif
     81}}}
     82
     83You can include this code in your library source files as
     84well if you want, although you probably shouldn't need to:
     85
     86 * If you ''don't'' use these in the library source
     87   files (but do in your library's headers) and the user
     88   attempts to compile the library source with a non-default ABI
     89   setting, then they will get compiler errors if there are any
     90   conflicts.
     91 * If you ''do'' include them in both the library's
     92   headers and the library source files, then the code should
     93   always compile no matter what the compiler settings used,
     94   although the result might not match what the user was
     95   expecting: since we've forced the ABI back into default
     96   mode.
     97
     98==== Rationale: ==== #abi.rationale
     99
     100Without some means of managing this issue, users often
     101report bugs along the line of "Your silly library always
     102crashes when I try and call it" and so on. These issues can be
     103extremely difficult and time consuming to track down, only to
     104discover in the end that it's a compiler setting that's changed
     105the ABI of the class and/or function types of the program
     106compared to those in the pre-compiled library. The use of
     107prefix/suffix headers can minimize this problem, although
     108probably not remove it completely.
     109
     110===== Counter Argument #1: ===== #abi.counter1
     111
     112Trust the user, if they want 13-byte alignment (!) let them
     113have it.
     114
     115===== Counter Argument #2: ===== #abi.counter2
     116
     117Prefix/suffix headers have a tendency to "spread" to other
     118boost libraries - for example if boost::shared_ptr<>
     119forms part of your class's ABI, then including prefix/suffix
     120headers in your code will be of no use unless shared_ptr.hpp
     121also uses them. Authors of header-only boost libraries may not
     122be so keen on this solution - with some justification - since
     123they don't face the same problem.
     124
     125=== Static or Dynamic Libraries === #static_or_dynamic
     126
     127When the users runtime is dynamically linked the Boost
     128libraries can be built either as dynamic libraries (.so's on
     129Unix platforms, .dll's on Windows) or as static libraries (.a's
     130on Unix, .lib's on Windows). So we have a choice as to which is
     131supported by default:
     132
     133 * On Unix platforms it typically makes no difference to the
     134   code: the user just selects in their makesfile which library
     135   they prefer to link to.
     136 * On Windows platforms, the code has to be specially
     137   annotated to support DLL's, so we need to pick one option as
     138   the default and one as an alternative.
     139 * On Windows platforms, we can inject special code to
     140   automatically select which library variant to link against:
     141   so again we need to decide which is to be the default (see
     142   the section on auto-linking below).
     143
     144The recomendation is to pick static linking by default.
     145
     146==== Rationale: ==== #static-or-dynamic.rationale
     147
     148There is no one policy that fits all here.
     149
     150The rationale for the current behaviour was inherited from
     151Boost.Regex (and it's ancestor regex++): this library
     152originally used dynamic linking by default whenever the runtime
     153was dynamic. It's actually safer that way should you be using
     154regex from a dll for example. However, this behavior brought a
     155persistent stream of user complaints: mainly about deployment,
     156all asking if static linking could be the default. After regex
     157changed behavior the complaints stopped, and the author hasn't
     158had one complaint about static linking by default being the
     159wrong choice.
     160
     161Note that other libraries might need to make other choices:
     162for example libraries that are intended to be used to implement
     163dll pluggin's would like need to use dynamic linking in almost
     164all cases.
     165
     166=== Supporting Windows Dll's === #windows-dlls
     167
     168On most Unix-like platforms no special annotations of source
     169code are required in order for that source to be compiled as a
     170shared library because all external symbols are exposed.
     171However the majority of Windows compilers require that symbols
     172that are to be imported or exported from a dll, be prefixed
     173with `__declspec(dllimport)` or `__declspec(dllexport)`. Without
     174this mangling of source code, it is not possible to correctly
     175build shared libraries on Windows (historical note - originally
     176these declaration modifiers were required on 16-bit Windows
     177where the memory layout for exported classes was different from
     178that of "local" classes - although this is no longer an issue,
     179there is still no way to instruct the linker to "export
     180everything", it also remains to be seen whether 64-bit Windows
     181will resurrect the segmented architecture that led to this
     182problem in the first place. Note also that the mangled names of
     183exported symbols are different from non-exported ones, so
     184`__declspec(dllimport)` is required in order to link to code
     185within a dll).
     186
     187In order to support the building of shared libraries on MS
     188Windows your code will have to prefix all the symbols that your
     189library exports with a macro (lets call it `BOOST_WHATEVER_DECL`)
     190that your library will define to expand to either
     191`__declspec(dllexport)` or `__declspec(dllimport)` or nothing,
     192depending upon how your library is being built or used. Typical
     193usage would look like this:
     194{{{
     195#ifndef BOOST_WHATEVER_HPP
     196#define BOOST_WHATEVER_HPP
     197
     198#include <boost/config.hpp>
     199
     200#ifdef BOOST_HAS_DECLSPEC // defined in config system
     201// we need to import/export our code only if the user has specifically
     202// asked for it by defining either BOOST_ALL_DYN_LINK if they want all boost
     203// libraries to be dynamically linked, or BOOST_WHATEVER_DYN_LINK
     204// if they want just this one to be dynamically liked:
     205#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_WHATEVER_DYN_LINK)
     206// export if this is our own source, otherwise import:
     207#ifdef BOOST_WHATEVER_SOURCE
     208# define BOOST_WHATEVER_DECL __declspec(dllexport)
     209#else
     210# define BOOST_WHATEVER_DECL __declspec(dllimport)
     211#endif  // BOOST_WHATEVER_SOURCE
     212#endif  // DYN_LINK
     213#endif  // BOOST_HAS_DECLSPEC
     214//
     215// if BOOST_WHATEVER_DECL isn't defined yet define it now:
     216#ifndef BOOST_WHATEVER_DECL
     217#define BOOST_WHATEVER_DECL
     218#endif
     219
     220//
     221// this header declares one class, and one function by way of examples:
     222//
     223class BOOST_WHATEVER_DECL whatever
     224{
     225   // details.
     226};
     227
     228BOOST_WHATEVER_DECL whatever get_whatever();
     229
     230#endif
     231}}}
     232
     233And then in the source code for this library one would use:
     234
     235{{{
     236 
     237//
     238// define BOOST_WHATEVER SOURCE so that our library's
     239// setup code knows that we are building the library (possibly exporting code),
     240// rather than using it (possibly importing code):
     241//
     242#define BOOST_WHATEVER_SOURCE
     243#include <boost/whatever.hpp>
     244
     245// class members don't need any further annotation:
     246whatever::whatever() { }
     247// but functions do:
     248BOOST_WHATEVER_DECL whatever get_whatever()
     249{
     250   return whatever();
     251}
     252}}}
     253
     254==== Importing/exporting dependencies ==== #importing-exporting
     255
     256As well as exporting your main classes and functions (those
     257that are actually documented), Microsoft Visual C++ will warn
     258loudly and often if you try to import/export a class whose
     259dependencies are not also exported. Dependencies include: any
     260base classes, any user defined types used as data members, plus
     261all of the dependencies of your dependencies and so on. This
     262causes particular problems when a dependency is a template
     263class, because although it is technically possible to export
     264these, it is not at all easy, especially if the template itself
     265has dependencies which are implementation-specific details. In
     266most cases it's probably better to simply suppress the warnings
     267using:
     268
     269{{{
     270#ifdef BOOST_MSVC
     271#  pragma warning(push)
     272#  pragma warning(disable : 4251 4231 4660)
     273#endif
     274
     275// code here
     276
     277#ifdef BOOST_MSVC
     278#pragma warning(pop)
     279#endif
     280}}}
     281
     282This is safe provided that there are no dependencies that
     283are (template) classes with non-constant static data members,
     284these really do need exporting, otherwise there will be
     285multiple copies of the static data members in the program, and
     286that's really really bad.
     287
     288Historical note: on 16-bit Windows you really did have to
     289export all dependencies or the code wouldn't work, however
     290since the latest Visual Studio .NET supports the import/export
     291of individual member functions, it's a reasonably safe bet that
     292Windows compilers won't do anything nasty - like changing the
     293class's ABI - when importing/exporting a class.
     294
     295==== Rationale: ==== #importing-exporting.rationale
     296
     297''Why bother - doesn't the import/export mechanism take up
     298more code that the classes themselves?''
     299
     300A good point, and probably true, however there are some
     301circumstances where library code must be placed in a shared
     302library - for example when the application consists of multiple
     303dll's as well as the executable, and more than one those dll's
     304link to the same Boost library - in this case if the library
     305isn't dynamically linked and it contains any global data (even
     306if that data is private to the internals of the library) then
     307really bad things can happen - even without global data, we
     308will still get a code bloating effect. Incidentally, for larger
     309applications, splitting the application into multiple dll's can
     310be highly advantageous - by using Microsoft's "delay load"
     311feature the application will load only those parts it really
     312needs at any one time, giving the impression of a much more
     313responsive and faster-loading application.
     314
     315''Why static linking by default?''
     316
     317In the worked example above, the code assumes that the
     318library will be statically linked unless the user asks
     319otherwise. Most users seem to prefer this (there are no
     320separate dll's to distribute, and the overall distribution size
     321is often significantly smaller this way as well: i.e. you pay
     322for what you use and no more), but this is a subjective call,
     323and some libraries may even only be available in dynamic
     324versions (Boost.threads for example).
     325
     326=== Automatic Library Selection and Linking with [http://www.boost.org/doc/libs/release/boost/config/auto_link.hpp auto_link.hpp] === #auto-link
     327
     328Many Windows compilers ship with multiple runtime libraries
     329- for example Microsoft Visual Studio .NET comes with 6
     330versions of the C and C++ runtime. It is essential that the
     331Boost library that the user links to is built against the same
     332C runtime as the program is built against. If that is not the
     333case, then the user will experience linker errors at best, and
     334runtime crashes at worst. The Boost build system manages this
     335by providing different build variants, each of which is build
     336against a different runtime, and gets a slightly different
     337mangled name depending upon which runtime it is built against.
     338For example the regex libraries get named as follows when built
     339with Visual Studio .NET 2003:
     340
     341{{{
     342boost_regex-vc71-mt-1_31.lib
     343boost_regex-vc71-mt-gd-1_31.lib
     344libboost_regex-vc71-mt-1_31.lib
     345libboost_regex-vc71-mt-gd-1_31.lib
     346libboost_regex-vc71-mt-s-1_31.lib
     347libboost_regex-vc71-mt-sgd-1_31.lib
     348libboost_regex-vc71-s-1_31.lib
     349libboost_regex-vc71-sgd-1_31.lib
     350}}}
     351
     352The difficulty now is selecting which of these the user
     353should link his or her code to.
     354
     355In contrast, most Unix compilers typically only have one
     356runtime (or sometimes two if there is a separate thread safe
     357option). For these systems the only choice in selecting the
     358right library variant is whether they want debugging info, and
     359possibly thread safety.
     360
     361Historically Microsoft Windows compilers have managed this
     362issue by providing a #pragma option that allows the header for
     363a library to automatically select the library to link to. This
     364makes everything automatic and extremely easy for the end user:
     365as soon as they include a header file that has separate source
     366code, the name of the right library build variant gets embedded
     367in the object file, and as long as that library is in the
     368linker search path, it will get pulled in by the linker without
     369any user intervention.
     370
     371Automatic library selection and linking can be enabled for a
     372Boost library by including the header
     373<boost/config/auto_link.hpp>, after first defining
     374BOOST_LIB_NAME and, if applicable, BOOST_DYN_LINK.
     375
     376{{{
     377//
     378// Automatically link to the correct build variant where possible.
     379//
     380#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_WHATEVER_NO_LIB) && !defined(BOOST_WHATEVER_SOURCE)
     381//
     382// Set the name of our library, this will get undef'ed by auto_link.hpp
     383// once it's done with it:
     384//
     385#define BOOST_LIB_NAME boost_whatever
     386//
     387// If we're importing code from a dll, then tell auto_link.hpp about it:
     388//
     389#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_WHATEVER_DYN_LINK)
     390#  define BOOST_DYN_LINK
     391#endif
     392//
     393// And include the header that does the work:
     394//
     395#include <boost/config/auto_link.hpp>
     396#endif  // auto-linking disabled
     397}}}
     398
     399The library's user documentation should note that the
     400feature can be disabled by defining either BOOST_ALL_NO_LIB or
     401BOOST_WHATEVER_NO_LIB:
     402
     403If for any reason you need to debug this feature, the header
     404<boost/config/auto_link.hpp> will output some helpful
     405diagnostic messages if you first define
     406BOOST_LIB_DIAGNOSTIC.
     407
     408== Changes Affecting the Build System == #build_changes
     409
     410=== Creating the library Jamfile === #jamfile
     411
     412The Jamfile for building library "whatever" typically lives
     413in boost-root/libs/whatever/build, the only extra step required
     414is to add a <define> requirement to the library target so
     415that your code knows whether it's building a dll or static
     416library, a typical Jamfile would like like this:
     417
     418{{{
     419lib boost_regex : ../src/whatever.cpp :
     420  <link>shared:<define>BOOST_WHATEVER_DYN_LINK=1 ;
     421}}}
     422
     423=== Testing Auto-linking === #testing
     424
     425Testing the auto-link feature is somewhat convoluted, and
     426requires access to a compiler that supports the feature: refer
     427to
     428[http://www.boost.org/doc/libs/release/libs/config/test/link/test/Jamfile.v2 libs/config/test/link/test/Jamfile.v2]
     429for an example.