summaryrefslogtreecommitdiff
path: root/ARCHITECTURE.md
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-06-01 12:55:17 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-06-02 16:02:19 -0700
commit49d3807e28d5f67c105f3bd92db12d8f32ae44f2 (patch)
tree05423e8e6e56a1d47ca914002aeef45cf9335f05 /ARCHITECTURE.md
parente1a58565c88a80e5b68181e69fd3a8b4bfe3e85c (diff)
downloadqtlocation-mapboxgl-49d3807e28d5f67c105f3bd92db12d8f32ae44f2.tar.gz
[docs] Start ARCHITECTURE.md
Diffstat (limited to 'ARCHITECTURE.md')
-rw-r--r--ARCHITECTURE.md72
1 files changed, 72 insertions, 0 deletions
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
new file mode 100644
index 0000000000..e971d9cccc
--- /dev/null
+++ b/ARCHITECTURE.md
@@ -0,0 +1,72 @@
+This document aims to outline at a high level the various parts that make up mapbox-gl-native and how they work together.
+
+# Repository structure
+
+mapbox-gl-native uses a monolithic that houses both core C++ code and code that wraps the C++ core with SDKs for Android, iOS, OS X, Node.js, and Qt. A "monorepo" allows us to:
+
+ * Make changes to the core API and SDKs simultaneously, ensuring no platform falls behind.
+ * Ensure that core changes do not inadvertently break SDK tests.
+ * Centralize discussions about features and defects that affect multiple platforms.
+
+In the repository, core C++ code is contained in the `include` and `src` directories. The former includes headers that are considered to make up the "public" core C++ API, while the latter includes `.cpp` implementation files and headers that are private to the implementation. Within both directories, files are nested under an `mbgl` directory, which has various subdirectories based on areas of functionality. Both public and private headers therefore can (and should) always be included with the form `#include <mbgl/___/___.hpp>`.
+
+Code and build scripts belonging to platform SDKs are contained in the `platform` directory, which has subdirectories for each platform. The `platform/darwin` and `platform/default` directories contain code shared by multiple platform SDKs.
+
+# Build system
+
+The mapbox-gl-native build system uses a variety of tools.
+
+## Make
+
+GNU Make and a master `Makefile` serves as the coordinating tool for all other build system tools. Most of your interaction with the build system will be via `make` commands. We aim to have a consistent pattern for make targets across platforms: for a given platform, e.g. `ios`, `make ios` builds a reasonable set of end products (though perhaps not all permutations of build options, which can be prohibitively expensive), and `make test-ios` runs a complete test suite for the platform.
+
+## Git submodules
+
+Git submodules are used to pull in several dependencies: mason (see below) and several iOS dependencies (though we have plans to phase these out). Initializing these submodules is handled automatically by the necessary `make` targets.
+
+## npm
+
+npm is a package manager for Node.js. mapbox-gl-native uses it to pull in several development dependencies that happen to be packaged as node modules -- mainly for testing needs.
+
+## Mason
+
+[Mason](https://github.com/mapbox/mason) is Mapbox's own cross platform C/C++ package manager. mapbox-gl-native uses mason packages as a source of precompiled binaries for third-party dependencies such as Boost, RapidJSON, and SQLite, and Mapbox's own C++ modules such as [earcut.hpp](https://github.com/mapbox/earcut.hpp) and [geojson-vt-cpp](https://github.com/mapbox/geojson-vt-cpp). It is also used to obtain a toolchain for Android platform cross-compiliation.
+
+We track mason dependencies for a given platform in the file `platform/<platform>/scripts/configure.sh`. The `configure` script at the root handles sourcing this file during the build, running the appropriate mason commands, and writing configuration settings for the subsequent build to a `config.gypi` in the build output directory.
+
+## gyp
+
+[gyp](https://gyp.gsrc.io/) is a build system originally created for Chromium and since adopted by Node.js. In mapbox-gl-native it's used to build the core C++ static library, the Node.js platform module, and the shared JNI module for Android.
+
+## Platform-specific subsystems
+
+Outside of the core C++ static library, platform SDKs typically rely on platform-native build tooling to complete the job.
+
+* For iOS and OS X this means Xcode and the xcodebuild command line tool.
+* For Android, Gradle and Android Studio.
+* For Qt, `qmake`.
+
+See the relevant platform-specific `README.md` / `INSTALL.md` for details.
+
+# Major functional components
+
+## Map
+## Style
+## FileSource
+## Layout
+## Rendering
+## Annotations
+
+# Threading
+
+At runtime, mapbox-gl-native uses the following threads:
+
+* The "main thread" (or other thread on which a `Map` object is created) handles direct `Map` API requests, owns the active `Style` and its associated objects, and renders the map. Since this thread is usually dispatching events triggered by user input, it's important that these duties not require significant computation or perform blocking I/O that would cause UI jank or hangs.
+* Many of the tasks that require significant computation are associated with layout and styling of map features: parsing vector tiles, computing text layout, and generating data buffers to be consumed by OpenGL. This work happens on "worker threads" that are spawned by the main thread, four per `Style` object. The `Style` and its associated objects handle dispatching tasks to the workers, typically on a tile-by-tile basis.
+* A "FileSource" thread handles network requests for styles, tiles, and other resources, and I/O on the SQLite database used for offline maps and caching. Requests originate from the main thread, are dispatched by a FileSource internally to its thread, and results are returned to the main thread via an asynchronous callback function. (This is implemented with platform-specific hooks into the native message pump for the requesting thread.)
+
+To minimize data races and invalid memory access, we aim for zero shared memory state between any two threads. Cross-thread communication occurs via one thread requesting the "invocation" of a task on another thread. The parameters for this task should be passed as value objects, so that they are copied, or as ownership-transferring values such as `std::unique_ptr`. (We're [not entirely there yet](https://github.com/mapbox/mapbox-gl-native/issues/667), but that's the goal.) The result (if any) is likewise passed as a value or ownership-transferring parameter to the callback function.
+
+Invoking a task on another thread itself creates an ownership obligation: the responsibility for the work happening on the other thread. This ownership is represented by the invocation method returning `std::unique_ptr<AsyncTask>`. Destroying this object indicates that the result of the task is no longer required: the callback is guaranteed not to be called, and the work on the other thread may be aborted (if doing so is convenient).
+
+All this is implemented by [Thread](https://github.com/mapbox/mapbox-gl-native/blob/master/src/mbgl/util/thread.hpp) and [RunLoop](https://github.com/mapbox/mapbox-gl-native/blob/master/include/mbgl/util/run_loop.hpp).