You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Documentation on when/why/how to write _impl.hpp #12
@tmpsantos thanks for working on mapbox/geojson-cpp#24. Now I'd like your help in documenting your work so others can do this again for further projects. Can you write up a quick guide on how you accomplished this, key terms, and why you chose _impl.hpp as an extention (let's standardize on that). Drop your notes into this ticket as a comment please and then we'll integrate into the main readme.
Header-only libraries are often easier to include in a project than external dependencies because they get compiled together with the project using them and they can just get bundled together with the project source files in a src/third-party directory.
This will make sure they get compiled with the same compiler flags as you use for your project and you don't need to build a new dependency package for every new architecture/operating system combination you support.
C++ libraries heavily using templates make a good candidate for a header-only library because templates are often implemented completely in a header. This is true as long as the header-only library does not have a dependency by itself.
Making header-only optional, geojson-cpp case
A library like geojson-cpp is small enough to be a good candidate for a header-only library. The problem is it depends on rapidjson, which is another header-only library.
Building it as a static library means we can hide the dependency on rapidjson. Deploying it as a header-only library assumes the project using geojson-cpp also depends on rapidjson, which is the case for Mapbox GL Native but not exactly obvious for developers only interested on a GeoJSON parser.
The _impl.hpp pattern
Fortunately there is a clean way to make a dependency be both a pre-compiled library and a header-only library, giving developers choice.
In the case of geojson-cpp, the part of the project depending on rapidjson got isolated in another header called geojson_impl.hpp. The project has a geojson.cpp that includes the implementation header:
#include <mapbox/geojson_impl.hpp>
Now the developer using geojson-cpp as a project dependency has two choices:
Include geojson.hpp and link with libgeojson.a.
or:
Include geojson.hpp, geojson_impl.hpp and make sure the project also has the headers for rapidjson available in the include path.
Including geojson_impl.hpp AND linking with libgeojson.a will cause a link error because the symbols are going to get duplicated. Remember that libgeojson.a was made from geojson.cpp that includes geojson_impl.hpp. It is like having geojson_impl.cpp at the end of the day.
Mason package
mason handles header-only packages differently from static/shared libraries. The header-only package is explicitly marked as MASON_HEADER_ONLY=true on the package description script.
When packing a library that offers both options, the library has to be packaged twice for each release, as we did for geojson-cpp:
When publishing the package to AWS, they won't conflict because they get posted to different directories.
Using in a project with mason and cmake
A project using geojson-cpp static library would simple need to add the following line to the build system:
mason_use(geojson VERSION 0.3.2)
Another project using the header only version would have to do:
mason_use(rapidjson VERSION 1.1.0 HEADER_ONLY)
mason_use(geojson VERSION 0.3.2 HEADER_ONLY)
Note that rapidjson is also needed in this case. Your project will also need to build a .cpp file including geojson_impl.hpp to satisfy the missing symbols like we have in Mapbox GL Native.
Activity
tmpsantos commentedon Oct 18, 2016
Motivations
Header-only libraries are often easier to include in a project than external dependencies because they get compiled together with the project using them and they can just get bundled together with the project source files in a
src/third-partydirectory.This will make sure they get compiled with the same compiler flags as you use for your project and you don't need to build a new dependency package for every new architecture/operating system combination you support.
C++ libraries heavily using templates make a good candidate for a header-only library because templates are often implemented completely in a header. This is true as long as the header-only library does not have a dependency by itself.
Making header-only optional,
geojson-cppcaseA library like
geojson-cppis small enough to be a good candidate for a header-only library. The problem is it depends onrapidjson, which is another header-only library.Building it as a static library means we can hide the dependency on
rapidjson. Deploying it as a header-only library assumes the project usinggeojson-cppalso depends onrapidjson, which is the case for Mapbox GL Native but not exactly obvious for developers only interested on a GeoJSON parser.The
_impl.hpppatternFortunately there is a clean way to make a dependency be both a pre-compiled library and a header-only library, giving developers choice.
In the case of
geojson-cpp, the part of the project depending onrapidjsongot isolated in another header calledgeojson_impl.hpp. The project has ageojson.cppthat includes the implementation header:Now the developer using
geojson-cppas a project dependency has two choices:geojson.hppand link withlibgeojson.a.or:
geojson.hpp,geojson_impl.hppand make sure the project also has the headers forrapidjsonavailable in the include path.Including
geojson_impl.hppAND linking withlibgeojson.awill cause a link error because the symbols are going to get duplicated. Remember thatlibgeojson.awas made fromgeojson.cppthat includesgeojson_impl.hpp. It is like havinggeojson_impl.cppat the end of the day.Mason package
masonhandles header-only packages differently from static/shared libraries. The header-only package is explicitly marked asMASON_HEADER_ONLY=trueon the package description script.When packing a library that offers both options, the library has to be packaged twice for each release, as we did for
geojson-cpp:https://github.com/mapbox/mason/blob/master/scripts/geojson/0.3.2/script.sh
https://github.com/mapbox/mason/blob/master/scripts/geojson/0.3.2-hpp/script.sh
When publishing the package to AWS, they won't conflict because they get posted to different directories.
Using in a project with
masonandcmakeA project using
geojson-cppstatic library would simple need to add the following line to the build system:Another project using the header only version would have to do:
Note that
rapidjsonis also needed in this case. Your project will also need to build a.cppfile includinggeojson_impl.hppto satisfy the missing symbols like we have in Mapbox GL Native.tmpsantos commentedon Oct 18, 2016
@springmeyer feel free to edit/add. Let me know if there is any other aspect of the
_impl.hppyou need better explained.springmeyer commentedon Oct 20, 2016
@tmpsantos this looks fantastic, thank you 🙏